2012-09-08 03:03:23 +00:00
|
|
|
/**
|
2011-12-20 18:20:44 +00:00
|
|
|
* Copyright (C) 2011 Whisper Systems
|
2012-09-08 03:03:23 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2012-09-08 03:03:23 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package org.thoughtcrime.securesms.database;
|
|
|
|
|
2012-09-08 03:03:23 +00:00
|
|
|
import android.content.ContentValues;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
|
|
import android.net.Uri;
|
2015-03-27 17:26:17 +00:00
|
|
|
import android.support.annotation.NonNull;
|
2014-03-07 21:05:35 +00:00
|
|
|
import android.telephony.TelephonyManager;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.text.TextUtils;
|
2012-09-08 03:03:23 +00:00
|
|
|
import android.util.Log;
|
2013-04-26 18:23:43 +00:00
|
|
|
import android.util.Pair;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2014-03-07 21:05:35 +00:00
|
|
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
|
|
|
2014-11-25 06:50:32 +00:00
|
|
|
import org.thoughtcrime.securesms.ApplicationContext;
|
2012-09-08 03:03:23 +00:00
|
|
|
import org.thoughtcrime.securesms.R;
|
2015-07-07 00:36:49 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2015-07-07 00:36:49 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
2015-01-15 21:35:35 +00:00
|
|
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
|
|
|
import org.thoughtcrime.securesms.database.documents.NetworkFailureList;
|
|
|
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
|
|
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchList;
|
2013-04-30 18:14:01 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
|
|
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|
|
|
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
2014-11-25 06:50:32 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
2013-07-19 00:42:45 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
|
|
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
2013-04-26 18:23:43 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.PartParser;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
2013-05-05 19:51:36 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.TextSlide;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
2011-12-20 18:20:44 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
|
|
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
2015-01-15 21:35:35 +00:00
|
|
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
2013-05-06 19:22:03 +00:00
|
|
|
import org.thoughtcrime.securesms.util.LRUCache;
|
2014-11-12 17:20:57 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2014-11-25 06:50:32 +00:00
|
|
|
import org.whispersystems.jobqueue.JobManager;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.whispersystems.libaxolotl.InvalidMessageException;
|
|
|
|
import org.whispersystems.libaxolotl.util.guava.Optional;
|
|
|
|
import org.whispersystems.textsecure.api.util.InvalidNumberException;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
import java.io.IOException;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2013-05-06 19:22:03 +00:00
|
|
|
import java.lang.ref.SoftReference;
|
|
|
|
import java.util.Collections;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import java.util.HashSet;
|
2015-01-15 21:35:35 +00:00
|
|
|
import java.util.LinkedList;
|
2013-09-09 01:19:05 +00:00
|
|
|
import java.util.List;
|
2013-05-06 19:22:03 +00:00
|
|
|
import java.util.Map;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import java.util.Set;
|
2013-04-26 18:23:43 +00:00
|
|
|
import java.util.concurrent.Callable;
|
|
|
|
import java.util.concurrent.ExecutorService;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2014-02-20 05:06:54 +00:00
|
|
|
import ws.com.google.android.mms.ContentType;
|
2011-12-20 18:20:44 +00:00
|
|
|
import ws.com.google.android.mms.InvalidHeaderValueException;
|
|
|
|
import ws.com.google.android.mms.MmsException;
|
|
|
|
import ws.com.google.android.mms.pdu.CharacterSets;
|
|
|
|
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
|
|
|
import ws.com.google.android.mms.pdu.NotificationInd;
|
|
|
|
import ws.com.google.android.mms.pdu.PduBody;
|
|
|
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
2013-09-09 01:19:05 +00:00
|
|
|
import ws.com.google.android.mms.pdu.PduPart;
|
2011-12-20 18:20:44 +00:00
|
|
|
import ws.com.google.android.mms.pdu.SendReq;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-10-21 04:06:34 +00:00
|
|
|
import static org.thoughtcrime.securesms.util.Util.canonicalizeNumber;
|
|
|
|
import static org.thoughtcrime.securesms.util.Util.canonicalizeNumberOrGroup;
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
// XXXX Clean up MMS efficiency:
|
|
|
|
// 1) We need to be careful about how much memory we're using for parts. SoftRefereences.
|
|
|
|
// 2) How many queries do we make? calling getMediaMessageForId() from within an existing query
|
|
|
|
// seems wasteful.
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
public class MmsDatabase extends MessagingDatabase {
|
|
|
|
|
|
|
|
private static final String TAG = MmsDatabase.class.getSimpleName();
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public static final String TABLE_NAME = "mms";
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
static final String DATE_SENT = "date";
|
|
|
|
static final String DATE_RECEIVED = "date_received";
|
2011-12-20 18:20:44 +00:00
|
|
|
public static final String MESSAGE_BOX = "msg_box";
|
|
|
|
private static final String MESSAGE_ID = "m_id";
|
|
|
|
private static final String SUBJECT = "sub";
|
|
|
|
private static final String SUBJECT_CHARSET = "sub_cs";
|
2013-05-05 19:51:36 +00:00
|
|
|
static final String CONTENT_TYPE = "ct_t";
|
|
|
|
static final String CONTENT_LOCATION = "ct_l";
|
|
|
|
static final String EXPIRY = "exp";
|
2011-12-20 18:20:44 +00:00
|
|
|
private static final String MESSAGE_CLASS = "m_cls";
|
|
|
|
public static final String MESSAGE_TYPE = "m_type";
|
|
|
|
private static final String MMS_VERSION = "v";
|
2013-05-05 19:51:36 +00:00
|
|
|
static final String MESSAGE_SIZE = "m_size";
|
2011-12-20 18:20:44 +00:00
|
|
|
private static final String PRIORITY = "pri";
|
|
|
|
private static final String READ_REPORT = "rr";
|
|
|
|
private static final String REPORT_ALLOWED = "rpt_a";
|
|
|
|
private static final String RESPONSE_STATUS = "resp_st";
|
2013-05-05 19:51:36 +00:00
|
|
|
static final String STATUS = "st";
|
|
|
|
static final String TRANSACTION_ID = "tr_id";
|
2011-12-20 18:20:44 +00:00
|
|
|
private static final String RETRIEVE_STATUS = "retr_st";
|
|
|
|
private static final String RETRIEVE_TEXT = "retr_txt";
|
|
|
|
private static final String RETRIEVE_TEXT_CS = "retr_txt_cs";
|
|
|
|
private static final String READ_STATUS = "read_status";
|
|
|
|
private static final String CONTENT_CLASS = "ct_cls";
|
|
|
|
private static final String RESPONSE_TEXT = "resp_txt";
|
|
|
|
private static final String DELIVERY_TIME = "d_tm";
|
|
|
|
private static final String DELIVERY_REPORT = "d_rpt";
|
2013-04-26 18:23:43 +00:00
|
|
|
static final String PART_COUNT = "part_count";
|
2015-01-15 21:35:35 +00:00
|
|
|
static final String NETWORK_FAILURE = "network_failures";
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
2013-01-07 02:47:20 +00:00
|
|
|
THREAD_ID + " INTEGER, " + DATE_SENT + " INTEGER, " + DATE_RECEIVED + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
|
2011-12-20 18:20:44 +00:00
|
|
|
READ + " INTEGER DEFAULT 0, " + MESSAGE_ID + " TEXT, " + SUBJECT + " TEXT, " +
|
2013-04-26 18:23:43 +00:00
|
|
|
SUBJECT_CHARSET + " INTEGER, " + BODY + " TEXT, " + PART_COUNT + " INTEGER, " +
|
2013-05-05 19:51:36 +00:00
|
|
|
CONTENT_TYPE + " TEXT, " + CONTENT_LOCATION + " TEXT, " + ADDRESS + " TEXT, " +
|
2014-02-03 03:38:06 +00:00
|
|
|
ADDRESS_DEVICE_ID + " INTEGER, " +
|
2011-12-20 18:20:44 +00:00
|
|
|
EXPIRY + " INTEGER, " + MESSAGE_CLASS + " TEXT, " + MESSAGE_TYPE + " INTEGER, " +
|
|
|
|
MMS_VERSION + " INTEGER, " + MESSAGE_SIZE + " INTEGER, " + PRIORITY + " INTEGER, " +
|
|
|
|
READ_REPORT + " INTEGER, " + REPORT_ALLOWED + " INTEGER, " + RESPONSE_STATUS + " INTEGER, " +
|
|
|
|
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + RETRIEVE_STATUS + " INTEGER, " +
|
2012-09-08 03:03:23 +00:00
|
|
|
RETRIEVE_TEXT + " TEXT, " + RETRIEVE_TEXT_CS + " INTEGER, " + READ_STATUS + " INTEGER, " +
|
2011-12-20 18:20:44 +00:00
|
|
|
CONTENT_CLASS + " INTEGER, " + RESPONSE_TEXT + " TEXT, " + DELIVERY_TIME + " INTEGER, " +
|
2015-01-15 21:35:35 +00:00
|
|
|
RECEIPT_COUNT + " INTEGER DEFAULT 0, " + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
|
|
|
NETWORK_FAILURE + " TEXT DEFAULT NULL," + DELIVERY_REPORT + " INTEGER);";
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2012-10-30 00:41:06 +00:00
|
|
|
public static final String[] CREATE_INDEXS = {
|
|
|
|
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
|
|
|
"CREATE INDEX IF NOT EXISTS mms_read_index ON " + TABLE_NAME + " (" + READ + ");",
|
|
|
|
"CREATE INDEX IF NOT EXISTS mms_read_and_thread_id_index ON " + TABLE_NAME + "(" + READ + "," + THREAD_ID + ");",
|
2014-07-25 22:14:29 +00:00
|
|
|
"CREATE INDEX IF NOT EXISTS mms_message_box_index ON " + TABLE_NAME + " (" + MESSAGE_BOX + ");",
|
2015-08-04 20:37:22 +00:00
|
|
|
"CREATE INDEX IF NOT EXISTS mms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ");",
|
|
|
|
"CREATE INDEX IF NOT EXISTS mms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");"
|
2012-10-30 00:41:06 +00:00
|
|
|
};
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
private static final String[] MMS_PROJECTION = new String[] {
|
2015-08-04 20:37:22 +00:00
|
|
|
ID, THREAD_ID, DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
|
|
|
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
MESSAGE_BOX, READ, MESSAGE_ID, SUBJECT, SUBJECT_CHARSET, CONTENT_TYPE,
|
|
|
|
CONTENT_LOCATION, EXPIRY, MESSAGE_CLASS, MESSAGE_TYPE, MMS_VERSION,
|
|
|
|
MESSAGE_SIZE, PRIORITY, REPORT_ALLOWED, STATUS, TRANSACTION_ID, RETRIEVE_STATUS,
|
|
|
|
RETRIEVE_TEXT, RETRIEVE_TEXT_CS, READ_STATUS, CONTENT_CLASS, RESPONSE_TEXT,
|
2014-02-17 19:42:51 +00:00
|
|
|
DELIVERY_TIME, DELIVERY_REPORT, BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
|
2015-01-15 21:35:35 +00:00
|
|
|
RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
};
|
|
|
|
|
2013-07-10 02:48:33 +00:00
|
|
|
public static final ExecutorService slideResolver = org.thoughtcrime.securesms.util.Util.newSingleThreadedLifoExecutor();
|
2015-05-18 15:16:06 +00:00
|
|
|
private static final Map<String, SoftReference<SlideDeck>> slideCache =
|
|
|
|
Collections.synchronizedMap(new LRUCache<String, SoftReference<SlideDeck>>(20));
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2014-11-25 06:50:32 +00:00
|
|
|
private final JobManager jobManager;
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
|
|
|
super(context, databaseHelper);
|
2014-11-25 06:50:32 +00:00
|
|
|
this.jobManager = ApplicationContext.getInstance(context).getJobManager();
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
@Override
|
|
|
|
protected String getTableName() {
|
|
|
|
return TABLE_NAME;
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public int getMessageCountForThread(long threadId) {
|
2012-09-08 03:03:23 +00:00
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
2011-12-20 18:20:44 +00:00
|
|
|
Cursor cursor = null;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
try {
|
|
|
|
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, THREAD_ID + " = ?", new String[] {threadId+""}, null, null, null);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
if (cursor != null && cursor.moveToFirst())
|
|
|
|
return cursor.getInt(0);
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
public void addFailures(long messageId, List<NetworkFailure> failure) {
|
|
|
|
try {
|
|
|
|
addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList.class);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeFailure(long messageId, NetworkFailure failure) {
|
|
|
|
try {
|
|
|
|
removeFromDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList.class);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-25 22:14:29 +00:00
|
|
|
public void incrementDeliveryReceiptCount(String address, long timestamp) {
|
|
|
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
try {
|
2015-08-04 20:37:22 +00:00
|
|
|
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX}, DATE_SENT + " = ?", new String[] {String.valueOf(timestamp)}, null, null, null, null);
|
2014-07-25 22:14:29 +00:00
|
|
|
|
|
|
|
while (cursor.moveToNext()) {
|
2014-10-21 04:06:34 +00:00
|
|
|
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
|
|
|
List<String> addresses = addressDatabase.getAddressesForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
|
|
|
|
|
|
|
for (String storedAddress : addresses) {
|
|
|
|
try {
|
|
|
|
String ourAddress = canonicalizeNumber(context, address);
|
|
|
|
String theirAddress = canonicalizeNumberOrGroup(context, storedAddress);
|
|
|
|
|
|
|
|
if (ourAddress.equals(theirAddress) || GroupUtil.isEncodedGroup(theirAddress)) {
|
|
|
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
|
|
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
|
|
|
|
|
|
|
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
|
|
|
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
|
|
|
new String[] {String.valueOf(id)});
|
|
|
|
|
|
|
|
notifyConversationListeners(threadId);
|
|
|
|
}
|
|
|
|
} catch (InvalidNumberException e) {
|
|
|
|
Log.w("MmsDatabase", e);
|
2014-07-25 22:14:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public long getThreadIdForMessage(long id) {
|
|
|
|
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
|
|
|
|
String[] sqlArgs = new String[] {id+""};
|
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
Cursor cursor = null;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
try {
|
|
|
|
cursor = db.rawQuery(sql, sqlArgs);
|
|
|
|
if (cursor != null && cursor.moveToFirst())
|
|
|
|
return cursor.getLong(0);
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-02-16 05:53:59 +00:00
|
|
|
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
2014-01-14 08:26:43 +00:00
|
|
|
if (retrieved.getGroupId() != null) {
|
2014-02-14 23:59:57 +00:00
|
|
|
Recipients groupRecipients = RecipientFactory.getRecipientsFromString(context, retrieved.getGroupId(), true);
|
|
|
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
2014-01-14 08:26:43 +00:00
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
try {
|
2013-07-19 00:42:45 +00:00
|
|
|
PduHeaders headers = retrieved.getPduHeaders();
|
2013-04-26 01:59:49 +00:00
|
|
|
Set<String> group = new HashSet<String>();
|
|
|
|
|
2014-01-14 08:26:43 +00:00
|
|
|
EncodedStringValue encodedFrom = headers.getEncodedStringValue(PduHeaders.FROM);
|
|
|
|
EncodedStringValue[] encodedCcList = headers.getEncodedStringValues(PduHeaders.CC);
|
|
|
|
EncodedStringValue[] encodedToList = headers.getEncodedStringValues(PduHeaders.TO);
|
|
|
|
|
2015-02-16 05:53:59 +00:00
|
|
|
if (encodedFrom == null) {
|
|
|
|
throw new MmsException("FROM value in PduHeaders did not exist.");
|
|
|
|
}
|
|
|
|
|
2013-04-26 01:59:49 +00:00
|
|
|
group.add(new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
|
|
|
|
2014-03-13 00:45:21 +00:00
|
|
|
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
|
|
|
String localNumber = telephonyManager.getLine1Number();
|
|
|
|
|
|
|
|
if (localNumber == null) {
|
|
|
|
localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
|
|
}
|
|
|
|
|
2013-04-26 01:59:49 +00:00
|
|
|
if (encodedCcList != null) {
|
|
|
|
for (EncodedStringValue encodedCc : encodedCcList) {
|
2014-03-13 00:45:21 +00:00
|
|
|
String cc = new String(encodedCc.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
2013-04-26 01:59:49 +00:00
|
|
|
|
2014-03-13 00:45:21 +00:00
|
|
|
PhoneNumberUtil.MatchType match;
|
2014-01-14 08:26:43 +00:00
|
|
|
|
2014-03-13 00:45:21 +00:00
|
|
|
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
|
|
|
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, cc);
|
|
|
|
|
|
|
|
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
|
|
|
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
|
|
|
{
|
|
|
|
group.add(cc);
|
|
|
|
}
|
2014-02-21 01:32:01 +00:00
|
|
|
}
|
2014-03-13 00:45:21 +00:00
|
|
|
}
|
2014-02-21 01:32:01 +00:00
|
|
|
|
2014-03-13 00:45:21 +00:00
|
|
|
if (encodedToList != null && (encodedToList.length > 1 || group.size() > 1)) {
|
2014-01-14 08:26:43 +00:00
|
|
|
for (EncodedStringValue encodedTo : encodedToList) {
|
|
|
|
String to = new String(encodedTo.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
|
|
|
|
2014-03-07 21:05:35 +00:00
|
|
|
PhoneNumberUtil.MatchType match;
|
|
|
|
|
|
|
|
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
|
|
|
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, to);
|
|
|
|
|
|
|
|
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
|
|
|
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
|
|
|
{
|
2014-01-14 08:26:43 +00:00
|
|
|
group.add(to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
String recipientsList = Util.join(group, ",");
|
|
|
|
Recipients recipients = RecipientFactory.getRecipientsFromString(context, recipientsList, false);
|
2013-04-26 01:59:49 +00:00
|
|
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-27 17:26:17 +00:00
|
|
|
private long getThreadIdFor(@NonNull NotificationInd notification) {
|
|
|
|
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
|
|
|
|
? Util.toIsoString(notification.getFrom().getTextString())
|
|
|
|
: "";
|
|
|
|
Recipients recipients = RecipientFactory.getRecipientsFromString(context, fromString, false);
|
2015-06-23 17:15:33 +00:00
|
|
|
if (recipients.isEmpty()) recipients = RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), false);
|
2015-03-27 17:26:17 +00:00
|
|
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
public Cursor getMessage(long messageId) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
|
|
Cursor cursor = db.query(TABLE_NAME, MMS_PROJECTION, ID_WHERE, new String[] {messageId+""},
|
|
|
|
null, null, null);
|
|
|
|
setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId));
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
public Reader getDecryptInProgressMessages(MasterSecret masterSecret) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
|
|
String where = MESSAGE_BOX + " & " + (Types.ENCRYPTION_ASYMMETRIC_BIT) + " != 0";
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
return readerFor(masterSecret, db.query(TABLE_NAME, MMS_PROJECTION, where, null, null, null, null));
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
private void updateMailboxBitmask(long id, long maskOff, long maskOn) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
db.execSQL("UPDATE " + TABLE_NAME +
|
2015-01-15 21:35:35 +00:00
|
|
|
" SET " + MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
|
|
|
|
" WHERE " + ID + " = ?", new String[] {id + ""});
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-02-16 02:31:25 +00:00
|
|
|
public void markAsOutbox(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_OUTBOX_TYPE);
|
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
2014-03-01 22:17:55 +00:00
|
|
|
}
|
|
|
|
|
2014-04-03 23:20:23 +00:00
|
|
|
public void markAsForcedSms(long messageId) {
|
2015-06-03 22:51:27 +00:00
|
|
|
updateMailboxBitmask(messageId, Types.PUSH_MESSAGE_BIT, Types.MESSAGE_FORCE_SMS_BIT);
|
2014-04-03 23:20:23 +00:00
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
2014-03-01 22:17:55 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 01:47:24 +00:00
|
|
|
public void markAsPendingInsecureSmsFallback(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_PENDING_INSECURE_SMS_FALLBACK);
|
2014-03-01 22:17:55 +00:00
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
2014-02-16 02:31:25 +00:00
|
|
|
}
|
|
|
|
|
2013-10-13 10:53:41 +00:00
|
|
|
public void markAsSending(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE);
|
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public void markAsSentFailed(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENT_FAILED_TYPE);
|
2011-12-20 18:20:44 +00:00
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
|
|
|
}
|
2013-07-17 02:52:02 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public void markAsSent(long messageId, byte[] mmsId, long status) {
|
2011-12-20 18:20:44 +00:00
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
ContentValues contentValues = new ContentValues();
|
|
|
|
contentValues.put(RESPONSE_STATUS, status);
|
|
|
|
contentValues.put(MESSAGE_ID, new String(mmsId));
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENT_TYPE);
|
2012-09-08 03:03:23 +00:00
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void markDownloadState(long messageId, long state) {
|
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
ContentValues contentValues = new ContentValues();
|
|
|
|
contentValues.put(STATUS, state);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-04-30 18:14:01 +00:00
|
|
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""});
|
2012-09-08 03:03:23 +00:00
|
|
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void markAsNoSession(long messageId, long threadId) {
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
|
2012-09-08 03:03:23 +00:00
|
|
|
notifyConversationListeners(threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-11-19 18:13:24 +00:00
|
|
|
public void markAsSecure(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, 0, Types.SECURE_MESSAGE_BIT);
|
|
|
|
}
|
|
|
|
|
2014-04-01 01:47:24 +00:00
|
|
|
public void markAsInsecure(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.SECURE_MESSAGE_BIT, 0);
|
|
|
|
}
|
|
|
|
|
2014-02-21 07:00:38 +00:00
|
|
|
public void markAsPush(long messageId) {
|
|
|
|
updateMailboxBitmask(messageId, 0, Types.PUSH_MESSAGE_BIT);
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void markAsDecryptFailed(long messageId, long threadId) {
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
2012-09-08 03:03:23 +00:00
|
|
|
notifyConversationListeners(threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-03-19 19:37:46 +00:00
|
|
|
public void markAsDecryptDuplicate(long messageId, long threadId) {
|
|
|
|
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_DUPLICATE_BIT);
|
|
|
|
notifyConversationListeners(threadId);
|
|
|
|
}
|
|
|
|
|
2014-04-10 03:02:46 +00:00
|
|
|
public void markAsLegacyVersion(long messageId, long threadId) {
|
2014-04-10 22:20:43 +00:00
|
|
|
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT);
|
2014-04-10 03:02:46 +00:00
|
|
|
notifyConversationListeners(threadId);
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void setMessagesRead(long threadId) {
|
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
ContentValues contentValues = new ContentValues();
|
|
|
|
contentValues.put(READ, 1);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId + ""});
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 20:59:40 +00:00
|
|
|
public void setAllMessagesRead() {
|
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
ContentValues contentValues = new ContentValues();
|
|
|
|
contentValues.put(READ, 1);
|
|
|
|
|
|
|
|
database.update(TABLE_NAME, contentValues, null, null);
|
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
public void updateMessageBody(MasterSecretUnion masterSecret, long messageId, String body) {
|
|
|
|
body = getEncryptedBody(masterSecret, body);
|
|
|
|
|
|
|
|
long type;
|
|
|
|
|
|
|
|
if (masterSecret.getMasterSecret().isPresent()) {
|
|
|
|
type = Types.ENCRYPTION_SYMMETRIC_BIT;
|
|
|
|
} else {
|
|
|
|
type = Types.ENCRYPTION_ASYMMETRIC_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateMessageBodyAndType(messageId, body, Types.ENCRYPTION_MASK, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
private Pair<Long, Long> updateMessageBodyAndType(long messageId, String body, long maskOff, long maskOn) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
db.execSQL("UPDATE " + TABLE_NAME + " SET " + BODY + " = ?, " +
|
|
|
|
MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + ") " +
|
|
|
|
"WHERE " + ID + " = ?",
|
|
|
|
new String[] {body, messageId + ""});
|
|
|
|
|
|
|
|
long threadId = getThreadIdForMessage(messageId);
|
|
|
|
|
|
|
|
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
|
|
|
notifyConversationListeners(threadId);
|
|
|
|
notifyConversationListListeners();
|
|
|
|
|
|
|
|
return new Pair<>(messageId, threadId);
|
|
|
|
}
|
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
public Optional<NotificationInd> getNotification(long messageId) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
|
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
|
|
|
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
cursor = db.query(TABLE_NAME, MMS_PROJECTION, ID_WHERE, new String[] {String.valueOf(messageId)}, null, null, null);
|
|
|
|
|
|
|
|
if (cursor != null && cursor.moveToNext()) {
|
|
|
|
PduHeaders headers = getHeadersFromCursor(cursor);
|
|
|
|
addressDatabase.getAddressesForId(messageId, headers);
|
|
|
|
|
|
|
|
return Optional.of(new NotificationInd(headers));
|
|
|
|
} else {
|
|
|
|
return Optional.absent();
|
|
|
|
}
|
|
|
|
} catch (InvalidHeaderValueException e) {
|
|
|
|
Log.w("MmsDatabase", e);
|
|
|
|
return Optional.absent();
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-08 19:35:58 +00:00
|
|
|
public SendReq getOutgoingMessage(MasterSecret masterSecret, long messageId)
|
|
|
|
throws MmsException, NoSuchMessageException
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
{
|
2013-09-09 01:19:05 +00:00
|
|
|
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
2014-12-12 09:03:24 +00:00
|
|
|
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
|
2013-09-09 01:19:05 +00:00
|
|
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
2014-11-08 19:35:58 +00:00
|
|
|
MasterCipher masterCipher = new MasterCipher(masterSecret);
|
2013-09-09 01:19:05 +00:00
|
|
|
Cursor cursor = null;
|
2013-05-05 19:51:36 +00:00
|
|
|
|
2014-11-08 19:35:58 +00:00
|
|
|
String selection = ID_WHERE;
|
|
|
|
String[] selectionArgs = new String[]{String.valueOf(messageId)};
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
try {
|
2013-05-05 19:51:36 +00:00
|
|
|
cursor = database.query(TABLE_NAME, MMS_PROJECTION, selection, selectionArgs, null, null, null);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-11-08 19:35:58 +00:00
|
|
|
if (cursor != null && cursor.moveToNext()) {
|
2014-02-20 05:06:54 +00:00
|
|
|
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
|
|
|
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
2014-07-25 22:14:29 +00:00
|
|
|
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
2014-02-20 05:06:54 +00:00
|
|
|
PduHeaders headers = getHeadersFromCursor(cursor);
|
2012-10-01 02:56:29 +00:00
|
|
|
addr.getAddressesForId(messageId, headers);
|
2013-05-05 19:51:36 +00:00
|
|
|
|
2014-12-12 09:03:24 +00:00
|
|
|
PduBody body = getPartsAsBody(partDatabase.getParts(messageId));
|
2013-05-05 19:51:36 +00:00
|
|
|
|
|
|
|
try {
|
2014-11-12 19:15:05 +00:00
|
|
|
if (!TextUtils.isEmpty(messageText) && Types.isSymmetricEncryption(outboxType)) {
|
2013-05-05 19:51:36 +00:00
|
|
|
body.addPart(new TextSlide(context, masterCipher.decryptBody(messageText)).getPart());
|
2014-11-12 19:15:05 +00:00
|
|
|
} else if (!TextUtils.isEmpty(messageText)) {
|
2013-05-05 19:51:36 +00:00
|
|
|
body.addPart(new TextSlide(context, messageText).getPart());
|
|
|
|
}
|
|
|
|
} catch (InvalidMessageException e) {
|
|
|
|
Log.w("MmsDatabase", e);
|
|
|
|
}
|
|
|
|
|
2014-11-08 19:35:58 +00:00
|
|
|
return new SendReq(headers, body, messageId, outboxType, timestamp);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
2014-11-08 19:35:58 +00:00
|
|
|
throw new NoSuchMessageException("No record found for id: " + messageId);
|
2011-12-20 18:20:44 +00:00
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
2012-09-08 03:03:23 +00:00
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
2014-10-23 01:28:03 +00:00
|
|
|
public long copyMessageInbox(MasterSecret masterSecret, long messageId) throws MmsException {
|
2014-11-08 19:35:58 +00:00
|
|
|
try {
|
|
|
|
SendReq request = getOutgoingMessage(masterSecret, messageId);
|
|
|
|
ContentValues contentValues = getContentValuesFromHeader(request.getPduHeaders());
|
|
|
|
|
|
|
|
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.ENCRYPTION_SYMMETRIC_BIT);
|
|
|
|
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
|
|
|
contentValues.put(READ, 1);
|
|
|
|
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
|
|
|
|
2015-09-04 17:56:59 +00:00
|
|
|
for (int i = 0; i < request.getBody().getPartsNum(); i++) {
|
|
|
|
request.getBody().getPart(i).setTransferProgress(PartDatabase.TRANSFER_PROGRESS_DONE);
|
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
return insertMediaMessage(new MasterSecretUnion(masterSecret), request.getPduHeaders(),
|
2014-11-08 19:35:58 +00:00
|
|
|
request.getBody(), contentValues);
|
|
|
|
} catch (NoSuchMessageException e) {
|
|
|
|
throw new MmsException(e);
|
|
|
|
}
|
2014-10-23 01:28:03 +00:00
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
private Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
|
|
|
|
IncomingMediaMessage retrieved,
|
|
|
|
String contentLocation,
|
|
|
|
long threadId, long mailbox)
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
throws MmsException
|
|
|
|
{
|
2013-12-07 19:00:20 +00:00
|
|
|
PduHeaders headers = retrieved.getPduHeaders();
|
2011-12-20 18:20:44 +00:00
|
|
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
2014-01-07 02:52:18 +00:00
|
|
|
boolean unread = org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
|
|
|
((mailbox & Types.SECURE_MESSAGE_BIT) != 0);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
if (threadId == -1 || retrieved.isGroupMessage()) {
|
2013-04-26 01:59:49 +00:00
|
|
|
try {
|
|
|
|
threadId = getThreadIdFor(retrieved);
|
|
|
|
} catch (RecipientFormattingException e) {
|
|
|
|
Log.w("MmsDatabase", e);
|
2013-07-19 00:42:45 +00:00
|
|
|
if (threadId == -1)
|
|
|
|
throw new MmsException(e);
|
2013-04-26 01:59:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
contentValues.put(MESSAGE_BOX, mailbox);
|
|
|
|
contentValues.put(THREAD_ID, threadId);
|
|
|
|
contentValues.put(CONTENT_LOCATION, contentLocation);
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
2015-08-04 20:37:22 +00:00
|
|
|
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp());
|
2013-12-07 19:00:20 +00:00
|
|
|
contentValues.put(READ, unread ? 0 : 1);
|
2013-01-06 21:13:14 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
if (!contentValues.containsKey(DATE_SENT)) {
|
2013-01-06 21:13:14 +00:00
|
|
|
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
2013-07-19 00:42:45 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
long messageId = insertMediaMessage(masterSecret, retrieved.getPduHeaders(),
|
|
|
|
retrieved.getBody(), contentValues);
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2013-12-07 19:00:20 +00:00
|
|
|
if (unread) {
|
|
|
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
|
|
|
}
|
|
|
|
|
2013-05-05 20:14:23 +00:00
|
|
|
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
|
|
|
notifyConversationListeners(threadId);
|
2014-11-25 06:50:32 +00:00
|
|
|
jobManager.add(new TrimThreadJob(context, threadId));
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2014-11-25 06:50:32 +00:00
|
|
|
return new Pair<>(messageId, threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
public Pair<Long, Long> insertMessageInbox(MasterSecretUnion masterSecret,
|
2013-07-19 00:42:45 +00:00
|
|
|
IncomingMediaMessage retrieved,
|
2013-04-26 18:23:43 +00:00
|
|
|
String contentLocation, long threadId)
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
throws MmsException
|
|
|
|
{
|
2015-07-07 00:36:49 +00:00
|
|
|
long type = Types.BASE_INBOX_TYPE;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
if (masterSecret.getMasterSecret().isPresent()) {
|
|
|
|
type |= Types.ENCRYPTION_SYMMETRIC_BIT;
|
|
|
|
} else {
|
|
|
|
type |= Types.ENCRYPTION_ASYMMETRIC_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.isPushMessage()) {
|
|
|
|
type |= Types.PUSH_MESSAGE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return insertMessageInbox(masterSecret, retrieved, contentLocation, threadId, type);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
public Pair<Long, Long> insertSecureDecryptedMessageInbox(MasterSecretUnion masterSecret,
|
2013-07-19 00:42:45 +00:00
|
|
|
IncomingMediaMessage retrieved,
|
2013-04-26 18:23:43 +00:00
|
|
|
long threadId)
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
throws MmsException
|
|
|
|
{
|
2015-07-07 00:36:49 +00:00
|
|
|
long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT;
|
|
|
|
|
|
|
|
if (masterSecret.getMasterSecret().isPresent()) {
|
|
|
|
type |= Types.ENCRYPTION_SYMMETRIC_BIT;
|
|
|
|
} else {
|
|
|
|
type |= Types.ENCRYPTION_ASYMMETRIC_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.isPushMessage()) {
|
|
|
|
type |= Types.PUSH_MESSAGE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return insertMessageInbox(masterSecret, retrieved, "", threadId, type);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-03-27 17:26:17 +00:00
|
|
|
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
|
|
|
long threadId = getThreadIdFor(notification);
|
|
|
|
PduHeaders headers = notification.getPduHeaders();
|
|
|
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
|
|
|
|
|
|
|
Log.w(TAG, "Message received type: " + headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
|
|
|
|
|
|
|
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
|
|
|
|
contentValues.put(THREAD_ID, threadId);
|
|
|
|
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
2015-08-04 20:37:22 +00:00
|
|
|
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp());
|
2015-03-27 17:26:17 +00:00
|
|
|
contentValues.put(READ, Util.isDefaultSmsProvider(context) ? 0 : 1);
|
|
|
|
|
|
|
|
if (!contentValues.containsKey(DATE_SENT))
|
|
|
|
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
|
|
|
|
|
|
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
|
|
|
addressDatabase.insertAddressesForId(messageId, headers);
|
|
|
|
|
|
|
|
return new Pair<>(messageId, threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
public void markIncomingNotificationReceived(long threadId) {
|
|
|
|
notifyConversationListeners(threadId);
|
|
|
|
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
2013-12-07 19:00:20 +00:00
|
|
|
|
2014-01-07 02:52:18 +00:00
|
|
|
if (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context)) {
|
2013-12-07 19:00:20 +00:00
|
|
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
|
|
|
}
|
|
|
|
|
2014-11-25 06:50:32 +00:00
|
|
|
jobManager.add(new TrimThreadJob(context, threadId));
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
public long insertMessageOutbox(@NonNull MasterSecretUnion masterSecret,
|
|
|
|
@NonNull OutgoingMediaMessage message,
|
2015-05-18 22:16:27 +00:00
|
|
|
long threadId, boolean forceSms, long timestamp)
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
throws MmsException
|
|
|
|
{
|
2015-07-07 00:36:49 +00:00
|
|
|
long type = Types.BASE_OUTBOX_TYPE;
|
|
|
|
|
|
|
|
if (masterSecret.getMasterSecret().isPresent()) type |= Types.ENCRYPTION_SYMMETRIC_BIT;
|
|
|
|
else type |= Types.ENCRYPTION_ASYMMETRIC_BIT;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-06-11 22:31:59 +00:00
|
|
|
if (message.isSecure()) type |= Types.SECURE_MESSAGE_BIT;
|
|
|
|
if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2014-02-20 05:06:54 +00:00
|
|
|
if (message.isGroup()) {
|
2014-02-22 01:51:25 +00:00
|
|
|
if (((OutgoingGroupMediaMessage)message).isGroupUpdate()) type |= Types.GROUP_UPDATE_BIT;
|
2014-02-20 05:06:54 +00:00
|
|
|
else if (((OutgoingGroupMediaMessage)message).isGroupQuit()) type |= Types.GROUP_QUIT_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendReq sendRequest = new SendReq();
|
2015-05-18 22:16:27 +00:00
|
|
|
sendRequest.setDate(timestamp / 1000L);
|
2014-02-20 05:06:54 +00:00
|
|
|
sendRequest.setBody(message.getPduBody());
|
|
|
|
sendRequest.setContentType(ContentType.MULTIPART_MIXED.getBytes());
|
|
|
|
|
|
|
|
String[] recipientsArray = message.getRecipients().toNumberStringArray(true);
|
|
|
|
EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(recipientsArray);
|
|
|
|
|
|
|
|
if (message.getRecipients().isSingleRecipient()) {
|
|
|
|
sendRequest.setTo(encodedNumbers);
|
|
|
|
} else if (message.getDistributionType() == ThreadDatabase.DistributionTypes.BROADCAST) {
|
|
|
|
sendRequest.setBcc(encodedNumbers);
|
|
|
|
} else if (message.getDistributionType() == ThreadDatabase.DistributionTypes.CONVERSATION ||
|
|
|
|
message.getDistributionType() == 0)
|
|
|
|
{
|
|
|
|
sendRequest.setTo(encodedNumbers);
|
|
|
|
}
|
|
|
|
|
|
|
|
PduHeaders headers = sendRequest.getPduHeaders();
|
|
|
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
contentValues.put(MESSAGE_BOX, type);
|
2011-12-20 18:20:44 +00:00
|
|
|
contentValues.put(THREAD_ID, threadId);
|
|
|
|
contentValues.put(READ, 1);
|
2013-01-06 21:13:14 +00:00
|
|
|
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
2013-05-05 19:51:36 +00:00
|
|
|
contentValues.remove(ADDRESS);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-06-27 03:14:51 +00:00
|
|
|
if (sendRequest.getBody() != null) {
|
|
|
|
for (int i = 0; i < sendRequest.getBody().getPartsNum(); i++) {
|
2015-08-24 22:24:31 +00:00
|
|
|
sendRequest.getBody().getPart(i).setTransferProgress(PartDatabase.TRANSFER_PROGRESS_STARTED);
|
2015-06-27 03:14:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
long messageId = insertMediaMessage(masterSecret,
|
|
|
|
sendRequest.getPduHeaders(),
|
2013-07-19 00:42:45 +00:00
|
|
|
sendRequest.getBody(), contentValues);
|
2014-11-25 06:50:32 +00:00
|
|
|
jobManager.add(new TrimThreadJob(context, threadId));
|
2013-01-10 05:06:56 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
return messageId;
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
private String getEncryptedBody(MasterSecretUnion masterSecret, String body) {
|
|
|
|
if (masterSecret.getMasterSecret().isPresent()) {
|
|
|
|
return new MasterCipher(masterSecret.getMasterSecret().get()).encryptBody(body);
|
|
|
|
} else {
|
|
|
|
return new AsymmetricMasterCipher(masterSecret.getAsymmetricMasterSecret().get()).encryptBody(body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private long insertMediaMessage(MasterSecretUnion masterSecret,
|
2013-07-19 00:42:45 +00:00
|
|
|
PduHeaders headers,
|
|
|
|
PduBody body,
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
ContentValues contentValues)
|
|
|
|
throws MmsException
|
|
|
|
{
|
2014-12-12 09:03:24 +00:00
|
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
PartDatabase partsDatabase = DatabaseFactory.getPartDatabase(context);
|
2011-12-20 18:20:44 +00:00
|
|
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2015-07-07 00:36:49 +00:00
|
|
|
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)) ||
|
|
|
|
Types.isAsymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)))
|
|
|
|
{
|
2013-04-26 18:23:43 +00:00
|
|
|
String messageText = PartParser.getMessageText(body);
|
2014-12-30 09:36:51 +00:00
|
|
|
body = PartParser.getSupportedMediaParts(body);
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
if (!TextUtils.isEmpty(messageText)) {
|
2015-07-07 00:36:49 +00:00
|
|
|
contentValues.put(BODY, getEncryptedBody(masterSecret, messageText));
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 09:36:51 +00:00
|
|
|
contentValues.put(PART_COUNT, PartParser.getSupportedMediaPartCount(body));
|
2013-04-26 18:23:43 +00:00
|
|
|
|
2015-04-28 05:16:37 +00:00
|
|
|
db.beginTransaction();
|
|
|
|
try {
|
|
|
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2015-04-28 05:16:37 +00:00
|
|
|
addressDatabase.insertAddressesForId(messageId, headers);
|
|
|
|
partsDatabase.insertParts(masterSecret, messageId, body);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2015-04-28 05:16:37 +00:00
|
|
|
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
|
|
|
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
|
|
|
db.setTransactionSuccessful();
|
|
|
|
return messageId;
|
|
|
|
} finally {
|
|
|
|
db.endTransaction();
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2015-03-31 20:36:04 +00:00
|
|
|
public boolean delete(long messageId) {
|
2011-12-20 18:20:44 +00:00
|
|
|
long threadId = getThreadIdForMessage(messageId);
|
|
|
|
MmsAddressDatabase addrDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
|
|
|
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
|
|
|
|
partDatabase.deleteParts(messageId);
|
|
|
|
addrDatabase.deleteAddressesForId(messageId);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
2015-03-31 20:36:04 +00:00
|
|
|
boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
notifyConversationListeners(threadId);
|
2015-03-31 20:36:04 +00:00
|
|
|
return threadDeleted;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void deleteThread(long threadId) {
|
|
|
|
Set<Long> singleThreadSet = new HashSet<Long>();
|
|
|
|
singleThreadSet.add(threadId);
|
|
|
|
deleteThreads(singleThreadSet);
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
/*package*/ void deleteThreads(Set<Long> threadIds) {
|
|
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
String where = "";
|
|
|
|
Cursor cursor = null;
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
for (long threadId : threadIds) {
|
|
|
|
where += THREAD_ID + " = '" + threadId + "' OR ";
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
where = where.substring(0, where.length() - 4);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
try {
|
|
|
|
cursor = db.query(TABLE_NAME, new String[] {ID}, where, null, null, null, null);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
while (cursor != null && cursor.moveToNext()) {
|
|
|
|
delete(cursor.getLong(0));
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
2012-09-08 03:03:23 +00:00
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 05:06:56 +00:00
|
|
|
/*package*/void deleteMessagesInThreadBeforeDate(long threadId, long date) {
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
String where = THREAD_ID + " = ? AND (CASE (" + MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + ") ";
|
2013-01-10 05:06:56 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
for (long outgoingType : Types.OUTGOING_MESSAGE_TYPES) {
|
2013-01-10 05:06:56 +00:00
|
|
|
where += " WHEN " + outgoingType + " THEN " + DATE_SENT + " < " + date;
|
|
|
|
}
|
|
|
|
|
|
|
|
where += (" ELSE " + DATE_RECEIVED + " < " + date + " END)");
|
|
|
|
|
|
|
|
Log.w("MmsDatabase", "Executing trim query: " + where);
|
|
|
|
cursor = db.query(TABLE_NAME, new String[] {ID}, where, new String[] {threadId+""}, null, null, null);
|
|
|
|
|
|
|
|
while (cursor != null && cursor.moveToNext()) {
|
|
|
|
Log.w("MmsDatabase", "Trimming: " + cursor.getLong(0));
|
|
|
|
delete(cursor.getLong(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
if (cursor != null)
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public void deleteAllThreads() {
|
|
|
|
DatabaseFactory.getPartDatabase(context).deleteAllParts();
|
|
|
|
DatabaseFactory.getMmsAddressDatabase(context).deleteAllAddresses();
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
|
|
|
database.delete(TABLE_NAME, null, null);
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2012-09-30 18:46:45 +00:00
|
|
|
public Cursor getCarrierMmsInformation(String apn) {
|
2012-11-21 03:09:46 +00:00
|
|
|
Uri uri = Uri.withAppendedPath(Uri.parse("content://telephony/carriers"), "current");
|
2014-11-12 19:15:05 +00:00
|
|
|
String selection = TextUtils.isEmpty(apn) ? null : "apn = ?";
|
|
|
|
String[] selectionArgs = TextUtils.isEmpty(apn) ? null : new String[] {apn.trim()};
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-03-17 18:19:36 +00:00
|
|
|
try {
|
|
|
|
return context.getContentResolver().query(uri, null, selection, selectionArgs, null);
|
|
|
|
} catch (NullPointerException npe) {
|
|
|
|
// NOTE - This is dumb, but on some devices there's an NPE in the Android framework
|
|
|
|
// for the provider of this call, which gets rethrown back to here through a binder
|
|
|
|
// call.
|
|
|
|
throw new IllegalArgumentException(npe);
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private PduHeaders getHeadersFromCursor(Cursor cursor) throws InvalidHeaderValueException {
|
|
|
|
PduHeaders headers = new PduHeaders();
|
|
|
|
PduHeadersBuilder phb = new PduHeadersBuilder(headers, cursor);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
phb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, PduHeaders.RETRIEVE_TEXT);
|
|
|
|
phb.add(SUBJECT, SUBJECT_CHARSET, PduHeaders.SUBJECT);
|
|
|
|
phb.addText(CONTENT_LOCATION, PduHeaders.CONTENT_LOCATION);
|
|
|
|
phb.addText(CONTENT_TYPE, PduHeaders.CONTENT_TYPE);
|
|
|
|
phb.addText(MESSAGE_CLASS, PduHeaders.MESSAGE_CLASS);
|
|
|
|
phb.addText(MESSAGE_ID, PduHeaders.MESSAGE_ID);
|
|
|
|
phb.addText(RESPONSE_TEXT, PduHeaders.RESPONSE_TEXT);
|
|
|
|
phb.addText(TRANSACTION_ID, PduHeaders.TRANSACTION_ID);
|
|
|
|
phb.addOctet(CONTENT_CLASS, PduHeaders.CONTENT_CLASS);
|
|
|
|
phb.addOctet(DELIVERY_REPORT, PduHeaders.DELIVERY_REPORT);
|
|
|
|
phb.addOctet(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE);
|
|
|
|
phb.addOctet(MMS_VERSION, PduHeaders.MMS_VERSION);
|
|
|
|
phb.addOctet(PRIORITY, PduHeaders.PRIORITY);
|
|
|
|
phb.addOctet(READ_STATUS, PduHeaders.READ_STATUS);
|
|
|
|
phb.addOctet(REPORT_ALLOWED, PduHeaders.REPORT_ALLOWED);
|
|
|
|
phb.addOctet(RETRIEVE_STATUS, PduHeaders.RETRIEVE_STATUS);
|
|
|
|
phb.addOctet(STATUS, PduHeaders.STATUS);
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
phb.addLong(NORMALIZED_DATE_SENT, PduHeaders.DATE);
|
2011-12-20 18:20:44 +00:00
|
|
|
phb.addLong(DELIVERY_TIME, PduHeaders.DELIVERY_TIME);
|
|
|
|
phb.addLong(EXPIRY, PduHeaders.EXPIRY);
|
|
|
|
phb.addLong(MESSAGE_SIZE, PduHeaders.MESSAGE_SIZE);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
headers.setLongInteger(headers.getLongInteger(PduHeaders.DATE) / 1000L, PduHeaders.DATE);
|
|
|
|
|
|
|
|
return headers;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
private ContentValues getContentValuesFromHeader(PduHeaders headers) {
|
|
|
|
ContentValues contentValues = new ContentValues();
|
|
|
|
ContentValuesBuilder cvb = new ContentValuesBuilder(contentValues);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
cvb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, headers.getEncodedStringValue(PduHeaders.RETRIEVE_TEXT));
|
|
|
|
cvb.add(SUBJECT, SUBJECT_CHARSET, headers.getEncodedStringValue(PduHeaders.SUBJECT));
|
|
|
|
cvb.add(CONTENT_LOCATION, headers.getTextString(PduHeaders.CONTENT_LOCATION));
|
|
|
|
cvb.add(CONTENT_TYPE, headers.getTextString(PduHeaders.CONTENT_TYPE));
|
|
|
|
cvb.add(MESSAGE_CLASS, headers.getTextString(PduHeaders.MESSAGE_CLASS));
|
|
|
|
cvb.add(MESSAGE_ID, headers.getTextString(PduHeaders.MESSAGE_ID));
|
|
|
|
cvb.add(RESPONSE_TEXT, headers.getTextString(PduHeaders.RESPONSE_TEXT));
|
|
|
|
cvb.add(TRANSACTION_ID, headers.getTextString(PduHeaders.TRANSACTION_ID));
|
|
|
|
cvb.add(CONTENT_CLASS, headers.getOctet(PduHeaders.CONTENT_CLASS));
|
|
|
|
cvb.add(DELIVERY_REPORT, headers.getOctet(PduHeaders.DELIVERY_REPORT));
|
|
|
|
cvb.add(MESSAGE_TYPE, headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
|
|
|
cvb.add(MMS_VERSION, headers.getOctet(PduHeaders.MMS_VERSION));
|
|
|
|
cvb.add(PRIORITY, headers.getOctet(PduHeaders.PRIORITY));
|
|
|
|
cvb.add(READ_REPORT, headers.getOctet(PduHeaders.READ_REPORT));
|
|
|
|
cvb.add(READ_STATUS, headers.getOctet(PduHeaders.READ_STATUS));
|
|
|
|
cvb.add(REPORT_ALLOWED, headers.getOctet(PduHeaders.REPORT_ALLOWED));
|
|
|
|
cvb.add(RETRIEVE_STATUS, headers.getOctet(PduHeaders.RETRIEVE_STATUS));
|
|
|
|
cvb.add(STATUS, headers.getOctet(PduHeaders.STATUS));
|
2015-08-04 20:37:22 +00:00
|
|
|
cvb.add(DATE_SENT, headers.getLongInteger(PduHeaders.DATE) * 1000L);
|
2011-12-20 18:20:44 +00:00
|
|
|
cvb.add(DELIVERY_TIME, headers.getLongInteger(PduHeaders.DELIVERY_TIME));
|
|
|
|
cvb.add(EXPIRY, headers.getLongInteger(PduHeaders.EXPIRY));
|
|
|
|
cvb.add(MESSAGE_SIZE, headers.getLongInteger(PduHeaders.MESSAGE_SIZE));
|
2013-05-31 03:29:13 +00:00
|
|
|
|
|
|
|
if (headers.getEncodedStringValue(PduHeaders.FROM) != null)
|
|
|
|
cvb.add(ADDRESS, headers.getEncodedStringValue(PduHeaders.FROM).getTextString());
|
|
|
|
else
|
|
|
|
cvb.add(ADDRESS, null);
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
return cvb.getContentValues();
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public Reader readerFor(MasterSecret masterSecret, Cursor cursor) {
|
|
|
|
return new Reader(masterSecret, cursor);
|
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public static class Status {
|
2011-12-20 18:20:44 +00:00
|
|
|
public static final int DOWNLOAD_INITIALIZED = 1;
|
|
|
|
public static final int DOWNLOAD_NO_CONNECTIVITY = 2;
|
|
|
|
public static final int DOWNLOAD_CONNECTING = 3;
|
2012-10-01 02:56:29 +00:00
|
|
|
public static final int DOWNLOAD_SOFT_FAILURE = 4;
|
|
|
|
public static final int DOWNLOAD_HARD_FAILURE = 5;
|
2013-09-16 07:55:01 +00:00
|
|
|
public static final int DOWNLOAD_APN_UNAVAILABLE = 6;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public static boolean isDisplayDownloadButton(int status) {
|
|
|
|
return
|
|
|
|
status == DOWNLOAD_INITIALIZED ||
|
|
|
|
status == DOWNLOAD_NO_CONNECTIVITY ||
|
|
|
|
status == DOWNLOAD_SOFT_FAILURE;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public static String getLabelForStatus(Context context, int status) {
|
|
|
|
switch (status) {
|
2013-09-16 07:55:01 +00:00
|
|
|
case DOWNLOAD_CONNECTING: return context.getString(R.string.MmsDatabase_connecting_to_mms_server);
|
|
|
|
case DOWNLOAD_INITIALIZED: return context.getString(R.string.MmsDatabase_downloading_mms);
|
|
|
|
case DOWNLOAD_HARD_FAILURE: return context.getString(R.string.MmsDatabase_mms_download_failed);
|
|
|
|
case DOWNLOAD_APN_UNAVAILABLE: return context.getString(R.string.MmsDatabase_mms_pending_download);
|
2013-01-10 05:06:56 +00:00
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
return context.getString(R.string.MmsDatabase_downloading);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public static boolean isHardError(int status) {
|
|
|
|
return status == DOWNLOAD_HARD_FAILURE;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public class Reader {
|
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
private final Cursor cursor;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
private final MasterSecret masterSecret;
|
2013-04-26 18:23:43 +00:00
|
|
|
private final MasterCipher masterCipher;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
|
|
|
public Reader(MasterSecret masterSecret, Cursor cursor) {
|
|
|
|
this.cursor = cursor;
|
|
|
|
this.masterSecret = masterSecret;
|
2013-04-26 18:23:43 +00:00
|
|
|
|
|
|
|
if (masterSecret != null) masterCipher = new MasterCipher(masterSecret);
|
|
|
|
else masterCipher = null;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public MessageRecord getNext() {
|
|
|
|
if (cursor == null || !cursor.moveToNext())
|
|
|
|
return null;
|
|
|
|
|
|
|
|
return getCurrent();
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public MessageRecord getCurrent() {
|
|
|
|
long mmsType = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_TYPE));
|
2012-09-08 03:03:23 +00:00
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
if (mmsType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
|
|
|
|
return getNotificationMmsMessageRecord(cursor);
|
|
|
|
} else {
|
|
|
|
return getMediaMmsMessageRecord(cursor);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
}
|
2012-09-08 03:03:23 +00:00
|
|
|
|
2013-05-05 19:51:36 +00:00
|
|
|
private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor cursor) {
|
|
|
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
|
|
|
|
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
|
|
|
|
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
|
|
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
|
|
|
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
|
|
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
2014-02-03 03:38:06 +00:00
|
|
|
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
2013-05-05 19:51:36 +00:00
|
|
|
Recipients recipients = getRecipientsFor(address);
|
|
|
|
|
|
|
|
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.CONTENT_LOCATION));
|
|
|
|
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.TRANSACTION_ID));
|
|
|
|
long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_SIZE));
|
|
|
|
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
|
|
|
|
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS));
|
2014-07-25 22:14:29 +00:00
|
|
|
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
2013-05-05 19:51:36 +00:00
|
|
|
|
|
|
|
byte[]contentLocationBytes = null;
|
|
|
|
byte[]transactionIdBytes = null;
|
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
if (!TextUtils.isEmpty(contentLocation))
|
2013-07-10 02:48:33 +00:00
|
|
|
contentLocationBytes = org.thoughtcrime.securesms.util.Util.toIsoBytes(contentLocation);
|
2013-05-05 19:51:36 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
if (!TextUtils.isEmpty(transactionId))
|
2013-07-10 02:48:33 +00:00
|
|
|
transactionIdBytes = org.thoughtcrime.securesms.util.Util.toIsoBytes(transactionId);
|
2013-05-05 19:51:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
2014-07-25 22:14:29 +00:00
|
|
|
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
|
2014-02-03 03:38:06 +00:00
|
|
|
contentLocationBytes, messageSize, expiry, status,
|
2014-02-20 05:06:54 +00:00
|
|
|
transactionIdBytes, mailbox);
|
2013-05-05 19:51:36 +00:00
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
2013-04-30 18:14:01 +00:00
|
|
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
|
|
|
|
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
|
|
|
|
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
|
|
|
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
|
|
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
2013-05-05 19:51:36 +00:00
|
|
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
2014-02-03 03:38:06 +00:00
|
|
|
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
2014-07-25 22:14:29 +00:00
|
|
|
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
2013-04-30 18:14:01 +00:00
|
|
|
DisplayRecord.Body body = getBody(cursor);
|
|
|
|
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
2015-01-15 21:35:35 +00:00
|
|
|
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
|
|
|
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
|
|
|
|
|
|
|
Recipients recipients = getRecipientsFor(address);
|
|
|
|
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
|
|
|
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2015-09-05 00:33:22 +00:00
|
|
|
ListenableFutureTask<SlideDeck> slideDeck = getSlideDeck(dateReceived, id);
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2013-05-05 19:51:36 +00:00
|
|
|
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
2014-07-25 22:14:29 +00:00
|
|
|
addressDeviceId, dateSent, dateReceived, receiptCount,
|
2015-01-15 21:35:35 +00:00
|
|
|
threadId, body, slideDeck, partCount, box, mismatches, networkFailures);
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 19:51:36 +00:00
|
|
|
private Recipients getRecipientsFor(String address) {
|
2015-03-03 19:44:49 +00:00
|
|
|
if (TextUtils.isEmpty(address) || address.equals("insert-address-token")) {
|
2015-08-05 00:40:19 +00:00
|
|
|
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
2015-03-03 19:44:49 +00:00
|
|
|
}
|
2013-05-05 19:51:36 +00:00
|
|
|
|
2015-08-05 00:40:19 +00:00
|
|
|
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address, true);
|
2013-05-05 19:51:36 +00:00
|
|
|
|
2015-03-03 19:44:49 +00:00
|
|
|
if (recipients == null || recipients.isEmpty()) {
|
2015-08-05 00:40:19 +00:00
|
|
|
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
2013-05-05 19:51:36 +00:00
|
|
|
}
|
2015-03-03 19:44:49 +00:00
|
|
|
|
|
|
|
return recipients;
|
2013-05-05 19:51:36 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 21:35:35 +00:00
|
|
|
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {
|
|
|
|
if (!TextUtils.isEmpty(document)) {
|
|
|
|
try {
|
|
|
|
return JsonUtils.fromJson(document, IdentityKeyMismatchList.class).getList();
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new LinkedList<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<NetworkFailure> getFailures(String document) {
|
|
|
|
if (!TextUtils.isEmpty(document)) {
|
|
|
|
try {
|
|
|
|
return JsonUtils.fromJson(document, NetworkFailureList.class).getList();
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.w(TAG, ioe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new LinkedList<>();
|
|
|
|
}
|
|
|
|
|
2013-04-30 18:14:01 +00:00
|
|
|
private DisplayRecord.Body getBody(Cursor cursor) {
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
try {
|
2013-04-26 18:23:43 +00:00
|
|
|
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.BODY));
|
|
|
|
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
if (!TextUtils.isEmpty(body) && masterCipher != null && Types.isSymmetricEncryption(box)) {
|
2013-04-30 18:14:01 +00:00
|
|
|
return new DisplayRecord.Body(masterCipher.decryptBody(body), true);
|
2014-11-12 19:15:05 +00:00
|
|
|
} else if (!TextUtils.isEmpty(body) && masterCipher == null && Types.isSymmetricEncryption(box)) {
|
2013-04-30 18:14:01 +00:00
|
|
|
return new DisplayRecord.Body(body, false);
|
2015-07-07 00:36:49 +00:00
|
|
|
} else if (!TextUtils.isEmpty(body) && Types.isAsymmetricEncryption(box)) {
|
|
|
|
return new DisplayRecord.Body(body, false);
|
2013-04-30 18:14:01 +00:00
|
|
|
} else {
|
|
|
|
return new DisplayRecord.Body(body == null ? "" : body, true);
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
} catch (InvalidMessageException e) {
|
|
|
|
Log.w("MmsDatabase", e);
|
2014-12-17 19:21:04 +00:00
|
|
|
return new DisplayRecord.Body(context.getString(R.string.MmsDatabase_error_decrypting_message), true);
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
|
2015-09-05 00:33:22 +00:00
|
|
|
private ListenableFutureTask<SlideDeck> getSlideDeck(final long timestamp,
|
2013-04-26 18:23:43 +00:00
|
|
|
final long id)
|
|
|
|
{
|
2015-05-18 15:16:06 +00:00
|
|
|
ListenableFutureTask<SlideDeck> future = getCachedSlideDeck(timestamp, id);
|
2013-05-06 19:22:03 +00:00
|
|
|
|
|
|
|
if (future != null) {
|
|
|
|
return future;
|
|
|
|
}
|
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
Callable<SlideDeck> task = new Callable<SlideDeck>() {
|
|
|
|
@Override
|
|
|
|
public SlideDeck call() throws Exception {
|
2014-12-12 09:03:24 +00:00
|
|
|
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
|
|
|
|
PduBody body = getPartsAsBody(partDatabase.getParts(id));
|
2015-09-05 00:33:22 +00:00
|
|
|
SlideDeck slideDeck = new SlideDeck(context, body);
|
2013-09-09 01:19:05 +00:00
|
|
|
|
|
|
|
if (!body.containsPushInProgress()) {
|
2015-05-18 15:16:06 +00:00
|
|
|
slideCache.put(timestamp + "::" + id, new SoftReference<>(slideDeck));
|
2013-09-09 01:19:05 +00:00
|
|
|
}
|
2013-05-06 19:22:03 +00:00
|
|
|
|
|
|
|
return slideDeck;
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-05-18 15:16:06 +00:00
|
|
|
future = new ListenableFutureTask<>(task);
|
2013-04-26 18:23:43 +00:00
|
|
|
slideResolver.execute(future);
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
return future;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 15:16:06 +00:00
|
|
|
private ListenableFutureTask<SlideDeck> getCachedSlideDeck(final long timestamp, final long id) {
|
|
|
|
SoftReference<SlideDeck> reference = slideCache.get(timestamp + "::" + id);
|
2013-05-06 19:22:03 +00:00
|
|
|
|
|
|
|
if (reference != null) {
|
|
|
|
final SlideDeck slideDeck = reference.get();
|
|
|
|
|
|
|
|
if (slideDeck != null) {
|
|
|
|
Callable<SlideDeck> task = new Callable<SlideDeck>() {
|
|
|
|
@Override
|
|
|
|
public SlideDeck call() throws Exception {
|
|
|
|
return slideDeck;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-05-18 15:16:06 +00:00
|
|
|
ListenableFutureTask<SlideDeck> future = new ListenableFutureTask<>(task);
|
2013-05-06 19:22:03 +00:00
|
|
|
future.run();
|
|
|
|
|
|
|
|
return future;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
public void close() {
|
|
|
|
cursor.close();
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
}
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2015-08-04 20:37:22 +00:00
|
|
|
private long generatePduCompatTimestamp() {
|
|
|
|
final long time = System.currentTimeMillis();
|
|
|
|
return time - (time % 1000);
|
|
|
|
}
|
|
|
|
|
2015-05-21 18:55:03 +00:00
|
|
|
private PduBody getPartsAsBody(List<PduPart> parts) {
|
2013-09-09 01:19:05 +00:00
|
|
|
PduBody body = new PduBody();
|
|
|
|
|
2015-05-21 18:55:03 +00:00
|
|
|
for (PduPart part : parts) {
|
|
|
|
body.addPart(part);
|
2013-09-09 01:19:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|