Home | History | Annotate | Download | only in provider
      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 
     21 package org.jivesoftware.smackx.provider;
     22 
     23 import org.jivesoftware.smack.packet.IQ;
     24 import org.jivesoftware.smack.provider.IQProvider;
     25 import org.jivesoftware.smack.util.StringUtils;
     26 import org.jivesoftware.smackx.packet.VCard;
     27 import org.w3c.dom.*;
     28 import org.xmlpull.v1.XmlPullParser;
     29 import org.xmlpull.v1.XmlPullParserException;
     30 
     31 import javax.xml.parsers.DocumentBuilder;
     32 import javax.xml.parsers.DocumentBuilderFactory;
     33 import java.io.ByteArrayInputStream;
     34 import java.io.IOException;
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 
     38 /**
     39  * vCard provider.
     40  *
     41  * @author Gaston Dombiak
     42  * @author Derek DeMoro
     43  */
     44 public 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