001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.vcardtemp.provider; 018 019import org.jivesoftware.smack.packet.IQ; 020import org.jivesoftware.smack.provider.IQProvider; 021import org.jivesoftware.smack.util.StringUtils; 022import org.jivesoftware.smackx.vcardtemp.packet.VCard; 023import org.w3c.dom.Document; 024import org.w3c.dom.Element; 025import org.w3c.dom.Node; 026import org.w3c.dom.NodeList; 027import org.w3c.dom.Text; 028import org.xmlpull.v1.XmlPullParser; 029import org.xmlpull.v1.XmlPullParserException; 030 031import javax.xml.parsers.DocumentBuilder; 032import javax.xml.parsers.DocumentBuilderFactory; 033 034import java.io.ByteArrayInputStream; 035import java.io.IOException; 036import java.util.ArrayList; 037import java.util.List; 038import java.util.logging.Level; 039import java.util.logging.Logger; 040 041/** 042 * vCard provider. 043 * 044 * @author Gaston Dombiak 045 * @author Derek DeMoro 046 */ 047public class VCardProvider implements IQProvider { 048 private static final Logger LOGGER = Logger.getLogger(VCardProvider.class.getName()); 049 050 private static final String PREFERRED_ENCODING = "UTF-8"; 051 052 public IQ parseIQ(XmlPullParser parser) throws Exception { 053 final StringBuilder sb = new StringBuilder(); 054 try { 055 int event = parser.getEventType(); 056 // get the content 057 while (true) { 058 switch (event) { 059 case XmlPullParser.TEXT: 060 // We must re-escape the xml so that the DOM won't throw an exception 061 sb.append(StringUtils.escapeForXML(parser.getText())); 062 break; 063 case XmlPullParser.START_TAG: 064 sb.append('<').append(parser.getName()).append('>'); 065 break; 066 case XmlPullParser.END_TAG: 067 sb.append("</").append(parser.getName()).append('>'); 068 break; 069 default: 070 } 071 072 if (event == XmlPullParser.END_TAG && "vCard".equals(parser.getName())) break; 073 074 event = parser.next(); 075 } 076 } 077 catch (XmlPullParserException e) { 078 LOGGER.log(Level.SEVERE, "Exception parsing VCard", e); 079 } 080 catch (IOException e) { 081 LOGGER.log(Level.SEVERE, "Exception parsing VCard", e); 082 } 083 084 String xmlText = sb.toString(); 085 return createVCardFromXML(xmlText); 086 } 087 088 /** 089 * Builds a users vCard from xml file. 090 * 091 * @param xml the xml representing a users vCard. 092 * @return the VCard. 093 * @throws Exception if an exception occurs. 094 */ 095 public static VCard createVCardFromXML(String xml) throws Exception { 096 VCard vCard = new VCard(); 097 098 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 099 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 100 Document document = documentBuilder.parse( 101 new ByteArrayInputStream(xml.getBytes(PREFERRED_ENCODING))); 102 103 new VCardReader(vCard, document).initializeFields(); 104 return vCard; 105 } 106 107 private static class VCardReader { 108 109 private final VCard vCard; 110 private final Document document; 111 112 VCardReader(VCard vCard, Document document) { 113 this.vCard = vCard; 114 this.document = document; 115 } 116 117 public void initializeFields() { 118 vCard.setFirstName(getTagContents("GIVEN")); 119 vCard.setLastName(getTagContents("FAMILY")); 120 vCard.setMiddleName(getTagContents("MIDDLE")); 121 setupPhoto(); 122 123 setupEmails(); 124 125 vCard.setOrganization(getTagContents("ORGNAME")); 126 vCard.setOrganizationUnit(getTagContents("ORGUNIT")); 127 128 setupSimpleFields(); 129 130 setupPhones(); 131 setupAddresses(); 132 } 133 134 private void setupPhoto() { 135 String binval = null; 136 String mimetype = null; 137 138 NodeList photo = document.getElementsByTagName("PHOTO"); 139 if (photo.getLength() != 1) 140 return; 141 142 Node photoNode = photo.item(0); 143 NodeList childNodes = photoNode.getChildNodes(); 144 145 int childNodeCount = childNodes.getLength(); 146 List<Node> nodes = new ArrayList<Node>(childNodeCount); 147 for (int i = 0; i < childNodeCount; i++) 148 nodes.add(childNodes.item(i)); 149 150 String name = null; 151 String value = null; 152 for (Node n : nodes) { 153 name = n.getNodeName(); 154 value = n.getTextContent(); 155 if (name.equals("BINVAL")) { 156 binval = value; 157 } 158 else if (name.equals("TYPE")) { 159 mimetype = value; 160 } 161 } 162 163 if (binval == null || mimetype == null) 164 return; 165 166 vCard.setAvatar(binval, mimetype); 167 } 168 169 private void setupEmails() { 170 NodeList nodes = document.getElementsByTagName("USERID"); 171 if (nodes == null) return; 172 for (int i = 0; i < nodes.getLength(); i++) { 173 Element element = (Element) nodes.item(i); 174 if ("WORK".equals(element.getParentNode().getFirstChild().getNodeName())) { 175 vCard.setEmailWork(getTextContent(element)); 176 } 177 else { 178 vCard.setEmailHome(getTextContent(element)); 179 } 180 } 181 } 182 183 private void setupPhones() { 184 NodeList allPhones = document.getElementsByTagName("TEL"); 185 if (allPhones == null) return; 186 for (int i = 0; i < allPhones.getLength(); i++) { 187 NodeList nodes = allPhones.item(i).getChildNodes(); 188 String type = null; 189 String code = null; 190 String value = null; 191 for (int j = 0; j < nodes.getLength(); j++) { 192 Node node = nodes.item(j); 193 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 194 String nodeName = node.getNodeName(); 195 if ("NUMBER".equals(nodeName)) { 196 value = getTextContent(node); 197 } 198 else if (isWorkHome(nodeName)) { 199 type = nodeName; 200 } 201 else { 202 code = nodeName; 203 } 204 } 205 if (value == null) continue; 206 if (code == null) 207 code = "VOICE"; 208 if ("HOME".equals(type)) { 209 vCard.setPhoneHome(code, value); 210 } 211 else { // By default, setup work phone 212 vCard.setPhoneWork(code, value); 213 } 214 } 215 } 216 217 private boolean isWorkHome(String nodeName) { 218 return "HOME".equals(nodeName) || "WORK".equals(nodeName); 219 } 220 221 private void setupAddresses() { 222 NodeList allAddresses = document.getElementsByTagName("ADR"); 223 if (allAddresses == null) return; 224 for (int i = 0; i < allAddresses.getLength(); i++) { 225 Element addressNode = (Element) allAddresses.item(i); 226 227 String type = null; 228 List<String> code = new ArrayList<String>(); 229 List<String> value = new ArrayList<String>(); 230 NodeList childNodes = addressNode.getChildNodes(); 231 for (int j = 0; j < childNodes.getLength(); j++) { 232 Node node = childNodes.item(j); 233 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 234 String nodeName = node.getNodeName(); 235 if (isWorkHome(nodeName)) { 236 type = nodeName; 237 } 238 else { 239 code.add(nodeName); 240 value.add(getTextContent(node)); 241 } 242 } 243 for (int j = 0; j < value.size(); j++) { 244 if ("HOME".equals(type)) { 245 vCard.setAddressFieldHome((String) code.get(j), (String) value.get(j)); 246 } 247 else { // By default, setup work address 248 vCard.setAddressFieldWork((String) code.get(j), (String) value.get(j)); 249 } 250 } 251 } 252 } 253 254 private String getTagContents(String tag) { 255 NodeList nodes = document.getElementsByTagName(tag); 256 if (nodes != null && nodes.getLength() == 1) { 257 return getTextContent(nodes.item(0)); 258 } 259 return null; 260 } 261 262 private void setupSimpleFields() { 263 NodeList childNodes = document.getDocumentElement().getChildNodes(); 264 for (int i = 0; i < childNodes.getLength(); i++) { 265 Node node = childNodes.item(i); 266 if (node instanceof Element) { 267 Element element = (Element) node; 268 269 String field = element.getNodeName(); 270 if (element.getChildNodes().getLength() == 0) { 271 vCard.setField(field, ""); 272 } 273 else if (element.getChildNodes().getLength() == 1 && 274 element.getChildNodes().item(0) instanceof Text) { 275 vCard.setField(field, getTextContent(element)); 276 } 277 } 278 } 279 } 280 281 private String getTextContent(Node node) { 282 StringBuilder result = new StringBuilder(); 283 appendText(result, node); 284 return result.toString(); 285 } 286 287 private void appendText(StringBuilder result, Node node) { 288 NodeList childNodes = node.getChildNodes(); 289 for (int i = 0; i < childNodes.getLength(); i++) { 290 Node nd = childNodes.item(i); 291 String nodeValue = nd.getNodeValue(); 292 if (nodeValue != null) { 293 result.append(nodeValue); 294 } 295 appendText(result, nd); 296 } 297 } 298 } 299}