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