1192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta/*
2192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Copyright (C) 2014 The Android Open Source Project
3192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
4192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Licensed under the Apache License, Version 2.0 (the "License");
5192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * you may not use this file except in compliance with the License.
6192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * You may obtain a copy of the License at
7192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
8192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *      http://www.apache.org/licenses/LICENSE-2.0
9192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
10192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Unless required by applicable law or agreed to in writing, software
11192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * distributed under the License is distributed on an "AS IS" BASIS,
12192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * See the License for the specific language governing permissions and
14192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * limitations under the License.
15192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta */
16192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
17192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptapackage android.bluetooth.client.map;
18192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
19192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.util.Log;
20192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
21192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardEntry;
22192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardEntryConstructor;
23192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardEntryHandler;
24192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardParser;
25192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardParser_V21;
26192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.VCardParser_V30;
27192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.exception.VCardException;
28192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport com.android.vcard.exception.VCardVersionException;
29192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.bluetooth.client.map.BluetoothMapBmessage.Status;
30192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.bluetooth.client.map.BluetoothMapBmessage.Type;
31192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.bluetooth.client.map.utils.BmsgTokenizer;
32192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.bluetooth.client.map.utils.BmsgTokenizer.Property;
33192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
34192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.ByteArrayInputStream;
35192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.IOException;
36d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwalimport java.nio.charset.StandardCharsets;
37192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.text.ParseException;
38192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
39192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaclass BluetoothMapBmessageParser {
40192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
41192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static String TAG = "BluetoothMapBmessageParser";
42fb93d457178a706fc3d20df5bbfcff4ca80a1fc2Sanket Agarwal    private final static boolean DBG = false;
43192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
44192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static String CRLF = "\r\n";
45192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
46192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property BEGIN_BMSG = new Property("BEGIN", "BMSG");
47192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property END_BMSG = new Property("END", "BMSG");
48192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
49192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property BEGIN_VCARD = new Property("BEGIN", "VCARD");
50192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property END_VCARD = new Property("END", "VCARD");
51192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
52192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property BEGIN_BENV = new Property("BEGIN", "BENV");
53192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property END_BENV = new Property("END", "BENV");
54192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
55192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property BEGIN_BBODY = new Property("BEGIN", "BBODY");
56192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property END_BBODY = new Property("END", "BBODY");
57192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
58192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property BEGIN_MSG = new Property("BEGIN", "MSG");
59192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static Property END_MSG = new Property("END", "MSG");
60192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
61192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static int CRLF_LEN = 2;
62192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
63192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /*
64192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * length of "container" for 'message' in bmessage-body-content:
65192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * BEGIN:MSG<CRLF> + <CRLF> + END:MSG<CRFL>
66192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
67192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static int MSG_CONTAINER_LEN = 22;
68192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
69192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private BmsgTokenizer mParser;
70192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
71192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final BluetoothMapBmessage mBmsg;
72192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
73192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private BluetoothMapBmessageParser() {
74192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mBmsg = new BluetoothMapBmessage();
75192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
76192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
77192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    static public BluetoothMapBmessage createBmessage(String str) {
78192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        BluetoothMapBmessageParser p = new BluetoothMapBmessageParser();
79192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
80d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal        if (DBG) {
81d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal            Log.d(TAG, "actual wired contents: " + str);
82d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal        }
83d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal
84192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        try {
85192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            p.parse(str);
86192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (IOException e) {
87192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.e(TAG, "I/O exception when parsing bMessage", e);
88192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            return null;
89192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (ParseException e) {
90192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.e(TAG, "Cannot parse bMessage", e);
91192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            return null;
92192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
93192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
94192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return p.mBmsg;
95192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
96192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
97192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private ParseException expected(Property... props) {
98192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        boolean first = true;
99192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        StringBuilder sb = new StringBuilder();
100192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
101192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        for (Property prop : props) {
102192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (!first) {
103192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                sb.append(" or ");
104192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
105192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            sb.append(prop);
106192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            first = false;
107192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
108192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
109192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return new ParseException("Expected: " + sb.toString(), mParser.pos());
110192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
111192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
112192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private void parse(String str) throws IOException, ParseException {
113192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
114192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        Property prop;
115192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
116192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
117192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-object>::= { "BEGIN:BMSG" <CRLF> <bmessage-property>
118192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * [<bmessage-originator>]* <bmessage-envelope> "END:BMSG" <CRLF> }
119192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
120192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
121192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mParser = new BmsgTokenizer(str + CRLF);
122192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
123192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = mParser.next();
124192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (!prop.equals(BEGIN_BMSG)) {
125192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(BEGIN_BMSG);
126192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
127192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
128192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = parseProperties();
129192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
130192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        while (prop.equals(BEGIN_VCARD)) {
131192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
132192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            /* <bmessage-originator>::= <vcard> <CRLF> */
133192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
134192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            StringBuilder vcard = new StringBuilder();
135192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = extractVcard(vcard);
136192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
137192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            VCardEntry entry = parseVcard(vcard.toString());
138192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mBmsg.mOriginators.add(entry);
139192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
140192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
141192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (!prop.equals(BEGIN_BENV)) {
142192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(BEGIN_BENV);
143192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
144192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
145192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = parseEnvelope(1);
146192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
147192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (!prop.equals(END_BMSG)) {
148192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(END_BENV);
149192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
150192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
151192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
152192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * there should be no meaningful data left in stream here so we just
153192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * ignore whatever is left
154192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
155192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
156192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mParser = null;
157192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
158192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
159192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private Property parseProperties() throws ParseException {
160192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
161192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        Property prop;
162192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
163192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
164192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-property>::=<bmessage-version-property>
165192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-readstatus-property> <bmessage-type-property>
166192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-folder-property> <bmessage-version-property>::="VERSION:"
167192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <common-digit>*"."<common-digit>* <CRLF>
168192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-readstatus-property>::="STATUS:" 'readstatus' <CRLF>
169192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-type-property>::="TYPE:" 'type' <CRLF>
170192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-folder-property>::="FOLDER:" 'foldername' <CRLF>
171192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
172192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
173192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        do {
174192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = mParser.next();
175192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
176192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (prop.name.equals("VERSION")) {
177192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mBmsgVersion = prop.value;
178192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
179192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("STATUS")) {
180192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                for (Status s : Status.values()) {
181192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    if (prop.value.equals(s.toString())) {
182192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mBmsg.mBmsgStatus = s;
183192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        break;
184192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    }
185192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
186192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
187192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("TYPE")) {
188192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                for (Type t : Type.values()) {
189192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    if (prop.value.equals(t.toString())) {
190192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mBmsg.mBmsgType = t;
191192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        break;
192192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    }
193192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
194192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
195192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("FOLDER")) {
196192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mBmsgFolder = prop.value;
197192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
198192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
199192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
200192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } while (!prop.equals(BEGIN_VCARD) && !prop.equals(BEGIN_BENV));
201192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
202192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return prop;
203192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
204192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
205192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private Property parseEnvelope(int level) throws IOException, ParseException {
206192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
207192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        Property prop;
208192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
209192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
210192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * we can support as many nesting level as we want, but MAP spec clearly
211192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * defines that there should be no more than 3 levels. so we verify it
212192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * here.
213192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
214192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
215192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (level > 3) {
216192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw new ParseException("bEnvelope is nested more than 3 times", mParser.pos());
217192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
218192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
219192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
220192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-envelope> ::= { "BEGIN:BENV" <CRLF> [<bmessage-recipient>]*
221192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-envelope> | <bmessage-content> "END:BENV" <CRLF> }
222192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
223192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
224192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = mParser.next();
225192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
226192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        while (prop.equals(BEGIN_VCARD)) {
227192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
228192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            /* <bmessage-originator>::= <vcard> <CRLF> */
229192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
230192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            StringBuilder vcard = new StringBuilder();
231192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = extractVcard(vcard);
232192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
233192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (level == 1) {
234192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                VCardEntry entry = parseVcard(vcard.toString());
235192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mRecipients.add(entry);
236192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
237192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
238192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
239192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (prop.equals(BEGIN_BENV)) {
240192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = parseEnvelope(level + 1);
241192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
242192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } else if (prop.equals(BEGIN_BBODY)) {
243192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = parseBody();
244192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
245192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } else {
246192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(BEGIN_BENV, BEGIN_BBODY);
247192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
248192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
249192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (!prop.equals(END_BENV)) {
250192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(END_BENV);
251192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
252192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
253192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mParser.next();
254192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
255192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
256192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private Property parseBody() throws IOException, ParseException {
257192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
258192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        Property prop;
259192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
260192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
261192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-content>::= { "BEGIN:BBODY"<CRLF> [<bmessage-body-part-ID>
262192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <CRLF>] <bmessage-body-property> <bmessage-body-content>* <CRLF>
263192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * "END:BBODY"<CRLF> } <bmessage-body-part-ID>::="PARTID:" 'Part-ID'
264192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-property>::=[<bmessage-body-encoding-property>]
265192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * [<bmessage-body-charset-property>]
266192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * [<bmessage-body-language-property>]
267192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-content-length-property>
268192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-encoding-property>::="ENCODING:"'encoding' <CRLF>
269192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-charset-property>::="CHARSET:"'charset' <CRLF>
270192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-language-property>::="LANGUAGE:"'language' <CRLF>
271192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-content-length-property>::= "LENGTH:" <common-digit>*
272192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <CRLF>
273192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
274192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
275192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        do {
276192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = mParser.next();
277192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
278192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (prop.name.equals("PARTID")) {
279192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("ENCODING")) {
280192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mBbodyEncoding = prop.value;
281192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
282192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("CHARSET")) {
283192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mBbodyCharset = prop.value;
284192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
285192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("LANGUAGE")) {
286192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mBmsg.mBbodyLanguage = prop.value;
287192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
288192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else if (prop.name.equals("LENGTH")) {
289192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                try {
2907b55edea45ee5e5447ef8afaa6b144b698ba6f49Narayan Kamath                    mBmsg.mBbodyLength = Integer.parseInt(prop.value);
291192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                } catch (NumberFormatException e) {
292192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    throw new ParseException("Invalid LENGTH value", mParser.pos());
293192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
294192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
295192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
296192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
297192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } while (!prop.equals(BEGIN_MSG));
298192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
299192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
300d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         * check that the charset is always set to UTF-8. We expect only text transfer (in lieu with
301d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         * the MAPv12 specifying only RFC2822 (text only) for MMS/EMAIL and SMS do not support
302d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         * non-text content. If the charset is not set to UTF-8, it is safe to set the message as
303d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         * empty. We force the getMessage (see BluetoothMasClient) to only call getMessage with
304d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         * UTF-8 as the MCE is not obliged to support native charset.
305d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal         */
306d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal        if (!mBmsg.mBbodyCharset.equals("UTF-8")) {
307d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal            Log.e(TAG, "The charset was not set to charset UTF-8: " + mBmsg.mBbodyCharset);
308d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal        }
309d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal
310d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal        /*
311192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * <bmessage-body-content>::={ "BEGIN:MSG"<CRLF> 'message'<CRLF>
312192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * "END:MSG"<CRLF> }
313192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
314192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
315192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        int messageLen = mBmsg.mBbodyLength - MSG_CONTAINER_LEN;
316192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        int offset = messageLen + CRLF_LEN;
317192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        int restartPos = mParser.pos() + offset;
318192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
319192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /*
320192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * length is specified in bytes so we need to convert from unicode
321192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         * string back to bytes array
322192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta         */
323192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
324192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        String remng = mParser.remaining();
325192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        byte[] data = remng.getBytes();
326192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
327192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        /* restart parsing from after 'message'<CRLF> */
328192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mParser = new BmsgTokenizer(new String(data, offset, data.length - offset), restartPos);
329192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
330192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = mParser.next(true);
331192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
3324231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta        if (prop != null) {
3334231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta            if (prop.equals(END_MSG)) {
334d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                if (mBmsg.mBbodyCharset.equals("UTF-8")) {
335d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                    mBmsg.mMessage = new String(data, 0, messageLen, StandardCharsets.UTF_8);
336d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                } else {
337d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                    mBmsg.mMessage = null;
338d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                }
3394231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta            } else {
3404231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                /* Handle possible exception for incorrect LENGTH value
3414231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                 * from MSE while parsing  GET Message response */
3424231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                Log.e(TAG, "Prop Invalid: "+ prop.toString());
3434231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                Log.e(TAG, "Possible Invalid LENGTH value");
3444231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                throw expected(END_MSG);
3454231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta            }
346192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } else {
347192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
348192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            data = null;
349192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
350192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            /*
351192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta             * now we check if bMessage can be parsed if LENGTH is handled as
352192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta             * number of characters instead of number of bytes
353192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta             */
3544231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta            if (offset < 0 || offset > remng.length()) {
3554231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                /* Handle possible exception for incorrect LENGTH value
3564231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                 * from MSE while parsing  GET Message response */
3574231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta                throw new ParseException("Invalid LENGTH value", mParser.pos());
3584231be1e03b7c5e563fea1fa7c56abfe2a1e61ddHemant Gupta            }
359192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
360192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.w(TAG, "byte LENGTH seems to be invalid, trying with char length");
361192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
362192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mParser = new BmsgTokenizer(remng.substring(offset));
363192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
364192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = mParser.next();
365192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
366192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (!prop.equals(END_MSG)) {
367192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                throw expected(END_MSG);
368192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
369192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
370d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal            if (mBmsg.mBbodyCharset.equals("UTF-8")) {
371d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                mBmsg.mMessage = remng.substring(0, messageLen);
372d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal            } else {
373d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal                mBmsg.mMessage = null;
374d87ff784eb2dfac818df247a153be548b13dfb02Sanket Agarwal            }
375192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
376192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
377192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        prop = mParser.next();
378192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
379192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (!prop.equals(END_BBODY)) {
380192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw expected(END_BBODY);
381192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
382192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
383192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mParser.next();
384192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
385192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
386192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private Property extractVcard(StringBuilder out) throws IOException, ParseException {
387192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        Property prop;
388192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
389192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        out.append(BEGIN_VCARD).append(CRLF);
390192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
391192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        do {
392192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            prop = mParser.next();
393192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            out.append(prop).append(CRLF);
394192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } while (!prop.equals(END_VCARD));
395192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
396192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mParser.next();
397192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
398192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
399192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private class VcardHandler implements VCardEntryHandler {
400192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
401192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        VCardEntry vcard;
402192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
403192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        @Override
404192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public void onStart() {
405192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
406192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
407192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        @Override
408192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public void onEntryCreated(VCardEntry entry) {
409192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            vcard = entry;
410192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
411192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
412192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        @Override
413192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public void onEnd() {
414192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
415192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    };
416192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
417192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private VCardEntry parseVcard(String str) throws IOException, ParseException {
418192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        VCardEntry vcard = null;
419192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
420192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        try {
421192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            VCardParser p = new VCardParser_V21();
422192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            VCardEntryConstructor c = new VCardEntryConstructor();
423192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            VcardHandler handler = new VcardHandler();
424192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            c.addEntryHandler(handler);
425192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            p.addInterpreter(c);
426192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            p.parse(new ByteArrayInputStream(str.getBytes()));
427192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
428192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            vcard = handler.vcard;
429192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
430192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (VCardVersionException e1) {
431192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
432192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            try {
433192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                VCardParser p = new VCardParser_V30();
434192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                VCardEntryConstructor c = new VCardEntryConstructor();
435192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                VcardHandler handler = new VcardHandler();
436192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                c.addEntryHandler(handler);
437192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                p.addInterpreter(c);
438192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                p.parse(new ByteArrayInputStream(str.getBytes()));
439192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
440192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                vcard = handler.vcard;
441192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
442192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (VCardVersionException e2) {
443192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                // will throw below
444192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (VCardException e2) {
445192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                // will throw below
446192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
447192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
448192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (VCardException e1) {
449192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            // will throw below
450192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
451192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
452192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (vcard == null) {
453192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            throw new ParseException("Cannot parse vCard object (neither 2.1 nor 3.0?)",
454192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    mParser.pos());
455192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
456192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
457192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return vcard;
458192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
459192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta}
460