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 java.io.IOException;
020
021import org.jivesoftware.smack.packet.XmlEnvironment;
022import org.jivesoftware.smack.provider.IQProvider;
023import org.jivesoftware.smack.util.StringUtils;
024import org.jivesoftware.smack.xml.XmlPullParser;
025import org.jivesoftware.smack.xml.XmlPullParserException;
026
027import org.jivesoftware.smackx.vcardtemp.packet.VCard;
028
029/**
030 * vCard provider.
031 *
032 * @author Gaston Dombiak
033 * @author Derek DeMoro
034 * @author Chris Deering
035 */
036public class VCardProvider extends IQProvider<VCard> {
037
038    // @formatter:off
039    private static final String[] ADR = new String[] {
040        "POSTAL",
041        "PARCEL",
042        "DOM",
043        "INTL",
044        "PREF",
045        "POBOX",
046        "EXTADR",
047        "STREET",
048        "LOCALITY",
049        "REGION",
050        "PCODE",
051        "CTRY",
052        "FF",
053    };
054
055    private static final String[] TEL = new String[] {
056        "VOICE",
057        "FAX",
058        "PAGER",
059        "MSG",
060        "CELL",
061        "VIDEO",
062        "BBS",
063        "MODEM",
064        "ISDN",
065        "PCS",
066        "PREF",
067    };
068    // @formatter:on
069
070    @Override
071    public VCard parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException {
072        VCard vCard = new VCard();
073        String name = null;
074
075        outerloop: while (true) {
076            XmlPullParser.Event eventType = parser.next();
077            switch (eventType) {
078            case START_ELEMENT:
079                name = parser.getName();
080                switch (name) {
081                case "N":
082                    parseName(parser, vCard);
083                    break;
084                case "ORG":
085                    parseOrg(parser, vCard);
086                    break;
087                case "TEL":
088                    parseTel(parser, vCard);
089                    break;
090                case "ADR":
091                    parseAddress(parser, vCard);
092                    break;
093                case "EMAIL":
094                    parseEmail(parser, vCard);
095                    break;
096                case "NICKNAME":
097                    vCard.setNickName(parser.nextText());
098                    break;
099                case "JABBERID":
100                    vCard.setJabberId(parser.nextText());
101                    break;
102                case "PHOTO":
103                    parsePhoto(parser, vCard);
104                    break;
105                default:
106                    break;
107                }
108                break;
109            case TEXT_CHARACTERS:
110                if (initialDepth + 1 == parser.getDepth()) {
111                    String text = parser.getText();
112                    vCard.setField(name, text);
113                }
114                break;
115            case END_ELEMENT:
116                if (parser.getDepth() == initialDepth) {
117                    break outerloop;
118                }
119                break;
120            default:
121                break;
122            }
123        }
124
125        return vCard;
126    }
127
128    private static void parseAddress(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
129        final int initialDepth = parser.getDepth();
130        boolean isWork = true;
131        outerloop: while (true) {
132            XmlPullParser.Event eventType = parser.next();
133            switch (eventType) {
134            case START_ELEMENT:
135                String name = parser.getName();
136                if ("HOME".equals(name)) {
137                    isWork = false;
138                }
139                else {
140                    for (String adr : ADR) {
141                        if (adr.equals(name)) {
142                            if (isWork) {
143                                vCard.setAddressFieldWork(name, parser.nextText());
144                            }
145                            else {
146                                vCard.setAddressFieldHome(name, parser.nextText());
147                            }
148                        }
149                    }
150                }
151                break;
152            case END_ELEMENT:
153                if (parser.getDepth() == initialDepth) {
154                    break outerloop;
155                }
156                break;
157            default:
158                break;
159            }
160        }
161    }
162
163    private static void parseTel(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
164        final int initialDepth = parser.getDepth();
165        boolean isWork = true;
166        String telLabel = null;
167
168        outerloop: while (true) {
169            XmlPullParser.Event eventType = parser.next();
170            switch (eventType) {
171            case START_ELEMENT:
172                String name = parser.getName();
173                if ("HOME".equals(name)) {
174                    isWork = false;
175                }
176                else {
177                    if ("NUMBER".equals(name)) {
178                        if (StringUtils.isNullOrEmpty(telLabel)) {
179                            // RFC 2426 ยง 3.3.1:
180                            // "The default type is 'voice'"
181                            telLabel = "VOICE";
182                        }
183                        if (isWork) {
184                            vCard.setPhoneWork(telLabel, parser.nextText());
185                        }
186                        else {
187                            vCard.setPhoneHome(telLabel, parser.nextText());
188                        }
189                    }
190                    else {
191                        for (String tel : TEL) {
192                            if (tel.equals(name)) {
193                                telLabel = name;
194                            }
195                        }
196                    }
197                }
198                break;
199            case END_ELEMENT:
200                if (parser.getDepth() == initialDepth) {
201                    break outerloop;
202                }
203                break;
204            default:
205                break;
206            }
207        }
208    }
209
210    private static void parseOrg(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
211        final int initialDepth = parser.getDepth();
212
213        outerloop: while (true) {
214            XmlPullParser.Event eventType = parser.next();
215            switch (eventType) {
216            case START_ELEMENT:
217                String name = parser.getName();
218                switch (name) {
219                case "ORGNAME":
220                    vCard.setOrganization(parser.nextText());
221                    break;
222                case "ORGUNIT":
223                    vCard.setOrganizationUnit(parser.nextText());
224                    break;
225                default:
226                    break;
227                }
228                break;
229            case END_ELEMENT:
230                if (parser.getDepth() == initialDepth) {
231                    break outerloop;
232                }
233                break;
234            default:
235                break;
236            }
237        }
238    }
239
240    private static void parseEmail(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
241        final int initialDepth = parser.getDepth();
242        boolean isWork = false;
243
244        outerloop: while (true) {
245            XmlPullParser.Event eventType = parser.next();
246            switch (eventType) {
247            case START_ELEMENT:
248                String name = parser.getName();
249                switch (name) {
250                case "WORK":
251                    isWork = true;
252                    break;
253                case "USERID":
254                    if (isWork) {
255                        vCard.setEmailWork(parser.nextText());
256                    }
257                    else {
258                        vCard.setEmailHome(parser.nextText());
259                    }
260                    break;
261                default:
262                    break;
263                }
264                break;
265            case END_ELEMENT:
266                if (parser.getDepth() == initialDepth) {
267                    break outerloop;
268                }
269                break;
270            default:
271                break;
272            }
273        }
274    }
275
276    private static void parseName(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
277        final int initialDepth = parser.getDepth();
278
279        outerloop: while (true) {
280            XmlPullParser.Event eventType = parser.next();
281            switch (eventType) {
282            case START_ELEMENT:
283                String name = parser.getName();
284                switch (name) {
285                case "FAMILY":
286                    vCard.setLastName(parser.nextText());
287                    break;
288                case "GIVEN":
289                    vCard.setFirstName(parser.nextText());
290                    break;
291                case "MIDDLE":
292                    vCard.setMiddleName(parser.nextText());
293                    break;
294                case "PREFIX":
295                    vCard.setPrefix(parser.nextText());
296                    break;
297                case "SUFFIX":
298                    vCard.setSuffix(parser.nextText());
299                    break;
300                default:
301                    break;
302                }
303                break;
304            case END_ELEMENT:
305                if (parser.getDepth() == initialDepth) {
306                    break outerloop;
307                }
308                break;
309            default:
310                break;
311
312            }
313        }
314    }
315
316    private static void parsePhoto(XmlPullParser parser, VCard vCard) throws XmlPullParserException, IOException {
317        final int initialDepth = parser.getDepth();
318        String binval = null;
319        String mimetype = null;
320
321        outerloop: while (true) {
322            XmlPullParser.Event eventType = parser.next();
323            switch (eventType) {
324            case START_ELEMENT:
325                String name = parser.getName();
326                switch (name) {
327                case "BINVAL":
328                    binval = parser.nextText();
329                    break;
330                case "TYPE":
331                    mimetype = parser.nextText();
332                    break;
333                default:
334                    break;
335                }
336                break;
337            case END_ELEMENT:
338                if (parser.getDepth() == initialDepth) {
339                    break outerloop;
340                }
341                break;
342            default:
343                break;
344            }
345        }
346
347        if (binval == null || mimetype == null) {
348            return;
349        }
350
351        vCard.setAvatar(binval, mimetype);
352    }
353}