BluetoothMapbMessage.java revision 326b5e610063ac24c0ba467ac585bd4c7f618a67
1fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie/* 2fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Copyright (C) 2013 Samsung System LSI 3fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Licensed under the Apache License, Version 2.0 (the "License"); 4fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* you may not use this file except in compliance with the License. 5fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* You may obtain a copy of the License at 6fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* 7fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* http://www.apache.org/licenses/LICENSE-2.0 8fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* 9fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Unless required by applicable law or agreed to in writing, software 10fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* distributed under the License is distributed on an "AS IS" BASIS, 11fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* See the License for the specific language governing permissions and 13fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* limitations under the License. 14fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*/ 15fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xiepackage com.android.bluetooth.map; 16fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 17fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.ByteArrayOutputStream; 1870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulzimport java.io.File; 1970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulzimport java.io.FileInputStream; 2070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulzimport java.io.FileNotFoundException; 2170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulzimport java.io.FileOutputStream; 22fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.IOException; 23fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.InputStream; 24fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.UnsupportedEncodingException; 25fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.util.ArrayList; 26fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 2770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulzimport android.os.Environment; 28fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.telephony.PhoneNumberUtils; 29fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.util.Log; 3070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 31fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport com.android.bluetooth.map.BluetoothMapUtils.TYPE; 32fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 33fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xiepublic abstract class BluetoothMapbMessage { 34fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 35fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie protected static String TAG = "BluetoothMapbMessage"; 36326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected static final boolean D = BluetoothMapService.DEBUG; 37326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected static final boolean V = BluetoothMapService.VERBOSE; 38326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 39fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private static final String VERSION = "VERSION:1.0"; 40fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 41fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public static int INVALID_VALUE = -1; 42fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 43326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected int mAppParamCharset = BluetoothMapAppParams.INVALID_VALUE_PARAMETER; 44fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 45fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* BMSG attributes */ 46326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mStatus = null; // READ/UNREAD 47326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected TYPE mType = null; // SMS/MMS/EMAIL 48fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 49326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mFolder = null; 50fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 51fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* BBODY attributes */ 52326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private long mPartId = INVALID_VALUE; 53326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected String mEncoding = null; 54326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected String mCharset = null; 55326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mLanguage = null; 56fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 57326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private int mBMsgLength = INVALID_VALUE; 58fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 59326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private ArrayList<vCard> mOriginator = null; 60326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private ArrayList<vCard> mRecipient = null; 61fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 62fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 63fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public static class vCard { 64fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* VCARD attributes */ 65326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mVersion; 66326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mName = null; 67326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mFormattedName = null; 68326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String[] mPhoneNumbers = {}; 69326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String[] mEmailAddresses = {}; 70326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private int mEnvLevel = 0; 71fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 72fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 73fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Construct a version 3.0 vCard 74fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name Structured 75fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param formattedName Formatted name 76fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers a String[] of phone numbers 77fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses a String[] of email addresses 78fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param the bmessage envelope level (0 is the top/most outer level) 79fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 80fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public vCard(String name, String formattedName, String[] phoneNumbers, 81fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] emailAddresses, int envLevel) { 82326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEnvLevel = envLevel; 83326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mVersion = "3.0"; 84326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mName = name != null ? name : ""; 85326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mFormattedName = formattedName != null ? formattedName : ""; 86fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie setPhoneNumbers(phoneNumbers); 87fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (emailAddresses != null) 88326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEmailAddresses = emailAddresses; 89fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 90fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 91fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 92fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Construct a version 2.1 vCard 93fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name Structured name 94fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers a String[] of phone numbers 95fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses a String[] of email addresses 96fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param the bmessage envelope level (0 is the top/most outer level) 97fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 98fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public vCard(String name, String[] phoneNumbers, 99fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] emailAddresses, int envLevel) { 100326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEnvLevel = envLevel; 101326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mVersion = "2.1"; 102326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mName = name != null ? name : ""; 103fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie setPhoneNumbers(phoneNumbers); 104fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (emailAddresses != null) 105326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEmailAddresses = emailAddresses; 106fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 107fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 108fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 109fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Construct a version 3.0 vCard 110fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name Structured name 111fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param formattedName Formatted name 112fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers a String[] of phone numbers 113fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses a String[] of email addresses 114fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 115fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public vCard(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) { 116326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mVersion = "3.0"; 117326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mName = (name != null) ? name : ""; 118326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mFormattedName = (formattedName != null) ? formattedName : ""; 119fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie setPhoneNumbers(phoneNumbers); 120fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (emailAddresses != null) 121326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEmailAddresses = emailAddresses; 122fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 123fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 124fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 125fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Construct a version 2.1 vCard 126fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name Structured Name 127fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers a String[] of phone numbers 128fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses a String[] of email addresses 129fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 130fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public vCard(String name, String[] phoneNumbers, String[] emailAddresses) { 131326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mVersion = "2.1"; 132326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mName = name != null ? name : ""; 133fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie setPhoneNumbers(phoneNumbers); 134fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (emailAddresses != null) 135326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEmailAddresses = emailAddresses; 136fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 137fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 138fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private void setPhoneNumbers(String[] numbers) { 139326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(numbers != null && numbers.length > 0) { 140326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mPhoneNumbers = new String[numbers.length]; 141fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for(int i = 0, n = numbers.length; i < n; i++){ 142326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String networkNumber = PhoneNumberUtils.extractNetworkPortion(numbers[i]); 143326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* extractNetworkPortion can return N if the number is a service "number" = a string 144326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * with the a name in (i.e. "Some-Tele-company" would return N because of the N in compaNy) 145326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Hence we need to check if the number is actually a string with alpha chars. 146326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * */ 147326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Boolean alpha = PhoneNumberUtils.stripSeparators(numbers[i]).matches("[0-9]*[a-zA-Z]+[0-9]*"); 148326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(networkNumber != null && networkNumber.length() > 1 && !alpha) { 149326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mPhoneNumbers[i] = networkNumber; 150326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 151326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mPhoneNumbers[i] = numbers[i]; 152326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 153fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 154fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 155fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 156fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 157fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public String getFirstPhoneNumber() { 158326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mPhoneNumbers.length > 0) { 159326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mPhoneNumbers[0]; 160fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else 161326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 162fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 163fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 164fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public int getEnvLevel() { 165326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mEnvLevel; 166326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 167326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 168326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public String getName() { 169326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mName; 170326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 171326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 172326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public String getFirstEmail() { 173326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mEmailAddresses.length > 0) { 174326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mEmailAddresses[0]; 175326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else 176326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 177fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 178fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 179fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void encode(StringBuilder sb) 180fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 181fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("BEGIN:VCARD").append("\r\n"); 182326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("VERSION:").append(mVersion).append("\r\n"); 183326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mVersion.equals("3.0") && mFormattedName != null) 184fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 185326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("FN:").append(mFormattedName).append("\r\n"); 186fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 187326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mName != null) 188326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("N:").append(mName).append("\r\n"); 189326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for(String phoneNumber : mPhoneNumbers) 190fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 191fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("TEL:").append(phoneNumber).append("\r\n"); 192fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 193326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for(String emailAddress : mEmailAddresses) 194fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 195fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("EMAIL:").append(emailAddress).append("\r\n"); 196fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 197fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("END:VCARD").append("\r\n"); 198fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 199fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 200fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 201fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Parse a vCard from a BMgsReader, where a line containing "BEGIN:VCARD" have just been read. 202fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param reader 203326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param mOriginator 204fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return 205fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 206fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public static vCard parseVcard(BMsgReader reader, int envLevel) { 207fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String formattedName = null; 208fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String name = null; 209fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie ArrayList<String> phoneNumbers = null; 210fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie ArrayList<String> emailAddresses = null; 211fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] parts; 212fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line = reader.getLineEnforce(); 213fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 214fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while(!line.contains("END:VCARD")) { 215fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = line.trim(); 216fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.startsWith("N:")){ 217fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':' 218fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(parts.length == 2) { 219fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie name = parts[1]; 220fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else 221fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie name = ""; 222fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 223fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.startsWith("FN:")){ 224fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':' 225fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(parts.length == 2) { 226fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie formattedName = parts[1]; 227fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else 228fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie formattedName = ""; 229fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 230fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.startsWith("TEL:")){ 231fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':' 232fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(parts.length == 2) { 233fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] subParts = parts[1].split("[^\\\\];"); 234fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(phoneNumbers == null) 235fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie phoneNumbers = new ArrayList<String>(1); 236fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie phoneNumbers.add(subParts[subParts.length-1]); // only keep actual phone number 237fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else {} 238fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie // Empty phone number - ignore 239fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 240fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.startsWith("EMAIL:")){ 241fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parts = line.split("[^\\\\]:"); // Split on "un-escaped" : 242fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(parts.length == 2) { 243fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] subParts = parts[1].split("[^\\\\];"); 244fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(emailAddresses == null) 245fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie emailAddresses = new ArrayList<String>(1); 246fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie emailAddresses.add(subParts[subParts.length-1]); // only keep actual email address 247fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else {} 248fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie // Empty email address entry - ignore 249fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 250fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 251fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 252fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return new vCard(name, formattedName, 253fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie phoneNumbers == null? null : phoneNumbers.toArray(new String[phoneNumbers.size()]), 254fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie emailAddresses == null ? null : emailAddresses.toArray(new String[emailAddresses.size()]), 255fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie envLevel); 256fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 257fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie }; 258fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 259fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private static class BMsgReader { 260fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie InputStream mInStream; 261fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public BMsgReader(InputStream is) 262fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 263fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie this.mInStream = is; 264fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 265fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 266fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private byte[] getLineAsBytes() { 267fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie int readByte; 268fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 269fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* TODO: Actually the vCard spec. allows to break lines by using a newLine 270fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * followed by a white space character(space or tab). Not sure this is a good idea to implement 271fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * as the Bluetooth MAP spec. illustrates vCards using tab alignment, hence actually 272fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * showing an invalid vCard format... 273fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * If we read such a folded line, the folded part will be skipped in the parser 274326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * UPDATE: Check if we actually do unfold before parsing the input stream 275fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 276fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 277fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie ByteArrayOutputStream output = new ByteArrayOutputStream(); 278fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 279fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while ((readByte = mInStream.read()) != -1) { 280fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (readByte == '\r') { 281fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if ((readByte = mInStream.read()) != -1 && readByte == '\n') { 282fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(output.size() == 0) 283fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie continue; /* Skip empty lines */ 284fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else 285fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie break; 286fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 287fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie output.write('\r'); 288fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 289fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else if (readByte == '\n' && output.size() == 0) { 290fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* Empty line - skip */ 291fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie continue; 292fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 293fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 294fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie output.write(readByte); 295fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 296fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (IOException e) { 297fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.w(TAG, e); 298fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 299fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 300fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return output.toByteArray(); 301fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 302fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 303fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 304fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Read a line of text from the BMessage. 305fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the next line of text, or null at end of file, or if UTF-8 is not supported. 306fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 307fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public String getLine() { 308fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 309fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie byte[] line = getLineAsBytes(); 310fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (line.length == 0) 311fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 312fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else 313fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return new String(line, "UTF-8"); 314fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (UnsupportedEncodingException e) { 315fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.w(TAG, e); 316fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 317fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 318fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 319fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 320fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 321fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * same as getLine(), but throws an exception, if we run out of lines. 322fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Use this function when ever more lines are needed for the bMessage to be complete. 323fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the next line 324fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 325fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public String getLineEnforce() { 32670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz String line = getLine(); 32770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if (line == null) 32870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz throw new IllegalArgumentException("Bmessage too short"); 32970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 33070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz return line; 331fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 332fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 333fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 334fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 335fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Reads a line from the InputStream, and examines if the subString 336fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * matches the line read. 337fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param subString 338fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * The string to match against the line. 339fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @throws IllegalArgumentException 340fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * If the expected substring is not found. 341fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 342fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 343fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void expect(String subString) throws IllegalArgumentException{ 344fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line = getLine(); 34570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(line == null || subString == null){ 34670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz throw new IllegalArgumentException("Line or substring is null"); 34770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz }else if(!line.toUpperCase().contains(subString.toUpperCase())) 348fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\""); 349fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 350fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 351fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 352fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Same as expect(String), but with two strings. 353fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param subString 354fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param subString2 355fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @throws IllegalArgumentException 356fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * If one or all of the strings are not found. 357fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 358fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void expect(String subString, String subString2) throws IllegalArgumentException{ 359fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line = getLine(); 36070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(!line.toUpperCase().contains(subString.toUpperCase())) 361fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\""); 36270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(!line.toUpperCase().contains(subString2.toUpperCase())) 363fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\""); 364fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 365fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 366fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 367fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Read a part of the bMessage as raw data. 368fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param length the number of bytes to read 369fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the byte[] containing the number of bytes or null if an error occurs or EOF is reached 370fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * before length bytes have been read. 371fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 372fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public byte[] getDataBytes(int length) { 373fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie byte[] data = new byte[length]; 374fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 375fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie int bytesRead; 376fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie int offset=0; 37770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz while ((bytesRead = mInStream.read(data, offset, length-offset)) != (length - offset)) { 378fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(bytesRead == -1) 379fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 380fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie offset += bytesRead; 381fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 382fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (IOException e) { 383fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.w(TAG, e); 384fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 385fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 386fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return data; 387fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 388fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie }; 389fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 39070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz public BluetoothMapbMessage(){ 391fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 392fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 393fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 394fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public static BluetoothMapbMessage parse(InputStream bMsgStream, int appParamCharset) throws IllegalArgumentException{ 39570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz BMsgReader reader; 396fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line = ""; 397fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie BluetoothMapbMessage newBMsg = null; 398fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie boolean status = false; 399fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie boolean statusFound = false; 400fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie TYPE type = null; 401fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String folder = null; 402fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 40370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* This section is used for debug. It will write the incoming message to a file on the SD-card, 40470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz * hence should only be used for test/debug. 40570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz * If an error occurs, it will result in a OBEX_HTTP_PRECON_FAILED to be send to the client, 40670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz * even though the message might be formatted correctly, hence only enable this code for test. */ 40770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(V) { 40870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* Read the entire stream into a file on the SD card*/ 40970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz File sdCard = Environment.getExternalStorageDirectory(); 41070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz File dir = new File (sdCard.getAbsolutePath() + "/bluetooth/log/"); 41170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz dir.mkdirs(); 41270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz File file = new File(dir, "receivedBMessage.txt"); 41370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz FileOutputStream outStream = null; 41470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz boolean failed = false; 41570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz int writtenLen = 0; 41670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 41770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz try { 41870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz outStream = new FileOutputStream(file, false); /* overwrite if it does already exist */ 41970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 42070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz byte[] buffer = new byte[4*1024]; 42170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz int len = 0; 42270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz while ((len = bMsgStream.read(buffer)) > 0) { 42370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz outStream.write(buffer, 0, len); 42470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz writtenLen += len; 42570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 42670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (FileNotFoundException e) { 42770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.e(TAG,"Unable to create output stream",e); 42870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (IOException e) { 42970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.e(TAG,"Failed to copy the received message",e); 43070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(writtenLen != 0) 43170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz failed = true; /* We failed to write the complete file, hence the received message is lost... */ 43270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } finally { 43370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(outStream != null) 43470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz try { 43570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz outStream.close(); 43670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (IOException e) { 43770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 43870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 43970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 44070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* Return if we corrupted the incoming bMessage. */ 44170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(failed) { 44270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz throw new IllegalArgumentException(); /* terminate this function with an error. */ 44370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 44470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 44570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if (outStream == null) { 44670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* We failed to create the the log-file, just continue using the original bMsgStream. */ 44770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } else { 44870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* overwrite the bMsgStream using the file written to the SD-Card */ 44970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz try { 45070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz bMsgStream.close(); 45170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (IOException e) { 45270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* Ignore if we cannot close the stream. */ 45370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 45470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* Open the file and overwrite bMsgStream to read from the file */ 45570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz try { 45670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz bMsgStream = new FileInputStream(file); 45770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (FileNotFoundException e) { 45870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.e(TAG,"Failed to open the bMessage file", e); 45970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz throw new IllegalArgumentException(); /* terminate this function with an error. */ 46070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 46170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 46270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.i(TAG, "The incoming bMessage have been dumped to " + file.getAbsolutePath()); 46370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } /* End of if(V) log-section */ 46470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 46570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz reader = new BMsgReader(bMsgStream); 46670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz reader.expect("BEGIN:BMSG"); 46770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz reader.expect("VERSION","1.0"); 46870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 469fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 470fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie // Parse the properties - which end with either a VCARD or a BENV 471fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while(!line.contains("BEGIN:VCARD") && !line.contains("BEGIN:BENV")) { 472fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("STATUS")){ 473fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 474fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 475fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg[1].trim().equals("READ")) { 476fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie status = true; 477fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else if (arg[1].trim().equals("UNREAD")) { 478fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie status =false; 479fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 480fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Wrong value in 'STATUS': " + arg[1]); 481fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 482fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 483fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'STATUS': " + line); 484fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 485fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 486fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("TYPE")) { 487fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 488fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 489fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String value = arg[1].trim(); 490fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie type = TYPE.valueOf(value); // Will throw IllegalArgumentException if value is wrong 491fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(appParamCharset == BluetoothMapAppParams.CHARSET_NATIVE 492fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie && type != TYPE.SMS_CDMA && type != TYPE.SMS_GSM) { 493fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Native appParamsCharset only supported for SMS"); 494fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 495fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie switch(type) { 496fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie case SMS_CDMA: 497fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie case SMS_GSM: 498fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie newBMsg = new BluetoothMapbMessageSms(); 499fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie break; 500fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie case MMS: 501326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newBMsg = new BluetoothMapbMessageMms(); 502326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 503fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie case EMAIL: 504326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newBMsg = new BluetoothMapbMessageEmail(); 505fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie break; 506fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie default: 507fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie break; 508fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 509fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 510fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'TYPE':" + line); 511fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 512fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 513fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("FOLDER")) { 514fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String[] arg = line.split(":"); 515fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 516fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie folder = arg[1].trim(); 517fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 51870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz // This can be empty for push message - hence ignore if there is no value 519fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 520fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 521fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 522fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(newBMsg == null) 523fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing bMessage TYPE: - unable to parse body-content"); 524fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie newBMsg.setType(type); 525326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newBMsg.mAppParamCharset = appParamCharset; 526fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(folder != null) 52770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz newBMsg.setCompleteFolder(folder); 528fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(statusFound) 529fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie newBMsg.setStatus(status); 530fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 531fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie // Now check for originator VCARDs 532fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while(line.contains("BEGIN:VCARD")){ 533fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding vCard"); 534fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie newBMsg.addOriginator(vCard.parseVcard(reader,0)); 535fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 536fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 537fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("BEGIN:BENV")) { 538fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie newBMsg.parseEnvelope(reader, 0); 539fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else 540fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Bmessage has no BEGIN:BENV - line:" + line); 541fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 542fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* TODO: Do we need to validate the END:* tags? They are only needed if someone puts additional info 543fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * below the END:MSG - in which case we don't handle it. 544326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * We need to parse the message based on the length field, to ensure MAP 1.0 compatibility, 545326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * since this spec. do not suggest to escape the end-tag if it occurs inside the message text. 546fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 54770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 54870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz try { 54970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz bMsgStream.close(); 55070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } catch (IOException e) { 55170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz /* Ignore if we cannot close the stream. */ 55270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 55370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 554fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return newBMsg; 555fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 556fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 557fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private void parseEnvelope(BMsgReader reader, int level) { 558fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line; 559fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 560fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding envelope level " + level); 561fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 562fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while(line.contains("BEGIN:VCARD")){ 563fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding recipient vCard level " + level); 564326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mRecipient == null) 565326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient = new ArrayList<vCard>(1); 566326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient.add(vCard.parseVcard(reader, level)); 567fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 568fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 569fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("BEGIN:BENV")) { 570fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding nested envelope"); 571fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parseEnvelope(reader, ++level); // Nested BENV 572fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 573fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("BEGIN:BBODY")){ 574fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding bbody"); 575fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parseBody(reader); 576fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 577fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 578fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 579fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie private void parseBody(BMsgReader reader) { 580fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String line; 581fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 582fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie while(!line.contains("END:")) { 583fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(line.contains("PARTID:")) { 584fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 585fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 586fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 587326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mPartId = Long.parseLong(arg[1].trim()); 588fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (NumberFormatException e) { 589fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Wrong value in 'PARTID': " + arg[1]); 590fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 591fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 592fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'PARTID': " + line); 593fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 594fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 595fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.contains("ENCODING:")) { 596fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 597fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 598326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mEncoding = arg[1].trim(); 599326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // If needed validation will be done when the value is used 600fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 601fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'ENCODING': " + line); 602fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 603fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 604fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.contains("CHARSET:")) { 605fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 606fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 607326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mCharset = arg[1].trim(); 608326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // If needed validation will be done when the value is used 609fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 610fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'CHARSET': " + line); 611fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 612fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 613fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.contains("LANGUAGE:")) { 614fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 615fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 616326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mLanguage = arg[1].trim(); 617326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // If needed validation will be done when the value is used 618fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 619fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'LANGUAGE': " + line); 620fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 621fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 622fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.contains("LENGTH:")) { 623fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String arg[] = line.split(":"); 624fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if (arg != null && arg.length == 2) { 625fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 626326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mBMsgLength = Integer.parseInt(arg[1].trim()); 627fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (NumberFormatException e) { 628fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Wrong value in 'LENGTH': " + arg[1]); 629fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 630fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } else { 631fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Missing value for 'LENGTH': " + line); 632fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 633fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 634fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else if(line.contains("BEGIN:MSG")) { 635326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mBMsgLength == INVALID_VALUE) 636326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Missing value for 'LENGTH'. " + 637326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde "Unable to read remaining part of the message"); 638326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* For SMS: Encoding of MSG is always UTF-8 compliant, regardless of any properties, 639326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde since PDUs are encodes as hex-strings */ 640fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* PTS has a bug regarding the message length, and sets it 2 bytes too short, hence 641fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * using the length field to determine the amount of data to read, might not be the 642fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * best solution. 643fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Since errata ???(bluetooth.org is down at the moment) introduced escaping of END:MSG 644fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * in the actual message content, it is now safe to use the END:MSG tag as terminator, 645fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * and simply ignore the length field.*/ 646326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde byte[] rawData = reader.getDataBytes(mBMsgLength - (line.getBytes().length + 2)); // 2 added to compensate for the removed \r\n 647fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String data; 648fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 649fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie data = new String(rawData, "UTF-8"); 650fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(V) { 651326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.v(TAG,"MsgLength: " + mBMsgLength); 652fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.v(TAG,"line.getBytes().length: " + line.getBytes().length); 653fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String debug = line.replaceAll("\\n", "<LF>\n"); 654fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie debug = debug.replaceAll("\\r", "<CR>"); 655fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.v(TAG,"The line: \"" + debug + "\""); 656fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie debug = data.replaceAll("\\n", "<LF>\n"); 657fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie debug = debug.replaceAll("\\r", "<CR>"); 658fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.v(TAG,"The msgString: \"" + debug + "\""); 659fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 660fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (UnsupportedEncodingException e) { 661fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.w(TAG,e); 662fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie throw new IllegalArgumentException("Unable to convert to UTF-8"); 663fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 664fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* Decoding of MSG: 665fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 1) split on "\r\nEND:MSG\r\n" 666fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 2) delete "BEGIN:MSG\r\n" for each msg 667fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 3) replace any occurrence of "\END:MSG" with "END:MSG" 668fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 4) based on charset from application properties either store as String[] or decode to raw PDUs 669fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * */ 670fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String messages[] = data.split("\r\nEND:MSG\r\n"); 671fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parseMsgInit(); 672fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for(int i = 0; i < messages.length; i++) { 67370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz messages[i] = messages[i].replaceFirst("^BEGIN:MSG\r\n", ""); 674fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie messages[i] = messages[i].replaceAll("\r\n([/]*)/END\\:MSG", "\r\n$1END:MSG"); 675fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie messages[i] = messages[i].trim(); 676fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie parseMsgPart(messages[i]); 677fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 678fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 679fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie line = reader.getLineEnforce(); 680fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 681fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 682fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 683fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 684fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Parse the 'message' part of <bmessage-body-content>" 685fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param msgPart 686fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 687fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public abstract void parseMsgPart(String msgPart); 688fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 689fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Set initial values before parsing - will be called is a message body is found 690fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * during parsing. 691fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 692fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public abstract void parseMsgInit(); 693fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 694fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public abstract byte[] encode() throws UnsupportedEncodingException; 695fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 696fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void setStatus(boolean read) { 697fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(read) 698326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mStatus = "READ"; 699fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie else 700326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mStatus = "UNREAD"; 701fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 702fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 703fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void setType(TYPE type) { 704326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mType = type; 705fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 706fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 707fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 708fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the type 709fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 710fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public TYPE getType() { 711326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mType; 712fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 713fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 71470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz public void setCompleteFolder(String folder) { 715326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mFolder = folder; 71670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 71770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 718fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void setFolder(String folder) { 719326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mFolder = "telecom/msg/" + folder; 720fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 721fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 72270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz public String getFolder() { 723326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mFolder; 72470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 72570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 72670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz 727fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void setEncoding(String encoding) { 728326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mEncoding = encoding; 729fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 730fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 731fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public ArrayList<vCard> getOriginators() { 732326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mOriginator; 733fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 734fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 735fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void addOriginator(vCard originator) { 736326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(this.mOriginator == null) 737326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mOriginator = new ArrayList<vCard>(); 738326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mOriginator.add(originator); 739fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 740fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 741fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 742fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Add a version 3.0 vCard with a formatted name 743fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name e.g. Bonde;Casper 744fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param formattedName e.g. "Casper Bonde" 745fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers 746fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses 747fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 748fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void addOriginator(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) { 749326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mOriginator == null) 750326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mOriginator = new ArrayList<vCard>(); 751326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mOriginator.add(new vCard(name, formattedName, phoneNumbers, emailAddresses)); 752fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 753fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 754fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** Add a version 2.1 vCard with only a name. 755fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * 756fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param name e.g. Bonde;Casper 757fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param phoneNumbers 758fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param emailAddresses 759fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 760fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void addOriginator(String name, String[] phoneNumbers, String[] emailAddresses) { 761326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mOriginator == null) 762326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mOriginator = new ArrayList<vCard>(); 763326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mOriginator.add(new vCard(name, phoneNumbers, emailAddresses)); 764fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 765fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 766fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public ArrayList<vCard> getRecipients() { 767326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mRecipient; 768fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 769fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 770fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void setRecipient(vCard recipient) { 771326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(this.mRecipient == null) 772326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mRecipient = new ArrayList<vCard>(); 773326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this.mRecipient.add(recipient); 774fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 775fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 776fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void addRecipient(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) { 777326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mRecipient == null) 778326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient = new ArrayList<vCard>(); 779326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient.add(new vCard(name, formattedName, phoneNumbers, emailAddresses)); 780fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 781fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 782fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public void addRecipient(String name, String[] phoneNumbers, String[] emailAddresses) { 783326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mRecipient == null) 784326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient = new ArrayList<vCard>(); 785326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRecipient.add(new vCard(name, phoneNumbers, emailAddresses)); 786fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 787fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 788fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 789fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Convert a byte[] of data to a hex string representation, converting each nibble to the corresponding 790fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * hex char. 791fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * NOTE: There is not need to escape instances of "\r\nEND:MSG" in the binary data represented as a string 792fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * as only the characters [0-9] and [a-f] is used. 793fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param pduData the byte-array of data. 794fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param scAddressData the byte-array of the encoded sc-Address. 795fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the resulting string. 796fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 797fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie protected String encodeBinary(byte[] pduData, byte[] scAddressData) { 798fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie StringBuilder out = new StringBuilder((pduData.length + scAddressData.length)*2); 799fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for(int i = 0; i < scAddressData.length; i++) { 800fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie out.append(Integer.toString((scAddressData[i] >> 4) & 0x0f,16)); // MS-nibble first 801fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie out.append(Integer.toString( scAddressData[i] & 0x0f,16)); 802fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 803fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for(int i = 0; i < pduData.length; i++) { 804fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie out.append(Integer.toString((pduData[i] >> 4) & 0x0f,16)); // MS-nibble first 805fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie out.append(Integer.toString( pduData[i] & 0x0f,16)); 806fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /*out.append(Integer.toHexString(data[i]));*/ /* This is the same as above, but does not include the needed 0's 807fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie e.g. it converts the value 3 to "3" and not "03" */ 808fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 809fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return out.toString(); 810fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 811fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 812fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /** 813fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * Decodes a binary hex-string encoded UTF-8 string to the represented binary data set. 814fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @param data The string representation of the data - must have an even number of characters. 815fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * @return the byte[] represented in the data. 816fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 817fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie protected byte[] decodeBinary(String data) { 818fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie byte[] out = new byte[data.length()/2]; 819fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie String value; 820fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(D) Log.d(TAG,"Decoding binary data: START:" + data + ":END"); 821fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for(int i = 0, j = 0, n = out.length; i < n; i++) 822fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 82370be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz value = data.substring(j++, ++j); // same as data.substring(2*i, 2*i+1+1) - substring() uses end-1 for last index 82470be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz out[i] = (byte)(Integer.valueOf(value, 16) & 0xff); 82570be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 82670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if(D) { 82770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz StringBuilder sb = new StringBuilder(out.length); 82870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz for(int i = 0, n = out.length; i < n; i++) 82970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz { 83070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz sb.append(String.format("%02X",out[i] & 0xff)); 83170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 83270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.d(TAG,"Decoded binary data: START:" + sb.toString() + ":END"); 833fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 834fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return out; 835fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 836fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 837fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie public byte[] encodeGeneric(ArrayList<byte[]> bodyFragments) throws UnsupportedEncodingException 838fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie { 839fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie StringBuilder sb = new StringBuilder(256); 840fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie byte[] msgStart, msgEnd; 841fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("BEGIN:BMSG").append("\r\n"); 842fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append(VERSION).append("\r\n"); 843326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("STATUS:").append(mStatus).append("\r\n"); 844326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("TYPE:").append(mType.name()).append("\r\n"); 845326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mFolder.length() > 512) 846326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("FOLDER:").append(mFolder.substring(mFolder.length()-512, mFolder.length())).append("\r\n"); 84770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz else 848326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("FOLDER:").append(mFolder).append("\r\n"); 849326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mOriginator != null){ 850326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for(vCard element : mOriginator) 851fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie element.encode(sb); 852fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 853326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* If we need the three levels of env. at some point - we do have a level in the 854326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * vCards that could be used to determine the levels of the envelope. 855fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */ 856fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 857fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("BEGIN:BENV").append("\r\n"); 858326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mRecipient != null){ 859326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for(vCard element : mRecipient) { 860326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(V) Log.v(TAG, "encodeGeneric: recipient email" + element.getFirstEmail()); 861fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie element.encode(sb); 862326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 863fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 864fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("BEGIN:BBODY").append("\r\n"); 865326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mEncoding != null && mEncoding != "") 866326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("ENCODING:").append(mEncoding).append("\r\n"); 867326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mCharset != null && mCharset != "") 868326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde sb.append("CHARSET:").append(mCharset).append("\r\n"); 869fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 870fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 871fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie int length = 0; 872fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie /* 22 is the length of the 'BEGIN:MSG' and 'END:MSG' + 3*CRLF */ 873fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for (byte[] fragment : bodyFragments) { 874fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie length += fragment.length + 22; 875fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 876fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("LENGTH:").append(length).append("\r\n"); 877fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 878fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie // Extract the initial part of the bMessage string 879fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie msgStart = sb.toString().getBytes("UTF-8"); 880fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 881fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb = new StringBuilder(31); 882fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("END:BBODY").append("\r\n"); 883fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("END:BENV").append("\r\n"); 884fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie sb.append("END:BMSG").append("\r\n"); 885fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 886fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie msgEnd = sb.toString().getBytes("UTF-8"); 887fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 888fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie try { 889fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 890fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie ByteArrayOutputStream stream = new ByteArrayOutputStream(msgStart.length + msgEnd.length + length); 891fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie stream.write(msgStart); 892fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 893fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie for (byte[] fragment : bodyFragments) { 894fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie stream.write("BEGIN:MSG\r\n".getBytes("UTF-8")); 895fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie stream.write(fragment); 896fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie stream.write("\r\nEND:MSG\r\n".getBytes("UTF-8")); 897fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 898fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie stream.write(msgEnd); 899fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie 900fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie if(V) Log.v(TAG,stream.toString("UTF-8")); 901fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return stream.toByteArray(); 902fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } catch (IOException e) { 903fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie Log.w(TAG,e); 904fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie return null; 905fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 906fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie } 907fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie} 908