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