1d02a064168ae5c916b977182b764580e601cb084Wink Saville/*
2d02a064168ae5c916b977182b764580e601cb084Wink Saville * Copyright (C) 2007-2008 Esmertec AG.
3d02a064168ae5c916b977182b764580e601cb084Wink Saville * Copyright (C) 2007-2008 The Android Open Source Project
4d02a064168ae5c916b977182b764580e601cb084Wink Saville *
5d02a064168ae5c916b977182b764580e601cb084Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
6d02a064168ae5c916b977182b764580e601cb084Wink Saville * you may not use this file except in compliance with the License.
7d02a064168ae5c916b977182b764580e601cb084Wink Saville * You may obtain a copy of the License at
8d02a064168ae5c916b977182b764580e601cb084Wink Saville *
9d02a064168ae5c916b977182b764580e601cb084Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
10d02a064168ae5c916b977182b764580e601cb084Wink Saville *
11d02a064168ae5c916b977182b764580e601cb084Wink Saville * Unless required by applicable law or agreed to in writing, software
12d02a064168ae5c916b977182b764580e601cb084Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
13d02a064168ae5c916b977182b764580e601cb084Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d02a064168ae5c916b977182b764580e601cb084Wink Saville * See the License for the specific language governing permissions and
15d02a064168ae5c916b977182b764580e601cb084Wink Saville * limitations under the License.
16d02a064168ae5c916b977182b764580e601cb084Wink Saville */
17d02a064168ae5c916b977182b764580e601cb084Wink Saville
18d02a064168ae5c916b977182b764580e601cb084Wink Savillepackage com.google.android.mms.pdu;
19d02a064168ae5c916b977182b764580e601cb084Wink Saville
20d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.ContentType;
21d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.InvalidHeaderValueException;
22d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.MmsException;
23d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.util.DownloadDrmHelper;
24d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.util.DrmConvertSession;
25d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.util.PduCache;
26d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.util.PduCacheEntry;
27d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.util.SqliteWrapper;
28d02a064168ae5c916b977182b764580e601cb084Wink Saville
29d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.content.ContentResolver;
30d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.content.ContentUris;
31d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.content.ContentValues;
32d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.content.Context;
33d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.database.Cursor;
34d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.database.DatabaseUtils;
35d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.database.sqlite.SQLiteException;
36d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.drm.DrmManagerClient;
37d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.net.Uri;
38d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.MediaStore;
39d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony;
40d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.Mms;
41d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.MmsSms;
42d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.Threads;
43d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.Mms.Addr;
44d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.Mms.Part;
45d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.provider.Telephony.MmsSms.PendingMessages;
46d02b0b273f4915d1873bbb5472492380451b84ffTom Taylorimport android.telephony.PhoneNumberUtils;
47d02b0b273f4915d1873bbb5472492380451b84ffTom Taylorimport android.telephony.TelephonyManager;
48d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.text.TextUtils;
49d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport android.util.Log;
50d02a064168ae5c916b977182b764580e601cb084Wink Saville
51d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.ByteArrayOutputStream;
52d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.File;
53d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.FileNotFoundException;
54d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.IOException;
55d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.InputStream;
56d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.OutputStream;
57d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.io.UnsupportedEncodingException;
58d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.ArrayList;
59d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.HashMap;
60d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.HashSet;
61d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.Map;
62d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.Set;
63d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport java.util.Map.Entry;
64d02a064168ae5c916b977182b764580e601cb084Wink Saville
65d02a064168ae5c916b977182b764580e601cb084Wink Savilleimport com.google.android.mms.pdu.EncodedStringValue;
66d02a064168ae5c916b977182b764580e601cb084Wink Saville
67d02a064168ae5c916b977182b764580e601cb084Wink Saville/**
68d02a064168ae5c916b977182b764580e601cb084Wink Saville * This class is the high-level manager of PDU storage.
69d02a064168ae5c916b977182b764580e601cb084Wink Saville */
70d02a064168ae5c916b977182b764580e601cb084Wink Savillepublic class PduPersister {
71d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final String TAG = "PduPersister";
72d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final boolean DEBUG = false;
73d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final boolean LOCAL_LOGV = false;
74d02a064168ae5c916b977182b764580e601cb084Wink Saville
75d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final long DUMMY_THREAD_ID = Long.MAX_VALUE;
76d02a064168ae5c916b977182b764580e601cb084Wink Saville
77d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
78d02a064168ae5c916b977182b764580e601cb084Wink Saville     * The uri of temporary drm objects.
79d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
80d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static final String TEMPORARY_DRM_OBJECT_URI =
81d02a064168ae5c916b977182b764580e601cb084Wink Saville        "content://mms/" + Long.MAX_VALUE + "/part";
82d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
83d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Indicate that we transiently failed to process a MM.
84d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
85d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static final int PROC_STATUS_TRANSIENT_FAILURE   = 1;
86d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
87d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Indicate that we permanently failed to process a MM.
88d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
89d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static final int PROC_STATUS_PERMANENTLY_FAILURE = 2;
90d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
91d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Indicate that we have successfully processed a MM.
92d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
93d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static final int PROC_STATUS_COMPLETED           = 3;
94d02a064168ae5c916b977182b764580e601cb084Wink Saville
95d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static PduPersister sPersister;
96d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final PduCache PDU_CACHE_INSTANCE;
97d02a064168ae5c916b977182b764580e601cb084Wink Saville
98d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int[] ADDRESS_FIELDS = new int[] {
99d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders.BCC,
100d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders.CC,
101d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders.FROM,
102d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders.TO
103d02a064168ae5c916b977182b764580e601cb084Wink Saville    };
104d02a064168ae5c916b977182b764580e601cb084Wink Saville
105d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final String[] PDU_PROJECTION = new String[] {
106d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms._ID,
107d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MESSAGE_BOX,
108d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.THREAD_ID,
109d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.RETRIEVE_TEXT,
110d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.SUBJECT,
111d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.CONTENT_LOCATION,
112d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.CONTENT_TYPE,
113d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MESSAGE_CLASS,
114d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MESSAGE_ID,
115d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.RESPONSE_TEXT,
116d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.TRANSACTION_ID,
117d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.CONTENT_CLASS,
118d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.DELIVERY_REPORT,
119d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MESSAGE_TYPE,
120d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MMS_VERSION,
121d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.PRIORITY,
122d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.READ_REPORT,
123d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.READ_STATUS,
124d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.REPORT_ALLOWED,
125d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.RETRIEVE_STATUS,
126d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.STATUS,
127d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.DATE,
128d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.DELIVERY_TIME,
129d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.EXPIRY,
130d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.MESSAGE_SIZE,
131d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.SUBJECT_CHARSET,
132d02a064168ae5c916b977182b764580e601cb084Wink Saville        Mms.RETRIEVE_TEXT_CHARSET,
133d02a064168ae5c916b977182b764580e601cb084Wink Saville    };
134d02a064168ae5c916b977182b764580e601cb084Wink Saville
135d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_ID                    = 0;
136d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MESSAGE_BOX           = 1;
137d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_THREAD_ID             = 2;
138d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_RETRIEVE_TEXT         = 3;
139d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_SUBJECT               = 4;
140d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_CONTENT_LOCATION      = 5;
141d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_CONTENT_TYPE          = 6;
142d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MESSAGE_CLASS         = 7;
143d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MESSAGE_ID            = 8;
144d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_RESPONSE_TEXT         = 9;
145d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_TRANSACTION_ID        = 10;
146d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_CONTENT_CLASS         = 11;
147d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_DELIVERY_REPORT       = 12;
148d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MESSAGE_TYPE          = 13;
149d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MMS_VERSION           = 14;
150d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_PRIORITY              = 15;
151d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_READ_REPORT           = 16;
152d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_READ_STATUS           = 17;
153d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_REPORT_ALLOWED        = 18;
154d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_RETRIEVE_STATUS       = 19;
155d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_STATUS                = 20;
156d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_DATE                  = 21;
157d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_DELIVERY_TIME         = 22;
158d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_EXPIRY                = 23;
159d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_MESSAGE_SIZE          = 24;
160d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_SUBJECT_CHARSET       = 25;
161d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PDU_COLUMN_RETRIEVE_TEXT_CHARSET = 26;
162d02a064168ae5c916b977182b764580e601cb084Wink Saville
163d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final String[] PART_PROJECTION = new String[] {
164d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part._ID,
165d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.CHARSET,
166d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.CONTENT_DISPOSITION,
167d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.CONTENT_ID,
168d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.CONTENT_LOCATION,
169d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.CONTENT_TYPE,
170d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.FILENAME,
171d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.NAME,
172d02a064168ae5c916b977182b764580e601cb084Wink Saville        Part.TEXT
173d02a064168ae5c916b977182b764580e601cb084Wink Saville    };
174d02a064168ae5c916b977182b764580e601cb084Wink Saville
175d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_ID                  = 0;
176d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_CHARSET             = 1;
177d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_CONTENT_DISPOSITION = 2;
178d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_CONTENT_ID          = 3;
179d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_CONTENT_LOCATION    = 4;
180d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_CONTENT_TYPE        = 5;
181d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_FILENAME            = 6;
182d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_NAME                = 7;
183d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final int PART_COLUMN_TEXT                = 8;
184d02a064168ae5c916b977182b764580e601cb084Wink Saville
185d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP;
186d02a064168ae5c916b977182b764580e601cb084Wink Saville    // These map are used for convenience in persist() and load().
187d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, Integer> CHARSET_COLUMN_INDEX_MAP;
188d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, Integer> ENCODED_STRING_COLUMN_INDEX_MAP;
189d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, Integer> TEXT_STRING_COLUMN_INDEX_MAP;
190d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, Integer> OCTET_COLUMN_INDEX_MAP;
191d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, Integer> LONG_COLUMN_INDEX_MAP;
192d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, String> CHARSET_COLUMN_NAME_MAP;
193d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, String> ENCODED_STRING_COLUMN_NAME_MAP;
194d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, String> TEXT_STRING_COLUMN_NAME_MAP;
195d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, String> OCTET_COLUMN_NAME_MAP;
196d02a064168ae5c916b977182b764580e601cb084Wink Saville    private static final HashMap<Integer, String> LONG_COLUMN_NAME_MAP;
197d02a064168ae5c916b977182b764580e601cb084Wink Saville
198d02a064168ae5c916b977182b764580e601cb084Wink Saville    static {
199d02a064168ae5c916b977182b764580e601cb084Wink Saville        MESSAGE_BOX_MAP = new HashMap<Uri, Integer>();
200d02a064168ae5c916b977182b764580e601cb084Wink Saville        MESSAGE_BOX_MAP.put(Mms.Inbox.CONTENT_URI,  Mms.MESSAGE_BOX_INBOX);
201d02a064168ae5c916b977182b764580e601cb084Wink Saville        MESSAGE_BOX_MAP.put(Mms.Sent.CONTENT_URI,   Mms.MESSAGE_BOX_SENT);
202d02a064168ae5c916b977182b764580e601cb084Wink Saville        MESSAGE_BOX_MAP.put(Mms.Draft.CONTENT_URI,  Mms.MESSAGE_BOX_DRAFTS);
203d02a064168ae5c916b977182b764580e601cb084Wink Saville        MESSAGE_BOX_MAP.put(Mms.Outbox.CONTENT_URI, Mms.MESSAGE_BOX_OUTBOX);
204d02a064168ae5c916b977182b764580e601cb084Wink Saville
205d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
206d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT_CHARSET);
207d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT_CHARSET);
208d02a064168ae5c916b977182b764580e601cb084Wink Saville
209d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
210d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT_CHARSET);
211d02a064168ae5c916b977182b764580e601cb084Wink Saville        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT_CHARSET);
212d02a064168ae5c916b977182b764580e601cb084Wink Saville
213d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Encoded string field code -> column index/name map.
214d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
215d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT);
216d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT);
217d02a064168ae5c916b977182b764580e601cb084Wink Saville
218d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
219d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT);
220d02a064168ae5c916b977182b764580e601cb084Wink Saville        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT);
221d02a064168ae5c916b977182b764580e601cb084Wink Saville
222d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Text string field code -> column index/name map.
223d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
224d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_LOCATION, PDU_COLUMN_CONTENT_LOCATION);
225d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_TYPE, PDU_COLUMN_CONTENT_TYPE);
226d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_CLASS, PDU_COLUMN_MESSAGE_CLASS);
227d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_ID, PDU_COLUMN_MESSAGE_ID);
228d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RESPONSE_TEXT, PDU_COLUMN_RESPONSE_TEXT);
229d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.TRANSACTION_ID, PDU_COLUMN_TRANSACTION_ID);
230d02a064168ae5c916b977182b764580e601cb084Wink Saville
231d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
232d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_LOCATION, Mms.CONTENT_LOCATION);
233d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_TYPE, Mms.CONTENT_TYPE);
234d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_CLASS, Mms.MESSAGE_CLASS);
235d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_ID, Mms.MESSAGE_ID);
236d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.RESPONSE_TEXT, Mms.RESPONSE_TEXT);
237d02a064168ae5c916b977182b764580e601cb084Wink Saville        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.TRANSACTION_ID, Mms.TRANSACTION_ID);
238d02a064168ae5c916b977182b764580e601cb084Wink Saville
239d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Octet field code -> column index/name map.
240d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
241d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_CLASS, PDU_COLUMN_CONTENT_CLASS);
242d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_REPORT, PDU_COLUMN_DELIVERY_REPORT);
243d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_TYPE, PDU_COLUMN_MESSAGE_TYPE);
244d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MMS_VERSION, PDU_COLUMN_MMS_VERSION);
245d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.PRIORITY, PDU_COLUMN_PRIORITY);
246d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_REPORT, PDU_COLUMN_READ_REPORT);
247d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_STATUS, PDU_COLUMN_READ_STATUS);
248d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.REPORT_ALLOWED, PDU_COLUMN_REPORT_ALLOWED);
249d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_STATUS, PDU_COLUMN_RETRIEVE_STATUS);
250d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.STATUS, PDU_COLUMN_STATUS);
251d02a064168ae5c916b977182b764580e601cb084Wink Saville
252d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
253d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_CLASS, Mms.CONTENT_CLASS);
254d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_REPORT, Mms.DELIVERY_REPORT);
255d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_TYPE, Mms.MESSAGE_TYPE);
256d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MMS_VERSION, Mms.MMS_VERSION);
257d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.PRIORITY, Mms.PRIORITY);
258d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_REPORT, Mms.READ_REPORT);
259d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_STATUS, Mms.READ_STATUS);
260d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.REPORT_ALLOWED, Mms.REPORT_ALLOWED);
261d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_STATUS, Mms.RETRIEVE_STATUS);
262d02a064168ae5c916b977182b764580e601cb084Wink Saville        OCTET_COLUMN_NAME_MAP.put(PduHeaders.STATUS, Mms.STATUS);
263d02a064168ae5c916b977182b764580e601cb084Wink Saville
264d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Long field code -> column index/name map.
265d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
266d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DATE, PDU_COLUMN_DATE);
267d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_TIME, PDU_COLUMN_DELIVERY_TIME);
268d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_INDEX_MAP.put(PduHeaders.EXPIRY, PDU_COLUMN_EXPIRY);
269d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_SIZE, PDU_COLUMN_MESSAGE_SIZE);
270d02a064168ae5c916b977182b764580e601cb084Wink Saville
271d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_NAME_MAP = new HashMap<Integer, String>();
272d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_NAME_MAP.put(PduHeaders.DATE, Mms.DATE);
273d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_TIME, Mms.DELIVERY_TIME);
274d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_NAME_MAP.put(PduHeaders.EXPIRY, Mms.EXPIRY);
275d02a064168ae5c916b977182b764580e601cb084Wink Saville        LONG_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_SIZE, Mms.MESSAGE_SIZE);
276d02a064168ae5c916b977182b764580e601cb084Wink Saville
277d02a064168ae5c916b977182b764580e601cb084Wink Saville        PDU_CACHE_INSTANCE = PduCache.getInstance();
278d02a064168ae5c916b977182b764580e601cb084Wink Saville     }
279d02a064168ae5c916b977182b764580e601cb084Wink Saville
280d02a064168ae5c916b977182b764580e601cb084Wink Saville    private final Context mContext;
281d02a064168ae5c916b977182b764580e601cb084Wink Saville    private final ContentResolver mContentResolver;
282d02a064168ae5c916b977182b764580e601cb084Wink Saville    private final DrmManagerClient mDrmManagerClient;
283d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor    private final TelephonyManager mTelephonyManager;
284d02a064168ae5c916b977182b764580e601cb084Wink Saville
285d02a064168ae5c916b977182b764580e601cb084Wink Saville    private PduPersister(Context context) {
286d02a064168ae5c916b977182b764580e601cb084Wink Saville        mContext = context;
287d02a064168ae5c916b977182b764580e601cb084Wink Saville        mContentResolver = context.getContentResolver();
288d02a064168ae5c916b977182b764580e601cb084Wink Saville        mDrmManagerClient = new DrmManagerClient(context);
289d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor        mTelephonyManager = (TelephonyManager)context
290d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                .getSystemService(Context.TELEPHONY_SERVICE);
291d02a064168ae5c916b977182b764580e601cb084Wink Saville     }
292d02a064168ae5c916b977182b764580e601cb084Wink Saville
293d02a064168ae5c916b977182b764580e601cb084Wink Saville    /** Get(or create if not exist) an instance of PduPersister */
294d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static PduPersister getPduPersister(Context context) {
295d02a064168ae5c916b977182b764580e601cb084Wink Saville        if ((sPersister == null) || !context.equals(sPersister.mContext)) {
296d02a064168ae5c916b977182b764580e601cb084Wink Saville            sPersister = new PduPersister(context);
297d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
298d02a064168ae5c916b977182b764580e601cb084Wink Saville
299d02a064168ae5c916b977182b764580e601cb084Wink Saville        return sPersister;
300d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
301d02a064168ae5c916b977182b764580e601cb084Wink Saville
302d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void setEncodedStringValueToHeaders(
303d02a064168ae5c916b977182b764580e601cb084Wink Saville            Cursor c, int columnIndex,
304d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders headers, int mapColumn) {
305d02a064168ae5c916b977182b764580e601cb084Wink Saville        String s = c.getString(columnIndex);
306d02a064168ae5c916b977182b764580e601cb084Wink Saville        if ((s != null) && (s.length() > 0)) {
307d02a064168ae5c916b977182b764580e601cb084Wink Saville            int charsetColumnIndex = CHARSET_COLUMN_INDEX_MAP.get(mapColumn);
308d02a064168ae5c916b977182b764580e601cb084Wink Saville            int charset = c.getInt(charsetColumnIndex);
309d02a064168ae5c916b977182b764580e601cb084Wink Saville            EncodedStringValue value = new EncodedStringValue(
310d02a064168ae5c916b977182b764580e601cb084Wink Saville                    charset, getBytes(s));
311d02a064168ae5c916b977182b764580e601cb084Wink Saville            headers.setEncodedStringValue(value, mapColumn);
312d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
313d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
314d02a064168ae5c916b977182b764580e601cb084Wink Saville
315d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void setTextStringToHeaders(
316d02a064168ae5c916b977182b764580e601cb084Wink Saville            Cursor c, int columnIndex,
317d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders headers, int mapColumn) {
318d02a064168ae5c916b977182b764580e601cb084Wink Saville        String s = c.getString(columnIndex);
319d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (s != null) {
320d02a064168ae5c916b977182b764580e601cb084Wink Saville            headers.setTextString(getBytes(s), mapColumn);
321d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
322d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
323d02a064168ae5c916b977182b764580e601cb084Wink Saville
324d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void setOctetToHeaders(
325d02a064168ae5c916b977182b764580e601cb084Wink Saville            Cursor c, int columnIndex,
326d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders headers, int mapColumn) throws InvalidHeaderValueException {
327d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!c.isNull(columnIndex)) {
328d02a064168ae5c916b977182b764580e601cb084Wink Saville            int b = c.getInt(columnIndex);
329d02a064168ae5c916b977182b764580e601cb084Wink Saville            headers.setOctet(b, mapColumn);
330d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
331d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
332d02a064168ae5c916b977182b764580e601cb084Wink Saville
333d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void setLongToHeaders(
334d02a064168ae5c916b977182b764580e601cb084Wink Saville            Cursor c, int columnIndex,
335d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders headers, int mapColumn) {
336d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!c.isNull(columnIndex)) {
337d02a064168ae5c916b977182b764580e601cb084Wink Saville            long l = c.getLong(columnIndex);
338d02a064168ae5c916b977182b764580e601cb084Wink Saville            headers.setLongInteger(l, mapColumn);
339d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
340d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
341d02a064168ae5c916b977182b764580e601cb084Wink Saville
342d02a064168ae5c916b977182b764580e601cb084Wink Saville    private Integer getIntegerFromPartColumn(Cursor c, int columnIndex) {
343d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!c.isNull(columnIndex)) {
344d02a064168ae5c916b977182b764580e601cb084Wink Saville            return c.getInt(columnIndex);
345d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
346d02a064168ae5c916b977182b764580e601cb084Wink Saville        return null;
347d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
348d02a064168ae5c916b977182b764580e601cb084Wink Saville
349d02a064168ae5c916b977182b764580e601cb084Wink Saville    private byte[] getByteArrayFromPartColumn(Cursor c, int columnIndex) {
350d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!c.isNull(columnIndex)) {
351d02a064168ae5c916b977182b764580e601cb084Wink Saville            return getBytes(c.getString(columnIndex));
352d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
353d02a064168ae5c916b977182b764580e601cb084Wink Saville        return null;
354d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
355d02a064168ae5c916b977182b764580e601cb084Wink Saville
356d02a064168ae5c916b977182b764580e601cb084Wink Saville    private PduPart[] loadParts(long msgId) throws MmsException {
357d02a064168ae5c916b977182b764580e601cb084Wink Saville        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
358d02a064168ae5c916b977182b764580e601cb084Wink Saville                Uri.parse("content://mms/" + msgId + "/part"),
359d02a064168ae5c916b977182b764580e601cb084Wink Saville                PART_PROJECTION, null, null, null);
360d02a064168ae5c916b977182b764580e601cb084Wink Saville
361d02a064168ae5c916b977182b764580e601cb084Wink Saville        PduPart[] parts = null;
362d02a064168ae5c916b977182b764580e601cb084Wink Saville
363d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
364d02a064168ae5c916b977182b764580e601cb084Wink Saville            if ((c == null) || (c.getCount() == 0)) {
365d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (LOCAL_LOGV) {
366d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.v(TAG, "loadParts(" + msgId + "): no part to load.");
367d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
368d02a064168ae5c916b977182b764580e601cb084Wink Saville                return null;
369d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
370d02a064168ae5c916b977182b764580e601cb084Wink Saville
371d02a064168ae5c916b977182b764580e601cb084Wink Saville            int partCount = c.getCount();
372d02a064168ae5c916b977182b764580e601cb084Wink Saville            int partIdx = 0;
373d02a064168ae5c916b977182b764580e601cb084Wink Saville            parts = new PduPart[partCount];
374d02a064168ae5c916b977182b764580e601cb084Wink Saville            while (c.moveToNext()) {
375d02a064168ae5c916b977182b764580e601cb084Wink Saville                PduPart part = new PduPart();
376d02a064168ae5c916b977182b764580e601cb084Wink Saville                Integer charset = getIntegerFromPartColumn(
377d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_CHARSET);
378d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (charset != null) {
379d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setCharset(charset);
380d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
381d02a064168ae5c916b977182b764580e601cb084Wink Saville
382d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] contentDisposition = getByteArrayFromPartColumn(
383d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_CONTENT_DISPOSITION);
384d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (contentDisposition != null) {
385d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setContentDisposition(contentDisposition);
386d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
387d02a064168ae5c916b977182b764580e601cb084Wink Saville
388d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] contentId = getByteArrayFromPartColumn(
389d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_CONTENT_ID);
390d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (contentId != null) {
391d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setContentId(contentId);
392d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
393d02a064168ae5c916b977182b764580e601cb084Wink Saville
394d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] contentLocation = getByteArrayFromPartColumn(
395d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_CONTENT_LOCATION);
396d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (contentLocation != null) {
397d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setContentLocation(contentLocation);
398d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
399d02a064168ae5c916b977182b764580e601cb084Wink Saville
400d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] contentType = getByteArrayFromPartColumn(
401d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_CONTENT_TYPE);
402d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (contentType != null) {
403d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setContentType(contentType);
404d02a064168ae5c916b977182b764580e601cb084Wink Saville                } else {
405d02a064168ae5c916b977182b764580e601cb084Wink Saville                    throw new MmsException("Content-Type must be set.");
406d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
407d02a064168ae5c916b977182b764580e601cb084Wink Saville
408d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] fileName = getByteArrayFromPartColumn(
409d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_FILENAME);
410d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (fileName != null) {
411d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setFilename(fileName);
412d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
413d02a064168ae5c916b977182b764580e601cb084Wink Saville
414d02a064168ae5c916b977182b764580e601cb084Wink Saville                byte[] name = getByteArrayFromPartColumn(
415d02a064168ae5c916b977182b764580e601cb084Wink Saville                        c, PART_COLUMN_NAME);
416d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (name != null) {
417d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setName(name);
418d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
419d02a064168ae5c916b977182b764580e601cb084Wink Saville
420d02a064168ae5c916b977182b764580e601cb084Wink Saville                // Construct a Uri for this part.
421d02a064168ae5c916b977182b764580e601cb084Wink Saville                long partId = c.getLong(PART_COLUMN_ID);
422d02a064168ae5c916b977182b764580e601cb084Wink Saville                Uri partURI = Uri.parse("content://mms/part/" + partId);
423d02a064168ae5c916b977182b764580e601cb084Wink Saville                part.setDataUri(partURI);
424d02a064168ae5c916b977182b764580e601cb084Wink Saville
425d02a064168ae5c916b977182b764580e601cb084Wink Saville                // For images/audio/video, we won't keep their data in Part
426d02a064168ae5c916b977182b764580e601cb084Wink Saville                // because their renderer accept Uri as source.
427d02a064168ae5c916b977182b764580e601cb084Wink Saville                String type = toIsoString(contentType);
428d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (!ContentType.isImageType(type)
429d02a064168ae5c916b977182b764580e601cb084Wink Saville                        && !ContentType.isAudioType(type)
430d02a064168ae5c916b977182b764580e601cb084Wink Saville                        && !ContentType.isVideoType(type)) {
431d02a064168ae5c916b977182b764580e601cb084Wink Saville                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
432d02a064168ae5c916b977182b764580e601cb084Wink Saville                    InputStream is = null;
433d02a064168ae5c916b977182b764580e601cb084Wink Saville
434d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // Store simple string values directly in the database instead of an
435d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // external file.  This makes the text searchable and retrieval slightly
436d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // faster.
437d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type)
438d02a064168ae5c916b977182b764580e601cb084Wink Saville                            || ContentType.TEXT_HTML.equals(type)) {
439d02a064168ae5c916b977182b764580e601cb084Wink Saville                        String text = c.getString(PART_COLUMN_TEXT);
440d02a064168ae5c916b977182b764580e601cb084Wink Saville                        byte [] blob = new EncodedStringValue(text != null ? text : "")
441d02a064168ae5c916b977182b764580e601cb084Wink Saville                            .getTextString();
442d02a064168ae5c916b977182b764580e601cb084Wink Saville                        baos.write(blob, 0, blob.length);
443d02a064168ae5c916b977182b764580e601cb084Wink Saville                    } else {
444d02a064168ae5c916b977182b764580e601cb084Wink Saville
445d02a064168ae5c916b977182b764580e601cb084Wink Saville                        try {
446d02a064168ae5c916b977182b764580e601cb084Wink Saville                            is = mContentResolver.openInputStream(partURI);
447d02a064168ae5c916b977182b764580e601cb084Wink Saville
448d02a064168ae5c916b977182b764580e601cb084Wink Saville                            byte[] buffer = new byte[256];
449d02a064168ae5c916b977182b764580e601cb084Wink Saville                            int len = is.read(buffer);
450d02a064168ae5c916b977182b764580e601cb084Wink Saville                            while (len >= 0) {
451d02a064168ae5c916b977182b764580e601cb084Wink Saville                                baos.write(buffer, 0, len);
452d02a064168ae5c916b977182b764580e601cb084Wink Saville                                len = is.read(buffer);
453d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
454d02a064168ae5c916b977182b764580e601cb084Wink Saville                        } catch (IOException e) {
455d02a064168ae5c916b977182b764580e601cb084Wink Saville                            Log.e(TAG, "Failed to load part data", e);
456d02a064168ae5c916b977182b764580e601cb084Wink Saville                            c.close();
457d02a064168ae5c916b977182b764580e601cb084Wink Saville                            throw new MmsException(e);
458d02a064168ae5c916b977182b764580e601cb084Wink Saville                        } finally {
459d02a064168ae5c916b977182b764580e601cb084Wink Saville                            if (is != null) {
460d02a064168ae5c916b977182b764580e601cb084Wink Saville                                try {
461d02a064168ae5c916b977182b764580e601cb084Wink Saville                                    is.close();
462d02a064168ae5c916b977182b764580e601cb084Wink Saville                                } catch (IOException e) {
463d02a064168ae5c916b977182b764580e601cb084Wink Saville                                    Log.e(TAG, "Failed to close stream", e);
464d02a064168ae5c916b977182b764580e601cb084Wink Saville                                } // Ignore
465d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
466d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
467d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
468d02a064168ae5c916b977182b764580e601cb084Wink Saville                    part.setData(baos.toByteArray());
469d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
470d02a064168ae5c916b977182b764580e601cb084Wink Saville                parts[partIdx++] = part;
471d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
472d02a064168ae5c916b977182b764580e601cb084Wink Saville        } finally {
473d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (c != null) {
474d02a064168ae5c916b977182b764580e601cb084Wink Saville                c.close();
475d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
476d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
477d02a064168ae5c916b977182b764580e601cb084Wink Saville
478d02a064168ae5c916b977182b764580e601cb084Wink Saville        return parts;
479d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
480d02a064168ae5c916b977182b764580e601cb084Wink Saville
481d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void loadAddress(long msgId, PduHeaders headers) {
482d02a064168ae5c916b977182b764580e601cb084Wink Saville        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
483d02a064168ae5c916b977182b764580e601cb084Wink Saville                Uri.parse("content://mms/" + msgId + "/addr"),
484d02a064168ae5c916b977182b764580e601cb084Wink Saville                new String[] { Addr.ADDRESS, Addr.CHARSET, Addr.TYPE },
485d02a064168ae5c916b977182b764580e601cb084Wink Saville                null, null, null);
486d02a064168ae5c916b977182b764580e601cb084Wink Saville
487d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (c != null) {
488d02a064168ae5c916b977182b764580e601cb084Wink Saville            try {
489d02a064168ae5c916b977182b764580e601cb084Wink Saville                while (c.moveToNext()) {
490d02a064168ae5c916b977182b764580e601cb084Wink Saville                    String addr = c.getString(0);
491d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (!TextUtils.isEmpty(addr)) {
492d02a064168ae5c916b977182b764580e601cb084Wink Saville                        int addrType = c.getInt(2);
493d02a064168ae5c916b977182b764580e601cb084Wink Saville                        switch (addrType) {
494d02a064168ae5c916b977182b764580e601cb084Wink Saville                            case PduHeaders.FROM:
495d02a064168ae5c916b977182b764580e601cb084Wink Saville                                headers.setEncodedStringValue(
496d02a064168ae5c916b977182b764580e601cb084Wink Saville                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
497d02a064168ae5c916b977182b764580e601cb084Wink Saville                                        addrType);
498d02a064168ae5c916b977182b764580e601cb084Wink Saville                                break;
499d02a064168ae5c916b977182b764580e601cb084Wink Saville                            case PduHeaders.TO:
500d02a064168ae5c916b977182b764580e601cb084Wink Saville                            case PduHeaders.CC:
501d02a064168ae5c916b977182b764580e601cb084Wink Saville                            case PduHeaders.BCC:
502d02a064168ae5c916b977182b764580e601cb084Wink Saville                                headers.appendEncodedStringValue(
503d02a064168ae5c916b977182b764580e601cb084Wink Saville                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
504d02a064168ae5c916b977182b764580e601cb084Wink Saville                                        addrType);
505d02a064168ae5c916b977182b764580e601cb084Wink Saville                                break;
506d02a064168ae5c916b977182b764580e601cb084Wink Saville                            default:
507d02a064168ae5c916b977182b764580e601cb084Wink Saville                                Log.e(TAG, "Unknown address type: " + addrType);
508d02a064168ae5c916b977182b764580e601cb084Wink Saville                                break;
509d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
510d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
511d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
512d02a064168ae5c916b977182b764580e601cb084Wink Saville            } finally {
513d02a064168ae5c916b977182b764580e601cb084Wink Saville                c.close();
514d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
515d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
516d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
517d02a064168ae5c916b977182b764580e601cb084Wink Saville
518d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
519d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Load a PDU from storage by given Uri.
520d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
521d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param uri The Uri of the PDU to be loaded.
522d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @return A generic PDU object, it may be cast to dedicated PDU.
523d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @throws MmsException Failed to load some fields of a PDU.
524d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
525d02a064168ae5c916b977182b764580e601cb084Wink Saville    public GenericPdu load(Uri uri) throws MmsException {
526d02a064168ae5c916b977182b764580e601cb084Wink Saville        GenericPdu pdu = null;
527d02a064168ae5c916b977182b764580e601cb084Wink Saville        PduCacheEntry cacheEntry = null;
528d02a064168ae5c916b977182b764580e601cb084Wink Saville        int msgBox = 0;
529d02a064168ae5c916b977182b764580e601cb084Wink Saville        long threadId = -1;
530d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
531d02a064168ae5c916b977182b764580e601cb084Wink Saville            synchronized(PDU_CACHE_INSTANCE) {
532d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
533d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (LOCAL_LOGV) {
534d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.v(TAG, "load: " + uri + " blocked by isUpdating()");
535d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
536d02a064168ae5c916b977182b764580e601cb084Wink Saville                    try {
537d02a064168ae5c916b977182b764580e601cb084Wink Saville                        PDU_CACHE_INSTANCE.wait();
538d02a064168ae5c916b977182b764580e601cb084Wink Saville                    } catch (InterruptedException e) {
539d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.e(TAG, "load: ", e);
540d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
541d02a064168ae5c916b977182b764580e601cb084Wink Saville                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
542d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (cacheEntry != null) {
543d02a064168ae5c916b977182b764580e601cb084Wink Saville                        return cacheEntry.getPdu();
544d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
545d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
546d02a064168ae5c916b977182b764580e601cb084Wink Saville                // Tell the cache to indicate to other callers that this item
547d02a064168ae5c916b977182b764580e601cb084Wink Saville                // is currently being updated.
548d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.setUpdating(uri, true);
549d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
550d02a064168ae5c916b977182b764580e601cb084Wink Saville
551d02a064168ae5c916b977182b764580e601cb084Wink Saville            Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
552d02a064168ae5c916b977182b764580e601cb084Wink Saville                    PDU_PROJECTION, null, null, null);
553d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduHeaders headers = new PduHeaders();
554d02a064168ae5c916b977182b764580e601cb084Wink Saville            Set<Entry<Integer, Integer>> set;
555d02a064168ae5c916b977182b764580e601cb084Wink Saville            long msgId = ContentUris.parseId(uri);
556d02a064168ae5c916b977182b764580e601cb084Wink Saville
557d02a064168ae5c916b977182b764580e601cb084Wink Saville            try {
558d02a064168ae5c916b977182b764580e601cb084Wink Saville                if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
559d02a064168ae5c916b977182b764580e601cb084Wink Saville                    throw new MmsException("Bad uri: " + uri);
560d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
561d02a064168ae5c916b977182b764580e601cb084Wink Saville
562d02a064168ae5c916b977182b764580e601cb084Wink Saville                msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
563d02a064168ae5c916b977182b764580e601cb084Wink Saville                threadId = c.getLong(PDU_COLUMN_THREAD_ID);
564d02a064168ae5c916b977182b764580e601cb084Wink Saville
565d02a064168ae5c916b977182b764580e601cb084Wink Saville                set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet();
566d02a064168ae5c916b977182b764580e601cb084Wink Saville                for (Entry<Integer, Integer> e : set) {
567d02a064168ae5c916b977182b764580e601cb084Wink Saville                    setEncodedStringValueToHeaders(
568d02a064168ae5c916b977182b764580e601cb084Wink Saville                            c, e.getValue(), headers, e.getKey());
569d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
570d02a064168ae5c916b977182b764580e601cb084Wink Saville
571d02a064168ae5c916b977182b764580e601cb084Wink Saville                set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet();
572d02a064168ae5c916b977182b764580e601cb084Wink Saville                for (Entry<Integer, Integer> e : set) {
573d02a064168ae5c916b977182b764580e601cb084Wink Saville                    setTextStringToHeaders(
574d02a064168ae5c916b977182b764580e601cb084Wink Saville                            c, e.getValue(), headers, e.getKey());
575d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
576d02a064168ae5c916b977182b764580e601cb084Wink Saville
577d02a064168ae5c916b977182b764580e601cb084Wink Saville                set = OCTET_COLUMN_INDEX_MAP.entrySet();
578d02a064168ae5c916b977182b764580e601cb084Wink Saville                for (Entry<Integer, Integer> e : set) {
579d02a064168ae5c916b977182b764580e601cb084Wink Saville                    setOctetToHeaders(
580d02a064168ae5c916b977182b764580e601cb084Wink Saville                            c, e.getValue(), headers, e.getKey());
581d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
582d02a064168ae5c916b977182b764580e601cb084Wink Saville
583d02a064168ae5c916b977182b764580e601cb084Wink Saville                set = LONG_COLUMN_INDEX_MAP.entrySet();
584d02a064168ae5c916b977182b764580e601cb084Wink Saville                for (Entry<Integer, Integer> e : set) {
585d02a064168ae5c916b977182b764580e601cb084Wink Saville                    setLongToHeaders(
586d02a064168ae5c916b977182b764580e601cb084Wink Saville                            c, e.getValue(), headers, e.getKey());
587d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
588d02a064168ae5c916b977182b764580e601cb084Wink Saville            } finally {
589d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (c != null) {
590d02a064168ae5c916b977182b764580e601cb084Wink Saville                    c.close();
591d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
592d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
593d02a064168ae5c916b977182b764580e601cb084Wink Saville
594d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Check whether 'msgId' has been assigned a valid value.
595d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (msgId == -1L) {
596d02a064168ae5c916b977182b764580e601cb084Wink Saville                throw new MmsException("Error! ID of the message: -1.");
597d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
598d02a064168ae5c916b977182b764580e601cb084Wink Saville
599d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Load address information of the MM.
600d02a064168ae5c916b977182b764580e601cb084Wink Saville            loadAddress(msgId, headers);
601d02a064168ae5c916b977182b764580e601cb084Wink Saville
602d02a064168ae5c916b977182b764580e601cb084Wink Saville            int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
603d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduBody body = new PduBody();
604d02a064168ae5c916b977182b764580e601cb084Wink Saville
605d02a064168ae5c916b977182b764580e601cb084Wink Saville            // For PDU which type is M_retrieve.conf or Send.req, we should
606d02a064168ae5c916b977182b764580e601cb084Wink Saville            // load multiparts and put them into the body of the PDU.
607d02a064168ae5c916b977182b764580e601cb084Wink Saville            if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
608d02a064168ae5c916b977182b764580e601cb084Wink Saville                    || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
609d02a064168ae5c916b977182b764580e601cb084Wink Saville                PduPart[] parts = loadParts(msgId);
610d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (parts != null) {
611d02a064168ae5c916b977182b764580e601cb084Wink Saville                    int partsNum = parts.length;
612d02a064168ae5c916b977182b764580e601cb084Wink Saville                    for (int i = 0; i < partsNum; i++) {
613d02a064168ae5c916b977182b764580e601cb084Wink Saville                        body.addPart(parts[i]);
614d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
615d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
616d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
617d02a064168ae5c916b977182b764580e601cb084Wink Saville
618d02a064168ae5c916b977182b764580e601cb084Wink Saville            switch (msgType) {
619d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
620d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new NotificationInd(headers);
621d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
622d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
623d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new DeliveryInd(headers);
624d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
625d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
626d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new ReadOrigInd(headers);
627d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
628d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
629d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new RetrieveConf(headers, body);
630d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
631d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
632d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new SendReq(headers, body);
633d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
634d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
635d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new AcknowledgeInd(headers);
636d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
637d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
638d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new NotifyRespInd(headers);
639d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
640d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
641d02a064168ae5c916b977182b764580e601cb084Wink Saville                pdu = new ReadRecInd(headers);
642d02a064168ae5c916b977182b764580e601cb084Wink Saville                break;
643d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
644d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_FORWARD_REQ:
645d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_FORWARD_CONF:
646d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ:
647d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF:
648d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ:
649d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF:
650d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ:
651d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF:
652d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ:
653d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF:
654d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_MBOX_DESCR:
655d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_DELETE_REQ:
656d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_DELETE_CONF:
657d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_CANCEL_REQ:
658d02a064168ae5c916b977182b764580e601cb084Wink Saville            case PduHeaders.MESSAGE_TYPE_CANCEL_CONF:
659d02a064168ae5c916b977182b764580e601cb084Wink Saville                throw new MmsException(
660d02a064168ae5c916b977182b764580e601cb084Wink Saville                        "Unsupported PDU type: " + Integer.toHexString(msgType));
661d02a064168ae5c916b977182b764580e601cb084Wink Saville
662d02a064168ae5c916b977182b764580e601cb084Wink Saville            default:
663d02a064168ae5c916b977182b764580e601cb084Wink Saville                throw new MmsException(
664d02a064168ae5c916b977182b764580e601cb084Wink Saville                        "Unrecognized PDU type: " + Integer.toHexString(msgType));
665d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
666d02a064168ae5c916b977182b764580e601cb084Wink Saville        } finally {
667d02a064168ae5c916b977182b764580e601cb084Wink Saville            synchronized(PDU_CACHE_INSTANCE) {
668d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (pdu != null) {
669d02a064168ae5c916b977182b764580e601cb084Wink Saville                    assert(PDU_CACHE_INSTANCE.get(uri) == null);
670d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // Update the cache entry with the real info
671d02a064168ae5c916b977182b764580e601cb084Wink Saville                    cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
672d02a064168ae5c916b977182b764580e601cb084Wink Saville                    PDU_CACHE_INSTANCE.put(uri, cacheEntry);
673d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
674d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.setUpdating(uri, false);
675d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead
676d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
677d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
678d02a064168ae5c916b977182b764580e601cb084Wink Saville        return pdu;
679d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
680d02a064168ae5c916b977182b764580e601cb084Wink Saville
681d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void persistAddress(
682d02a064168ae5c916b977182b764580e601cb084Wink Saville            long msgId, int type, EncodedStringValue[] array) {
683d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues(3);
684d02a064168ae5c916b977182b764580e601cb084Wink Saville
685d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (EncodedStringValue addr : array) {
686d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.clear(); // Clear all values first.
687d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Addr.ADDRESS, toIsoString(addr.getTextString()));
688d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Addr.CHARSET, addr.getCharacterSet());
689d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Addr.TYPE, type);
690d02a064168ae5c916b977182b764580e601cb084Wink Saville
691d02a064168ae5c916b977182b764580e601cb084Wink Saville            Uri uri = Uri.parse("content://mms/" + msgId + "/addr");
692d02a064168ae5c916b977182b764580e601cb084Wink Saville            SqliteWrapper.insert(mContext, mContentResolver, uri, values);
693d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
694d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
695d02a064168ae5c916b977182b764580e601cb084Wink Saville
69623480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor    private static String getPartContentType(PduPart part) {
69723480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        return part.getContentType() == null ? null : toIsoString(part.getContentType());
69823480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor    }
69923480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor
7004c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor    public Uri persistPart(PduPart part, long msgId, HashMap<Uri, InputStream> preOpenedFiles)
701d02a064168ae5c916b977182b764580e601cb084Wink Saville            throws MmsException {
702d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri uri = Uri.parse("content://mms/" + msgId + "/part");
703d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues(8);
704d02a064168ae5c916b977182b764580e601cb084Wink Saville
705d02a064168ae5c916b977182b764580e601cb084Wink Saville        int charset = part.getCharset();
706d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (charset != 0 ) {
707d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CHARSET, charset);
708d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
709d02a064168ae5c916b977182b764580e601cb084Wink Saville
71023480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        String contentType = getPartContentType(part);
71123480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        if (contentType != null) {
712d02a064168ae5c916b977182b764580e601cb084Wink Saville            // There is no "image/jpg" in Android (and it's an invalid mimetype).
713d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Change it to "image/jpeg"
714d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (ContentType.IMAGE_JPG.equals(contentType)) {
715d02a064168ae5c916b977182b764580e601cb084Wink Saville                contentType = ContentType.IMAGE_JPEG;
716d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
717d02a064168ae5c916b977182b764580e601cb084Wink Saville
718d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_TYPE, contentType);
719d02a064168ae5c916b977182b764580e601cb084Wink Saville            // To ensure the SMIL part is always the first part.
720d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (ContentType.APP_SMIL.equals(contentType)) {
721d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(Part.SEQ, -1);
722d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
723d02a064168ae5c916b977182b764580e601cb084Wink Saville        } else {
724d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException("MIME type of the part must be set.");
725d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
726d02a064168ae5c916b977182b764580e601cb084Wink Saville
727d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getFilename() != null) {
728d02a064168ae5c916b977182b764580e601cb084Wink Saville            String fileName = new String(part.getFilename());
729d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.FILENAME, fileName);
730d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
731d02a064168ae5c916b977182b764580e601cb084Wink Saville
732d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getName() != null) {
733d02a064168ae5c916b977182b764580e601cb084Wink Saville            String name = new String(part.getName());
734d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.NAME, name);
735d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
736d02a064168ae5c916b977182b764580e601cb084Wink Saville
737d02a064168ae5c916b977182b764580e601cb084Wink Saville        Object value = null;
738d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentDisposition() != null) {
739d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentDisposition());
740d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_DISPOSITION, (String) value);
741d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
742d02a064168ae5c916b977182b764580e601cb084Wink Saville
743d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentId() != null) {
744d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentId());
745d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_ID, (String) value);
746d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
747d02a064168ae5c916b977182b764580e601cb084Wink Saville
748d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentLocation() != null) {
749d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentLocation());
750d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_LOCATION, (String) value);
751d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
752d02a064168ae5c916b977182b764580e601cb084Wink Saville
753d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
754d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (res == null) {
755d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException("Failed to persist part, return null.");
756d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
757d02a064168ae5c916b977182b764580e601cb084Wink Saville
7584c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor        persistData(part, res, contentType, preOpenedFiles);
759d02a064168ae5c916b977182b764580e601cb084Wink Saville        // After successfully store the data, we should update
760d02a064168ae5c916b977182b764580e601cb084Wink Saville        // the dataUri of the part.
761d02a064168ae5c916b977182b764580e601cb084Wink Saville        part.setDataUri(res);
762d02a064168ae5c916b977182b764580e601cb084Wink Saville
763d02a064168ae5c916b977182b764580e601cb084Wink Saville        return res;
764d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
765d02a064168ae5c916b977182b764580e601cb084Wink Saville
766d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
767d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Save data of the part into storage. The source data may be given
768d02a064168ae5c916b977182b764580e601cb084Wink Saville     * by a byte[] or a Uri. If it's a byte[], directly save it
769d02a064168ae5c916b977182b764580e601cb084Wink Saville     * into storage, otherwise load source data from the dataUri and then
770d02a064168ae5c916b977182b764580e601cb084Wink Saville     * save it. If the data is an image, we may scale down it according
771d02a064168ae5c916b977182b764580e601cb084Wink Saville     * to user preference.
772d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
773d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param part The PDU part which contains data to be saved.
774d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param uri The URI of the part.
775d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param contentType The MIME type of the part.
7764c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
777d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @throws MmsException Cannot find source data or error occurred
778d02a064168ae5c916b977182b764580e601cb084Wink Saville     *         while saving the data.
779d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
780d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void persistData(PduPart part, Uri uri,
7814c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor            String contentType, HashMap<Uri, InputStream> preOpenedFiles)
782d02a064168ae5c916b977182b764580e601cb084Wink Saville            throws MmsException {
783d02a064168ae5c916b977182b764580e601cb084Wink Saville        OutputStream os = null;
784d02a064168ae5c916b977182b764580e601cb084Wink Saville        InputStream is = null;
785d02a064168ae5c916b977182b764580e601cb084Wink Saville        DrmConvertSession drmConvertSession = null;
786d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri dataUri = null;
787d02a064168ae5c916b977182b764580e601cb084Wink Saville        String path = null;
788d02a064168ae5c916b977182b764580e601cb084Wink Saville
789d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
790d02a064168ae5c916b977182b764580e601cb084Wink Saville            byte[] data = part.getData();
791d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (ContentType.TEXT_PLAIN.equals(contentType)
792d02a064168ae5c916b977182b764580e601cb084Wink Saville                    || ContentType.APP_SMIL.equals(contentType)
793d02a064168ae5c916b977182b764580e601cb084Wink Saville                    || ContentType.TEXT_HTML.equals(contentType)) {
794d02a064168ae5c916b977182b764580e601cb084Wink Saville                ContentValues cv = new ContentValues();
795d02a064168ae5c916b977182b764580e601cb084Wink Saville                cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString());
796d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (mContentResolver.update(uri, cv, null, null) != 1) {
797d02a064168ae5c916b977182b764580e601cb084Wink Saville                    throw new MmsException("unable to update " + uri.toString());
798d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
799d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else {
800d02a064168ae5c916b977182b764580e601cb084Wink Saville                boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
801d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (isDrm) {
802d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (uri != null) {
803d02a064168ae5c916b977182b764580e601cb084Wink Saville                        try {
804d02a064168ae5c916b977182b764580e601cb084Wink Saville                            path = convertUriToPath(mContext, uri);
805d02a064168ae5c916b977182b764580e601cb084Wink Saville                            if (LOCAL_LOGV) {
806d02a064168ae5c916b977182b764580e601cb084Wink Saville                                Log.v(TAG, "drm uri: " + uri + " path: " + path);
807d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
808d02a064168ae5c916b977182b764580e601cb084Wink Saville                            File f = new File(path);
809d02a064168ae5c916b977182b764580e601cb084Wink Saville                            long len = f.length();
810d02a064168ae5c916b977182b764580e601cb084Wink Saville                            if (LOCAL_LOGV) {
811d02a064168ae5c916b977182b764580e601cb084Wink Saville                                Log.v(TAG, "drm path: " + path + " len: " + len);
812d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
813d02a064168ae5c916b977182b764580e601cb084Wink Saville                            if (len > 0) {
814d02a064168ae5c916b977182b764580e601cb084Wink Saville                                // we're not going to re-persist and re-encrypt an already
815d02a064168ae5c916b977182b764580e601cb084Wink Saville                                // converted drm file
816d02a064168ae5c916b977182b764580e601cb084Wink Saville                                return;
817d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
818d02a064168ae5c916b977182b764580e601cb084Wink Saville                        } catch (Exception e) {
819d02a064168ae5c916b977182b764580e601cb084Wink Saville                            Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
820d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
821d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
822d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // We haven't converted the file yet, start the conversion
823d02a064168ae5c916b977182b764580e601cb084Wink Saville                    drmConvertSession = DrmConvertSession.open(mContext, contentType);
824d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (drmConvertSession == null) {
825d02a064168ae5c916b977182b764580e601cb084Wink Saville                        throw new MmsException("Mimetype " + contentType +
826d02a064168ae5c916b977182b764580e601cb084Wink Saville                                " can not be converted.");
827d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
828d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
8294c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                // uri can look like:
8304c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                // content://mms/part/98
831d02a064168ae5c916b977182b764580e601cb084Wink Saville                os = mContentResolver.openOutputStream(uri);
832d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (data == null) {
833d02a064168ae5c916b977182b764580e601cb084Wink Saville                    dataUri = part.getDataUri();
834d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if ((dataUri == null) || (dataUri == uri)) {
835d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.w(TAG, "Can't find data for this part.");
836d02a064168ae5c916b977182b764580e601cb084Wink Saville                        return;
837d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
8384c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    // dataUri can look like:
8394c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    // content://com.google.android.gallery3d.provider/picasa/item/5720646660183715586
8404c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    if (preOpenedFiles != null && preOpenedFiles.containsKey(dataUri)) {
8414c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                        is = preOpenedFiles.get(dataUri);
8424c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    }
8434c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    if (is == null) {
8444c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                        is = mContentResolver.openInputStream(dataUri);
8454c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    }
846d02a064168ae5c916b977182b764580e601cb084Wink Saville
847d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (LOCAL_LOGV) {
848d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.v(TAG, "Saving data to: " + uri);
849d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
850d02a064168ae5c916b977182b764580e601cb084Wink Saville
851d02a064168ae5c916b977182b764580e601cb084Wink Saville                    byte[] buffer = new byte[8192];
852d02a064168ae5c916b977182b764580e601cb084Wink Saville                    for (int len = 0; (len = is.read(buffer)) != -1; ) {
853d02a064168ae5c916b977182b764580e601cb084Wink Saville                        if (!isDrm) {
854d02a064168ae5c916b977182b764580e601cb084Wink Saville                            os.write(buffer, 0, len);
855d02a064168ae5c916b977182b764580e601cb084Wink Saville                        } else {
856d02a064168ae5c916b977182b764580e601cb084Wink Saville                            byte[] convertedData = drmConvertSession.convert(buffer, len);
857d02a064168ae5c916b977182b764580e601cb084Wink Saville                            if (convertedData != null) {
858d02a064168ae5c916b977182b764580e601cb084Wink Saville                                os.write(convertedData, 0, convertedData.length);
859d02a064168ae5c916b977182b764580e601cb084Wink Saville                            } else {
860d02a064168ae5c916b977182b764580e601cb084Wink Saville                                throw new MmsException("Error converting drm data.");
861d02a064168ae5c916b977182b764580e601cb084Wink Saville                            }
862d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
863d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
864d02a064168ae5c916b977182b764580e601cb084Wink Saville                } else {
865d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (LOCAL_LOGV) {
866d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.v(TAG, "Saving data to: " + uri);
867d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
868d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (!isDrm) {
869d02a064168ae5c916b977182b764580e601cb084Wink Saville                        os.write(data);
870d02a064168ae5c916b977182b764580e601cb084Wink Saville                    } else {
871d02a064168ae5c916b977182b764580e601cb084Wink Saville                        dataUri = uri;
872d02a064168ae5c916b977182b764580e601cb084Wink Saville                        byte[] convertedData = drmConvertSession.convert(data, data.length);
873d02a064168ae5c916b977182b764580e601cb084Wink Saville                        if (convertedData != null) {
874d02a064168ae5c916b977182b764580e601cb084Wink Saville                            os.write(convertedData, 0, convertedData.length);
875d02a064168ae5c916b977182b764580e601cb084Wink Saville                        } else {
876d02a064168ae5c916b977182b764580e601cb084Wink Saville                            throw new MmsException("Error converting drm data.");
877d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
878d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
879d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
880d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
881d02a064168ae5c916b977182b764580e601cb084Wink Saville        } catch (FileNotFoundException e) {
882d02a064168ae5c916b977182b764580e601cb084Wink Saville            Log.e(TAG, "Failed to open Input/Output stream.", e);
883d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException(e);
884d02a064168ae5c916b977182b764580e601cb084Wink Saville        } catch (IOException e) {
885d02a064168ae5c916b977182b764580e601cb084Wink Saville            Log.e(TAG, "Failed to read/write data.", e);
886d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException(e);
887d02a064168ae5c916b977182b764580e601cb084Wink Saville        } finally {
888d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (os != null) {
889d02a064168ae5c916b977182b764580e601cb084Wink Saville                try {
890d02a064168ae5c916b977182b764580e601cb084Wink Saville                    os.close();
891d02a064168ae5c916b977182b764580e601cb084Wink Saville                } catch (IOException e) {
892d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.e(TAG, "IOException while closing: " + os, e);
893d02a064168ae5c916b977182b764580e601cb084Wink Saville                } // Ignore
894d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
895d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (is != null) {
896d02a064168ae5c916b977182b764580e601cb084Wink Saville                try {
897d02a064168ae5c916b977182b764580e601cb084Wink Saville                    is.close();
898d02a064168ae5c916b977182b764580e601cb084Wink Saville                } catch (IOException e) {
899d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.e(TAG, "IOException while closing: " + is, e);
900d02a064168ae5c916b977182b764580e601cb084Wink Saville                } // Ignore
901d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
902d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (drmConvertSession != null) {
903d02a064168ae5c916b977182b764580e601cb084Wink Saville                drmConvertSession.close(path);
904d02a064168ae5c916b977182b764580e601cb084Wink Saville
905d02a064168ae5c916b977182b764580e601cb084Wink Saville                // Reset the permissions on the encrypted part file so everyone has only read
906d02a064168ae5c916b977182b764580e601cb084Wink Saville                // permission.
907d02a064168ae5c916b977182b764580e601cb084Wink Saville                File f = new File(path);
908d02a064168ae5c916b977182b764580e601cb084Wink Saville                ContentValues values = new ContentValues(0);
909d02a064168ae5c916b977182b764580e601cb084Wink Saville                SqliteWrapper.update(mContext, mContentResolver,
910d02a064168ae5c916b977182b764580e601cb084Wink Saville                                     Uri.parse("content://mms/resetFilePerm/" + f.getName()),
911d02a064168ae5c916b977182b764580e601cb084Wink Saville                                     values, null, null);
912d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
913d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
914d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
915d02a064168ae5c916b977182b764580e601cb084Wink Saville
916d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
917d02a064168ae5c916b977182b764580e601cb084Wink Saville     * This method expects uri in the following format
918d02a064168ae5c916b977182b764580e601cb084Wink Saville     *     content://media/<table_name>/<row_index> (or)
919d02a064168ae5c916b977182b764580e601cb084Wink Saville     *     file://sdcard/test.mp4
920d02a064168ae5c916b977182b764580e601cb084Wink Saville     *     http://test.com/test.mp4
921d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
922d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Here <table_name> shall be "video" or "audio" or "images"
923d02a064168ae5c916b977182b764580e601cb084Wink Saville     * <row_index> the index of the content in given table
924d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
925d02a064168ae5c916b977182b764580e601cb084Wink Saville    static public String convertUriToPath(Context context, Uri uri) {
926d02a064168ae5c916b977182b764580e601cb084Wink Saville        String path = null;
927d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (null != uri) {
928d02a064168ae5c916b977182b764580e601cb084Wink Saville            String scheme = uri.getScheme();
929d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (null == scheme || scheme.equals("") ||
930d02a064168ae5c916b977182b764580e601cb084Wink Saville                    scheme.equals(ContentResolver.SCHEME_FILE)) {
931d02a064168ae5c916b977182b764580e601cb084Wink Saville                path = uri.getPath();
932d02a064168ae5c916b977182b764580e601cb084Wink Saville
933d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else if (scheme.equals("http")) {
934d02a064168ae5c916b977182b764580e601cb084Wink Saville                path = uri.toString();
935d02a064168ae5c916b977182b764580e601cb084Wink Saville
936d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
937d02a064168ae5c916b977182b764580e601cb084Wink Saville                String[] projection = new String[] {MediaStore.MediaColumns.DATA};
938d02a064168ae5c916b977182b764580e601cb084Wink Saville                Cursor cursor = null;
939d02a064168ae5c916b977182b764580e601cb084Wink Saville                try {
940d02a064168ae5c916b977182b764580e601cb084Wink Saville                    cursor = context.getContentResolver().query(uri, projection, null,
941d02a064168ae5c916b977182b764580e601cb084Wink Saville                            null, null);
942d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
943d02a064168ae5c916b977182b764580e601cb084Wink Saville                        throw new IllegalArgumentException("Given Uri could not be found" +
944d02a064168ae5c916b977182b764580e601cb084Wink Saville                                " in media store");
945d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
946d02a064168ae5c916b977182b764580e601cb084Wink Saville                    int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
947d02a064168ae5c916b977182b764580e601cb084Wink Saville                    path = cursor.getString(pathIndex);
948d02a064168ae5c916b977182b764580e601cb084Wink Saville                } catch (SQLiteException e) {
949d02a064168ae5c916b977182b764580e601cb084Wink Saville                    throw new IllegalArgumentException("Given Uri is not formatted in a way " +
950d02a064168ae5c916b977182b764580e601cb084Wink Saville                            "so that it can be found in media store.");
951d02a064168ae5c916b977182b764580e601cb084Wink Saville                } finally {
952d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (null != cursor) {
953d02a064168ae5c916b977182b764580e601cb084Wink Saville                        cursor.close();
954d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
955d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
956d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else {
957d02a064168ae5c916b977182b764580e601cb084Wink Saville                throw new IllegalArgumentException("Given Uri scheme is not supported");
958d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
959d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
960d02a064168ae5c916b977182b764580e601cb084Wink Saville        return path;
961d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
962d02a064168ae5c916b977182b764580e601cb084Wink Saville
963d02a064168ae5c916b977182b764580e601cb084Wink Saville    private void updateAddress(
964d02a064168ae5c916b977182b764580e601cb084Wink Saville            long msgId, int type, EncodedStringValue[] array) {
965d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Delete old address information and then insert new ones.
966d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.delete(mContext, mContentResolver,
967d02a064168ae5c916b977182b764580e601cb084Wink Saville                Uri.parse("content://mms/" + msgId + "/addr"),
968d02a064168ae5c916b977182b764580e601cb084Wink Saville                Addr.TYPE + "=" + type, null);
969d02a064168ae5c916b977182b764580e601cb084Wink Saville
970d02a064168ae5c916b977182b764580e601cb084Wink Saville        persistAddress(msgId, type, array);
971d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
972d02a064168ae5c916b977182b764580e601cb084Wink Saville
973d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
974d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Update headers of a SendReq.
975d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
976d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param uri The PDU which need to be updated.
977d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param pdu New headers.
978d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @throws MmsException Bad URI or updating failed.
979d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
980d02a064168ae5c916b977182b764580e601cb084Wink Saville    public void updateHeaders(Uri uri, SendReq sendReq) {
981d02a064168ae5c916b977182b764580e601cb084Wink Saville        synchronized(PDU_CACHE_INSTANCE) {
982d02a064168ae5c916b977182b764580e601cb084Wink Saville            // If the cache item is getting updated, wait until it's done updating before
983d02a064168ae5c916b977182b764580e601cb084Wink Saville            // purging it.
984d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
985d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (LOCAL_LOGV) {
986d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.v(TAG, "updateHeaders: " + uri + " blocked by isUpdating()");
987d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
988d02a064168ae5c916b977182b764580e601cb084Wink Saville                try {
989d02a064168ae5c916b977182b764580e601cb084Wink Saville                    PDU_CACHE_INSTANCE.wait();
990d02a064168ae5c916b977182b764580e601cb084Wink Saville                } catch (InterruptedException e) {
991d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.e(TAG, "updateHeaders: ", e);
992d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
993d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
994d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
995d02a064168ae5c916b977182b764580e601cb084Wink Saville        PDU_CACHE_INSTANCE.purge(uri);
996d02a064168ae5c916b977182b764580e601cb084Wink Saville
997d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues(10);
998d02a064168ae5c916b977182b764580e601cb084Wink Saville        byte[] contentType = sendReq.getContentType();
999d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (contentType != null) {
1000d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.CONTENT_TYPE, toIsoString(contentType));
1001d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1002d02a064168ae5c916b977182b764580e601cb084Wink Saville
1003d02a064168ae5c916b977182b764580e601cb084Wink Saville        long date = sendReq.getDate();
1004d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (date != -1) {
1005d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.DATE, date);
1006d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1007d02a064168ae5c916b977182b764580e601cb084Wink Saville
1008d02a064168ae5c916b977182b764580e601cb084Wink Saville        int deliveryReport = sendReq.getDeliveryReport();
1009d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (deliveryReport != 0) {
1010d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.DELIVERY_REPORT, deliveryReport);
1011d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1012d02a064168ae5c916b977182b764580e601cb084Wink Saville
1013d02a064168ae5c916b977182b764580e601cb084Wink Saville        long expiry = sendReq.getExpiry();
1014d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (expiry != -1) {
1015d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.EXPIRY, expiry);
1016d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1017d02a064168ae5c916b977182b764580e601cb084Wink Saville
1018d02a064168ae5c916b977182b764580e601cb084Wink Saville        byte[] msgClass = sendReq.getMessageClass();
1019d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (msgClass != null) {
1020d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.MESSAGE_CLASS, toIsoString(msgClass));
1021d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1022d02a064168ae5c916b977182b764580e601cb084Wink Saville
1023d02a064168ae5c916b977182b764580e601cb084Wink Saville        int priority = sendReq.getPriority();
1024d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (priority != 0) {
1025d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.PRIORITY, priority);
1026d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1027d02a064168ae5c916b977182b764580e601cb084Wink Saville
1028d02a064168ae5c916b977182b764580e601cb084Wink Saville        int readReport = sendReq.getReadReport();
1029d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (readReport != 0) {
1030d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.READ_REPORT, readReport);
1031d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1032d02a064168ae5c916b977182b764580e601cb084Wink Saville
1033d02a064168ae5c916b977182b764580e601cb084Wink Saville        byte[] transId = sendReq.getTransactionId();
1034d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (transId != null) {
1035d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.TRANSACTION_ID, toIsoString(transId));
1036d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1037d02a064168ae5c916b977182b764580e601cb084Wink Saville
1038d02a064168ae5c916b977182b764580e601cb084Wink Saville        EncodedStringValue subject = sendReq.getSubject();
1039d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (subject != null) {
1040d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.SUBJECT, toIsoString(subject.getTextString()));
1041d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet());
1042d02a064168ae5c916b977182b764580e601cb084Wink Saville        } else {
1043d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.SUBJECT, "");
1044d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1045d02a064168ae5c916b977182b764580e601cb084Wink Saville
1046d02a064168ae5c916b977182b764580e601cb084Wink Saville        long messageSize = sendReq.getMessageSize();
1047d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (messageSize > 0) {
1048d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.MESSAGE_SIZE, messageSize);
1049d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1050d02a064168ae5c916b977182b764580e601cb084Wink Saville
1051d02a064168ae5c916b977182b764580e601cb084Wink Saville        PduHeaders headers = sendReq.getPduHeaders();
1052d02a064168ae5c916b977182b764580e601cb084Wink Saville        HashSet<String> recipients = new HashSet<String>();
1053d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (int addrType : ADDRESS_FIELDS) {
1054d02a064168ae5c916b977182b764580e601cb084Wink Saville            EncodedStringValue[] array = null;
1055d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (addrType == PduHeaders.FROM) {
1056d02a064168ae5c916b977182b764580e601cb084Wink Saville                EncodedStringValue v = headers.getEncodedStringValue(addrType);
1057d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (v != null) {
1058d02a064168ae5c916b977182b764580e601cb084Wink Saville                    array = new EncodedStringValue[1];
1059d02a064168ae5c916b977182b764580e601cb084Wink Saville                    array[0] = v;
1060d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1061d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else {
1062d02a064168ae5c916b977182b764580e601cb084Wink Saville                array = headers.getEncodedStringValues(addrType);
1063d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1064d02a064168ae5c916b977182b764580e601cb084Wink Saville
1065d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (array != null) {
1066d02a064168ae5c916b977182b764580e601cb084Wink Saville                long msgId = ContentUris.parseId(uri);
1067d02a064168ae5c916b977182b764580e601cb084Wink Saville                updateAddress(msgId, addrType, array);
1068d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (addrType == PduHeaders.TO) {
1069d02a064168ae5c916b977182b764580e601cb084Wink Saville                    for (EncodedStringValue v : array) {
1070d02a064168ae5c916b977182b764580e601cb084Wink Saville                        if (v != null) {
1071d02a064168ae5c916b977182b764580e601cb084Wink Saville                            recipients.add(v.getString());
1072d02a064168ae5c916b977182b764580e601cb084Wink Saville                        }
1073d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
1074d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1075d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1076d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1077d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!recipients.isEmpty()) {
1078d02a064168ae5c916b977182b764580e601cb084Wink Saville            long threadId = Threads.getOrCreateThreadId(mContext, recipients);
1079d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Mms.THREAD_ID, threadId);
1080d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1081d02a064168ae5c916b977182b764580e601cb084Wink Saville
1082d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1083d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1084d02a064168ae5c916b977182b764580e601cb084Wink Saville
10854c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor    private void updatePart(Uri uri, PduPart part, HashMap<Uri, InputStream> preOpenedFiles)
10864c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor            throws MmsException {
1087d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues(7);
1088d02a064168ae5c916b977182b764580e601cb084Wink Saville
1089d02a064168ae5c916b977182b764580e601cb084Wink Saville        int charset = part.getCharset();
1090d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (charset != 0 ) {
1091d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CHARSET, charset);
1092d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1093d02a064168ae5c916b977182b764580e601cb084Wink Saville
1094d02a064168ae5c916b977182b764580e601cb084Wink Saville        String contentType = null;
1095d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentType() != null) {
1096d02a064168ae5c916b977182b764580e601cb084Wink Saville            contentType = toIsoString(part.getContentType());
1097d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_TYPE, contentType);
1098d02a064168ae5c916b977182b764580e601cb084Wink Saville        } else {
1099d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException("MIME type of the part must be set.");
1100d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1101d02a064168ae5c916b977182b764580e601cb084Wink Saville
1102d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getFilename() != null) {
1103d02a064168ae5c916b977182b764580e601cb084Wink Saville            String fileName = new String(part.getFilename());
1104d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.FILENAME, fileName);
1105d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1106d02a064168ae5c916b977182b764580e601cb084Wink Saville
1107d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getName() != null) {
1108d02a064168ae5c916b977182b764580e601cb084Wink Saville            String name = new String(part.getName());
1109d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.NAME, name);
1110d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1111d02a064168ae5c916b977182b764580e601cb084Wink Saville
1112d02a064168ae5c916b977182b764580e601cb084Wink Saville        Object value = null;
1113d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentDisposition() != null) {
1114d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentDisposition());
1115d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_DISPOSITION, (String) value);
1116d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1117d02a064168ae5c916b977182b764580e601cb084Wink Saville
1118d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentId() != null) {
1119d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentId());
1120d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_ID, (String) value);
1121d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1122d02a064168ae5c916b977182b764580e601cb084Wink Saville
1123d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (part.getContentLocation() != null) {
1124d02a064168ae5c916b977182b764580e601cb084Wink Saville            value = toIsoString(part.getContentLocation());
1125d02a064168ae5c916b977182b764580e601cb084Wink Saville            values.put(Part.CONTENT_LOCATION, (String) value);
1126d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1127d02a064168ae5c916b977182b764580e601cb084Wink Saville
1128d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1129d02a064168ae5c916b977182b764580e601cb084Wink Saville
1130d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Only update the data when:
1131d02a064168ae5c916b977182b764580e601cb084Wink Saville        // 1. New binary data supplied or
1132d02a064168ae5c916b977182b764580e601cb084Wink Saville        // 2. The Uri of the part is different from the current one.
1133d02a064168ae5c916b977182b764580e601cb084Wink Saville        if ((part.getData() != null)
1134d02a064168ae5c916b977182b764580e601cb084Wink Saville                || (uri != part.getDataUri())) {
11354c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor            persistData(part, uri, contentType, preOpenedFiles);
1136d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1137d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1138d02a064168ae5c916b977182b764580e601cb084Wink Saville
1139d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1140d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Update all parts of a PDU.
1141d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
1142d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param uri The PDU which need to be updated.
1143d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param body New message body of the PDU.
11444c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
1145d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @throws MmsException Bad URI or updating failed.
1146d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
11474c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor    public void updateParts(Uri uri, PduBody body, HashMap<Uri, InputStream> preOpenedFiles)
1148d02a064168ae5c916b977182b764580e601cb084Wink Saville            throws MmsException {
1149d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
1150d02a064168ae5c916b977182b764580e601cb084Wink Saville            PduCacheEntry cacheEntry;
1151d02a064168ae5c916b977182b764580e601cb084Wink Saville            synchronized(PDU_CACHE_INSTANCE) {
1152d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1153d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (LOCAL_LOGV) {
1154d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.v(TAG, "updateParts: " + uri + " blocked by isUpdating()");
1155d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
1156d02a064168ae5c916b977182b764580e601cb084Wink Saville                    try {
1157d02a064168ae5c916b977182b764580e601cb084Wink Saville                        PDU_CACHE_INSTANCE.wait();
1158d02a064168ae5c916b977182b764580e601cb084Wink Saville                    } catch (InterruptedException e) {
1159d02a064168ae5c916b977182b764580e601cb084Wink Saville                        Log.e(TAG, "updateParts: ", e);
1160d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
1161d02a064168ae5c916b977182b764580e601cb084Wink Saville                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
1162d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (cacheEntry != null) {
1163d02a064168ae5c916b977182b764580e601cb084Wink Saville                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
1164d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
1165d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1166d02a064168ae5c916b977182b764580e601cb084Wink Saville                // Tell the cache to indicate to other callers that this item
1167d02a064168ae5c916b977182b764580e601cb084Wink Saville                // is currently being updated.
1168d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.setUpdating(uri, true);
1169d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1170d02a064168ae5c916b977182b764580e601cb084Wink Saville
1171d02a064168ae5c916b977182b764580e601cb084Wink Saville            ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
1172d02a064168ae5c916b977182b764580e601cb084Wink Saville            HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();
1173d02a064168ae5c916b977182b764580e601cb084Wink Saville
1174d02a064168ae5c916b977182b764580e601cb084Wink Saville            int partsNum = body.getPartsNum();
1175d02a064168ae5c916b977182b764580e601cb084Wink Saville            StringBuilder filter = new StringBuilder().append('(');
1176d02a064168ae5c916b977182b764580e601cb084Wink Saville            for (int i = 0; i < partsNum; i++) {
1177d02a064168ae5c916b977182b764580e601cb084Wink Saville                PduPart part = body.getPart(i);
1178d02a064168ae5c916b977182b764580e601cb084Wink Saville                Uri partUri = part.getDataUri();
1179d02a064168ae5c916b977182b764580e601cb084Wink Saville                if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
1180d02a064168ae5c916b977182b764580e601cb084Wink Saville                    toBeCreated.add(part);
1181d02a064168ae5c916b977182b764580e601cb084Wink Saville                } else {
1182d02a064168ae5c916b977182b764580e601cb084Wink Saville                    toBeUpdated.put(partUri, part);
1183d02a064168ae5c916b977182b764580e601cb084Wink Saville
1184d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // Don't use 'i > 0' to determine whether we should append
1185d02a064168ae5c916b977182b764580e601cb084Wink Saville                    // 'AND' since 'i = 0' may be skipped in another branch.
1186d02a064168ae5c916b977182b764580e601cb084Wink Saville                    if (filter.length() > 1) {
1187d02a064168ae5c916b977182b764580e601cb084Wink Saville                        filter.append(" AND ");
1188d02a064168ae5c916b977182b764580e601cb084Wink Saville                    }
1189d02a064168ae5c916b977182b764580e601cb084Wink Saville
1190d02a064168ae5c916b977182b764580e601cb084Wink Saville                    filter.append(Part._ID);
1191d02a064168ae5c916b977182b764580e601cb084Wink Saville                    filter.append("!=");
1192d02a064168ae5c916b977182b764580e601cb084Wink Saville                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
1193d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1194d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1195d02a064168ae5c916b977182b764580e601cb084Wink Saville            filter.append(')');
1196d02a064168ae5c916b977182b764580e601cb084Wink Saville
1197d02a064168ae5c916b977182b764580e601cb084Wink Saville            long msgId = ContentUris.parseId(uri);
1198d02a064168ae5c916b977182b764580e601cb084Wink Saville
1199d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Remove the parts which doesn't exist anymore.
1200d02a064168ae5c916b977182b764580e601cb084Wink Saville            SqliteWrapper.delete(mContext, mContentResolver,
1201d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
1202d02a064168ae5c916b977182b764580e601cb084Wink Saville                    filter.length() > 2 ? filter.toString() : null, null);
1203d02a064168ae5c916b977182b764580e601cb084Wink Saville
1204d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Create new parts which didn't exist before.
1205d02a064168ae5c916b977182b764580e601cb084Wink Saville            for (PduPart part : toBeCreated) {
12064c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                persistPart(part, msgId, preOpenedFiles);
1207d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1208d02a064168ae5c916b977182b764580e601cb084Wink Saville
1209d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Update the modified parts.
1210d02a064168ae5c916b977182b764580e601cb084Wink Saville            for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
12114c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                updatePart(e.getKey(), e.getValue(), preOpenedFiles);
1212d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1213d02a064168ae5c916b977182b764580e601cb084Wink Saville        } finally {
1214d02a064168ae5c916b977182b764580e601cb084Wink Saville            synchronized(PDU_CACHE_INSTANCE) {
1215d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.setUpdating(uri, false);
1216d02a064168ae5c916b977182b764580e601cb084Wink Saville                PDU_CACHE_INSTANCE.notifyAll();
1217d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1218d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1219d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1220d02a064168ae5c916b977182b764580e601cb084Wink Saville
1221d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1222d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Persist a PDU object to specific location in the storage.
1223d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
1224d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param pdu The PDU object to be stored.
1225d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param uri Where to store the given PDU object.
1226a67e3955994a976ab5fafceb86055d98a100bcc0Tom Taylor     * @param createThreadId if true, this function may create a thread id for the recipients
1227ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor     * @param groupMmsEnabled if true, all of the recipients addressed in the PDU will be used
1228ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor     *  to create the associated thread. When false, only the sender will be used in finding or
1229ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor     *  creating the appropriate thread or conversation.
12304c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
1231a67e3955994a976ab5fafceb86055d98a100bcc0Tom Taylor     * @return A Uri which can be used to access the stored PDU.
1232a67e3955994a976ab5fafceb86055d98a100bcc0Tom Taylor     */
1233a67e3955994a976ab5fafceb86055d98a100bcc0Tom Taylor
12344c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor    public Uri persist(GenericPdu pdu, Uri uri, boolean createThreadId, boolean groupMmsEnabled,
12354c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor            HashMap<Uri, InputStream> preOpenedFiles)
1236ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor            throws MmsException {
1237d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (uri == null) {
1238d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException("Uri may not be null.");
1239d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1240d02a064168ae5c916b977182b764580e601cb084Wink Saville        long msgId = -1;
1241d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
1242d02a064168ae5c916b977182b764580e601cb084Wink Saville            msgId = ContentUris.parseId(uri);
1243d02a064168ae5c916b977182b764580e601cb084Wink Saville        } catch (NumberFormatException e) {
1244d02a064168ae5c916b977182b764580e601cb084Wink Saville            // the uri ends with "inbox" or something else like that
1245d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1246d02a064168ae5c916b977182b764580e601cb084Wink Saville        boolean existingUri = msgId != -1;
1247d02a064168ae5c916b977182b764580e601cb084Wink Saville
1248d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
1249d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException(
1250d02a064168ae5c916b977182b764580e601cb084Wink Saville                    "Bad destination, must be one of "
1251d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/inbox, content://mms/sent, "
1252d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/drafts, content://mms/outbox, "
1253d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/temp.");
1254d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1255d02a064168ae5c916b977182b764580e601cb084Wink Saville        synchronized(PDU_CACHE_INSTANCE) {
1256d02a064168ae5c916b977182b764580e601cb084Wink Saville            // If the cache item is getting updated, wait until it's done updating before
1257d02a064168ae5c916b977182b764580e601cb084Wink Saville            // purging it.
1258d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1259d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (LOCAL_LOGV) {
1260d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.v(TAG, "persist: " + uri + " blocked by isUpdating()");
1261d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1262d02a064168ae5c916b977182b764580e601cb084Wink Saville                try {
1263d02a064168ae5c916b977182b764580e601cb084Wink Saville                    PDU_CACHE_INSTANCE.wait();
1264d02a064168ae5c916b977182b764580e601cb084Wink Saville                } catch (InterruptedException e) {
1265d02a064168ae5c916b977182b764580e601cb084Wink Saville                    Log.e(TAG, "persist1: ", e);
1266d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1267d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1268d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1269d02a064168ae5c916b977182b764580e601cb084Wink Saville        PDU_CACHE_INSTANCE.purge(uri);
1270d02a064168ae5c916b977182b764580e601cb084Wink Saville
1271d02a064168ae5c916b977182b764580e601cb084Wink Saville        PduHeaders header = pdu.getPduHeaders();
1272d02a064168ae5c916b977182b764580e601cb084Wink Saville        PduBody body = null;
1273d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues();
1274d02a064168ae5c916b977182b764580e601cb084Wink Saville        Set<Entry<Integer, String>> set;
1275d02a064168ae5c916b977182b764580e601cb084Wink Saville
1276d02a064168ae5c916b977182b764580e601cb084Wink Saville        set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet();
1277d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (Entry<Integer, String> e : set) {
1278d02a064168ae5c916b977182b764580e601cb084Wink Saville            int field = e.getKey();
1279d02a064168ae5c916b977182b764580e601cb084Wink Saville            EncodedStringValue encodedString = header.getEncodedStringValue(field);
1280d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (encodedString != null) {
1281d02a064168ae5c916b977182b764580e601cb084Wink Saville                String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field);
1282d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(e.getValue(), toIsoString(encodedString.getTextString()));
1283d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(charsetColumn, encodedString.getCharacterSet());
1284d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1285d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1286d02a064168ae5c916b977182b764580e601cb084Wink Saville
1287d02a064168ae5c916b977182b764580e601cb084Wink Saville        set = TEXT_STRING_COLUMN_NAME_MAP.entrySet();
1288d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (Entry<Integer, String> e : set){
1289d02a064168ae5c916b977182b764580e601cb084Wink Saville            byte[] text = header.getTextString(e.getKey());
1290d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (text != null) {
1291d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(e.getValue(), toIsoString(text));
1292d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1293d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1294d02a064168ae5c916b977182b764580e601cb084Wink Saville
1295d02a064168ae5c916b977182b764580e601cb084Wink Saville        set = OCTET_COLUMN_NAME_MAP.entrySet();
1296d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (Entry<Integer, String> e : set){
1297d02a064168ae5c916b977182b764580e601cb084Wink Saville            int b = header.getOctet(e.getKey());
1298d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (b != 0) {
1299d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(e.getValue(), b);
1300d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1301d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1302d02a064168ae5c916b977182b764580e601cb084Wink Saville
1303d02a064168ae5c916b977182b764580e601cb084Wink Saville        set = LONG_COLUMN_NAME_MAP.entrySet();
1304d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (Entry<Integer, String> e : set){
1305d02a064168ae5c916b977182b764580e601cb084Wink Saville            long l = header.getLongInteger(e.getKey());
1306d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (l != -1L) {
1307d02a064168ae5c916b977182b764580e601cb084Wink Saville                values.put(e.getValue(), l);
1308d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1309d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1310d02a064168ae5c916b977182b764580e601cb084Wink Saville
1311d02a064168ae5c916b977182b764580e601cb084Wink Saville        HashMap<Integer, EncodedStringValue[]> addressMap =
1312d02a064168ae5c916b977182b764580e601cb084Wink Saville                new HashMap<Integer, EncodedStringValue[]>(ADDRESS_FIELDS.length);
1313d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Save address information.
1314d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (int addrType : ADDRESS_FIELDS) {
1315d02a064168ae5c916b977182b764580e601cb084Wink Saville            EncodedStringValue[] array = null;
1316d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (addrType == PduHeaders.FROM) {
1317d02a064168ae5c916b977182b764580e601cb084Wink Saville                EncodedStringValue v = header.getEncodedStringValue(addrType);
1318d02a064168ae5c916b977182b764580e601cb084Wink Saville                if (v != null) {
1319d02a064168ae5c916b977182b764580e601cb084Wink Saville                    array = new EncodedStringValue[1];
1320d02a064168ae5c916b977182b764580e601cb084Wink Saville                    array[0] = v;
1321d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1322d02a064168ae5c916b977182b764580e601cb084Wink Saville            } else {
1323d02a064168ae5c916b977182b764580e601cb084Wink Saville                array = header.getEncodedStringValues(addrType);
1324d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1325d02a064168ae5c916b977182b764580e601cb084Wink Saville            addressMap.put(addrType, array);
1326d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1327d02a064168ae5c916b977182b764580e601cb084Wink Saville
1328d02a064168ae5c916b977182b764580e601cb084Wink Saville        HashSet<String> recipients = new HashSet<String>();
1329d02a064168ae5c916b977182b764580e601cb084Wink Saville        int msgType = pdu.getMessageType();
1330d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Here we only allocate thread ID for M-Notification.ind,
1331d02a064168ae5c916b977182b764580e601cb084Wink Saville        // M-Retrieve.conf and M-Send.req.
1332d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Some of other PDU types may be allocated a thread ID outside
1333d02a064168ae5c916b977182b764580e601cb084Wink Saville        // this scope.
1334d02a064168ae5c916b977182b764580e601cb084Wink Saville        if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
1335d02a064168ae5c916b977182b764580e601cb084Wink Saville                || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
1336d02a064168ae5c916b977182b764580e601cb084Wink Saville                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
1337d02a064168ae5c916b977182b764580e601cb084Wink Saville            switch (msgType) {
1338d02a064168ae5c916b977182b764580e601cb084Wink Saville                case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
1339d02a064168ae5c916b977182b764580e601cb084Wink Saville                case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
13401ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor                    loadRecipients(PduHeaders.FROM, recipients, addressMap, false);
1341e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor
1342e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // For received messages when group MMS is enabled, we want to associate this
1343e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // message with the thread composed of all the recipients -- all but our own
1344e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // number, that is. This includes the person who sent the
1345e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // message or the FROM field (above) in addition to the other people the message
1346e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // was addressed to or the TO field. Our own number is in that TO field and
1347e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor                    // we have to ignore it in loadRecipients.
1348ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor                    if (groupMmsEnabled) {
1349ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor                        loadRecipients(PduHeaders.TO, recipients, addressMap, true);
1350ab17014baf326d69a5bfd153622a1d7da6a4f9ceTom Taylor                    }
1351d02a064168ae5c916b977182b764580e601cb084Wink Saville                    break;
1352d02a064168ae5c916b977182b764580e601cb084Wink Saville                case PduHeaders.MESSAGE_TYPE_SEND_REQ:
13531ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor                    loadRecipients(PduHeaders.TO, recipients, addressMap, false);
1354d02a064168ae5c916b977182b764580e601cb084Wink Saville                    break;
1355d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
135634d50cb71769cc37fd733722ca2891bf9e364da6Tom Taylor            long threadId = 0;
1357a67e3955994a976ab5fafceb86055d98a100bcc0Tom Taylor            if (createThreadId && !recipients.isEmpty()) {
1358d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                // Given all the recipients associated with this message, find (or create) the
1359d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                // correct thread.
136034d50cb71769cc37fd733722ca2891bf9e364da6Tom Taylor                threadId = Threads.getOrCreateThreadId(mContext, recipients);
1361d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
136234d50cb71769cc37fd733722ca2891bf9e364da6Tom Taylor            values.put(Mms.THREAD_ID, threadId);
1363d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1364d02a064168ae5c916b977182b764580e601cb084Wink Saville
1365d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Save parts first to avoid inconsistent message is loaded
1366d02a064168ae5c916b977182b764580e601cb084Wink Saville        // while saving the parts.
1367d02a064168ae5c916b977182b764580e601cb084Wink Saville        long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
136823480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor
136923480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        // Figure out if this PDU is a text-only message
137023480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        boolean textOnly = true;
137123480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor
1372d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Get body if the PDU is a RetrieveConf or SendReq.
1373d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (pdu instanceof MultimediaMessagePdu) {
1374d02a064168ae5c916b977182b764580e601cb084Wink Saville            body = ((MultimediaMessagePdu) pdu).getBody();
1375d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Start saving parts if necessary.
1376d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (body != null) {
1377d02a064168ae5c916b977182b764580e601cb084Wink Saville                int partsNum = body.getPartsNum();
137823480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                if (partsNum > 2) {
137923480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // For a text-only message there will be two parts: 1-the SMIL, 2-the text.
138023480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // Down a few lines below we're checking to make sure we've only got SMIL or
138123480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // text. We also have to check then we don't have more than two parts.
138223480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // Otherwise, a slideshow with two text slides would be marked as textOnly.
138323480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    textOnly = false;
138423480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                }
1385d02a064168ae5c916b977182b764580e601cb084Wink Saville                for (int i = 0; i < partsNum; i++) {
1386d02a064168ae5c916b977182b764580e601cb084Wink Saville                    PduPart part = body.getPart(i);
13874c80e1addeee093e0b9e7ad6f918cdcda92f6c3bTom Taylor                    persistPart(part, dummyId, preOpenedFiles);
138823480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor
138923480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // If we've got anything besides text/plain or SMIL part, then we've got
139023480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    // an mms message with some other type of attachment.
139123480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    String contentType = getPartContentType(part);
139223480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    if (contentType != null && !ContentType.APP_SMIL.equals(contentType)
139323480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                            && !ContentType.TEXT_PLAIN.equals(contentType)) {
139423480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                        textOnly = false;
139523480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor                    }
1396d02a064168ae5c916b977182b764580e601cb084Wink Saville                }
1397d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1398d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
139923480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        // Record whether this mms message is a simple plain text or not. This is a hint for the
140023480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        // UI.
140123480fbe75113d2658cc5437d9b0745de17c8fafTom Taylor        values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0);
1402d02a064168ae5c916b977182b764580e601cb084Wink Saville
1403d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri res = null;
1404d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (existingUri) {
1405d02a064168ae5c916b977182b764580e601cb084Wink Saville            res = uri;
1406d02a064168ae5c916b977182b764580e601cb084Wink Saville            SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
1407d02a064168ae5c916b977182b764580e601cb084Wink Saville        } else {
1408d02a064168ae5c916b977182b764580e601cb084Wink Saville            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
1409d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (res == null) {
1410d02a064168ae5c916b977182b764580e601cb084Wink Saville                throw new MmsException("persist() failed: return null.");
1411d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1412d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Get the real ID of the PDU and update all parts which were
1413d02a064168ae5c916b977182b764580e601cb084Wink Saville            // saved with the dummy ID.
1414d02a064168ae5c916b977182b764580e601cb084Wink Saville            msgId = ContentUris.parseId(res);
1415d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1416d02a064168ae5c916b977182b764580e601cb084Wink Saville
1417d02a064168ae5c916b977182b764580e601cb084Wink Saville        values = new ContentValues(1);
1418d02a064168ae5c916b977182b764580e601cb084Wink Saville        values.put(Part.MSG_ID, msgId);
1419d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.update(mContext, mContentResolver,
1420d02a064168ae5c916b977182b764580e601cb084Wink Saville                             Uri.parse("content://mms/" + dummyId + "/part"),
1421d02a064168ae5c916b977182b764580e601cb084Wink Saville                             values, null, null);
1422d02a064168ae5c916b977182b764580e601cb084Wink Saville        // We should return the longest URI of the persisted PDU, for
1423d02a064168ae5c916b977182b764580e601cb084Wink Saville        // example, if input URI is "content://mms/inbox" and the _ID of
1424d02a064168ae5c916b977182b764580e601cb084Wink Saville        // persisted PDU is '8', we should return "content://mms/inbox/8"
1425d02a064168ae5c916b977182b764580e601cb084Wink Saville        // instead of "content://mms/8".
1426d02a064168ae5c916b977182b764580e601cb084Wink Saville        // FIXME: Should the MmsProvider be responsible for this???
1427d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (!existingUri) {
1428d02a064168ae5c916b977182b764580e601cb084Wink Saville            res = Uri.parse(uri + "/" + msgId);
1429d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1430d02a064168ae5c916b977182b764580e601cb084Wink Saville
1431d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Save address information.
1432d02a064168ae5c916b977182b764580e601cb084Wink Saville        for (int addrType : ADDRESS_FIELDS) {
1433d02a064168ae5c916b977182b764580e601cb084Wink Saville            EncodedStringValue[] array = addressMap.get(addrType);
1434d02a064168ae5c916b977182b764580e601cb084Wink Saville            if (array != null) {
1435d02a064168ae5c916b977182b764580e601cb084Wink Saville                persistAddress(msgId, addrType, array);
1436d02a064168ae5c916b977182b764580e601cb084Wink Saville            }
1437d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1438d02a064168ae5c916b977182b764580e601cb084Wink Saville
1439d02a064168ae5c916b977182b764580e601cb084Wink Saville        return res;
1440d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1441d02a064168ae5c916b977182b764580e601cb084Wink Saville
1442d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1443d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     * For a given address type, extract the recipients from the headers.
1444d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     *
1445d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     * @param addressType can be PduHeaders.FROM or PduHeaders.TO
1446d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     * @param recipients a HashSet that is loaded with the recipients from the FROM or TO headers
1447d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     * @param addressMap a HashMap of the addresses from the ADDRESS_FIELDS header
14481ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor     * @param excludeMyNumber if true, the number of this phone will be excluded from recipients
1449d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor     */
1450d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor    private void loadRecipients(int addressType, HashSet<String> recipients,
14511ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor            HashMap<Integer, EncodedStringValue[]> addressMap, boolean excludeMyNumber) {
1452d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor        EncodedStringValue[] array = addressMap.get(addressType);
14531ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor        if (array == null) {
14541ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor            return;
14551ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor        }
1456e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor        // If the TO recipients is only a single address, then we can skip loadRecipients when
1457e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor        // we're excluding our own number because we know that address is our own.
1458e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor        if (excludeMyNumber && array.length == 1) {
1459e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor            return;
1460e1f17ce8cd1f968b1273938a05ef9237862827d4Tom Taylor        }
14611ed1a2641e07daf80d7a9dda693b4384ad8d0b37Tom Taylor        String myNumber = excludeMyNumber ? mTelephonyManager.getLine1Number() : null;
1462d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor        for (EncodedStringValue v : array) {
1463d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor            if (v != null) {
1464d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                String number = v.getString();
1465d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                if ((myNumber == null || !PhoneNumberUtils.compare(number, myNumber)) &&
1466d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                        !recipients.contains(number)) {
1467d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                    // Only add numbers which aren't my own number.
1468d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                    recipients.add(number);
1469d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor                }
1470d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor            }
1471d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor        }
1472d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor    }
1473d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor
1474d02b0b273f4915d1873bbb5472492380451b84ffTom Taylor    /**
1475d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Move a PDU object from one location to another.
1476d02a064168ae5c916b977182b764580e601cb084Wink Saville     *
1477d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param from Specify the PDU object to be moved.
1478d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @param to The destination location, should be one of the following:
1479d02a064168ae5c916b977182b764580e601cb084Wink Saville     *        "content://mms/inbox", "content://mms/sent",
1480d02a064168ae5c916b977182b764580e601cb084Wink Saville     *        "content://mms/drafts", "content://mms/outbox",
1481d02a064168ae5c916b977182b764580e601cb084Wink Saville     *        "content://mms/trash".
1482d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @return New Uri of the moved PDU.
1483d02a064168ae5c916b977182b764580e601cb084Wink Saville     * @throws MmsException Error occurred while moving the message.
1484d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
1485d02a064168ae5c916b977182b764580e601cb084Wink Saville    public Uri move(Uri from, Uri to) throws MmsException {
1486d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Check whether the 'msgId' has been assigned a valid value.
1487d02a064168ae5c916b977182b764580e601cb084Wink Saville        long msgId = ContentUris.parseId(from);
1488d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (msgId == -1L) {
1489d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException("Error! ID of the message: -1.");
1490d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1491d02a064168ae5c916b977182b764580e601cb084Wink Saville
1492d02a064168ae5c916b977182b764580e601cb084Wink Saville        // Get corresponding int value of destination box.
1493d02a064168ae5c916b977182b764580e601cb084Wink Saville        Integer msgBox = MESSAGE_BOX_MAP.get(to);
1494d02a064168ae5c916b977182b764580e601cb084Wink Saville        if (msgBox == null) {
1495d02a064168ae5c916b977182b764580e601cb084Wink Saville            throw new MmsException(
1496d02a064168ae5c916b977182b764580e601cb084Wink Saville                    "Bad destination, must be one of "
1497d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/inbox, content://mms/sent, "
1498d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/drafts, content://mms/outbox, "
1499d02a064168ae5c916b977182b764580e601cb084Wink Saville                    + "content://mms/temp.");
1500d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1501d02a064168ae5c916b977182b764580e601cb084Wink Saville
1502d02a064168ae5c916b977182b764580e601cb084Wink Saville        ContentValues values = new ContentValues(1);
1503d02a064168ae5c916b977182b764580e601cb084Wink Saville        values.put(Mms.MESSAGE_BOX, msgBox);
1504d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.update(mContext, mContentResolver, from, values, null, null);
1505d02a064168ae5c916b977182b764580e601cb084Wink Saville        return ContentUris.withAppendedId(to, msgId);
1506d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1507d02a064168ae5c916b977182b764580e601cb084Wink Saville
1508d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1509d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Wrap a byte[] into a String.
1510d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
1511d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static String toIsoString(byte[] bytes) {
1512d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
1513d02a064168ae5c916b977182b764580e601cb084Wink Saville            return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
1514d02a064168ae5c916b977182b764580e601cb084Wink Saville        } catch (UnsupportedEncodingException e) {
1515d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Impossible to reach here!
1516d02a064168ae5c916b977182b764580e601cb084Wink Saville            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1517d02a064168ae5c916b977182b764580e601cb084Wink Saville            return "";
1518d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1519d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1520d02a064168ae5c916b977182b764580e601cb084Wink Saville
1521d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1522d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Unpack a given String into a byte[].
1523d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
1524d02a064168ae5c916b977182b764580e601cb084Wink Saville    public static byte[] getBytes(String data) {
1525d02a064168ae5c916b977182b764580e601cb084Wink Saville        try {
1526d02a064168ae5c916b977182b764580e601cb084Wink Saville            return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
1527d02a064168ae5c916b977182b764580e601cb084Wink Saville        } catch (UnsupportedEncodingException e) {
1528d02a064168ae5c916b977182b764580e601cb084Wink Saville            // Impossible to reach here!
1529d02a064168ae5c916b977182b764580e601cb084Wink Saville            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1530d02a064168ae5c916b977182b764580e601cb084Wink Saville            return new byte[0];
1531d02a064168ae5c916b977182b764580e601cb084Wink Saville        }
1532d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1533d02a064168ae5c916b977182b764580e601cb084Wink Saville
1534d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1535d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Remove all objects in the temporary path.
1536d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
1537d02a064168ae5c916b977182b764580e601cb084Wink Saville    public void release() {
1538d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri uri = Uri.parse(TEMPORARY_DRM_OBJECT_URI);
1539d02a064168ae5c916b977182b764580e601cb084Wink Saville        SqliteWrapper.delete(mContext, mContentResolver, uri, null, null);
1540d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1541d02a064168ae5c916b977182b764580e601cb084Wink Saville
1542d02a064168ae5c916b977182b764580e601cb084Wink Saville    /**
1543d02a064168ae5c916b977182b764580e601cb084Wink Saville     * Find all messages to be sent or downloaded before certain time.
1544d02a064168ae5c916b977182b764580e601cb084Wink Saville     */
1545d02a064168ae5c916b977182b764580e601cb084Wink Saville    public Cursor getPendingMessages(long dueTime) {
1546d02a064168ae5c916b977182b764580e601cb084Wink Saville        Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon();
1547d02a064168ae5c916b977182b764580e601cb084Wink Saville        uriBuilder.appendQueryParameter("protocol", "mms");
1548d02a064168ae5c916b977182b764580e601cb084Wink Saville
1549d02a064168ae5c916b977182b764580e601cb084Wink Saville        String selection = PendingMessages.ERROR_TYPE + " < ?"
1550d02a064168ae5c916b977182b764580e601cb084Wink Saville                + " AND " + PendingMessages.DUE_TIME + " <= ?";
1551d02a064168ae5c916b977182b764580e601cb084Wink Saville
1552d02a064168ae5c916b977182b764580e601cb084Wink Saville        String[] selectionArgs = new String[] {
1553d02a064168ae5c916b977182b764580e601cb084Wink Saville                String.valueOf(MmsSms.ERR_TYPE_GENERIC_PERMANENT),
1554d02a064168ae5c916b977182b764580e601cb084Wink Saville                String.valueOf(dueTime)
1555d02a064168ae5c916b977182b764580e601cb084Wink Saville        };
1556d02a064168ae5c916b977182b764580e601cb084Wink Saville
1557d02a064168ae5c916b977182b764580e601cb084Wink Saville        return SqliteWrapper.query(mContext, mContentResolver,
1558d02a064168ae5c916b977182b764580e601cb084Wink Saville                uriBuilder.build(), null, selection, selectionArgs,
1559d02a064168ae5c916b977182b764580e601cb084Wink Saville                PendingMessages.DUE_TIME);
1560d02a064168ae5c916b977182b764580e601cb084Wink Saville    }
1561d02a064168ae5c916b977182b764580e601cb084Wink Saville}
1562