mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-21 19:42:05 +01:00
Re-implementing the vCard provider using a pull parser. Extended unit tests.
This commit is contained in:
parent
1630b44b8d
commit
0b4072ad66
3 changed files with 502 additions and 319 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -24,3 +24,4 @@ experimental/bin
|
||||||
extensions/bin
|
extensions/bin
|
||||||
|
|
||||||
target/
|
target/
|
||||||
|
.metadata
|
||||||
|
|
|
@ -18,339 +18,321 @@ package org.jivesoftware.smackx.vcardtemp.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
|
||||||
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
|
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.w3c.dom.Text;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vCard provider.
|
* vCard provider.
|
||||||
*
|
*
|
||||||
* @author Gaston Dombiak
|
* @author Gaston Dombiak
|
||||||
* @author Derek DeMoro
|
* @author Derek DeMoro
|
||||||
|
* @author Chris Deering
|
||||||
*/
|
*/
|
||||||
public class VCardProvider extends IQProvider<VCard> {
|
public class VCardProvider extends IQProvider<VCard> {
|
||||||
private static final Logger LOGGER = Logger.getLogger(VCardProvider.class.getName());
|
|
||||||
|
|
||||||
private static final String PREFERRED_ENCODING = "UTF-8";
|
|
||||||
|
|
||||||
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY;
|
// @formatter:off
|
||||||
|
private static final String[] ADR = new String[] {
|
||||||
|
"POSTAL",
|
||||||
|
"PARCEL",
|
||||||
|
"DOM",
|
||||||
|
"INTL",
|
||||||
|
"PREF",
|
||||||
|
"POBOX",
|
||||||
|
"EXTADR",
|
||||||
|
"STREET",
|
||||||
|
"LOCALITY",
|
||||||
|
"REGION",
|
||||||
|
"PCODE",
|
||||||
|
"CTRY",
|
||||||
|
"FF",
|
||||||
|
};
|
||||||
|
|
||||||
static {
|
private static final String[] TEL = new String[] {
|
||||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
"VOICE",
|
||||||
try {
|
"FAX",
|
||||||
documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
"PAGER",
|
||||||
} catch (ParserConfigurationException e) {
|
"MSG",
|
||||||
LOGGER.finer("Could not disallow doctype decl: " + e.getMessage());
|
"CELL",
|
||||||
// If we can't disable DTDs, then at least try the following
|
"VIDEO",
|
||||||
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
"BBS",
|
||||||
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
|
"MODEM",
|
||||||
try {
|
"ISDN",
|
||||||
documentBuilderFactory.setFeature( "http://xml.org/sax/features/external-general-entities", false);
|
"PCS",
|
||||||
documentBuilderFactory.setFeature( "http://xml.org/sax/features/external-parameter-entities", false);
|
"PREF",
|
||||||
} catch (ParserConfigurationException e1) {
|
};
|
||||||
LOGGER.finer("Could not disallow external entities for xerces parser: " + e1.getMessage());
|
// @formatter:on
|
||||||
}
|
|
||||||
}
|
|
||||||
// Android throws an UnsupportedOperationException when calling setXIncludeAware() and for some dumb reason also
|
|
||||||
// when calling isXIncludeWare(), while it defaults according to the docs to 'false'.
|
|
||||||
boolean isXIncludeAware;
|
|
||||||
try {
|
|
||||||
isXIncludeAware = documentBuilderFactory.isXIncludeAware();
|
|
||||||
} catch (UnsupportedOperationException e) {
|
|
||||||
// Assume we are on Android where isXIncludeAware defaults to 'false'
|
|
||||||
isXIncludeAware = false;
|
|
||||||
}
|
|
||||||
if (isXIncludeAware) {
|
|
||||||
documentBuilderFactory.setXIncludeAware(false);
|
|
||||||
}
|
|
||||||
documentBuilderFactory.setExpandEntityReferences(false);
|
|
||||||
|
|
||||||
// Harden the parser even further
|
|
||||||
documentBuilderFactory.setIgnoringComments(true);
|
|
||||||
documentBuilderFactory.setCoalescing(false);
|
|
||||||
documentBuilderFactory.setValidating(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
|
||||||
} catch (ParserConfigurationException e) {
|
|
||||||
LOGGER.info("Could not enable secure processing parsing feature: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
DOCUMENT_BUILDER_FACTORY = documentBuilderFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VCard parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException {
|
public VCard parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException,
|
||||||
final StringBuilder sb = new StringBuilder();
|
SmackException {
|
||||||
try {
|
VCard vCard = new VCard();
|
||||||
int event = parser.getEventType();
|
String name = null;
|
||||||
// get the content
|
|
||||||
while (true) {
|
outerloop: while (true) {
|
||||||
switch (event) {
|
int eventType = parser.next();
|
||||||
case XmlPullParser.TEXT:
|
switch (eventType) {
|
||||||
// We must re-escape the xml so that the DOM won't throw an exception
|
case XmlPullParser.START_TAG:
|
||||||
sb.append(StringUtils.escapeForXML(parser.getText()));
|
name = parser.getName();
|
||||||
break;
|
switch (name) {
|
||||||
case XmlPullParser.START_TAG:
|
case "N":
|
||||||
sb.append('<').append(parser.getName()).append('>');
|
parseName(parser, vCard);
|
||||||
break;
|
break;
|
||||||
case XmlPullParser.END_TAG:
|
case "ORG":
|
||||||
sb.append("</").append(parser.getName()).append('>');
|
parseOrg(parser, vCard);
|
||||||
break;
|
break;
|
||||||
default:
|
case "TEL":
|
||||||
|
parseTel(parser, vCard);
|
||||||
|
break;
|
||||||
|
case "ADR":
|
||||||
|
parseAddress(parser, vCard);
|
||||||
|
break;
|
||||||
|
case "EMAIL":
|
||||||
|
parseEmail(parser, vCard);
|
||||||
|
break;
|
||||||
|
case "NICKNAME":
|
||||||
|
vCard.setNickName(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "JABBERID":
|
||||||
|
vCard.setJabberId(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "PHOTO":
|
||||||
|
parsePhoto(parser, vCard);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if (event == XmlPullParser.END_TAG && "vCard".equals(parser.getName())) break;
|
case XmlPullParser.TEXT:
|
||||||
|
if (initialDepth + 1 == parser.getDepth()) {
|
||||||
event = parser.next();
|
vCard.setField(name, parser.getText());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (XmlPullParserException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Exception parsing VCard", e);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Exception parsing VCard", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
String xmlText = sb.toString();
|
|
||||||
try {
|
|
||||||
return createVCardFromXML(xmlText);
|
|
||||||
} catch (SAXException | ParserConfigurationException e) {
|
|
||||||
throw new SmackException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a users vCard from xml file.
|
|
||||||
*
|
|
||||||
* @param xml the xml representing a users vCard.
|
|
||||||
* @return the VCard.
|
|
||||||
* @throws IOException
|
|
||||||
* @throws SAXException
|
|
||||||
* @throws UnsupportedEncodingException
|
|
||||||
* @throws ParserConfigurationException
|
|
||||||
*/
|
|
||||||
public static VCard createVCardFromXML(String xml) throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException {
|
|
||||||
VCard vCard = new VCard();
|
|
||||||
|
|
||||||
DocumentBuilder documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
|
|
||||||
Document document = documentBuilder.parse(
|
|
||||||
new ByteArrayInputStream(xml.getBytes(PREFERRED_ENCODING)));
|
|
||||||
|
|
||||||
new VCardReader(vCard, document).initializeFields();
|
|
||||||
return vCard;
|
return vCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class VCardReader {
|
private static void parseAddress(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
private final VCard vCard;
|
boolean isWork = true;
|
||||||
private final Document document;
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
VCardReader(VCard vCard, Document document) {
|
switch (eventType) {
|
||||||
this.vCard = vCard;
|
case XmlPullParser.START_TAG:
|
||||||
this.document = document;
|
String name = parser.getName();
|
||||||
}
|
if ("HOME".equals(name)) {
|
||||||
|
isWork = false;
|
||||||
public void initializeFields() {
|
|
||||||
vCard.setFirstName(getTagContents("GIVEN"));
|
|
||||||
vCard.setLastName(getTagContents("FAMILY"));
|
|
||||||
vCard.setMiddleName(getTagContents("MIDDLE"));
|
|
||||||
setupPhoto();
|
|
||||||
|
|
||||||
setupEmails();
|
|
||||||
|
|
||||||
vCard.setOrganization(getTagContents("ORGNAME"));
|
|
||||||
vCard.setOrganizationUnit(getTagContents("ORGUNIT"));
|
|
||||||
|
|
||||||
setupSimpleFields();
|
|
||||||
|
|
||||||
setupPhones();
|
|
||||||
setupAddresses();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupPhoto() {
|
|
||||||
String binval = null;
|
|
||||||
String mimetype = null;
|
|
||||||
|
|
||||||
NodeList photo = document.getElementsByTagName("PHOTO");
|
|
||||||
if (photo.getLength() != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Node photoNode = photo.item(0);
|
|
||||||
NodeList childNodes = photoNode.getChildNodes();
|
|
||||||
|
|
||||||
int childNodeCount = childNodes.getLength();
|
|
||||||
List<Node> nodes = new ArrayList<Node>(childNodeCount);
|
|
||||||
for (int i = 0; i < childNodeCount; i++)
|
|
||||||
nodes.add(childNodes.item(i));
|
|
||||||
|
|
||||||
String name = null;
|
|
||||||
String value = null;
|
|
||||||
for (Node n : nodes) {
|
|
||||||
name = n.getNodeName();
|
|
||||||
value = n.getTextContent();
|
|
||||||
if (name.equals("BINVAL")) {
|
|
||||||
binval = value;
|
|
||||||
}
|
|
||||||
else if (name.equals("TYPE")) {
|
|
||||||
mimetype = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binval == null || mimetype == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vCard.setAvatar(binval, mimetype);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupEmails() {
|
|
||||||
NodeList nodes = document.getElementsByTagName("USERID");
|
|
||||||
if (nodes == null) return;
|
|
||||||
for (int i = 0; i < nodes.getLength(); i++) {
|
|
||||||
Element element = (Element) nodes.item(i);
|
|
||||||
if ("WORK".equals(element.getParentNode().getFirstChild().getNodeName())) {
|
|
||||||
vCard.setEmailWork(getTextContent(element));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
vCard.setEmailHome(getTextContent(element));
|
for (String adr : ADR) {
|
||||||
}
|
if (adr.equals(name)) {
|
||||||
}
|
if (isWork) {
|
||||||
}
|
vCard.setAddressFieldWork(name, parser.nextText());
|
||||||
|
}
|
||||||
private void setupPhones() {
|
else {
|
||||||
NodeList allPhones = document.getElementsByTagName("TEL");
|
vCard.setAddressFieldHome(name, parser.nextText());
|
||||||
if (allPhones == null) return;
|
}
|
||||||
for (int i = 0; i < allPhones.getLength(); i++) {
|
}
|
||||||
NodeList nodes = allPhones.item(i).getChildNodes();
|
|
||||||
String type = null;
|
|
||||||
String code = null;
|
|
||||||
String value = null;
|
|
||||||
for (int j = 0; j < nodes.getLength(); j++) {
|
|
||||||
Node node = nodes.item(j);
|
|
||||||
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
|
|
||||||
String nodeName = node.getNodeName();
|
|
||||||
if ("NUMBER".equals(nodeName)) {
|
|
||||||
value = getTextContent(node);
|
|
||||||
}
|
|
||||||
else if (isWorkHome(nodeName)) {
|
|
||||||
type = nodeName;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
code = nodeName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (value == null) continue;
|
break;
|
||||||
if (code == null)
|
case XmlPullParser.END_TAG:
|
||||||
code = "VOICE";
|
if (parser.getDepth() == initialDepth) {
|
||||||
if ("HOME".equals(type)) {
|
break outerloop;
|
||||||
vCard.setPhoneHome(code, value);
|
|
||||||
}
|
}
|
||||||
else { // By default, setup work phone
|
break;
|
||||||
vCard.setPhoneWork(code, value);
|
default:
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWorkHome(String nodeName) {
|
|
||||||
return "HOME".equals(nodeName) || "WORK".equals(nodeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddresses() {
|
|
||||||
NodeList allAddresses = document.getElementsByTagName("ADR");
|
|
||||||
if (allAddresses == null) return;
|
|
||||||
for (int i = 0; i < allAddresses.getLength(); i++) {
|
|
||||||
Element addressNode = (Element) allAddresses.item(i);
|
|
||||||
|
|
||||||
String type = null;
|
|
||||||
List<String> code = new ArrayList<String>();
|
|
||||||
List<String> value = new ArrayList<String>();
|
|
||||||
NodeList childNodes = addressNode.getChildNodes();
|
|
||||||
for (int j = 0; j < childNodes.getLength(); j++) {
|
|
||||||
Node node = childNodes.item(j);
|
|
||||||
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
|
|
||||||
String nodeName = node.getNodeName();
|
|
||||||
if (isWorkHome(nodeName)) {
|
|
||||||
type = nodeName;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
code.add(nodeName);
|
|
||||||
value.add(getTextContent(node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int j = 0; j < value.size(); j++) {
|
|
||||||
if ("HOME".equals(type)) {
|
|
||||||
vCard.setAddressFieldHome((String) code.get(j), (String) value.get(j));
|
|
||||||
}
|
|
||||||
else { // By default, setup work address
|
|
||||||
vCard.setAddressFieldWork((String) code.get(j), (String) value.get(j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTagContents(String tag) {
|
|
||||||
NodeList nodes = document.getElementsByTagName(tag);
|
|
||||||
if (nodes != null && nodes.getLength() == 1) {
|
|
||||||
return getTextContent(nodes.item(0));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupSimpleFields() {
|
|
||||||
NodeList childNodes = document.getDocumentElement().getChildNodes();
|
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
|
||||||
Node node = childNodes.item(i);
|
|
||||||
if (node instanceof Element) {
|
|
||||||
Element element = (Element) node;
|
|
||||||
|
|
||||||
String field = element.getNodeName();
|
|
||||||
if (element.getChildNodes().getLength() == 0) {
|
|
||||||
vCard.setField(field, "");
|
|
||||||
}
|
|
||||||
else if (element.getChildNodes().getLength() == 1 &&
|
|
||||||
element.getChildNodes().item(0) instanceof Text) {
|
|
||||||
vCard.setField(field, getTextContent(element));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTextContent(Node node) {
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
appendText(result, node);
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendText(StringBuilder result, Node node) {
|
|
||||||
NodeList childNodes = node.getChildNodes();
|
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
|
||||||
Node nd = childNodes.item(i);
|
|
||||||
String nodeValue = nd.getNodeValue();
|
|
||||||
if (nodeValue != null) {
|
|
||||||
result.append(nodeValue);
|
|
||||||
}
|
|
||||||
appendText(result, nd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void parseTel(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
boolean isWork = true;
|
||||||
|
String telLabel = null;
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
if ("HOME".equals(name)) {
|
||||||
|
isWork = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (telLabel != null && "NUMBER".equals(name)) {
|
||||||
|
if (isWork) {
|
||||||
|
vCard.setPhoneWork(telLabel, parser.nextText());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vCard.setPhoneHome(telLabel, parser.nextText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (String tel : TEL) {
|
||||||
|
if (tel.equals(name)) {
|
||||||
|
telLabel = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseOrg(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch (name) {
|
||||||
|
case "ORGNAME":
|
||||||
|
vCard.setOrganization(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "ORGUNIT":
|
||||||
|
vCard.setOrganizationUnit(parser.nextText());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseEmail(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
boolean isWork = false;
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch (name) {
|
||||||
|
case "WORK":
|
||||||
|
isWork = true;
|
||||||
|
break;
|
||||||
|
case "USERID":
|
||||||
|
if (isWork) {
|
||||||
|
vCard.setEmailWork(parser.nextText());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vCard.setEmailHome(parser.nextText());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseName(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch (name) {
|
||||||
|
case "FAMILY":
|
||||||
|
vCard.setLastName(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "GIVEN":
|
||||||
|
vCard.setFirstName(parser.nextText());
|
||||||
|
break;
|
||||||
|
case "MIDDLE":
|
||||||
|
vCard.setMiddleName(parser.nextText());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parsePhoto(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
String binval = null;
|
||||||
|
String mimetype = null;
|
||||||
|
|
||||||
|
outerloop: while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
String name = parser.getName();
|
||||||
|
switch (name) {
|
||||||
|
case "BINVAL":
|
||||||
|
binval = parser.nextText();
|
||||||
|
break;
|
||||||
|
case "TYPE":
|
||||||
|
mimetype = parser.nextText();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binval == null || mimetype == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vCard.setAvatar(binval, mimetype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,15 +15,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx;
|
package org.jivesoftware.smackx;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
|
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
|
||||||
import org.jivesoftware.smackx.vcardtemp.provider.VCardProvider;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -34,41 +35,240 @@ public class VCardUnitTest extends InitExtensions {
|
||||||
SmackTestSuite.init();
|
SmackTestSuite.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseFullVCardIQStanza() throws Throwable {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'>"
|
||||||
|
+ "<FN>User Name</FN>"
|
||||||
|
+ "<N>"
|
||||||
|
+ "<FAMILY>Name</FAMILY>"
|
||||||
|
+ "<GIVEN>User</GIVEN>"
|
||||||
|
+ "<MIDDLE>PJ</MIDDLE>"
|
||||||
|
+ "</N>"
|
||||||
|
+ "<NICKNAME>User dude</NICKNAME>"
|
||||||
|
+ "<URL>http://www.igniterealtime.org</URL>"
|
||||||
|
+ "<BDAY>1970-17-03</BDAY>"
|
||||||
|
+ "<ORG>"
|
||||||
|
+ "<ORGNAME>Ignite Realtime</ORGNAME>"
|
||||||
|
+ "<ORGUNIT>Smack</ORGUNIT>"
|
||||||
|
+ "</ORG>"
|
||||||
|
+ "<TITLE>Programmer & tester</TITLE>"
|
||||||
|
+ "<ROLE>Bug fixer</ROLE>"
|
||||||
|
+ "<TEL><WORK/><VOICE/><NUMBER>123-456-7890</NUMBER></TEL>"
|
||||||
|
+ "<TEL><WORK/><FAX/><NUMBER/></TEL>"
|
||||||
|
+ "<TEL><WORK/><MSG/><NUMBER/></TEL>"
|
||||||
|
+ "<ADR>"
|
||||||
|
+ "<WORK/>"
|
||||||
|
+ "<EXTADD></EXTADD>"
|
||||||
|
+ "<STREET>Work Street</STREET>"
|
||||||
|
+ "<LOCALITY>Work Locality</LOCALITY>"
|
||||||
|
+ "<REGION>Work Region</REGION>"
|
||||||
|
+ "<PCODE>Work Post Code</PCODE>"
|
||||||
|
+ "<CTRY>Work Country</CTRY>"
|
||||||
|
+ "</ADR>"
|
||||||
|
+ "<TEL><HOME/><VOICE/><NUMBER>123-098-7654</NUMBER></TEL>"
|
||||||
|
+ "<TEL><HOME/><FAX/><NUMBER/></TEL>"
|
||||||
|
+ "<TEL><HOME/><MSG/><NUMBER/></TEL>"
|
||||||
|
+ "<ADR>"
|
||||||
|
+ "<HOME/>"
|
||||||
|
+ "<EXTADD/>"
|
||||||
|
+ "<STREET/>"
|
||||||
|
+ "<LOCALITY>Home Locality</LOCALITY>"
|
||||||
|
+ "<REGION>Home Region</REGION>"
|
||||||
|
+ "<PCODE>Home Post Code</PCODE>"
|
||||||
|
+ "<CTRY>Home Country</CTRY>"
|
||||||
|
+ "</ADR>"
|
||||||
|
+ "<EMAIL><INTERNET/><PREF/><USERID>user@igniterealtime.org</USERID></EMAIL>"
|
||||||
|
+ "<EMAIL><INTERNET/><WORK/><USERID>work@igniterealtime.org</USERID></EMAIL>"
|
||||||
|
+ "<JABBERID>user@igniterealtime.org</JABBERID>"
|
||||||
|
+ "<DESC>"
|
||||||
|
+ "<Check out our website: http://www.igniterealtime.org>"
|
||||||
|
+ "</DESC>"
|
||||||
|
+ "<PHOTO><BINVAL>" + getAvatarEncoded() + "</BINVAL><TYPE>" + MIME_TYPE + "</TYPE></PHOTO>"
|
||||||
|
+ "</vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("User", vCard.getFirstName());
|
||||||
|
assertEquals("Name", vCard.getLastName());
|
||||||
|
assertEquals("PJ", vCard.getMiddleName());
|
||||||
|
assertEquals("User dude", vCard.getNickName());
|
||||||
|
|
||||||
|
assertEquals("Programmer & tester", vCard.getField("TITLE"));
|
||||||
|
assertEquals("Bug fixer", vCard.getField("ROLE"));
|
||||||
|
assertEquals("<Check out our website: http://www.igniterealtime.org>", vCard.getField("DESC"));
|
||||||
|
assertEquals("http://www.igniterealtime.org", vCard.getField("URL"));
|
||||||
|
|
||||||
|
assertEquals("user@igniterealtime.org", vCard.getEmailHome());
|
||||||
|
assertEquals("work@igniterealtime.org", vCard.getEmailWork());
|
||||||
|
|
||||||
|
assertEquals("user@igniterealtime.org", vCard.getJabberId());
|
||||||
|
assertEquals("Ignite Realtime", vCard.getOrganization());
|
||||||
|
assertEquals("Smack", vCard.getOrganizationUnit());
|
||||||
|
|
||||||
|
assertEquals("123-098-7654", vCard.getPhoneHome("VOICE"));
|
||||||
|
assertEquals("123-456-7890", vCard.getPhoneWork("VOICE"));
|
||||||
|
|
||||||
|
assertEquals("Work Locality", vCard.getAddressFieldWork("LOCALITY"));
|
||||||
|
assertEquals("Work Region", vCard.getAddressFieldWork("REGION"));
|
||||||
|
assertEquals("Work Post Code", vCard.getAddressFieldWork("PCODE"));
|
||||||
|
assertEquals("Work Country", vCard.getAddressFieldWork("CTRY"));
|
||||||
|
|
||||||
|
assertEquals("Home Locality", vCard.getAddressFieldHome("LOCALITY"));
|
||||||
|
assertEquals("Home Region", vCard.getAddressFieldHome("REGION"));
|
||||||
|
assertEquals("Home Post Code", vCard.getAddressFieldHome("PCODE"));
|
||||||
|
assertEquals("Home Country", vCard.getAddressFieldHome("CTRY"));
|
||||||
|
|
||||||
|
byte[] expectedAvatar = getAvatarBinary();
|
||||||
|
assertTrue(Arrays.equals(vCard.getAvatar(), expectedAvatar));
|
||||||
|
assertEquals(MIME_TYPE, vCard.getAvatarMimeType());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoWorkHomeSpecifier_EMAIL() throws Throwable {
|
public void testNoWorkHomeSpecifier_EMAIL() throws Throwable {
|
||||||
VCard card = VCardProvider.createVCardFromXML("<vcard><EMAIL><USERID>foo@fee.www.bar</USERID></EMAIL></vcard>");
|
|
||||||
assertEquals("foo@fee.www.bar", card.getEmailHome());
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><EMAIL><USERID>foo@fee.www.bar</USERID></EMAIL></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("foo@fee.www.bar", vCard.getEmailHome());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoWorkHomeSpecifier_TEL() throws Throwable {
|
public void testNoWorkHomeSpecifier_TEL() throws Throwable {
|
||||||
VCard card = VCardProvider.createVCardFromXML("<vcard><TEL><FAX/><NUMBER>3443233</NUMBER></TEL></vcard>");
|
|
||||||
assertEquals("3443233", card.getPhoneWork("FAX"));
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><TEL><FAX/><NUMBER>3443233</NUMBER></TEL></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("3443233", vCard.getPhoneWork("FAX"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnknownTopLevelElementAdded() throws Throwable {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><UNKNOWN>1234</UNKNOWN></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("1234", vCard.getField("UNKNOWN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnknownComplexTopLevelElementNotAdded() throws Throwable {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><UNKNOWN><FOO/></UNKNOWN></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals(null, vCard.getField("UNKNOWN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnknownAddressElementNotAdded() throws Throwable {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><ADR><UNKNOWN>1234</UNKNOWN></ADR></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
assertEquals(null, vCard.getField("UNKNOWN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnknownDeepElementNotAdded() throws Throwable {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><UNKNOWN><UNKNOWN>1234</UNKNOWN></UNKNOWN></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
assertEquals(null, vCard.getField("UNKNOWN"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoWorkHomeSpecifier_ADDR() throws Throwable {
|
public void testNoWorkHomeSpecifier_ADDR() throws Throwable {
|
||||||
VCard card = VCardProvider.createVCardFromXML("<vcard><ADR><STREET>Some street</STREET><FF>ddss</FF></ADR></vcard>");
|
|
||||||
assertEquals("Some street", card.getAddressFieldWork("STREET"));
|
// @formatter:off
|
||||||
assertEquals("ddss", card.getAddressFieldWork("FF"));
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><ADR><STREET>Some street</STREET><FF>ddss</FF></ADR></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("Some street", vCard.getAddressFieldWork("STREET"));
|
||||||
|
assertEquals("ddss", vCard.getAddressFieldWork("FF"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFN() throws Throwable {
|
public void testFN() throws Throwable {
|
||||||
VCard card = VCardProvider.createVCardFromXML("<vcard><FN>kir max</FN></vcard>");
|
|
||||||
assertEquals("kir max", card.getField("FN"));
|
// @formatter:off
|
||||||
// assertEquals("kir max", card.getFullName());
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ "<vCard xmlns='vcard-temp'><FN>kir max</FN></vCard>"
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
assertEquals("kir max", vCard.getField("FN"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static String MIME_TYPE = "testtype";
|
private final static String MIME_TYPE = "testtype";
|
||||||
private final static String VCARD_XML = "<vcard><PHOTO><BINVAL>" + getAvatarEncoded() + "</BINVAL><TYPE>" + MIME_TYPE + "</TYPE></PHOTO></vcard>";
|
private final static String VCARD_XML = "<vCard xmlns='vcard-temp'><PHOTO><BINVAL>" + getAvatarEncoded()
|
||||||
|
+ "</BINVAL><TYPE>" + MIME_TYPE + "</TYPE></PHOTO></vCard>";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPhoto() throws Throwable {
|
public void testPhoto() throws Throwable {
|
||||||
VCard vc = VCardProvider.createVCardFromXML(VCARD_XML);
|
|
||||||
byte[] avatar = vc.getAvatar();
|
// @formatter:off
|
||||||
String mimeType = vc.getAvatarMimeType();
|
final String request =
|
||||||
|
"<iq id='v1' to='user@igniterealtime.org/mobile' type='result'>"
|
||||||
|
+ VCARD_XML
|
||||||
|
+ "</iq>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
VCard vCard = (VCard) PacketParserUtils.parseStanza(request);
|
||||||
|
|
||||||
|
byte[] avatar = vCard.getAvatar();
|
||||||
|
String mimeType = vCard.getAvatarMimeType();
|
||||||
assertEquals(mimeType, MIME_TYPE);
|
assertEquals(mimeType, MIME_TYPE);
|
||||||
|
|
||||||
byte[] expectedAvatar = getAvatarBinary();
|
byte[] expectedAvatar = getAvatarBinary();
|
||||||
assertTrue(Arrays.equals(avatar, expectedAvatar));
|
assertTrue(Arrays.equals(avatar, expectedAvatar));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue