1/** 2 * $RCSfile$ 3 * $Revision$ 4 * $Date$ 5 * 6 * Copyright 2003-2007 Jive Software. 7 * 8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21package org.jivesoftware.smackx.provider; 22 23import org.jivesoftware.smack.packet.IQ; 24import org.jivesoftware.smack.provider.IQProvider; 25import org.jivesoftware.smack.util.StringUtils; 26import org.jivesoftware.smackx.packet.VCard; 27import org.w3c.dom.*; 28import org.xmlpull.v1.XmlPullParser; 29import org.xmlpull.v1.XmlPullParserException; 30 31import javax.xml.parsers.DocumentBuilder; 32import javax.xml.parsers.DocumentBuilderFactory; 33import java.io.ByteArrayInputStream; 34import java.io.IOException; 35import java.util.ArrayList; 36import java.util.List; 37 38/** 39 * vCard provider. 40 * 41 * @author Gaston Dombiak 42 * @author Derek DeMoro 43 */ 44public class VCardProvider implements IQProvider { 45 46 private static final String PREFERRED_ENCODING = "UTF-8"; 47 48 public IQ parseIQ(XmlPullParser parser) throws Exception { 49 final StringBuilder sb = new StringBuilder(); 50 try { 51 int event = parser.getEventType(); 52 // get the content 53 while (true) { 54 switch (event) { 55 case XmlPullParser.TEXT: 56 // We must re-escape the xml so that the DOM won't throw an exception 57 sb.append(StringUtils.escapeForXML(parser.getText())); 58 break; 59 case XmlPullParser.START_TAG: 60 sb.append('<').append(parser.getName()).append('>'); 61 break; 62 case XmlPullParser.END_TAG: 63 sb.append("</").append(parser.getName()).append('>'); 64 break; 65 default: 66 } 67 68 if (event == XmlPullParser.END_TAG && "vCard".equals(parser.getName())) break; 69 70 event = parser.next(); 71 } 72 } 73 catch (XmlPullParserException e) { 74 e.printStackTrace(); 75 } 76 catch (IOException e) { 77 e.printStackTrace(); 78 } 79 80 String xmlText = sb.toString(); 81 return createVCardFromXML(xmlText); 82 } 83 84 /** 85 * Builds a users vCard from xml file. 86 * 87 * @param xml the xml representing a users vCard. 88 * @return the VCard. 89 * @throws Exception if an exception occurs. 90 */ 91 public static VCard createVCardFromXML(String xml) throws Exception { 92 VCard vCard = new VCard(); 93 94 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 95 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 96 Document document = documentBuilder.parse( 97 new ByteArrayInputStream(xml.getBytes(PREFERRED_ENCODING))); 98 99 new VCardReader(vCard, document).initializeFields(); 100 return vCard; 101 } 102 103 private static class VCardReader { 104 105 private final VCard vCard; 106 private final Document document; 107 108 VCardReader(VCard vCard, Document document) { 109 this.vCard = vCard; 110 this.document = document; 111 } 112 113 public void initializeFields() { 114 vCard.setFirstName(getTagContents("GIVEN")); 115 vCard.setLastName(getTagContents("FAMILY")); 116 vCard.setMiddleName(getTagContents("MIDDLE")); 117 setupPhoto(); 118 119 setupEmails(); 120 121 vCard.setOrganization(getTagContents("ORGNAME")); 122 vCard.setOrganizationUnit(getTagContents("ORGUNIT")); 123 124 setupSimpleFields(); 125 126 setupPhones(); 127 setupAddresses(); 128 } 129 130 private void setupPhoto() { 131 String binval = null; 132 String mimetype = null; 133 134 NodeList photo = document.getElementsByTagName("PHOTO"); 135 if (photo.getLength() != 1) 136 return; 137 138 Node photoNode = photo.item(0); 139 NodeList childNodes = photoNode.getChildNodes(); 140 141 int childNodeCount = childNodes.getLength(); 142 List<Node> nodes = new ArrayList<Node>(childNodeCount); 143 for (int i = 0; i < childNodeCount; i++) 144 nodes.add(childNodes.item(i)); 145 146 String name = null; 147 String value = null; 148 for (Node n : nodes) { 149 name = n.getNodeName(); 150 value = n.getTextContent(); 151 if (name.equals("BINVAL")) { 152 binval = value; 153 } 154 else if (name.equals("TYPE")) { 155 mimetype = value; 156 } 157 } 158 159 if (binval == null || mimetype == null) 160 return; 161 162 vCard.setAvatar(binval, mimetype); 163 } 164 165 private void setupEmails() { 166 NodeList nodes = document.getElementsByTagName("USERID"); 167 if (nodes == null) return; 168 for (int i = 0; i < nodes.getLength(); i++) { 169 Element element = (Element) nodes.item(i); 170 if ("WORK".equals(element.getParentNode().getFirstChild().getNodeName())) { 171 vCard.setEmailWork(getTextContent(element)); 172 } 173 else { 174 vCard.setEmailHome(getTextContent(element)); 175 } 176 } 177 } 178 179 private void setupPhones() { 180 NodeList allPhones = document.getElementsByTagName("TEL"); 181 if (allPhones == null) return; 182 for (int i = 0; i < allPhones.getLength(); i++) { 183 NodeList nodes = allPhones.item(i).getChildNodes(); 184 String type = null; 185 String code = null; 186 String value = null; 187 for (int j = 0; j < nodes.getLength(); j++) { 188 Node node = nodes.item(j); 189 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 190 String nodeName = node.getNodeName(); 191 if ("NUMBER".equals(nodeName)) { 192 value = getTextContent(node); 193 } 194 else if (isWorkHome(nodeName)) { 195 type = nodeName; 196 } 197 else { 198 code = nodeName; 199 } 200 } 201 if (code == null || value == null) continue; 202 if ("HOME".equals(type)) { 203 vCard.setPhoneHome(code, value); 204 } 205 else { // By default, setup work phone 206 vCard.setPhoneWork(code, value); 207 } 208 } 209 } 210 211 private boolean isWorkHome(String nodeName) { 212 return "HOME".equals(nodeName) || "WORK".equals(nodeName); 213 } 214 215 private void setupAddresses() { 216 NodeList allAddresses = document.getElementsByTagName("ADR"); 217 if (allAddresses == null) return; 218 for (int i = 0; i < allAddresses.getLength(); i++) { 219 Element addressNode = (Element) allAddresses.item(i); 220 221 String type = null; 222 List<String> code = new ArrayList<String>(); 223 List<String> value = new ArrayList<String>(); 224 NodeList childNodes = addressNode.getChildNodes(); 225 for (int j = 0; j < childNodes.getLength(); j++) { 226 Node node = childNodes.item(j); 227 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 228 String nodeName = node.getNodeName(); 229 if (isWorkHome(nodeName)) { 230 type = nodeName; 231 } 232 else { 233 code.add(nodeName); 234 value.add(getTextContent(node)); 235 } 236 } 237 for (int j = 0; j < value.size(); j++) { 238 if ("HOME".equals(type)) { 239 vCard.setAddressFieldHome((String) code.get(j), (String) value.get(j)); 240 } 241 else { // By default, setup work address 242 vCard.setAddressFieldWork((String) code.get(j), (String) value.get(j)); 243 } 244 } 245 } 246 } 247 248 private String getTagContents(String tag) { 249 NodeList nodes = document.getElementsByTagName(tag); 250 if (nodes != null && nodes.getLength() == 1) { 251 return getTextContent(nodes.item(0)); 252 } 253 return null; 254 } 255 256 private void setupSimpleFields() { 257 NodeList childNodes = document.getDocumentElement().getChildNodes(); 258 for (int i = 0; i < childNodes.getLength(); i++) { 259 Node node = childNodes.item(i); 260 if (node instanceof Element) { 261 Element element = (Element) node; 262 263 String field = element.getNodeName(); 264 if (element.getChildNodes().getLength() == 0) { 265 vCard.setField(field, ""); 266 } 267 else if (element.getChildNodes().getLength() == 1 && 268 element.getChildNodes().item(0) instanceof Text) { 269 vCard.setField(field, getTextContent(element)); 270 } 271 } 272 } 273 } 274 275 private String getTextContent(Node node) { 276 StringBuilder result = new StringBuilder(); 277 appendText(result, node); 278 return result.toString(); 279 } 280 281 private void appendText(StringBuilder result, Node node) { 282 NodeList childNodes = node.getChildNodes(); 283 for (int i = 0; i < childNodes.getLength(); i++) { 284 Node nd = childNodes.item(i); 285 String nodeValue = nd.getNodeValue(); 286 if (nodeValue != null) { 287 result.append(nodeValue); 288 } 289 appendText(result, nd); 290 } 291 } 292 } 293} 294