1 /* 2 * Copyright (C) 2014 Samsung System LSI 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package com.android.bluetooth.map; 16 17 import org.apache.http.util.ByteArrayBuffer; 18 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.database.Cursor; 23 import android.net.Uri; 24 import android.os.Debug; 25 import android.os.ParcelFileDescriptor; 26 import android.provider.BaseColumns; 27 import com.android.bluetooth.mapapi.BluetoothMapContract; 28 import com.android.bluetooth.mapapi.BluetoothMapContract.MessageColumns; 29 import android.provider.ContactsContract; 30 import android.provider.ContactsContract.Contacts; 31 import android.provider.ContactsContract.PhoneLookup; 32 import android.provider.Telephony.Mms; 33 import android.provider.Telephony.Sms; 34 import android.telephony.PhoneNumberUtils; 35 import android.telephony.TelephonyManager; 36 import android.text.util.Rfc822Token; 37 import android.text.util.Rfc822Tokenizer; 38 import android.util.Log; 39 40 import com.android.bluetooth.map.BluetoothMapSmsPdu.SmsPdu; 41 import com.android.bluetooth.map.BluetoothMapUtils.TYPE; 42 import com.google.android.mms.pdu.CharacterSets; 43 import com.google.android.mms.pdu.PduHeaders; 44 import com.android.bluetooth.map.BluetoothMapAppParams; 45 46 import java.io.ByteArrayOutputStream; 47 import java.io.FileInputStream; 48 import java.io.FileNotFoundException; 49 import java.io.IOException; 50 import java.io.InputStream; 51 import java.io.UnsupportedEncodingException; 52 import java.text.ParseException; 53 import java.text.SimpleDateFormat; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.Date; 57 import java.util.List; 58 59 public class BluetoothMapContent { 60 private static final String TAG = "BluetoothMapContent"; 61 62 private static final boolean D = BluetoothMapService.DEBUG; 63 private static final boolean V = BluetoothMapService.VERBOSE; 64 65 private static final int MASK_SUBJECT = 0x1; 66 private static final int MASK_DATETIME = 0x2; 67 private static final int MASK_SENDER_NAME = 0x4; 68 private static final int MASK_SENDER_ADDRESSING = 0x8; 69 70 private static final int MASK_RECIPIENT_NAME = 0x10; 71 private static final int MASK_RECIPIENT_ADDRESSING = 0x20; 72 private static final int MASK_TYPE = 0x40; 73 private static final int MASK_SIZE = 0x80; 74 75 private static final int MASK_RECEPTION_STATUS = 0x100; 76 private static final int MASK_TEXT = 0x200; 77 private static final int MASK_ATTACHMENT_SIZE = 0x400; 78 private static final int MASK_PRIORITY = 0x800; 79 80 private static final int MASK_READ = 0x1000; 81 private static final int MASK_SENT = 0x2000; 82 private static final int MASK_PROTECTED = 0x4000; 83 private static final int MASK_REPLYTO_ADDRESSING = 0x8000; 84 85 /* Type of MMS address. From Telephony.java it must be one of PduHeaders.BCC, */ 86 /* PduHeaders.CC, PduHeaders.FROM, PduHeaders.TO. These are from PduHeaders.java */ 87 public static final int MMS_FROM = 0x89; 88 public static final int MMS_TO = 0x97; 89 public static final int MMS_BCC = 0x81; 90 public static final int MMS_CC = 0x82; 91 92 public static final String INSERT_ADDRES_TOKEN = "insert-address-token"; 93 94 private Context mContext; 95 private ContentResolver mResolver; 96 private String mBaseEmailUri = null; 97 98 static final String[] SMS_PROJECTION = new String[] { 99 BaseColumns._ID, 100 Sms.THREAD_ID, 101 Sms.ADDRESS, 102 Sms.BODY, 103 Sms.DATE, 104 Sms.READ, 105 Sms.TYPE, 106 Sms.STATUS, 107 Sms.LOCKED, 108 Sms.ERROR_CODE 109 }; 110 111 static final String[] MMS_PROJECTION = new String[] { 112 BaseColumns._ID, 113 Mms.THREAD_ID, 114 Mms.MESSAGE_ID, 115 Mms.MESSAGE_SIZE, 116 Mms.SUBJECT, 117 Mms.CONTENT_TYPE, 118 Mms.TEXT_ONLY, 119 Mms.DATE, 120 Mms.DATE_SENT, 121 Mms.READ, 122 Mms.MESSAGE_BOX, 123 Mms.STATUS, 124 Mms.PRIORITY 125 }; 126 127 private class FilterInfo { 128 public static final int TYPE_SMS = 0; 129 public static final int TYPE_MMS = 1; 130 public static final int TYPE_EMAIL = 2; 131 132 int mMsgType = TYPE_SMS; 133 int mPhoneType = 0; 134 String mPhoneNum = null; 135 String mPhoneAlphaTag = null; 136 /*column indices used to optimize queries */ 137 public int mEmailColThreadId = -1; 138 public int mEmailColProtected = -1; 139 public int mEmailColFolder = -1; 140 public int mMmsColFolder = -1; 141 public int mSmsColFolder = -1; 142 public int mEmailColRead = -1; 143 public int mSmsColRead = -1; 144 public int mMmsColRead = -1; 145 public int mEmailColPriority = -1; 146 public int mMmsColAttachmentSize = -1; 147 public int mEmailColAttachment = -1; 148 public int mEmailColAttachementSize = -1; 149 public int mMmsColTextOnly = -1; 150 public int mMmsColId = -1; 151 public int mSmsColId = -1; 152 public int mEmailColSize = -1; 153 public int mSmsColSubject = -1; 154 public int mMmsColSize = -1; 155 public int mEmailColToAddress = -1; 156 public int mEmailColCcAddress = -1; 157 public int mEmailColBccAddress = -1; 158 public int mSmsColAddress = -1; 159 public int mSmsColDate = -1; 160 public int mMmsColDate = -1; 161 public int mEmailColDate = -1; 162 public int mMmsColSubject = -1; 163 public int mEmailColSubject = -1; 164 public int mSmsColType = -1; 165 public int mEmailColFromAddress = -1; 166 public int mEmailColId = -1; 167 168 169 public void setEmailColumns(Cursor c) { 170 mEmailColThreadId = c.getColumnIndex(BluetoothMapContract.MessageColumns.THREAD_ID); 171 mEmailColProtected = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_PROTECTED); 172 mEmailColFolder = c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID); 173 mEmailColRead = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ); 174 mEmailColPriority = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY); 175 mEmailColAttachment = c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT); 176 mEmailColAttachementSize = c.getColumnIndex(BluetoothMapContract.MessageColumns.ATTACHMENT_SIZE); 177 mEmailColSize = c.getColumnIndex(BluetoothMapContract.MessageColumns.MESSAGE_SIZE); 178 mEmailColToAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST); 179 mEmailColCcAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.CC_LIST); 180 mEmailColBccAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.BCC_LIST); 181 mEmailColDate = c.getColumnIndex(BluetoothMapContract.MessageColumns.DATE); 182 mEmailColSubject = c.getColumnIndex(BluetoothMapContract.MessageColumns.SUBJECT); 183 mEmailColFromAddress = c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST); 184 mEmailColId = c.getColumnIndex(BluetoothMapContract.MessageColumns._ID); 185 } 186 187 public void setSmsColumns(Cursor c) { 188 mSmsColId = c.getColumnIndex(BaseColumns._ID); 189 mSmsColFolder = c.getColumnIndex(Sms.TYPE); 190 mSmsColRead = c.getColumnIndex(Sms.READ); 191 mSmsColSubject = c.getColumnIndex(Sms.BODY); 192 mSmsColAddress = c.getColumnIndex(Sms.ADDRESS); 193 mSmsColDate = c.getColumnIndex(Sms.DATE); 194 mSmsColType = c.getColumnIndex(Sms.TYPE); 195 } 196 197 public void setMmsColumns(Cursor c) { 198 mMmsColId = c.getColumnIndex(BaseColumns._ID); 199 mMmsColFolder = c.getColumnIndex(Mms.MESSAGE_BOX); 200 mMmsColRead = c.getColumnIndex(Mms.READ); 201 mMmsColAttachmentSize = c.getColumnIndex(Mms.MESSAGE_SIZE); 202 mMmsColTextOnly = c.getColumnIndex(Mms.TEXT_ONLY); 203 mMmsColSize = c.getColumnIndex(Mms.MESSAGE_SIZE); 204 mMmsColDate = c.getColumnIndex(Mms.DATE); 205 mMmsColSubject = c.getColumnIndex(Mms.SUBJECT); 206 207 } 208 } 209 210 public BluetoothMapContent(final Context context, String emailBaseUri) { 211 mContext = context; 212 mResolver = mContext.getContentResolver(); 213 if (mResolver == null) { 214 if (D) Log.d(TAG, "getContentResolver failed"); 215 } 216 mBaseEmailUri = emailBaseUri; 217 } 218 219 220 221 private void printSms(Cursor c) { 222 String body = c.getString(c.getColumnIndex(Sms.BODY)); 223 if (V) Log.v(TAG, "printSms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) + 224 "\n " + Sms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Sms.THREAD_ID)) + 225 "\n " + Sms.ADDRESS + " : " + c.getString(c.getColumnIndex(Sms.ADDRESS)) + 226 "\n " + Sms.BODY + " : " + body.substring(0, Math.min(body.length(), 8)) + 227 "\n " + Sms.DATE + " : " + c.getLong(c.getColumnIndex(Sms.DATE)) + 228 "\n " + Sms.READ + " : " + c.getLong(c.getColumnIndex(Sms.READ)) + 229 "\n " + Sms.TYPE + " : " + c.getInt(c.getColumnIndex(Sms.TYPE)) + 230 "\n " + Sms.STATUS + " : " + c.getInt(c.getColumnIndex(Sms.STATUS)) + 231 "\n " + Sms.LOCKED + " : " + c.getInt(c.getColumnIndex(Sms.LOCKED)) + 232 "\n " + Sms.ERROR_CODE + " : " + c.getInt(c.getColumnIndex(Sms.ERROR_CODE))); 233 234 235 } 236 237 private void printMms(Cursor c) { 238 if (V) Log.v(TAG, "printMms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) + 239 "\n " + Mms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Mms.THREAD_ID)) + 240 "\n " + Mms.MESSAGE_ID + " : " + c.getString(c.getColumnIndex(Mms.MESSAGE_ID)) + 241 "\n " + Mms.SUBJECT + " : " + c.getString(c.getColumnIndex(Mms.SUBJECT)) + 242 "\n " + Mms.CONTENT_TYPE + " : " + c.getString(c.getColumnIndex(Mms.CONTENT_TYPE)) + 243 "\n " + Mms.TEXT_ONLY + " : " + c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) + 244 "\n " + Mms.DATE + " : " + c.getLong(c.getColumnIndex(Mms.DATE)) + 245 "\n " + Mms.DATE_SENT + " : " + c.getLong(c.getColumnIndex(Mms.DATE_SENT)) + 246 "\n " + Mms.READ + " : " + c.getInt(c.getColumnIndex(Mms.READ)) + 247 "\n " + Mms.MESSAGE_BOX + " : " + c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)) + 248 "\n " + Mms.STATUS + " : " + c.getInt(c.getColumnIndex(Mms.STATUS)) + 249 "\n " + Mms.PRIORITY + " : " + c.getInt(c.getColumnIndex(Mms.PRIORITY)) + 250 "\n " + Mms.MESSAGE_SIZE + " : " + c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE))); 251 } 252 253 private String getDateTimeString(long timestamp) { 254 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 255 Date date = new Date(timestamp); 256 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 257 } 258 private void printEmail(Cursor c) { 259 if (V) Log.v(TAG, "printEmail " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) + 260 "\n " + BluetoothMapContract.MessageColumns.DATE + " : " + getDateTimeString(c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.DATE))) + 261 "\n " + BluetoothMapContract.MessageColumns.SUBJECT + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.SUBJECT)) + 262 "\n " + BluetoothMapContract.MessageColumns.FLAG_READ + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ)) + 263 "\n " + BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY)) + 264 "\n " + BluetoothMapContract.MessageColumns.RECEPTION_STATE + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.RECEPTION_STATE)) + 265 "\n " + BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_ATTACHMENT)) + 266 "\n " + BluetoothMapContract.MessageColumns.MESSAGE_SIZE + " : " + c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.MESSAGE_SIZE)) + 267 "\n " + BluetoothMapContract.MessageColumns.FLAG_PROTECTED + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_PROTECTED)) + 268 "\n " + BluetoothMapContract.MessageColumns.FROM_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST)) + 269 "\n " + BluetoothMapContract.MessageColumns.TO_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST)) + 270 "\n " + BluetoothMapContract.MessageColumns.CC_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.CC_LIST)) + 271 "\n " + BluetoothMapContract.MessageColumns.BCC_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.BCC_LIST)) + 272 "\n " + BluetoothMapContract.MessageColumns.REPLY_TO_LIST + " : " + c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.REPLY_TO_LIST)) + 273 "\n " + BluetoothMapContract.MessageColumns.FOLDER_ID + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID)) + 274 "\n " + BluetoothMapContract.MessageColumns.ACCOUNT_ID + " : " + c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.ACCOUNT_ID)) ); 275 } 276 277 private void printMmsAddr(long id) { 278 final String[] projection = null; 279 String selection = new String("msg_id=" + id); 280 String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr"); 281 Uri uriAddress = Uri.parse(uriStr); 282 Cursor c = mResolver.query(uriAddress, projection, selection, null, null); 283 284 if (c.moveToFirst()) { 285 do { 286 String add = c.getString(c.getColumnIndex("address")); 287 Integer type = c.getInt(c.getColumnIndex("type")); 288 if (type == MMS_TO) { 289 if (D) Log.d(TAG, " recipient: " + add + " (type: " + type + ")"); 290 } else if (type == MMS_FROM) { 291 if (D) Log.d(TAG, " originator: " + add + " (type: " + type + ")"); 292 } else { 293 if (D) Log.d(TAG, " address other: " + add + " (type: " + type + ")"); 294 } 295 296 } while(c.moveToNext()); 297 } 298 } 299 300 private void printMmsPartImage(long partid) { 301 String uriStr = new String(Mms.CONTENT_URI + "/part/" + partid); 302 Uri uriAddress = Uri.parse(uriStr); 303 int ch; 304 StringBuffer sb = new StringBuffer(""); 305 InputStream is = null; 306 307 try { 308 is = mResolver.openInputStream(uriAddress); 309 310 while ((ch = is.read()) != -1) { 311 sb.append((char)ch); 312 } 313 if (D) Log.d(TAG, sb.toString()); 314 315 } catch (IOException e) { 316 // do nothing for now 317 e.printStackTrace(); 318 } 319 } 320 321 private void printMmsParts(long id) { 322 final String[] projection = null; 323 String selection = new String("mid=" + id); 324 String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/part"); 325 Uri uriAddress = Uri.parse(uriStr); 326 Cursor c = mResolver.query(uriAddress, projection, selection, null, null); 327 328 if (D) Log.d(TAG, " parts:"); 329 if (c.moveToFirst()) { 330 do { 331 Long partid = c.getLong(c.getColumnIndex(BaseColumns._ID)); 332 String ct = c.getString(c.getColumnIndex("ct")); 333 String name = c.getString(c.getColumnIndex("name")); 334 String charset = c.getString(c.getColumnIndex("chset")); 335 String filename = c.getString(c.getColumnIndex("fn")); 336 String text = c.getString(c.getColumnIndex("text")); 337 Integer fd = c.getInt(c.getColumnIndex("_data")); 338 String cid = c.getString(c.getColumnIndex("cid")); 339 String cl = c.getString(c.getColumnIndex("cl")); 340 String cdisp = c.getString(c.getColumnIndex("cd")); 341 342 if (D) Log.d(TAG, " _id : " + partid + 343 "\n ct : " + ct + 344 "\n partname : " + name + 345 "\n charset : " + charset + 346 "\n filename : " + filename + 347 "\n text : " + text + 348 "\n fd : " + fd + 349 "\n cid : " + cid + 350 "\n cl : " + cl + 351 "\n cdisp : " + cdisp); 352 353 /* if (ct.equals("image/jpeg")) { */ 354 /* printMmsPartImage(partid); */ 355 /* } */ 356 } while(c.moveToNext()); 357 } 358 } 359 360 361 private void setProtected(BluetoothMapMessageListingElement e, Cursor c, 362 FilterInfo fi, BluetoothMapAppParams ap) { 363 if ((ap.getParameterMask() & MASK_PROTECTED) != 0) { 364 String protect = "no"; 365 if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 366 int flagProtected = c.getInt(fi.mEmailColProtected); 367 if (flagProtected == 1) { 368 protect = "yes"; 369 } 370 } 371 if (V) Log.d(TAG, "setProtected: " + protect + "\n"); 372 e.setProtect(protect); 373 } 374 } 375 376 /** 377 * Email only 378 */ 379 private void setThreadId(BluetoothMapMessageListingElement e, Cursor c, 380 FilterInfo fi, BluetoothMapAppParams ap) { 381 if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 382 long threadId = c.getLong(fi.mEmailColThreadId); 383 e.setThreadId(threadId); 384 if (V) Log.d(TAG, "setThreadId: " + threadId + "\n"); 385 } 386 } 387 388 private void setSent(BluetoothMapMessageListingElement e, Cursor c, 389 FilterInfo fi, BluetoothMapAppParams ap) { 390 if ((ap.getParameterMask() & MASK_SENT) != 0) { 391 int msgType = 0; 392 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 393 msgType = c.getInt(fi.mSmsColFolder); 394 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 395 msgType = c.getInt(fi.mMmsColFolder); 396 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 397 msgType = c.getInt(fi.mEmailColFolder); 398 } 399 String sent = null; 400 if (msgType == 2) { 401 sent = "yes"; 402 } else { 403 sent = "no"; 404 } 405 if (V) Log.d(TAG, "setSent: " + sent); 406 e.setSent(sent); 407 } 408 } 409 410 private void setRead(BluetoothMapMessageListingElement e, Cursor c, 411 FilterInfo fi, BluetoothMapAppParams ap) { 412 int read = 0; 413 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 414 read = c.getInt(fi.mSmsColRead); 415 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 416 read = c.getInt(fi.mMmsColRead); 417 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 418 read = c.getInt(fi.mEmailColRead); 419 } 420 String setread = null; 421 422 if (V) Log.d(TAG, "setRead: " + setread); 423 e.setRead((read==1?true:false), ((ap.getParameterMask() & MASK_READ) != 0)); 424 } 425 426 private void setPriority(BluetoothMapMessageListingElement e, Cursor c, 427 FilterInfo fi, BluetoothMapAppParams ap) { 428 if ((ap.getParameterMask() & MASK_PRIORITY) != 0) { 429 String priority = "no"; 430 if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 431 int highPriority = c.getInt(fi.mEmailColPriority); 432 if (highPriority == 1) { 433 priority = "yes"; 434 } 435 } 436 int pri = 0; 437 if (fi.mMsgType == FilterInfo.TYPE_MMS) { 438 pri = c.getInt(c.getColumnIndex(Mms.PRIORITY)); 439 } 440 if (pri == PduHeaders.PRIORITY_HIGH) { 441 priority = "yes"; 442 } 443 if (V) Log.d(TAG, "setPriority: " + priority); 444 e.setPriority(priority); 445 } 446 } 447 448 /** 449 * For SMS we set the attachment size to 0, as all data will be text data, hence 450 * attachments for SMS is not possible. 451 * For MMS all data is actually attachments, hence we do set the attachment size to 452 * the total message size. To provide a more accurate attachment size, one could 453 * extract the length (in bytes) of the text parts. 454 */ 455 private void setAttachmentSize(BluetoothMapMessageListingElement e, Cursor c, 456 FilterInfo fi, BluetoothMapAppParams ap) { 457 if ((ap.getParameterMask() & MASK_ATTACHMENT_SIZE) != 0) { 458 int size = 0; 459 if (fi.mMsgType == FilterInfo.TYPE_MMS) { 460 if(c.getInt(fi.mMmsColTextOnly) == 0) { 461 size = c.getInt(fi.mMmsColAttachmentSize); 462 if(size <= 0) { 463 // We know there are attachments, since it is not TextOnly 464 // Hence the size in the database must be wrong. 465 // Set size to 1 to indicate to the client, that attachments are present 466 if (D) Log.d(TAG, "Error in message database, size reported as: " + size 467 + " Changing size to 1"); 468 size = 1; 469 } 470 } 471 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 472 int attachment = c.getInt(fi.mEmailColAttachment); 473 size = c.getInt(fi.mEmailColAttachementSize); 474 if(attachment == 1 && size == 0) { 475 if (D) Log.d(TAG, "Error in message database, attachment size reported as: " + size 476 + " Changing size to 1"); 477 size = 1; /* Ensure we indicate we have attachments in the size, if the 478 message has attachments, in case the e-mail client do not 479 report a size */ 480 } 481 } 482 if (V) Log.d(TAG, "setAttachmentSize: " + size); 483 e.setAttachmentSize(size); 484 } 485 } 486 487 private void setText(BluetoothMapMessageListingElement e, Cursor c, 488 FilterInfo fi, BluetoothMapAppParams ap) { 489 if ((ap.getParameterMask() & MASK_TEXT) != 0) { 490 String hasText = ""; 491 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 492 hasText = "yes"; 493 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 494 int textOnly = c.getInt(fi.mMmsColTextOnly); 495 if (textOnly == 1) { 496 hasText = "yes"; 497 } else { 498 long id = c.getLong(fi.mMmsColId); 499 String text = getTextPartsMms(id); 500 if (text != null && text.length() > 0) { 501 hasText = "yes"; 502 } else { 503 hasText = "no"; 504 } 505 } 506 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 507 hasText = "yes"; 508 } 509 if (V) Log.d(TAG, "setText: " + hasText); 510 e.setText(hasText); 511 } 512 } 513 514 private void setReceptionStatus(BluetoothMapMessageListingElement e, Cursor c, 515 FilterInfo fi, BluetoothMapAppParams ap) { 516 if ((ap.getParameterMask() & MASK_RECEPTION_STATUS) != 0) { 517 String status = "complete"; 518 if (V) Log.d(TAG, "setReceptionStatus: " + status); 519 e.setReceptionStatus(status); 520 } 521 } 522 523 private void setSize(BluetoothMapMessageListingElement e, Cursor c, 524 FilterInfo fi, BluetoothMapAppParams ap) { 525 if ((ap.getParameterMask() & MASK_SIZE) != 0) { 526 int size = 0; 527 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 528 String subject = c.getString(fi.mSmsColSubject); 529 size = subject.length(); 530 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 531 size = c.getInt(fi.mMmsColSize); 532 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 533 size = c.getInt(fi.mEmailColSize); 534 } 535 if(size <= 0) { 536 // A message cannot have size 0 537 // Hence the size in the database must be wrong. 538 // Set size to 1 to indicate to the client, that the message has content. 539 if (D) Log.d(TAG, "Error in message database, size reported as: " + size 540 + " Changing size to 1"); 541 size = 1; 542 } 543 if (V) Log.d(TAG, "setSize: " + size); 544 e.setSize(size); 545 } 546 } 547 548 private void setType(BluetoothMapMessageListingElement e, Cursor c, 549 FilterInfo fi, BluetoothMapAppParams ap) { 550 if ((ap.getParameterMask() & MASK_TYPE) != 0) { 551 TYPE type = null; 552 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 553 if (fi.mPhoneType == TelephonyManager.PHONE_TYPE_GSM) { 554 type = TYPE.SMS_GSM; 555 } else if (fi.mPhoneType == TelephonyManager.PHONE_TYPE_CDMA) { 556 type = TYPE.SMS_CDMA; 557 } 558 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 559 type = TYPE.MMS; 560 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 561 type = TYPE.EMAIL; 562 } 563 if (V) Log.d(TAG, "setType: " + type); 564 e.setType(type); 565 } 566 } 567 568 private String setRecipientAddressingEmail(BluetoothMapMessageListingElement e, Cursor c, FilterInfo fi) { 569 String toAddress, ccAddress, bccAddress; 570 toAddress = c.getString(fi.mEmailColToAddress); 571 ccAddress = c.getString(fi.mEmailColCcAddress); 572 bccAddress = c.getString(fi.mEmailColBccAddress); 573 574 String address = ""; 575 if (toAddress != null) { 576 address += toAddress; 577 if (ccAddress != null) { 578 address += ","; 579 } 580 } 581 if (ccAddress != null) { 582 address += ccAddress; 583 if (bccAddress != null) { 584 address += ","; 585 } 586 } 587 if (bccAddress != null) { 588 address += bccAddress; 589 } 590 return address; 591 } 592 593 private void setRecipientAddressing(BluetoothMapMessageListingElement e, Cursor c, 594 FilterInfo fi, BluetoothMapAppParams ap) { 595 if ((ap.getParameterMask() & MASK_RECIPIENT_ADDRESSING) != 0) { 596 String address = null; 597 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 598 int msgType = c.getInt(fi.mSmsColType); 599 if (msgType == 1) { 600 address = fi.mPhoneNum; 601 } else { 602 address = c.getString(c.getColumnIndex(Sms.ADDRESS)); 603 } 604 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 605 long id = c.getLong(c.getColumnIndex(BaseColumns._ID)); 606 address = getAddressMms(mResolver, id, MMS_TO); 607 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 608 /* Might be another way to handle addresses */ 609 address = setRecipientAddressingEmail(e, c,fi); 610 } 611 if (V) Log.v(TAG, "setRecipientAddressing: " + address); 612 if(address == null) 613 address = ""; 614 e.setRecipientAddressing(address); 615 } 616 } 617 618 private void setRecipientName(BluetoothMapMessageListingElement e, Cursor c, 619 FilterInfo fi, BluetoothMapAppParams ap) { 620 if ((ap.getParameterMask() & MASK_RECIPIENT_NAME) != 0) { 621 String name = null; 622 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 623 int msgType = c.getInt(fi.mSmsColType); 624 if (msgType != 1) { 625 String phone = c.getString(fi.mSmsColAddress); 626 if (phone != null && !phone.isEmpty()) 627 name = getContactNameFromPhone(phone); 628 } else { 629 name = fi.mPhoneAlphaTag; 630 } 631 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 632 long id = c.getLong(fi.mMmsColId); 633 String phone; 634 if(e.getRecipientAddressing() != null){ 635 phone = getAddressMms(mResolver, id, MMS_TO); 636 } else { 637 phone = e.getRecipientAddressing(); 638 } 639 if (phone != null && !phone.isEmpty()) 640 name = getContactNameFromPhone(phone); 641 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 642 /* Might be another way to handle address and names */ 643 name = setRecipientAddressingEmail(e,c,fi); 644 } 645 if (V) Log.v(TAG, "setRecipientName: " + name); 646 if(name == null) 647 name = ""; 648 e.setRecipientName(name); 649 } 650 } 651 652 private void setSenderAddressing(BluetoothMapMessageListingElement e, Cursor c, 653 FilterInfo fi, BluetoothMapAppParams ap) { 654 if ((ap.getParameterMask() & MASK_SENDER_ADDRESSING) != 0) { 655 String address = null; 656 String tempAddress; 657 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 658 int msgType = c.getInt(fi.mSmsColType); 659 if (msgType == 1) { // INBOX 660 tempAddress = c.getString(fi.mSmsColAddress); 661 } else { 662 tempAddress = fi.mPhoneNum; 663 } 664 if(tempAddress == null) { 665 /* This can only happen on devices with no SIM - 666 hence will typically not have any SMS messages. */ 667 } else { 668 address = PhoneNumberUtils.extractNetworkPortion(tempAddress); 669 /* extractNetworkPortion can return N if the number is a service "number" = a string 670 * with the a name in (i.e. "Some-Tele-company" would return N because of the N in compaNy) 671 * Hence we need to check if the number is actually a string with alpha chars. 672 * */ 673 Boolean alpha = PhoneNumberUtils.stripSeparators(tempAddress).matches("[0-9]*[a-zA-Z]+[0-9]*"); 674 675 if(address == null || address.length() < 2 || alpha) { 676 address = tempAddress; // if the number is a service acsii text just use it 677 } 678 } 679 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 680 long id = c.getLong(fi.mMmsColId); 681 tempAddress = getAddressMms(mResolver, id, MMS_FROM); 682 address = PhoneNumberUtils.extractNetworkPortion(tempAddress); 683 if(address == null || address.length() < 1){ 684 address = tempAddress; // if the number is a service acsii text just use it 685 } 686 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 687 address = c.getString(fi.mEmailColFromAddress); 688 } 689 if (V) Log.v(TAG, "setSenderAddressing: " + address); 690 if(address == null) 691 address = ""; 692 e.setSenderAddressing(address); 693 } 694 } 695 696 private void setSenderName(BluetoothMapMessageListingElement e, Cursor c, 697 FilterInfo fi, BluetoothMapAppParams ap) { 698 if ((ap.getParameterMask() & MASK_SENDER_NAME) != 0) { 699 String name = null; 700 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 701 int msgType = c.getInt(c.getColumnIndex(Sms.TYPE)); 702 if (msgType == 1) { 703 String phone = c.getString(fi.mSmsColAddress); 704 if (phone != null && !phone.isEmpty()) 705 name = getContactNameFromPhone(phone); 706 } else { 707 name = fi.mPhoneAlphaTag; 708 } 709 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 710 long id = c.getLong(fi.mMmsColId); 711 String phone; 712 if(e.getSenderAddressing() != null){ 713 phone = getAddressMms(mResolver, id, MMS_FROM); 714 } else { 715 phone = e.getSenderAddressing(); 716 } 717 if (phone != null && !phone.isEmpty() ) 718 name = getContactNameFromPhone(phone); 719 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 720 name = c.getString(fi.mEmailColFromAddress); 721 } 722 if (V) Log.v(TAG, "setSenderName: " + name); 723 if(name == null) 724 name = ""; 725 e.setSenderName(name); 726 } 727 } 728 729 private void setDateTime(BluetoothMapMessageListingElement e, Cursor c, 730 FilterInfo fi, BluetoothMapAppParams ap) { 731 if ((ap.getParameterMask() & MASK_DATETIME) != 0) { 732 long date = 0; 733 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 734 date = c.getLong(fi.mSmsColDate); 735 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 736 /* Use Mms.DATE for all messages. Although contract class states */ 737 /* Mms.DATE_SENT are for outgoing messages. But that is not working. */ 738 date = c.getLong(fi.mMmsColDate) * 1000L; 739 740 /* int msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)); */ 741 /* if (msgBox == Mms.MESSAGE_BOX_INBOX) { */ 742 /* date = c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L; */ 743 /* } else { */ 744 /* date = c.getLong(c.getColumnIndex(Mms.DATE_SENT)) * 1000L; */ 745 /* } */ 746 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 747 date = c.getLong(fi.mEmailColDate); 748 } 749 e.setDateTime(date); 750 if (V) Log.v(TAG, "setDateTime: " + e.getDateTimeString()); 751 } 752 } 753 754 private String getTextPartsMms(long id) { 755 String text = ""; 756 String selection = new String("mid=" + id); 757 String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/part"); 758 Uri uriAddress = Uri.parse(uriStr); 759 // TODO: maybe use a projection with only "ct" and "text" 760 Cursor c = mResolver.query(uriAddress, null, selection, 761 null, null); 762 763 if (c != null && c.moveToFirst()) { 764 do { 765 String ct = c.getString(c.getColumnIndex("ct")); 766 if (ct.equals("text/plain")) { 767 String part = c.getString(c.getColumnIndex("text")); 768 if(part != null) { 769 text += part; 770 } 771 } 772 } while(c.moveToNext()); 773 } 774 if (c != null) { 775 c.close(); 776 } 777 return text; 778 } 779 780 private void setSubject(BluetoothMapMessageListingElement e, Cursor c, 781 FilterInfo fi, BluetoothMapAppParams ap) { 782 String subject = ""; 783 int subLength = ap.getSubjectLength(); 784 if(subLength == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 785 subLength = 256; 786 787 if ((ap.getParameterMask() & MASK_SUBJECT) != 0) { 788 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 789 subject = c.getString(fi.mSmsColSubject); 790 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 791 subject = c.getString(fi.mMmsColSubject); 792 if (subject == null || subject.length() == 0) { 793 /* Get subject from mms text body parts - if any exists */ 794 long id = c.getLong(fi.mMmsColId); 795 subject = getTextPartsMms(id); 796 } 797 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 798 subject = c.getString(fi.mEmailColSubject); 799 } 800 if (subject != null && subject.length() > subLength) { 801 subject = subject.substring(0, subLength); 802 } 803 if (V) Log.d(TAG, "setSubject: " + subject); 804 e.setSubject(subject); 805 } 806 } 807 808 private void setHandle(BluetoothMapMessageListingElement e, Cursor c, 809 FilterInfo fi, BluetoothMapAppParams ap) { 810 long handle = -1; 811 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 812 handle = c.getLong(fi.mSmsColId); 813 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 814 handle = c.getLong(fi.mMmsColId); 815 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 816 handle = c.getLong(fi.mEmailColId); 817 } 818 if (V) Log.d(TAG, "setHandle: " + handle ); 819 e.setHandle(handle); 820 } 821 822 private BluetoothMapMessageListingElement element(Cursor c, FilterInfo fi, 823 BluetoothMapAppParams ap) { 824 BluetoothMapMessageListingElement e = new BluetoothMapMessageListingElement(); 825 setHandle(e, c, fi, ap); 826 setDateTime(e, c, fi, ap); 827 setType(e, c, fi, ap); 828 setRead(e, c, fi, ap); 829 // we set number and name for sender/recipient later 830 // they require lookup on contacts so no need to 831 // do it for all elements unless they are to be used. 832 e.setCursorIndex(c.getPosition()); 833 return e; 834 } 835 836 private String getContactNameFromPhone(String phone) { 837 String name = null; 838 839 Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, 840 Uri.encode(phone)); 841 842 String[] projection = {Contacts._ID, Contacts.DISPLAY_NAME}; 843 String selection = Contacts.IN_VISIBLE_GROUP + "=1"; 844 String orderBy = Contacts.DISPLAY_NAME + " ASC"; 845 846 Cursor c = mResolver.query(uri, projection, selection, null, orderBy); 847 848 if (c != null && c.getCount() >= 1) { 849 c.moveToFirst(); 850 name = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME)); 851 } 852 853 c.close(); 854 return name; 855 } 856 857 static public String getAddressMms(ContentResolver r, long id, int type) { 858 String selection = new String("msg_id=" + id + " AND type=" + type); 859 String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr"); 860 Uri uriAddress = Uri.parse(uriStr); 861 String addr = null; 862 Cursor c = r.query(uriAddress, null, selection, null, null); 863 864 if (c != null && c.moveToFirst()) { 865 addr = c.getString(c.getColumnIndex(Mms.Addr.ADDRESS)); 866 if(addr.equals(INSERT_ADDRES_TOKEN)) 867 addr = ""; 868 } 869 870 if (c != null) { 871 c.close(); 872 } 873 return addr; 874 } 875 876 /** 877 * Matching functions for originator and recipient for MMS 878 * @return true if found a match 879 */ 880 private boolean matchRecipientMms(Cursor c, FilterInfo fi, String recip) { 881 boolean res; 882 long id = c.getLong(c.getColumnIndex(BaseColumns._ID)); 883 String phone = getAddressMms(mResolver, id, MMS_TO); 884 if (phone != null && phone.length() > 0) { 885 if (phone.matches(recip)) { 886 if (V) Log.v(TAG, "matchRecipientMms: match recipient phone = " + phone); 887 res = true; 888 } else { 889 String name = getContactNameFromPhone(phone); 890 if (name != null && name.length() > 0 && name.matches(recip)) { 891 if (V) Log.v(TAG, "matchRecipientMms: match recipient name = " + name); 892 res = true; 893 } else { 894 res = false; 895 } 896 } 897 } else { 898 res = false; 899 } 900 return res; 901 } 902 903 private boolean matchRecipientSms(Cursor c, FilterInfo fi, String recip) { 904 boolean res; 905 int msgType = c.getInt(c.getColumnIndex(Sms.TYPE)); 906 if (msgType == 1) { 907 String phone = fi.mPhoneNum; 908 String name = fi.mPhoneAlphaTag; 909 if (phone != null && phone.length() > 0 && phone.matches(recip)) { 910 if (V) Log.v(TAG, "matchRecipientSms: match recipient phone = " + phone); 911 res = true; 912 } else if (name != null && name.length() > 0 && name.matches(recip)) { 913 if (V) Log.v(TAG, "matchRecipientSms: match recipient name = " + name); 914 res = true; 915 } else { 916 res = false; 917 } 918 } else { 919 String phone = c.getString(c.getColumnIndex(Sms.ADDRESS)); 920 if (phone != null && phone.length() > 0) { 921 if (phone.matches(recip)) { 922 if (V) Log.v(TAG, "matchRecipientSms: match recipient phone = " + phone); 923 res = true; 924 } else { 925 String name = getContactNameFromPhone(phone); 926 if (name != null && name.length() > 0 && name.matches(recip)) { 927 if (V) Log.v(TAG, "matchRecipientSms: match recipient name = " + name); 928 res = true; 929 } else { 930 res = false; 931 } 932 } 933 } else { 934 res = false; 935 } 936 } 937 return res; 938 } 939 940 private boolean matchRecipient(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) { 941 boolean res; 942 String recip = ap.getFilterRecipient(); 943 if (recip != null && recip.length() > 0) { 944 recip = recip.replace("*", ".*"); 945 recip = ".*" + recip + ".*"; 946 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 947 res = matchRecipientSms(c, fi, recip); 948 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 949 res = matchRecipientMms(c, fi, recip); 950 } else { 951 if (D) Log.d(TAG, "matchRecipient: Unknown msg type: " + fi.mMsgType); 952 res = false; 953 } 954 } else { 955 res = true; 956 } 957 return res; 958 } 959 960 private boolean matchOriginatorMms(Cursor c, FilterInfo fi, String orig) { 961 boolean res; 962 long id = c.getLong(c.getColumnIndex(BaseColumns._ID)); 963 String phone = getAddressMms(mResolver, id, MMS_FROM); 964 if (phone != null && phone.length() > 0) { 965 if (phone.matches(orig)) { 966 if (V) Log.v(TAG, "matchOriginatorMms: match originator phone = " + phone); 967 res = true; 968 } else { 969 String name = getContactNameFromPhone(phone); 970 if (name != null && name.length() > 0 && name.matches(orig)) { 971 if (V) Log.v(TAG, "matchOriginatorMms: match originator name = " + name); 972 res = true; 973 } else { 974 res = false; 975 } 976 } 977 } else { 978 res = false; 979 } 980 return res; 981 } 982 983 private boolean matchOriginatorSms(Cursor c, FilterInfo fi, String orig) { 984 boolean res; 985 int msgType = c.getInt(c.getColumnIndex(Sms.TYPE)); 986 if (msgType == 1) { 987 String phone = c.getString(c.getColumnIndex(Sms.ADDRESS)); 988 if (phone !=null && phone.length() > 0) { 989 if (phone.matches(orig)) { 990 if (V) Log.v(TAG, "matchOriginatorSms: match originator phone = " + phone); 991 res = true; 992 } else { 993 String name = getContactNameFromPhone(phone); 994 if (name != null && name.length() > 0 && name.matches(orig)) { 995 if (V) Log.v(TAG, "matchOriginatorSms: match originator name = " + name); 996 res = true; 997 } else { 998 res = false; 999 } 1000 } 1001 } else { 1002 res = false; 1003 } 1004 } else { 1005 String phone = fi.mPhoneNum; 1006 String name = fi.mPhoneAlphaTag; 1007 if (phone != null && phone.length() > 0 && phone.matches(orig)) { 1008 if (V) Log.v(TAG, "matchOriginatorSms: match originator phone = " + phone); 1009 res = true; 1010 } else if (name != null && name.length() > 0 && name.matches(orig)) { 1011 if (V) Log.v(TAG, "matchOriginatorSms: match originator name = " + name); 1012 res = true; 1013 } else { 1014 res = false; 1015 } 1016 } 1017 return res; 1018 } 1019 1020 private boolean matchOriginator(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) { 1021 boolean res; 1022 String orig = ap.getFilterOriginator(); 1023 if (orig != null && orig.length() > 0) { 1024 orig = orig.replace("*", ".*"); 1025 orig = ".*" + orig + ".*"; 1026 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 1027 res = matchOriginatorSms(c, fi, orig); 1028 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 1029 res = matchOriginatorMms(c, fi, orig); 1030 } else { 1031 if(D) Log.d(TAG, "matchOriginator: Unknown msg type: " + fi.mMsgType); 1032 res = false; 1033 } 1034 } else { 1035 res = true; 1036 } 1037 return res; 1038 } 1039 1040 private boolean matchAddresses(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) { 1041 if (matchOriginator(c, fi, ap) && matchRecipient(c, fi, ap)) { 1042 return true; 1043 } else { 1044 return false; 1045 } 1046 } 1047 1048 /* 1049 * Where filter functions 1050 * */ 1051 private String setWhereFilterFolderTypeSms(String folder) { 1052 String where = ""; 1053 if (BluetoothMapContract.FOLDER_NAME_INBOX.equalsIgnoreCase(folder)) { 1054 where = Sms.TYPE + " = 1 AND " + Sms.THREAD_ID + " <> -1"; 1055 } else if (BluetoothMapContract.FOLDER_NAME_OUTBOX.equalsIgnoreCase(folder)) { 1056 where = "(" + Sms.TYPE + " = 4 OR " + Sms.TYPE + " = 5 OR " 1057 + Sms.TYPE + " = 6) AND " + Sms.THREAD_ID + " <> -1"; 1058 } else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) { 1059 where = Sms.TYPE + " = 2 AND " + Sms.THREAD_ID + " <> -1"; 1060 } else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) { 1061 where = Sms.TYPE + " = 3 AND " + Sms.THREAD_ID + " <> -1"; 1062 } else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) { 1063 where = Sms.THREAD_ID + " = -1"; 1064 } 1065 1066 return where; 1067 } 1068 1069 private String setWhereFilterFolderTypeMms(String folder) { 1070 String where = ""; 1071 if (BluetoothMapContract.FOLDER_NAME_INBOX.equalsIgnoreCase(folder)) { 1072 where = Mms.MESSAGE_BOX + " = 1 AND " + Mms.THREAD_ID + " <> -1"; 1073 } else if (BluetoothMapContract.FOLDER_NAME_OUTBOX.equalsIgnoreCase(folder)) { 1074 where = Mms.MESSAGE_BOX + " = 4 AND " + Mms.THREAD_ID + " <> -1"; 1075 } else if (BluetoothMapContract.FOLDER_NAME_SENT.equalsIgnoreCase(folder)) { 1076 where = Mms.MESSAGE_BOX + " = 2 AND " + Mms.THREAD_ID + " <> -1"; 1077 } else if (BluetoothMapContract.FOLDER_NAME_DRAFT.equalsIgnoreCase(folder)) { 1078 where = Mms.MESSAGE_BOX + " = 3 AND " + Mms.THREAD_ID + " <> -1"; 1079 } else if (BluetoothMapContract.FOLDER_NAME_DELETED.equalsIgnoreCase(folder)) { 1080 where = Mms.THREAD_ID + " = -1"; 1081 } 1082 1083 return where; 1084 } 1085 1086 private String setWhereFilterFolderTypeEmail(long folderId) { 1087 String where = ""; 1088 if (folderId >= 0) { 1089 where = BluetoothMapContract.MessageColumns.FOLDER_ID + " = " + folderId; 1090 } else { 1091 Log.e(TAG, "setWhereFilterFolderTypeEmail: not valid!" ); 1092 throw new IllegalArgumentException("Invalid folder ID"); 1093 } 1094 return where; 1095 } 1096 1097 private String setWhereFilterFolderType(BluetoothMapFolderElement folderElement, FilterInfo fi) { 1098 String where = ""; 1099 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 1100 where = setWhereFilterFolderTypeSms(folderElement.getName()); 1101 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 1102 where = setWhereFilterFolderTypeMms(folderElement.getName()); 1103 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 1104 where = setWhereFilterFolderTypeEmail(folderElement.getEmailFolderId()); 1105 } 1106 return where; 1107 } 1108 1109 private String setWhereFilterReadStatus(BluetoothMapAppParams ap, FilterInfo fi) { 1110 String where = ""; 1111 if (ap.getFilterReadStatus() != -1) { 1112 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 1113 if ((ap.getFilterReadStatus() & 0x01) != 0) { 1114 where = " AND " + Sms.READ + "= 0"; 1115 } 1116 1117 if ((ap.getFilterReadStatus() & 0x02) != 0) { 1118 where = " AND " + Sms.READ + "= 1"; 1119 } 1120 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 1121 if ((ap.getFilterReadStatus() & 0x01) != 0) { 1122 where = " AND " + Mms.READ + "= 0"; 1123 } 1124 1125 if ((ap.getFilterReadStatus() & 0x02) != 0) { 1126 where = " AND " + Mms.READ + "= 1"; 1127 } 1128 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 1129 if ((ap.getFilterReadStatus() & 0x01) != 0) { 1130 where = " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "= 0"; 1131 } 1132 1133 if ((ap.getFilterReadStatus() & 0x02) != 0) { 1134 where = " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "= 1"; 1135 } 1136 } 1137 } 1138 return where; 1139 } 1140 1141 private String setWhereFilterPeriod(BluetoothMapAppParams ap, FilterInfo fi) { 1142 String where = ""; 1143 if ((ap.getFilterPeriodBegin() != -1)) { 1144 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 1145 where = " AND " + Sms.DATE + " >= " + ap.getFilterPeriodBegin(); 1146 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 1147 where = " AND " + Mms.DATE + " >= " + (ap.getFilterPeriodBegin() / 1000L); 1148 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 1149 where = " AND " + BluetoothMapContract.MessageColumns.DATE + " >= " + (ap.getFilterPeriodBegin()); 1150 } 1151 } 1152 1153 if ((ap.getFilterPeriodEnd() != -1)) { 1154 if (fi.mMsgType == FilterInfo.TYPE_SMS) { 1155 where += " AND " + Sms.DATE + " < " + ap.getFilterPeriodEnd(); 1156 } else if (fi.mMsgType == FilterInfo.TYPE_MMS) { 1157 where += " AND " + Mms.DATE + " < " + (ap.getFilterPeriodEnd() / 1000L); 1158 } else if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 1159 where += " AND " + BluetoothMapContract.MessageColumns.DATE + " < " + (ap.getFilterPeriodEnd()); 1160 } 1161 } 1162 1163 1164 return where; 1165 } 1166 1167 private String setWhereFilterPhones(String str) { 1168 String where = ""; 1169 str = str.replace("*", "%"); 1170 1171 Cursor c = mResolver.query(ContactsContract.Contacts.CONTENT_URI, null, 1172 ContactsContract.Contacts.DISPLAY_NAME + " like ?", 1173 new String[]{str}, 1174 ContactsContract.Contacts.DISPLAY_NAME + " ASC"); 1175 1176 while (c != null && c.moveToNext()) { 1177 String contactId = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID)); 1178 1179 Cursor p = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 1180 ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", 1181 new String[]{contactId}, 1182 null); 1183 1184 while (p != null && p.moveToNext()) { 1185 String number = p.getString( 1186 p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 1187 1188 where += " address = " + "'" + number + "'"; 1189 if (!p.isLast()) { 1190 where += " OR "; 1191 } 1192 } 1193 if (!c.isLast()) { 1194 where += " OR "; 1195 } 1196 p.close(); 1197 } 1198 c.close(); 1199 1200 if (str != null && str.length() > 0) { 1201 if (where.length() > 0) { 1202 where += " OR "; 1203 } 1204 where += " address like " + "'" + str + "'"; 1205 } 1206 1207 return where; 1208 } 1209 1210 private String setWhereFilterOriginatorEmail(BluetoothMapAppParams ap) { 1211 String where = ""; 1212 String orig = ap.getFilterOriginator(); 1213 1214 /* Be aware of wild cards in the beginning of string, may not be valid? */ 1215 if (orig != null && orig.length() > 0) { 1216 orig = orig.replace("*", "%"); 1217 where = " AND " + BluetoothMapContract.MessageColumns.FROM_LIST + " LIKE '%" + orig + "%'"; 1218 } 1219 return where; 1220 } 1221 private String setWhereFilterPriority(BluetoothMapAppParams ap, FilterInfo fi) { 1222 String where = ""; 1223 int pri = ap.getFilterPriority(); 1224 /*only MMS have priority info */ 1225 if(fi.mMsgType == FilterInfo.TYPE_MMS) 1226 { 1227 if(pri == 0x0002) 1228 { 1229 where += " AND " + Mms.PRIORITY + "<=" + 1230 Integer.toString(PduHeaders.PRIORITY_NORMAL); 1231 }else if(pri == 0x0001) { 1232 where += " AND " + Mms.PRIORITY + "=" + 1233 Integer.toString(PduHeaders.PRIORITY_HIGH); 1234 } 1235 } 1236 return where; 1237 } 1238 1239 private String setWhereFilterRecipientEmail(BluetoothMapAppParams ap) { 1240 String where = ""; 1241 String recip = ap.getFilterRecipient(); 1242 1243 /* Be aware of wild cards in the beginning of string, may not be valid? */ 1244 if (recip != null && recip.length() > 0) { 1245 recip = recip.replace("*", "%"); 1246 where = " AND (" 1247 + BluetoothMapContract.MessageColumns.TO_LIST + " LIKE '%" + recip + "%' OR " 1248 + BluetoothMapContract.MessageColumns.CC_LIST + " LIKE '%" + recip + "%' OR " 1249 + BluetoothMapContract.MessageColumns.BCC_LIST + " LIKE '%" + recip + "%' )"; 1250 } 1251 return where; 1252 } 1253 1254 private String setWhereFilter(BluetoothMapFolderElement folderElement, 1255 FilterInfo fi, BluetoothMapAppParams ap) { 1256 String where = ""; 1257 1258 where += setWhereFilterFolderType(folderElement, fi); 1259 if(!where.isEmpty()) { 1260 where += setWhereFilterReadStatus(ap, fi); 1261 where += setWhereFilterPeriod(ap, fi); 1262 where += setWhereFilterPriority(ap,fi); 1263 1264 if (fi.mMsgType == FilterInfo.TYPE_EMAIL) { 1265 where += setWhereFilterOriginatorEmail(ap); 1266 where += setWhereFilterRecipientEmail(ap); 1267 } 1268 } 1269 1270 1271 return where; 1272 } 1273 1274 /** 1275 * Determine from application parameter if sms should be included. 1276 * The filter mask is set for message types not selected 1277 * @param fi 1278 * @param ap 1279 * @return boolean true if sms is selected, false if not 1280 */ 1281 private boolean smsSelected(FilterInfo fi, BluetoothMapAppParams ap) { 1282 int msgType = ap.getFilterMessageType(); 1283 int phoneType = fi.mPhoneType; 1284 1285 if (D) Log.d(TAG, "smsSelected msgType: " + msgType); 1286 1287 if (msgType == -1) 1288 return true; 1289 1290 if ((msgType & 0x03) == 0) 1291 return true; 1292 1293 if (((msgType & 0x01) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_GSM)) 1294 return true; 1295 1296 if (((msgType & 0x02) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_CDMA)) 1297 return true; 1298 1299 return false; 1300 } 1301 1302 /** 1303 * Determine from application parameter if mms should be included. 1304 * The filter mask is set for message types not selected 1305 * @param fi 1306 * @param ap 1307 * @return boolean true if sms is selected, false if not 1308 */ 1309 private boolean mmsSelected(FilterInfo fi, BluetoothMapAppParams ap) { 1310 int msgType = ap.getFilterMessageType(); 1311 1312 if (D) Log.d(TAG, "mmsSelected msgType: " + msgType); 1313 1314 if (msgType == -1) 1315 return true; 1316 1317 if ((msgType & 0x08) == 0) 1318 return true; 1319 1320 return false; 1321 } 1322 1323 /** 1324 * Determine from application parameter if email should be included. 1325 * The filter mask is set for message types not selected 1326 * @param fi 1327 * @param ap 1328 * @return boolean true if sms is selected, false if not 1329 */ 1330 private boolean emailSelected(FilterInfo fi, BluetoothMapAppParams ap) { 1331 int msgType = ap.getFilterMessageType(); 1332 1333 if (D) Log.d(TAG, "emailSelected msgType: " + msgType); 1334 1335 if (msgType == -1) 1336 return true; 1337 1338 if ((msgType & 0x04) == 0) 1339 return true; 1340 1341 return false; 1342 } 1343 1344 private void setFilterInfo(FilterInfo fi) { 1345 TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); 1346 if (tm != null) { 1347 fi.mPhoneType = tm.getPhoneType(); 1348 fi.mPhoneNum = tm.getLine1Number(); 1349 fi.mPhoneAlphaTag = tm.getLine1AlphaTag(); 1350 if (D) Log.d(TAG, "phone type = " + fi.mPhoneType + 1351 " phone num = " + fi.mPhoneNum + 1352 " phone alpha tag = " + fi.mPhoneAlphaTag); 1353 } 1354 } 1355 1356 /** 1357 * Get a listing of message in folder after applying filter. 1358 * @param folder Must contain a valid folder string != null 1359 * @param ap Parameters specifying message content and filters 1360 * @return Listing object containing requested messages 1361 */ 1362 public BluetoothMapMessageListing msgListing(BluetoothMapFolderElement folderElement, 1363 BluetoothMapAppParams ap) { 1364 if (D) Log.d(TAG, "msgListing: folderName = " + folderElement.getName() 1365 + " folderId = " + folderElement.getEmailFolderId() 1366 + " messageType = " + ap.getFilterMessageType() ); 1367 BluetoothMapMessageListing bmList = new BluetoothMapMessageListing(); 1368 1369 1370 /* We overwrite the parameter mask here if it is 0 or not present, as this 1371 * should cause all parameters to be included in the message list. */ 1372 if(ap.getParameterMask() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER || 1373 ap.getParameterMask() == 0) { 1374 ap.setParameterMask(BluetoothMapAppParams.PARAMETER_MASK_ALL_ENABLED); 1375 if (V) Log.v(TAG, "msgListing(): appParameterMask is zero or not present, " + 1376 "changing to: " + ap.getParameterMask()); 1377 } 1378 1379 /* Cache some info used throughout filtering */ 1380 FilterInfo fi = new FilterInfo(); 1381 setFilterInfo(fi); 1382 Cursor smsCursor = null; 1383 Cursor mmsCursor = null; 1384 Cursor emailCursor = null; 1385 String limit = ""; 1386 int countNum = ap.getMaxListCount(); 1387 int offsetNum = ap.getStartOffset(); 1388 if(ap.getMaxListCount()>0){ 1389 limit=" LIMIT "+ (ap.getMaxListCount()+ap.getStartOffset()); 1390 } 1391 1392 if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1393 if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL| 1394 BluetoothMapAppParams.FILTER_NO_MMS| 1395 BluetoothMapAppParams.FILTER_NO_SMS_GSM)|| 1396 ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL| 1397 BluetoothMapAppParams.FILTER_NO_MMS| 1398 BluetoothMapAppParams.FILTER_NO_SMS_CDMA)){ 1399 //set real limit and offset if only this type is used (only if offset/limit is used 1400 limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset(); 1401 if(D) Log.d(TAG, "SMS Limit => "+limit); 1402 offsetNum = 0; 1403 } 1404 fi.mMsgType = FilterInfo.TYPE_SMS; 1405 if(ap.getFilterPriority() != 1){ /*SMS cannot have high priority*/ 1406 String where = setWhereFilter(folderElement, fi, ap); 1407 if(!where.isEmpty()) { 1408 if (D) Log.d(TAG, "msgType: " + fi.mMsgType); 1409 smsCursor = mResolver.query(Sms.CONTENT_URI, 1410 SMS_PROJECTION, where, null, Sms.DATE + " DESC" + limit); 1411 if (smsCursor != null) { 1412 BluetoothMapMessageListingElement e = null; 1413 // store column index so we dont have to look them up anymore (optimization) 1414 if(D) Log.d(TAG, "Found " + smsCursor.getCount() + " sms messages."); 1415 fi.setSmsColumns(smsCursor); 1416 while (smsCursor.moveToNext()) { 1417 if (matchAddresses(smsCursor, fi, ap)) { 1418 if(V) printSms(smsCursor); 1419 e = element(smsCursor, fi, ap); 1420 bmList.add(e); 1421 } 1422 } 1423 } 1424 } 1425 } 1426 } 1427 1428 if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1429 if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_EMAIL| 1430 BluetoothMapAppParams.FILTER_NO_SMS_CDMA| 1431 BluetoothMapAppParams.FILTER_NO_SMS_GSM)){ 1432 //set real limit and offset if only this type is used (only if offset/limit is used 1433 limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset(); 1434 if(D) Log.d(TAG, "MMS Limit => "+limit); 1435 offsetNum = 0; 1436 } 1437 fi.mMsgType = FilterInfo.TYPE_MMS; 1438 String where = setWhereFilter(folderElement, fi, ap); 1439 if(!where.isEmpty()) { 1440 if (D) Log.d(TAG, "msgType: " + fi.mMsgType); 1441 mmsCursor = mResolver.query(Mms.CONTENT_URI, 1442 MMS_PROJECTION, where, null, Mms.DATE + " DESC" + limit); 1443 if (mmsCursor != null) { 1444 BluetoothMapMessageListingElement e = null; 1445 // store column index so we dont have to look them up anymore (optimization) 1446 fi.setMmsColumns(mmsCursor); 1447 int cnt = 0; 1448 if(D) Log.d(TAG, "Found " + mmsCursor.getCount() + " mms messages."); 1449 while (mmsCursor.moveToNext()) { 1450 if (matchAddresses(mmsCursor, fi, ap)) { 1451 if(V) printMms(mmsCursor); 1452 e = element(mmsCursor, fi, ap); 1453 bmList.add(e); 1454 } 1455 } 1456 } 1457 } 1458 } 1459 1460 if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) { 1461 if(ap.getFilterMessageType() == (BluetoothMapAppParams.FILTER_NO_MMS| 1462 BluetoothMapAppParams.FILTER_NO_SMS_CDMA| 1463 BluetoothMapAppParams.FILTER_NO_SMS_GSM)){ 1464 //set real limit and offset if only this type is used (only if offset/limit is used 1465 limit = " LIMIT " + ap.getMaxListCount()+" OFFSET "+ ap.getStartOffset(); 1466 if(D) Log.d(TAG, "Email Limit => "+limit); 1467 offsetNum = 0; 1468 } 1469 fi.mMsgType = FilterInfo.TYPE_EMAIL; 1470 String where = setWhereFilter(folderElement, fi, ap); 1471 1472 if(!where.isEmpty()) { 1473 if (D) Log.d(TAG, "msgType: " + fi.mMsgType); 1474 Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE); 1475 emailCursor = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION, 1476 where, null, BluetoothMapContract.MessageColumns.DATE + " DESC" + limit); 1477 if (emailCursor != null) { 1478 BluetoothMapMessageListingElement e = null; 1479 // store column index so we dont have to look them up anymore (optimization) 1480 fi.setEmailColumns(emailCursor); 1481 int cnt = 0; 1482 while (emailCursor.moveToNext()) { 1483 if(V) printEmail(emailCursor); 1484 if(D) Log.d(TAG, "Found " + emailCursor.getCount() + " email messages."); 1485 e = element(emailCursor, fi, ap); 1486 bmList.add(e); 1487 } 1488 // emailCursor.close(); 1489 } 1490 } 1491 } 1492 1493 /* Enable this if post sorting and segmenting needed */ 1494 bmList.sort(); 1495 bmList.segment(ap.getMaxListCount(), offsetNum); 1496 List<BluetoothMapMessageListingElement> list = bmList.getList(); 1497 int listSize = list.size(); 1498 Cursor tmpCursor = null; 1499 for(int x=0;x<listSize;x++){ 1500 BluetoothMapMessageListingElement ele = list.get(x); 1501 if((ele.getType().equals(TYPE.SMS_GSM)||ele.getType().equals(TYPE.SMS_CDMA)) && smsCursor != null){ 1502 tmpCursor = smsCursor; 1503 fi.mMsgType = FilterInfo.TYPE_SMS; 1504 }else if(ele.getType().equals(TYPE.MMS) && mmsCursor != null){ 1505 tmpCursor = mmsCursor; 1506 fi.mMsgType = FilterInfo.TYPE_MMS; 1507 }else if(ele.getType().equals(TYPE.EMAIL) && emailCursor != null){ 1508 tmpCursor = emailCursor; 1509 fi.mMsgType = FilterInfo.TYPE_EMAIL; 1510 } 1511 if(tmpCursor != null){ 1512 tmpCursor.moveToPosition(ele.getCursorIndex()); 1513 setSenderAddressing(ele, tmpCursor, fi, ap); 1514 setSenderName(ele, tmpCursor, fi, ap); 1515 setRecipientAddressing(ele, tmpCursor, fi, ap); 1516 setRecipientName(ele, tmpCursor, fi, ap); 1517 setSubject(ele, tmpCursor, fi, ap); 1518 setSize(ele, tmpCursor, fi, ap); 1519 setReceptionStatus(ele, tmpCursor, fi, ap); 1520 setText(ele, tmpCursor, fi, ap); 1521 setAttachmentSize(ele, tmpCursor, fi, ap); 1522 setPriority(ele, tmpCursor, fi, ap); 1523 setSent(ele, tmpCursor, fi, ap); 1524 setProtected(ele, tmpCursor, fi, ap); 1525 setThreadId(ele, tmpCursor, fi, ap); 1526 } 1527 } 1528 if(emailCursor != null)emailCursor.close(); 1529 if(smsCursor != null)smsCursor.close(); 1530 if(mmsCursor != null)mmsCursor.close(); 1531 if(D)Log.d(TAG, "messagelisting end"); 1532 return bmList; 1533 } 1534 1535 /** 1536 * Get the size of the message listing 1537 * @param folder Must contain a valid folder string != null 1538 * @param ap Parameters specifying message content and filters 1539 * @return Integer equal to message listing size 1540 */ 1541 public int msgListingSize(BluetoothMapFolderElement folderElement, 1542 BluetoothMapAppParams ap) { 1543 if (D) Log.d(TAG, "msgListingSize: folder = " + folderElement.getName()); 1544 int cnt = 0; 1545 1546 /* Cache some info used throughout filtering */ 1547 FilterInfo fi = new FilterInfo(); 1548 setFilterInfo(fi); 1549 1550 if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1551 fi.mMsgType = FilterInfo.TYPE_SMS; 1552 String where = setWhereFilter(folderElement, fi, ap); 1553 Cursor c = mResolver.query(Sms.CONTENT_URI, 1554 SMS_PROJECTION, where, null, Sms.DATE + " DESC"); 1555 1556 if (c != null) { 1557 cnt = c.getCount(); 1558 c.close(); 1559 } 1560 } 1561 1562 if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1563 fi.mMsgType = FilterInfo.TYPE_MMS; 1564 String where = setWhereFilter(folderElement, fi, ap); 1565 Cursor c = mResolver.query(Mms.CONTENT_URI, 1566 MMS_PROJECTION, where, null, Mms.DATE + " DESC"); 1567 if (c != null) { 1568 cnt += c.getCount(); 1569 c.close(); 1570 } 1571 } 1572 1573 if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) { 1574 fi.mMsgType = FilterInfo.TYPE_EMAIL; 1575 String where = setWhereFilter(folderElement, fi, ap); 1576 if(!where.isEmpty()) { 1577 Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE); 1578 Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION, 1579 where, null, BluetoothMapContract.MessageColumns.DATE + " DESC"); 1580 if (c != null) { 1581 cnt += c.getCount(); 1582 c.close(); 1583 } 1584 } 1585 } 1586 1587 if (D) Log.d(TAG, "msgListingSize: size = " + cnt); 1588 return cnt; 1589 } 1590 1591 /** 1592 * Return true if there are unread messages in the requested list of messages 1593 * @param folder folder where the message listing should come from 1594 * @param ap application parameter object 1595 * @return true if unread messages are in the list, else false 1596 */ 1597 public boolean msgListingHasUnread(BluetoothMapFolderElement folderElement, 1598 BluetoothMapAppParams ap) { 1599 if (D) Log.d(TAG, "msgListingHasUnread: folder = " + folderElement.getName()); 1600 int cnt = 0; 1601 1602 /* Cache some info used throughout filtering */ 1603 FilterInfo fi = new FilterInfo(); 1604 setFilterInfo(fi); 1605 1606 if (smsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1607 fi.mMsgType = FilterInfo.TYPE_SMS; 1608 String where = setWhereFilterFolderType(folderElement, fi); 1609 where += " AND " + Sms.READ + "=0 "; 1610 where += setWhereFilterPeriod(ap, fi); 1611 Cursor c = mResolver.query(Sms.CONTENT_URI, 1612 SMS_PROJECTION, where, null, Sms.DATE + " DESC"); 1613 1614 if (c != null) { 1615 cnt = c.getCount(); 1616 c.close(); 1617 } 1618 } 1619 1620 if (mmsSelected(fi, ap) && folderElement.hasSmsMmsContent()) { 1621 fi.mMsgType = FilterInfo.TYPE_MMS; 1622 String where = setWhereFilterFolderType(folderElement, fi); 1623 where += " AND " + Mms.READ + "=0 "; 1624 where += setWhereFilterPeriod(ap, fi); 1625 Cursor c = mResolver.query(Mms.CONTENT_URI, 1626 MMS_PROJECTION, where, null, Sms.DATE + " DESC"); 1627 1628 if (c != null) { 1629 cnt += c.getCount(); 1630 c.close(); 1631 } 1632 } 1633 1634 1635 if (emailSelected(fi, ap) && folderElement.getEmailFolderId() != -1) { 1636 fi.mMsgType = FilterInfo.TYPE_EMAIL; 1637 String where = setWhereFilterFolderType(folderElement, fi); 1638 if(!where.isEmpty()) { 1639 where += " AND " + BluetoothMapContract.MessageColumns.FLAG_READ + "=0 "; 1640 where += setWhereFilterPeriod(ap, fi); 1641 Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE); 1642 Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION, 1643 where, null, BluetoothMapContract.MessageColumns.DATE + " DESC"); 1644 if (c != null) { 1645 cnt += c.getCount(); 1646 c.close(); 1647 } 1648 } 1649 } 1650 1651 if (D) Log.d(TAG, "msgListingHasUnread: numUnread = " + cnt); 1652 return (cnt>0)?true:false; 1653 } 1654 1655 /** 1656 * Get the folder name of an SMS message or MMS message. 1657 * @param c the cursor pointing at the message 1658 * @return the folder name. 1659 */ 1660 private String getFolderName(int type, int threadId) { 1661 1662 if(threadId == -1) 1663 return BluetoothMapContract.FOLDER_NAME_DELETED; 1664 1665 switch(type) { 1666 case 1: 1667 return BluetoothMapContract.FOLDER_NAME_INBOX; 1668 case 2: 1669 return BluetoothMapContract.FOLDER_NAME_SENT; 1670 case 3: 1671 return BluetoothMapContract.FOLDER_NAME_DRAFT; 1672 case 4: // Just name outbox, failed and queued "outbox" 1673 case 5: 1674 case 6: 1675 return BluetoothMapContract.FOLDER_NAME_OUTBOX; 1676 } 1677 return ""; 1678 } 1679 1680 public byte[] getMessage(String handle, BluetoothMapAppParams appParams, 1681 BluetoothMapFolderElement folderElement) throws UnsupportedEncodingException{ 1682 TYPE type = BluetoothMapUtils.getMsgTypeFromHandle(handle); 1683 long id = BluetoothMapUtils.getCpHandle(handle); 1684 if(appParams.getFractionRequest() == BluetoothMapAppParams.FRACTION_REQUEST_NEXT) { 1685 throw new IllegalArgumentException("FRACTION_REQUEST_NEXT does not make sence as" + 1686 " we always return the full message."); 1687 } 1688 switch(type) { 1689 case SMS_GSM: 1690 case SMS_CDMA: 1691 return getSmsMessage(id, appParams.getCharset()); 1692 case MMS: 1693 return getMmsMessage(id, appParams); 1694 case EMAIL: 1695 return getEmailMessage(id, appParams, folderElement); 1696 } 1697 throw new IllegalArgumentException("Invalid message handle."); 1698 } 1699 1700 private String setVCardFromPhoneNumber(BluetoothMapbMessage message, String phone, boolean incoming) { 1701 String contactId = null, contactName = null; 1702 String[] phoneNumbers = null; 1703 String[] emailAddresses = null; 1704 Cursor p; 1705 1706 Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, 1707 Uri.encode(phone)); 1708 1709 String[] projection = {Contacts._ID, Contacts.DISPLAY_NAME}; 1710 String selection = Contacts.IN_VISIBLE_GROUP + "=1"; 1711 String orderBy = Contacts._ID + " ASC"; 1712 1713 // Get the contact _ID and name 1714 p = mResolver.query(uri, projection, selection, null, orderBy); 1715 if (p != null && p.getCount() >= 1) { 1716 p.moveToFirst(); 1717 contactId = p.getString(p.getColumnIndex(Contacts._ID)); 1718 contactName = p.getString(p.getColumnIndex(Contacts.DISPLAY_NAME)); 1719 } 1720 p.close(); 1721 1722 // Bail out if we are unable to find a contact, based on the phone number 1723 if(contactId == null) { 1724 phoneNumbers = new String[1]; 1725 phoneNumbers[0] = phone; 1726 } else { 1727 // use only actual phone number 1728 phoneNumbers = new String[1]; 1729 phoneNumbers[0] = phone; 1730 1731 // Fetch contact e-mail addresses 1732 p = mResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, 1733 ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", 1734 new String[]{contactId}, 1735 null); 1736 if(p != null) { 1737 int i = 0; 1738 emailAddresses = new String[p.getCount()]; 1739 while (p != null && p.moveToNext()) { 1740 String emailAddress = p.getString( 1741 p.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS)); 1742 emailAddresses[i++] = emailAddress; 1743 } 1744 p.close(); 1745 } 1746 } 1747 if(incoming == true) { 1748 if(V) Log.d(TAG, "Adding originator for phone:" + phone); 1749 message.addOriginator(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name 1750 } else { 1751 if(V) Log.d(TAG, "Adding recipient for phone:" + phone); 1752 message.addRecipient(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name 1753 } 1754 return contactName; 1755 } 1756 1757 public static final int MAP_MESSAGE_CHARSET_NATIVE = 0; 1758 public static final int MAP_MESSAGE_CHARSET_UTF8 = 1; 1759 1760 public byte[] getSmsMessage(long id, int charset) throws UnsupportedEncodingException{ 1761 int type, threadId; 1762 long time = -1; 1763 String msgBody; 1764 BluetoothMapbMessageSms message = new BluetoothMapbMessageSms(); 1765 TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); 1766 Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, "_ID = " + id, null, null); 1767 1768 if(c != null && c.moveToFirst()) 1769 { 1770 if(V) Log.v(TAG,"c.count: " + c.getCount()); 1771 1772 if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { 1773 message.setType(TYPE.SMS_GSM); 1774 } else if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 1775 message.setType(TYPE.SMS_CDMA); 1776 } 1777 1778 String read = c.getString(c.getColumnIndex(Sms.READ)); 1779 if (read.equalsIgnoreCase("1")) 1780 message.setStatus(true); 1781 else 1782 message.setStatus(false); 1783 1784 type = c.getInt(c.getColumnIndex(Sms.TYPE)); 1785 threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID)); 1786 message.setFolder(getFolderName(type, threadId)); 1787 1788 msgBody = c.getString(c.getColumnIndex(Sms.BODY)); 1789 1790 String phone = c.getString(c.getColumnIndex(Sms.ADDRESS)); 1791 1792 time = c.getLong(c.getColumnIndex(Sms.DATE)); 1793 if(type == 1) // Inbox message needs to set the vCard as originator 1794 setVCardFromPhoneNumber(message, phone, true); 1795 else // Other messages sets the vCard as the recipient 1796 setVCardFromPhoneNumber(message, phone, false); 1797 1798 if(charset == MAP_MESSAGE_CHARSET_NATIVE) { 1799 if(type == 1) //Inbox 1800 message.setSmsBodyPdus(BluetoothMapSmsPdu.getDeliverPdus(msgBody, phone, time)); 1801 else 1802 message.setSmsBodyPdus(BluetoothMapSmsPdu.getSubmitPdus(msgBody, phone)); 1803 } else /*if (charset == MAP_MESSAGE_CHARSET_UTF8)*/ { 1804 message.setSmsBody(msgBody); 1805 } 1806 1807 c.close(); 1808 1809 return message.encode(); 1810 } 1811 throw new IllegalArgumentException("SMS handle not found"); 1812 } 1813 1814 private void extractMmsAddresses(long id, BluetoothMapbMessageMms message) { 1815 final String[] projection = null; 1816 String selection = new String(Mms.Addr.MSG_ID + "=" + id); 1817 String uriStr = new String(Mms.CONTENT_URI + "/" + id + "/addr"); 1818 Uri uriAddress = Uri.parse(uriStr); 1819 String contactName = null; 1820 Cursor c = mResolver.query( uriAddress, projection, selection, null, null); 1821 if (c.moveToFirst()) { 1822 do { 1823 String address = c.getString(c.getColumnIndex(Mms.Addr.ADDRESS)); 1824 if(address.equals(INSERT_ADDRES_TOKEN)) 1825 continue; 1826 Integer type = c.getInt(c.getColumnIndex(Mms.Addr.TYPE)); 1827 switch(type) { 1828 case MMS_FROM: 1829 contactName = setVCardFromPhoneNumber(message, address, true); 1830 message.addFrom(contactName, address); 1831 break; 1832 case MMS_TO: 1833 contactName = setVCardFromPhoneNumber(message, address, false); 1834 message.addTo(contactName, address); 1835 break; 1836 case MMS_CC: 1837 contactName = setVCardFromPhoneNumber(message, address, false); 1838 message.addCc(contactName, address); 1839 break; 1840 case MMS_BCC: 1841 contactName = setVCardFromPhoneNumber(message, address, false); 1842 message.addBcc(contactName, address); 1843 break; 1844 default: 1845 break; 1846 } 1847 } while(c.moveToNext()); 1848 } 1849 } 1850 1851 /** 1852 * Read out a mms data part and return the data in a byte array. 1853 * @param partid the content provider id of the mms. 1854 * @return 1855 */ 1856 private byte[] readMmsDataPart(long partid) { 1857 String uriStr = new String(Mms.CONTENT_URI + "/part/" + partid); 1858 Uri uriAddress = Uri.parse(uriStr); 1859 InputStream is = null; 1860 ByteArrayOutputStream os = new ByteArrayOutputStream(); 1861 int bufferSize = 8192; 1862 byte[] buffer = new byte[bufferSize]; 1863 byte[] retVal = null; 1864 1865 try { 1866 is = mResolver.openInputStream(uriAddress); 1867 int len = 0; 1868 while ((len = is.read(buffer)) != -1) { 1869 os.write(buffer, 0, len); // We need to specify the len, as it can be != bufferSize 1870 } 1871 retVal = os.toByteArray(); 1872 } catch (IOException e) { 1873 // do nothing for now 1874 Log.w(TAG,"Error reading part data",e); 1875 } finally { 1876 try { 1877 os.close(); 1878 is.close(); 1879 } catch (IOException e) { 1880 } 1881 } 1882 return retVal; 1883 } 1884 1885 /** 1886 * Read out the mms parts and update the bMessage object provided i {@linkplain message} 1887 * @param id the content provider ID of the message 1888 * @param message the bMessage object to add the information to 1889 */ 1890 private void extractMmsParts(long id, BluetoothMapbMessageMms message) 1891 { 1892 /* Handling of filtering out non-text parts for exclude 1893 * attachments is handled within the bMessage object. */ 1894 final String[] projection = null; 1895 String selection = new String(Mms.Part.MSG_ID + "=" + id); 1896 String uriStr = new String(Mms.CONTENT_URI + "/"+ id + "/part"); 1897 Uri uriAddress = Uri.parse(uriStr); 1898 BluetoothMapbMessageMms.MimePart part; 1899 Cursor c = mResolver.query( 1900 uriAddress, 1901 projection, 1902 selection, 1903 null, null); 1904 1905 if (c.moveToFirst()) { 1906 do { 1907 Long partId = c.getLong(c.getColumnIndex(BaseColumns._ID)); 1908 String contentType = c.getString(c.getColumnIndex(Mms.Part.CONTENT_TYPE)); 1909 String name = c.getString(c.getColumnIndex(Mms.Part.NAME)); 1910 String charset = c.getString(c.getColumnIndex(Mms.Part.CHARSET)); 1911 String filename = c.getString(c.getColumnIndex(Mms.Part.FILENAME)); 1912 String text = c.getString(c.getColumnIndex(Mms.Part.TEXT)); 1913 Integer fd = c.getInt(c.getColumnIndex(Mms.Part._DATA)); 1914 String cid = c.getString(c.getColumnIndex(Mms.Part.CONTENT_ID)); 1915 String cl = c.getString(c.getColumnIndex(Mms.Part.CONTENT_LOCATION)); 1916 String cdisp = c.getString(c.getColumnIndex(Mms.Part.CONTENT_DISPOSITION)); 1917 1918 if(V) Log.d(TAG, " _id : " + partId + 1919 "\n ct : " + contentType + 1920 "\n partname : " + name + 1921 "\n charset : " + charset + 1922 "\n filename : " + filename + 1923 "\n text : " + text + 1924 "\n fd : " + fd + 1925 "\n cid : " + cid + 1926 "\n cl : " + cl + 1927 "\n cdisp : " + cdisp); 1928 1929 part = message.addMimePart(); 1930 part.mContentType = contentType; 1931 part.mPartName = name; 1932 part.mContentId = cid; 1933 part.mContentLocation = cl; 1934 part.mContentDisposition = cdisp; 1935 1936 try { 1937 if(text != null) { 1938 part.mData = text.getBytes("UTF-8"); 1939 part.mCharsetName = "utf-8"; 1940 } else { 1941 part.mData = readMmsDataPart(partId); 1942 if(charset != null) 1943 part.mCharsetName = CharacterSets.getMimeName(Integer.parseInt(charset)); 1944 } 1945 } catch (NumberFormatException e) { 1946 Log.d(TAG,"extractMmsParts",e); 1947 part.mData = null; 1948 part.mCharsetName = null; 1949 } catch (UnsupportedEncodingException e) { 1950 Log.d(TAG,"extractMmsParts",e); 1951 part.mData = null; 1952 part.mCharsetName = null; 1953 } finally { 1954 } 1955 part.mFileName = filename; 1956 } while(c.moveToNext()); 1957 } 1958 message.updateCharset(); 1959 } 1960 1961 /** 1962 * 1963 * @param id the content provider id for the message to fetch. 1964 * @param appParams The application parameter object received from the client. 1965 * @return a byte[] containing the utf-8 encoded bMessage to send to the client. 1966 * @throws UnsupportedEncodingException if UTF-8 is not supported, 1967 * which is guaranteed to be supported on an android device 1968 */ 1969 public byte[] getMmsMessage(long id, BluetoothMapAppParams appParams) throws UnsupportedEncodingException { 1970 int msgBox, threadId; 1971 if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE) 1972 throw new IllegalArgumentException("MMS charset native not allowed for MMS - must be utf-8"); 1973 1974 BluetoothMapbMessageMms message = new BluetoothMapbMessageMms(); 1975 Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, "_ID = " + id, null, null); 1976 if(c != null && c.moveToFirst()) 1977 { 1978 message.setType(TYPE.MMS); 1979 1980 // The MMS info: 1981 String read = c.getString(c.getColumnIndex(Mms.READ)); 1982 if (read.equalsIgnoreCase("1")) 1983 message.setStatus(true); 1984 else 1985 message.setStatus(false); 1986 1987 msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)); 1988 threadId = c.getInt(c.getColumnIndex(Mms.THREAD_ID)); 1989 message.setFolder(getFolderName(msgBox, threadId)); 1990 message.setSubject(c.getString(c.getColumnIndex(Mms.SUBJECT))); 1991 message.setMessageId(c.getString(c.getColumnIndex(Mms.MESSAGE_ID))); 1992 message.setContentType(c.getString(c.getColumnIndex(Mms.CONTENT_TYPE))); 1993 message.setDate(c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L); 1994 message.setTextOnly(c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) == 0 ? false : true); 1995 message.setIncludeAttachments(appParams.getAttachment() == 0 ? false : true); 1996 // c.getLong(c.getColumnIndex(Mms.DATE_SENT)); - this is never used 1997 // c.getInt(c.getColumnIndex(Mms.STATUS)); - don't know what this is 1998 1999 // The parts 2000 extractMmsParts(id, message); 2001 2002 // The addresses 2003 extractMmsAddresses(id, message); 2004 2005 c.close(); 2006 2007 return message.encode(); 2008 } else if(c != null) { 2009 c.close(); 2010 } 2011 2012 throw new IllegalArgumentException("MMS handle not found"); 2013 } 2014 2015 /** 2016 * 2017 * @param id the content provider id for the message to fetch. 2018 * @param appParams The application parameter object received from the client. 2019 * @return a byte[] containing the utf-8 encoded bMessage to send to the client. 2020 * @throws UnsupportedEncodingException if UTF-8 is not supported, 2021 * which is guaranteed to be supported on an android device 2022 */ 2023 public byte[] getEmailMessage(long id, BluetoothMapAppParams appParams, 2024 BluetoothMapFolderElement currentFolder) throws UnsupportedEncodingException { 2025 // Log print out of application parameters set 2026 if(D && appParams != null) { 2027 Log.d(TAG,"TYPE_MESSAGE (GET): Attachment = " + appParams.getAttachment() + 2028 ", Charset = " + appParams.getCharset() + 2029 ", FractionRequest = " + appParams.getFractionRequest()); 2030 } 2031 2032 // Throw exception if requester NATIVE charset for Email 2033 // Exception is caught by MapObexServer sendGetMessageResp 2034 if (appParams.getCharset() == MAP_MESSAGE_CHARSET_NATIVE) 2035 throw new IllegalArgumentException("EMAIL charset not UTF-8"); 2036 2037 BluetoothMapbMessageEmail message = new BluetoothMapbMessageEmail(); 2038 Uri contentUri = Uri.parse(mBaseEmailUri + BluetoothMapContract.TABLE_MESSAGE); 2039 Cursor c = mResolver.query(contentUri, BluetoothMapContract.BT_MESSAGE_PROJECTION, "_ID = " + id, null, null); 2040 if(c != null && c.moveToFirst()) 2041 { 2042 BluetoothMapFolderElement folderElement; 2043 FileInputStream is = null; 2044 ParcelFileDescriptor fd = null; 2045 2046 // Handle fraction requests 2047 int fractionRequest = appParams.getFractionRequest(); 2048 if (fractionRequest != BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 2049 // Fraction requested 2050 if(V) { 2051 String fractionStr = (fractionRequest == 0) ? "FIRST" : "NEXT"; 2052 Log.v(TAG, "getEmailMessage - FractionRequest " + fractionStr 2053 + " - send compete message" ); 2054 } 2055 // Check if message is complete and if not - request message from server 2056 if (c.getString(c.getColumnIndex( 2057 BluetoothMapContract.MessageColumns.RECEPTION_STATE)).equalsIgnoreCase( 2058 BluetoothMapContract.RECEPTION_STATE_COMPLETE) == false) { 2059 // TODO: request message from server 2060 Log.w(TAG, "getEmailMessage - receptionState not COMPLETE - Not Implemented!" ); 2061 } 2062 } 2063 // Set read status: 2064 String read = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FLAG_READ)); 2065 if (read != null && read.equalsIgnoreCase("1")) 2066 message.setStatus(true); 2067 else 2068 message.setStatus(false); 2069 2070 // Set message type: 2071 message.setType(TYPE.EMAIL); 2072 2073 // Set folder: 2074 long folderId = c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns.FOLDER_ID)); 2075 folderElement = currentFolder.getEmailFolderById(folderId); 2076 message.setCompleteFolder(folderElement.getFullPath()); 2077 2078 // Set recipient: 2079 String nameEmail = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.TO_LIST)); 2080 Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(nameEmail); 2081 if (tokens.length != 0) { 2082 if(D) Log.d(TAG, "Recipient count= " + tokens.length); 2083 int i = 0; 2084 while (i < tokens.length) { 2085 if(V) Log.d(TAG, "Recipient = " + tokens[i].toString()); 2086 String[] emails = new String[1]; 2087 emails[0] = tokens[i].getAddress(); 2088 String name = tokens[i].getName(); 2089 message.addRecipient(name, name, null, emails); 2090 i++; 2091 } 2092 } 2093 2094 // Set originator: 2095 nameEmail = c.getString(c.getColumnIndex(BluetoothMapContract.MessageColumns.FROM_LIST)); 2096 tokens = Rfc822Tokenizer.tokenize(nameEmail); 2097 if (tokens.length != 0) { 2098 if(D) Log.d(TAG, "Originator count= " + tokens.length); 2099 int i = 0; 2100 while (i < tokens.length) { 2101 if(V) Log.d(TAG, "Originator = " + tokens[i].toString()); 2102 String[] emails = new String[1]; 2103 emails[0] = tokens[i].getAddress(); 2104 String name = tokens[i].getName(); 2105 message.addOriginator(name, name, null, emails); 2106 i++; 2107 } 2108 } 2109 c.close(); 2110 2111 // Find out if we get attachments 2112 String attStr = (appParams.getAttachment() == 0) ? "/" + BluetoothMapContract.FILE_MSG_NO_ATTACHMENTS : ""; 2113 Uri uri = Uri.parse(contentUri + "/" + id + attStr); 2114 2115 // Get email message body content 2116 int count = 0; 2117 try { 2118 fd = mResolver.openFileDescriptor(uri, "r"); 2119 is = new FileInputStream(fd.getFileDescriptor()); 2120 StringBuilder email = new StringBuilder(""); 2121 byte[] buffer = new byte[1024]; 2122 while((count = is.read(buffer)) != -1) { 2123 // TODO: Handle breaks within a UTF8 character 2124 email.append(new String(buffer,0,count)); 2125 if(V) Log.d(TAG, "Email part = " + new String(buffer,0,count) + " count=" + count); 2126 } 2127 // Set email message body: 2128 message.setEmailBody(email.toString()); 2129 } catch (FileNotFoundException e) { 2130 Log.w(TAG, e); 2131 } catch (NullPointerException e) { 2132 Log.w(TAG, e); 2133 } catch (IOException e) { 2134 Log.w(TAG, e); 2135 } 2136 finally { 2137 try { 2138 if(is != null) 2139 is.close(); 2140 } catch (IOException e) {} 2141 try { 2142 if(fd != null) 2143 fd.close(); 2144 } catch (IOException e) {} 2145 } 2146 return message.encode(); 2147 } else if(c != null) { 2148 c.close(); 2149 } 2150 throw new IllegalArgumentException("EMAIL handle not found"); 2151 } 2152 } 2153