mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-26 07:30:16 +00:00
Switch MMS groups to use the group database infrastructure
Eliminate the concept of 'Recipients' (plural). There is now just a 'Recipient', which contains an Address that is either an individual or a group ID. MMS groups now exist as part of the group database, just like push groups. // FREEBIE
This commit is contained in:
@@ -96,20 +96,14 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
return Util.join(escapedAddresses, delimiter + "");
|
||||
}
|
||||
|
||||
public static Address[] fromParcelable(Parcelable[] parcelables) {
|
||||
Address[] addresses = new Address[parcelables.length];
|
||||
|
||||
for (int i=0;i<parcelables.length;i++) {
|
||||
addresses[i] = (Address)parcelables[i];
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public boolean isGroup() {
|
||||
return GroupUtil.isEncodedGroup(address);
|
||||
}
|
||||
|
||||
public boolean isMmsGroup() {
|
||||
return GroupUtil.isMmsGroup(address);
|
||||
}
|
||||
|
||||
public boolean isEmail() {
|
||||
return NumberUtil.isValidEmail(address);
|
||||
}
|
||||
@@ -204,9 +198,9 @@ public class Address implements Parcelable, Comparable<Address> {
|
||||
}
|
||||
|
||||
public String format(@Nullable String number) {
|
||||
if (number == null) return "Unknown";
|
||||
if (number.startsWith("__textsecure_group__!")) return number;
|
||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
||||
if (number == null) return "Unknown";
|
||||
if (GroupUtil.isEncodedGroup(number)) return number;
|
||||
if (ALPHA_PATTERN.matcher(number).find()) return number.trim();
|
||||
|
||||
String bareNumber = number.replaceAll("[^0-9+]", "");
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber;
|
||||
@@ -41,10 +39,10 @@ import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -56,12 +54,12 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DatabaseFactory {
|
||||
@@ -102,7 +100,8 @@ public class DatabaseFactory {
|
||||
private static final int INTRODUCED_IDENTITY_TIMESTAMP = 35;
|
||||
private static final int SANIFY_ATTACHMENT_DOWNLOAD = 36;
|
||||
private static final int NO_MORE_CANONICAL_ADDRESS_DATABASE = 37;
|
||||
private static final int DATABASE_VERSION = 37;
|
||||
private static final int NO_MORE_RECIPIENTS_PLURAL = 38;
|
||||
private static final int DATABASE_VERSION = 38;
|
||||
|
||||
private static final String DATABASE_NAME = "messages.db";
|
||||
private static final Object lock = new Object();
|
||||
@@ -117,7 +116,6 @@ public class DatabaseFactory {
|
||||
private final AttachmentDatabase attachments;
|
||||
private final MediaDatabase media;
|
||||
private final ThreadDatabase thread;
|
||||
private final MmsAddressDatabase mmsAddress;
|
||||
private final MmsSmsDatabase mmsSmsDatabase;
|
||||
private final IdentityDatabase identityDatabase;
|
||||
private final DraftDatabase draftDatabase;
|
||||
@@ -163,10 +161,6 @@ public class DatabaseFactory {
|
||||
return getInstance(context).media;
|
||||
}
|
||||
|
||||
public static MmsAddressDatabase getMmsAddressDatabase(Context context) {
|
||||
return getInstance(context).mmsAddress;
|
||||
}
|
||||
|
||||
public static IdentityDatabase getIdentityDatabase(Context context) {
|
||||
return getInstance(context).identityDatabase;
|
||||
}
|
||||
@@ -199,7 +193,6 @@ public class DatabaseFactory {
|
||||
this.attachments = new AttachmentDatabase(context, databaseHelper);
|
||||
this.media = new MediaDatabase(context, databaseHelper);
|
||||
this.thread = new ThreadDatabase(context, databaseHelper);
|
||||
this.mmsAddress = new MmsAddressDatabase(context, databaseHelper);
|
||||
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
|
||||
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
|
||||
this.draftDatabase = new DraftDatabase(context, databaseHelper);
|
||||
@@ -218,7 +211,6 @@ public class DatabaseFactory {
|
||||
this.mms.reset(databaseHelper);
|
||||
this.attachments.reset(databaseHelper);
|
||||
this.thread.reset(databaseHelper);
|
||||
this.mmsAddress.reset(databaseHelper);
|
||||
this.mmsSmsDatabase.reset(databaseHelper);
|
||||
this.identityDatabase.reset(databaseHelper);
|
||||
this.draftDatabase.reset(databaseHelper);
|
||||
@@ -533,7 +525,6 @@ public class DatabaseFactory {
|
||||
db.execSQL(MmsDatabase.CREATE_TABLE);
|
||||
db.execSQL(AttachmentDatabase.CREATE_TABLE);
|
||||
db.execSQL(ThreadDatabase.CREATE_TABLE);
|
||||
db.execSQL(MmsAddressDatabase.CREATE_TABLE);
|
||||
db.execSQL(IdentityDatabase.CREATE_TABLE);
|
||||
db.execSQL(DraftDatabase.CREATE_TABLE);
|
||||
db.execSQL(PushDatabase.CREATE_TABLE);
|
||||
@@ -544,7 +535,6 @@ public class DatabaseFactory {
|
||||
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, AttachmentDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, ThreadDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, MmsAddressDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, DraftDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, GroupDatabase.CREATE_INDEXS);
|
||||
}
|
||||
@@ -1209,6 +1199,80 @@ public class DatabaseFactory {
|
||||
|
||||
}
|
||||
|
||||
if (oldVersion < NO_MORE_RECIPIENTS_PLURAL) {
|
||||
db.execSQL("ALTER TABLE groups ADD COLUMN mms INTEGER DEFAULT 0");
|
||||
|
||||
Cursor cursor = db.query("thread", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long threadId = cursor.getLong(0);
|
||||
String addressListString = cursor.getString(1);
|
||||
String[] addressList = DelimiterUtil.split(addressListString, ' ');
|
||||
|
||||
if (addressList.length == 1) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put("recipient_ids", DelimiterUtil.unescape(addressListString, ' '));
|
||||
db.update("thread", contentValues, "_id = ?", new String[] {String.valueOf(threadId)});
|
||||
} else {
|
||||
byte[] groupId = new byte[16];
|
||||
List<String> members = new LinkedList<>();
|
||||
|
||||
new SecureRandom().nextBytes(groupId);
|
||||
|
||||
for (String address : addressList) {
|
||||
members.add(DelimiterUtil.escape(DelimiterUtil.unescape(address, ' '), ','));
|
||||
}
|
||||
|
||||
String encodedGroupId = "__signal_mms_group__!" + Hex.toStringCondensed(groupId);
|
||||
ContentValues groupValues = new ContentValues();
|
||||
ContentValues threadValues = new ContentValues();
|
||||
|
||||
groupValues.put("group_id", encodedGroupId);
|
||||
groupValues.put("members", Util.join(members, ","));
|
||||
groupValues.put("mms", 1);
|
||||
|
||||
threadValues.put("recipient_ids", encodedGroupId);
|
||||
|
||||
db.insert("groups", null, groupValues);
|
||||
db.update("thread", threadValues, "_id = ?", new String[] {String.valueOf(threadId)});
|
||||
db.update("recipient_preferences", threadValues, "recipient_ids = ?", new String[] {addressListString});
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor != null) cursor.close();
|
||||
|
||||
cursor = db.query("recipient_preferences", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long id = cursor.getLong(0);
|
||||
String addressListString = cursor.getString(1);
|
||||
String[] addressList = DelimiterUtil.split(addressListString, ' ');
|
||||
|
||||
if (addressList.length == 1) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put("recipient_ids", DelimiterUtil.unescape(addressListString, ' '));
|
||||
db.update("recipient_preferences", contentValues, "_id = ?", new String[] {String.valueOf(id)});
|
||||
} else {
|
||||
Log.w(TAG, "Found preferences for MMS thread that appears to be gone: " + addressListString);
|
||||
db.delete("recipient_preferences", "_id = ?", new String[] {String.valueOf(id)});
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor != null) cursor.close();
|
||||
|
||||
cursor = db.rawQuery("SELECT mms._id, thread.recipient_ids FROM mms, thread WHERE mms.address IS NULL AND mms.thread_id = thread._id", null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long id = cursor.getLong(0);
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
|
||||
contentValues.put("address", cursor.getString(1));
|
||||
db.update("mms", contentValues, "_id = ?", new String[] {String.valueOf(id)});
|
||||
}
|
||||
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -23,6 +22,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,6 +45,7 @@ public class GroupDatabase extends Database {
|
||||
private static final String AVATAR_DIGEST = "avatar_digest";
|
||||
private static final String TIMESTAMP = "timestamp";
|
||||
private static final String ACTIVE = "active";
|
||||
private static final String MMS = "mms";
|
||||
|
||||
public static final String CREATE_TABLE =
|
||||
"CREATE TABLE " + TABLE_NAME +
|
||||
@@ -59,7 +60,8 @@ public class GroupDatabase extends Database {
|
||||
AVATAR_RELAY + " TEXT, " +
|
||||
TIMESTAMP + " INTEGER, " +
|
||||
ACTIVE + " INTEGER DEFAULT 1, " +
|
||||
AVATAR_DIGEST + " BLOB);";
|
||||
AVATAR_DIGEST + " BLOB, " +
|
||||
MMS + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");",
|
||||
@@ -69,10 +71,10 @@ public class GroupDatabase extends Database {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public @Nullable GroupRecord getGroup(byte[] groupId) {
|
||||
public @Nullable GroupRecord getGroup(String groupId) {
|
||||
@SuppressLint("Recycle")
|
||||
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(groupId)},
|
||||
new String[] {groupId},
|
||||
null, null, null);
|
||||
|
||||
Reader reader = new Reader(cursor);
|
||||
@@ -82,7 +84,7 @@ public class GroupDatabase extends Database {
|
||||
return record;
|
||||
}
|
||||
|
||||
public boolean isUnknownGroup(byte[] groupId) {
|
||||
public boolean isUnknownGroup(String groupId) {
|
||||
return getGroup(groupId) == null;
|
||||
}
|
||||
|
||||
@@ -94,12 +96,32 @@ public class GroupDatabase extends Database {
|
||||
return new Reader(cursor);
|
||||
}
|
||||
|
||||
public String getOrCreateGroupForMembers(List<Address> members, boolean mms) {
|
||||
Collections.sort(members);
|
||||
|
||||
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {GROUP_ID},
|
||||
MEMBERS + " = ? AND " + MMS + " = ?",
|
||||
new String[] {Address.toSerializedList(members, ','), mms ? "1" : "0"},
|
||||
null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
|
||||
} else {
|
||||
String groupId = GroupUtil.getEncodedId(allocateGroupId(), mms);
|
||||
create(groupId, null, members, null, null);
|
||||
return groupId;
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public Reader getGroups() {
|
||||
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, null, null, null, null, null);
|
||||
return new Reader(cursor);
|
||||
}
|
||||
|
||||
public @NonNull Recipients getGroupMembers(byte[] groupId, boolean includeSelf) {
|
||||
public @NonNull List<Recipient> getGroupMembers(String groupId, boolean includeSelf) {
|
||||
List<Address> members = getCurrentMembers(groupId);
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
@@ -110,14 +132,16 @@ public class GroupDatabase extends Database {
|
||||
recipients.add(RecipientFactory.getRecipientFor(context, member, false));
|
||||
}
|
||||
|
||||
return RecipientFactory.getRecipientsFor(context, recipients, false);
|
||||
return recipients;
|
||||
}
|
||||
|
||||
public void create(byte[] groupId, String title, List<Address> members,
|
||||
SignalServiceAttachmentPointer avatar, String relay)
|
||||
public void create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
|
||||
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay)
|
||||
{
|
||||
Collections.sort(members);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(GROUP_ID, GroupUtil.getEncodedId(groupId));
|
||||
contentValues.put(GROUP_ID, groupId);
|
||||
contentValues.put(TITLE, title);
|
||||
contentValues.put(MEMBERS, Address.toSerializedList(members, ','));
|
||||
|
||||
@@ -131,13 +155,14 @@ public class GroupDatabase extends Database {
|
||||
contentValues.put(AVATAR_RELAY, relay);
|
||||
contentValues.put(TIMESTAMP, System.currentTimeMillis());
|
||||
contentValues.put(ACTIVE, 1);
|
||||
contentValues.put(MMS, GroupUtil.isMmsGroup(groupId));
|
||||
|
||||
databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);
|
||||
RecipientFactory.clearCache(context);
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void update(byte[] groupId, String title, SignalServiceAttachmentPointer avatar) {
|
||||
public void update(String groupId, String title, SignalServiceAttachmentPointer avatar) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
if (title != null) contentValues.put(TITLE, title);
|
||||
|
||||
@@ -150,65 +175,67 @@ public class GroupDatabase extends Database {
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
|
||||
GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(groupId)});
|
||||
new String[] {groupId});
|
||||
|
||||
RecipientFactory.clearCache(context);
|
||||
notifyDatabaseListeners();
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void updateTitle(byte[] groupId, String title) {
|
||||
public void updateTitle(String groupId, String title) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TITLE, title);
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(groupId)});
|
||||
new String[] {groupId});
|
||||
|
||||
RecipientFactory.clearCache(context);
|
||||
notifyDatabaseListeners();
|
||||
}
|
||||
|
||||
public void updateAvatar(byte[] groupId, Bitmap avatar) {
|
||||
public void updateAvatar(String groupId, Bitmap avatar) {
|
||||
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
|
||||
}
|
||||
|
||||
public void updateAvatar(byte[] groupId, byte[] avatar) {
|
||||
public void updateAvatar(String groupId, byte[] avatar) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(AVATAR, avatar);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(groupId)});
|
||||
new String[] {groupId});
|
||||
|
||||
RecipientFactory.clearCache(context);
|
||||
notifyDatabaseListeners();
|
||||
}
|
||||
|
||||
public void updateMembers(byte[] id, List<Address> members) {
|
||||
public void updateMembers(String groupId, List<Address> members) {
|
||||
Collections.sort(members);
|
||||
|
||||
ContentValues contents = new ContentValues();
|
||||
contents.put(MEMBERS, Address.toSerializedList(members, ','));
|
||||
contents.put(ACTIVE, 1);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(id)});
|
||||
new String[] {groupId});
|
||||
}
|
||||
|
||||
public void remove(byte[] id, Address source) {
|
||||
List<Address> currentMembers = getCurrentMembers(id);
|
||||
public void remove(String groupId, Address source) {
|
||||
List<Address> currentMembers = getCurrentMembers(groupId);
|
||||
currentMembers.remove(source);
|
||||
|
||||
ContentValues contents = new ContentValues();
|
||||
contents.put(MEMBERS, Address.toSerializedList(currentMembers, ','));
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(id)});
|
||||
new String[] {groupId});
|
||||
}
|
||||
|
||||
private List<Address> getCurrentMembers(byte[] id) {
|
||||
private List<Address> getCurrentMembers(String groupId) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS},
|
||||
GROUP_ID + " = ?",
|
||||
new String[] {GroupUtil.getEncodedId(id)},
|
||||
new String[] {groupId},
|
||||
null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@@ -223,16 +250,16 @@ public class GroupDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive(byte[] id) {
|
||||
GroupRecord record = getGroup(id);
|
||||
public boolean isActive(String groupId) {
|
||||
GroupRecord record = getGroup(groupId);
|
||||
return record != null && record.isActive();
|
||||
}
|
||||
|
||||
public void setActive(byte[] id, boolean active) {
|
||||
public void setActive(String groupId, boolean active) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ACTIVE, active ? 1 : 0);
|
||||
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {GroupUtil.getEncodedId(id)});
|
||||
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId});
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +300,8 @@ public class GroupDatabase extends Database {
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_CONTENT_TYPE)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_RELAY)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1,
|
||||
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)));
|
||||
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(MMS)) == 1);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
@@ -294,10 +322,11 @@ public class GroupDatabase extends Database {
|
||||
private final String avatarContentType;
|
||||
private final String relay;
|
||||
private final boolean active;
|
||||
private final boolean mms;
|
||||
|
||||
public GroupRecord(String id, String title, String members, byte[] avatar,
|
||||
long avatarId, byte[] avatarKey, String avatarContentType,
|
||||
String relay, boolean active, byte[] avatarDigest)
|
||||
String relay, boolean active, byte[] avatarDigest, boolean mms)
|
||||
{
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
@@ -309,6 +338,7 @@ public class GroupDatabase extends Database {
|
||||
this.avatarContentType = avatarContentType;
|
||||
this.relay = relay;
|
||||
this.active = active;
|
||||
this.mms = mms;
|
||||
}
|
||||
|
||||
public byte[] getId() {
|
||||
@@ -358,5 +388,9 @@ public class GroupDatabase extends Database {
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public boolean isMms() {
|
||||
return mms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.google.android.mms.pdu_alt.PduHeaders;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class MmsAddressDatabase extends Database {
|
||||
|
||||
private static final String TAG = MmsAddressDatabase.class.getSimpleName();
|
||||
|
||||
private static final String TABLE_NAME = "mms_addresses";
|
||||
private static final String ID = "_id";
|
||||
private static final String MMS_ID = "mms_id";
|
||||
private static final String TYPE = "type";
|
||||
private static final String ADDRESS = "address";
|
||||
private static final String ADDRESS_CHARSET = "address_charset";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
MMS_ID + " INTEGER, " + TYPE + " INTEGER, " + ADDRESS + " TEXT, " +
|
||||
ADDRESS_CHARSET + " INTEGER);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS mms_addresses_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
|
||||
};
|
||||
|
||||
public MmsAddressDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
private void insertAddress(long messageId, int type, @NonNull Address value) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(MMS_ID, messageId);
|
||||
contentValues.put(TYPE, type);
|
||||
contentValues.put(ADDRESS, value.serialize());
|
||||
contentValues.put(ADDRESS_CHARSET, "UTF-8");
|
||||
database.insert(TABLE_NAME, null, contentValues);
|
||||
}
|
||||
|
||||
private void insertAddress(long messageId, int type, @NonNull List<Address> addresses) {
|
||||
for (Address address : addresses) {
|
||||
insertAddress(messageId, type, address);
|
||||
}
|
||||
}
|
||||
|
||||
public void insertAddressesForId(long messageId, MmsAddresses addresses) {
|
||||
if (addresses.getFrom() != null) {
|
||||
insertAddress(messageId, PduHeaders.FROM, addresses.getFrom());
|
||||
}
|
||||
|
||||
insertAddress(messageId, PduHeaders.TO, addresses.getTo());
|
||||
insertAddress(messageId, PduHeaders.CC, addresses.getCc());
|
||||
insertAddress(messageId, PduHeaders.BCC, addresses.getBcc());
|
||||
}
|
||||
|
||||
public MmsAddresses getAddressesForId(long messageId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
Address from = null;
|
||||
List<Address> to = new LinkedList<>();
|
||||
List<Address> cc = new LinkedList<>();
|
||||
List<Address> bcc = new LinkedList<>();
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {messageId+""}, null, null, null);
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
|
||||
if (type == PduHeaders.FROM) from = address;
|
||||
if (type == PduHeaders.TO) to.add(address);
|
||||
if (type == PduHeaders.CC) cc.add(address);
|
||||
if (type == PduHeaders.BCC) bcc.add(address);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return new MmsAddresses(from, to, cc, bcc);
|
||||
}
|
||||
|
||||
public List<Address> getAddressesListForId(long messageId) {
|
||||
List<Address> results = new LinkedList<>();
|
||||
MmsAddresses addresses = getAddressesForId(messageId);
|
||||
|
||||
if (addresses.getFrom() != null) {
|
||||
results.add(addresses.getFrom());
|
||||
}
|
||||
|
||||
results.addAll(addresses.getTo());
|
||||
results.addAll(addresses.getCc());
|
||||
results.addAll(addresses.getBcc());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public Recipients getRecipientsForId(long messageId) {
|
||||
List<Address> addresses = getAddressesListForId(messageId);
|
||||
List<Recipient> results = new LinkedList<>();
|
||||
|
||||
for (Address address : addresses) {
|
||||
if (!PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.equals(address.serialize())) {
|
||||
results.add(RecipientFactory.getRecipientFor(context, address, false));
|
||||
}
|
||||
}
|
||||
|
||||
return RecipientFactory.getRecipientsFor(context, results, false);
|
||||
}
|
||||
|
||||
|
||||
public void deleteAddressesForId(long messageId) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.delete(TABLE_NAME, MMS_ID + " = ?", new String[] {messageId+""});
|
||||
}
|
||||
|
||||
public void deleteAllAddresses() {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.delete(TABLE_NAME, null, null);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class MmsAddresses {
|
||||
|
||||
private final @Nullable Address from;
|
||||
private final @NonNull List<Address> to;
|
||||
private final @NonNull List<Address> cc;
|
||||
private final @NonNull List<Address> bcc;
|
||||
|
||||
public MmsAddresses(@Nullable Address from, @NonNull List<Address> to,
|
||||
@NonNull List<Address> cc, @NonNull List<Address> bcc)
|
||||
{
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.cc = cc;
|
||||
this.bcc = bcc;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Address> getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Address> getCc() {
|
||||
return cc;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Address> getBcc() {
|
||||
return bcc;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Address getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public static MmsAddresses forTo(@NonNull List<Address> to) {
|
||||
return new MmsAddresses(null, to, new LinkedList<Address>(), new LinkedList<Address>());
|
||||
}
|
||||
|
||||
public static MmsAddresses forBcc(@NonNull List<Address> bcc) {
|
||||
return new MmsAddresses(null, new LinkedList<Address>(), new LinkedList<Address>(), bcc);
|
||||
}
|
||||
|
||||
public static MmsAddresses forFrom(@NonNull Address from) {
|
||||
return new MmsAddresses(from, new LinkedList<Address>(), new LinkedList<Address>(), new LinkedList<Address>());
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import android.util.Pair;
|
||||
|
||||
import com.google.android.mms.pdu_alt.NotificationInd;
|
||||
import com.google.android.mms.pdu_alt.PduHeaders;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -57,12 +56,10 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
@@ -195,34 +192,30 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
public void incrementDeliveryReceiptCount(SyncMessageId messageId) {
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
Cursor cursor = null;
|
||||
boolean found = false;
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
Cursor cursor = null;
|
||||
boolean found = false;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
||||
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
|
||||
for (Address theirAddress : addresses) {
|
||||
Address ourAddress = messageId.getAddress();
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
found = true;
|
||||
|
||||
found = true;
|
||||
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
||||
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
||||
new String[] {String.valueOf(id)});
|
||||
|
||||
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
||||
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
||||
new String[] {String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,66 +250,20 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
||||
if (retrieved.getGroupId() != null) {
|
||||
Recipients groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {retrieved.getGroupId()}, true);
|
||||
Recipient groupRecipients = RecipientFactory.getRecipientFor(context, retrieved.getGroupId(), true);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
||||
}
|
||||
|
||||
String localNumber;
|
||||
Set<Address> group = new HashSet<>();
|
||||
|
||||
if (retrieved.getAddresses().getFrom() == null) {
|
||||
throw new MmsException("FROM value in PduHeaders did not exist.");
|
||||
}
|
||||
|
||||
group.add(retrieved.getAddresses().getFrom());
|
||||
|
||||
if (TextSecurePreferences.isPushRegistered(context)) {
|
||||
localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
} else {
|
||||
localNumber = ServiceUtil.getTelephonyManager(context).getLine1Number();
|
||||
Recipient sender = RecipientFactory.getRecipientFor(context, retrieved.getFrom(), true);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender);
|
||||
}
|
||||
|
||||
for (Address cc : retrieved.getAddresses().getCc()) {
|
||||
PhoneNumberUtil.MatchType match;
|
||||
|
||||
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
||||
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, cc.serialize());
|
||||
|
||||
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
||||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
||||
{
|
||||
group.add(cc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (retrieved.getAddresses().getTo().size() > 1) {
|
||||
for (Address to : retrieved.getAddresses().getTo()) {
|
||||
PhoneNumberUtil.MatchType match;
|
||||
|
||||
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
||||
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, to.serialize());
|
||||
|
||||
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
||||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
||||
{
|
||||
group.add(to);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, group.toArray(new Address[0]), false);
|
||||
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
}
|
||||
|
||||
private long getThreadIdFor(@NonNull NotificationInd notification) {
|
||||
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
|
||||
? Util.toIsoString(notification.getFrom().getTextString())
|
||||
: "";
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, fromString)}, false);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, fromString), false);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
}
|
||||
|
||||
private Cursor rawQuery(@NonNull String where, @Nullable String[] arguments) {
|
||||
@@ -489,39 +436,35 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
public List<Pair<Long, Long>> setTimestampRead(SyncMessageId messageId, long expireStarted) {
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
|
||||
for (Address theirAddress : addresses) {
|
||||
Address ourAddress = messageId.getAddress();
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(READ, 1);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(READ, 1);
|
||||
|
||||
if (expiresIn > 0) {
|
||||
values.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
notifyConversationListeners(threadId);
|
||||
if (expiresIn > 0) {
|
||||
values.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -592,7 +535,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
public OutgoingMediaMessage getOutgoingMessage(MasterSecret masterSecret, long messageId)
|
||||
throws MmsException, NoSuchMessageException
|
||||
{
|
||||
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
||||
Cursor cursor = null;
|
||||
|
||||
@@ -600,31 +542,27 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
|
||||
MmsAddresses addresses = addr.getAddressesForId(messageId);
|
||||
List<Address> destinations = new LinkedList<>();
|
||||
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
int distributionType = DatabaseFactory.getThreadDatabase(context).getDistributionType(threadId);
|
||||
|
||||
destinations.addAll(addresses.getBcc());
|
||||
destinations.addAll(addresses.getCc());
|
||||
destinations.addAll(addresses.getTo());
|
||||
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, destinations.toArray(new Address[0]), false);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(address), false);
|
||||
|
||||
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
|
||||
return new OutgoingGroupMediaMessage(recipients, body, attachments, timestamp, 0);
|
||||
return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0);
|
||||
} else if (Types.isExpirationTimerUpdate(outboxType)) {
|
||||
return new OutgoingExpirationUpdateMessage(recipients, timestamp, expiresIn);
|
||||
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
|
||||
}
|
||||
|
||||
OutgoingMediaMessage message = new OutgoingMediaMessage(recipients, body, attachments, timestamp, subscriptionId, expiresIn,
|
||||
!addresses.getBcc().isEmpty() ? ThreadDatabase.DistributionTypes.BROADCAST :
|
||||
ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, distributionType);
|
||||
|
||||
if (Types.isSecureType(outboxType)) {
|
||||
return new OutgoingSecureMediaMessage(message);
|
||||
}
|
||||
@@ -645,7 +583,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
try {
|
||||
OutgoingMediaMessage request = getOutgoingMessage(masterSecret, messageId);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(ADDRESS, request.getRecipients().getPrimaryRecipient().getAddress().serialize());
|
||||
contentValues.put(ADDRESS, request.getRecipient().getAddress().serialize());
|
||||
contentValues.put(DATE_SENT, request.getSentTimeMillis());
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.ENCRYPTION_SYMMETRIC_BIT);
|
||||
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
||||
@@ -674,7 +612,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
return insertMediaMessage(new MasterSecretUnion(masterSecret),
|
||||
MmsAddresses.forTo(request.getRecipients().getAddressesList()),
|
||||
request.getBody(),
|
||||
attachments,
|
||||
contentValues,
|
||||
@@ -703,7 +640,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
|
||||
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
|
||||
contentValues.put(ADDRESS, retrieved.getAddresses().getFrom().serialize());
|
||||
contentValues.put(ADDRESS, retrieved.getFrom().serialize());
|
||||
|
||||
contentValues.put(MESSAGE_BOX, mailbox);
|
||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
||||
@@ -725,9 +662,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
long messageId = insertMediaMessage(masterSecret, retrieved.getAddresses(),
|
||||
retrieved.getBody(), retrieved.getAttachments(),
|
||||
contentValues, null);
|
||||
long messageId = insertMediaMessage(masterSecret, retrieved.getBody(), retrieved.getAttachments(), contentValues, null);
|
||||
|
||||
if (!Types.isExpirationTimerUpdate(mailbox)) {
|
||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||
@@ -789,8 +724,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long threadId = getThreadIdFor(notification);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
ContentValuesBuilder contentBuilder = new ContentValuesBuilder(contentValues);
|
||||
@@ -806,9 +740,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentBuilder.add(MESSAGE_TYPE, notification.getMessageType());
|
||||
|
||||
if (notification.getFrom() != null) {
|
||||
contentBuilder.add(ADDRESS, notification.getFrom().getTextString());
|
||||
} else {
|
||||
contentBuilder.add(ADDRESS, null);
|
||||
contentValues.put(ADDRESS, Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString())).serialize());
|
||||
}
|
||||
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
|
||||
@@ -823,10 +755,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
if (notification.getFrom() != null) {
|
||||
addressDatabase.insertAddressesForId(messageId, MmsAddresses.forFrom(Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString()))));
|
||||
}
|
||||
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
@@ -864,18 +792,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
|
||||
}
|
||||
|
||||
List<Address> recipientNumbers = message.getRecipients().getAddressesList();
|
||||
|
||||
MmsAddresses addresses;
|
||||
|
||||
if (!message.getRecipients().isSingleRecipient() &&
|
||||
message.getDistributionType() == ThreadDatabase.DistributionTypes.BROADCAST)
|
||||
{
|
||||
addresses = MmsAddresses.forBcc(recipientNumbers);
|
||||
} else {
|
||||
addresses = MmsAddresses.forTo(recipientNumbers);
|
||||
}
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(DATE_SENT, message.getSentTimeMillis());
|
||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
|
||||
@@ -886,15 +802,10 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
|
||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipient().getAddress()));
|
||||
|
||||
if (message.getRecipients().isSingleRecipient()) {
|
||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipients().getPrimaryRecipient().getAddress()));
|
||||
}
|
||||
|
||||
contentValues.remove(ADDRESS);
|
||||
|
||||
long messageId = insertMediaMessage(masterSecret, addresses, message.getBody(),
|
||||
message.getAttachments(), contentValues, insertListener);
|
||||
long messageId = insertMediaMessage(masterSecret, message.getBody(), message.getAttachments(), contentValues, insertListener);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
jobManager.add(new TrimThreadJob(context, threadId));
|
||||
@@ -928,7 +839,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
private long insertMediaMessage(@NonNull MasterSecretUnion masterSecret,
|
||||
@NonNull MmsAddresses addresses,
|
||||
@Nullable String body,
|
||||
@NonNull List<Attachment> attachments,
|
||||
@NonNull ContentValues contentValues,
|
||||
@@ -937,7 +847,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
{
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
AttachmentDatabase partsDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
|
||||
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)) ||
|
||||
Types.isAsymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX)))
|
||||
@@ -953,7 +862,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
try {
|
||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
addressDatabase.insertAddressesForId(messageId, addresses);
|
||||
partsDatabase.insertAttachmentsForMessage(masterSecret, messageId, attachments);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
@@ -972,10 +880,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
public boolean delete(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
MmsAddressDatabase addrDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
||||
attachmentDatabase.deleteAttachmentsForMessage(messageId);
|
||||
addrDatabase.deleteAddressesForId(messageId);
|
||||
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
||||
@@ -993,7 +899,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
private boolean isDuplicate(IncomingMediaMessage message, long threadId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||
new String[]{String.valueOf(message.getSentTimeMillis()), message.getAddresses().getFrom().serialize(), String.valueOf(threadId)},
|
||||
new String[]{String.valueOf(message.getSentTimeMillis()), message.getFrom().serialize(), String.valueOf(threadId)},
|
||||
null, null, null, "1");
|
||||
|
||||
try {
|
||||
@@ -1058,7 +964,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
public void deleteAllThreads() {
|
||||
DatabaseFactory.getAttachmentDatabase(context).deleteAllAttachments();
|
||||
DatabaseFactory.getMmsAddressDatabase(context).deleteAllAddresses();
|
||||
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.delete(TABLE_NAME, null, null);
|
||||
@@ -1139,8 +1044,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
public MessageRecord getCurrent() {
|
||||
SlideDeck slideDeck = new SlideDeck(context, message.getAttachments());
|
||||
|
||||
return new MediaMmsMessageRecord(context, id, message.getRecipients(),
|
||||
message.getRecipients().getPrimaryRecipient(),
|
||||
return new MediaMmsMessageRecord(context, id, message.getRecipient(), message.getRecipient(),
|
||||
1, System.currentTimeMillis(), System.currentTimeMillis(),
|
||||
0, threadId, new DisplayRecord.Body(message.getBody(), true),
|
||||
slideDeck, slideDeck.getSlides().size(),
|
||||
@@ -1192,7 +1096,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||
Recipients recipients = getRecipientsFor(address);
|
||||
Recipient recipient = getRecipientFor(address);
|
||||
|
||||
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.CONTENT_LOCATION));
|
||||
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.TRANSACTION_ID));
|
||||
@@ -1214,7 +1118,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
SlideDeck slideDeck = new SlideDeck(context, new MmsNotificationAttachment(status, messageSize));
|
||||
|
||||
|
||||
return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
||||
return new NotificationMmsMessageRecord(context, id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
|
||||
contentLocationBytes, messageSize, expiry, status,
|
||||
transactionIdBytes, mailbox, subscriptionId, slideDeck);
|
||||
@@ -1237,18 +1141,18 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||
|
||||
Recipients recipients = getRecipientsFor(address);
|
||||
Recipient recipient = getRecipientFor(address);
|
||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
||||
SlideDeck slideDeck = getSlideDeck(cursor);
|
||||
|
||||
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
||||
return new MediaMmsMessageRecord(context, id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount,
|
||||
threadId, body, slideDeck, partCount, box, mismatches,
|
||||
networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||
}
|
||||
|
||||
private Recipients getRecipientsFor(String serialized) {
|
||||
private Recipient getRecipientFor(String serialized) {
|
||||
Address address;
|
||||
|
||||
if (TextUtils.isEmpty(serialized) || "insert-address-token".equals(serialized)) {
|
||||
@@ -1257,7 +1161,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
address = Address.fromSerialized(serialized);
|
||||
|
||||
}
|
||||
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||
return RecipientFactory.getRecipientFor(context, address, true);
|
||||
}
|
||||
|
||||
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
@@ -34,8 +34,8 @@ public class PlaintextBackupImporter {
|
||||
XmlBackup.XmlBackupItem item;
|
||||
|
||||
while ((item = backup.getNext()) != null) {
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, item.getAddress())}, false);
|
||||
long threadId = threads.getThreadIdFor(recipients);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, item.getAddress()), false);
|
||||
long threadId = threads.getThreadIdFor(recipient);
|
||||
SQLiteStatement statement = db.createInsertStatement(transaction);
|
||||
|
||||
if (item.getAddress() == null || item.getAddress().equals("null"))
|
||||
|
||||
@@ -12,13 +12,10 @@ import android.util.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class RecipientPreferenceDatabase extends Database {
|
||||
|
||||
private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
|
||||
@@ -26,7 +23,7 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
|
||||
private static final String TABLE_NAME = "recipient_preferences";
|
||||
private static final String ID = "_id";
|
||||
private static final String ADDRESSES = "recipient_ids";
|
||||
private static final String ADDRESS = "recipient_ids";
|
||||
private static final String BLOCK = "block";
|
||||
private static final String NOTIFICATION = "notification";
|
||||
private static final String VIBRATE = "vibrate";
|
||||
@@ -57,7 +54,7 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
public static final String CREATE_TABLE =
|
||||
"CREATE TABLE " + TABLE_NAME +
|
||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
ADDRESSES + " TEXT UNIQUE, " +
|
||||
ADDRESS + " TEXT UNIQUE, " +
|
||||
BLOCK + " INTEGER DEFAULT 0," +
|
||||
NOTIFICATION + " TEXT DEFAULT NULL, " +
|
||||
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
@@ -74,7 +71,7 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
public Cursor getBlocked() {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
|
||||
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESSES}, BLOCK + " = 1",
|
||||
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, BLOCK + " = 1",
|
||||
null, null, null, null, null);
|
||||
cursor.setNotificationUri(context.getContentResolver(), Uri.parse(RECIPIENT_PREFERENCES_URI));
|
||||
|
||||
@@ -85,14 +82,13 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
return new BlockedReader(context, cursor);
|
||||
}
|
||||
|
||||
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address[] addresses) {
|
||||
|
||||
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address address) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, ADDRESSES + " = ?",
|
||||
new String[] {Address.toSerializedList(Arrays.asList(addresses), ' ')},
|
||||
null, null, null);
|
||||
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
|
||||
@@ -128,69 +124,68 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(Recipients recipients, MaterialColor color) {
|
||||
public void setColor(Recipient recipient, MaterialColor color) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLOR, color.serialize());
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setDefaultSubscriptionId(@NonNull Recipients recipients, int defaultSubscriptionId) {
|
||||
public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
|
||||
updateOrInsert(recipients, values);
|
||||
EventBus.getDefault().post(new RecipientPreferenceEvent(recipients));
|
||||
updateOrInsert(recipient, values);
|
||||
EventBus.getDefault().post(new RecipientPreferenceEvent(recipient));
|
||||
}
|
||||
|
||||
public void setBlocked(Recipients recipients, boolean blocked) {
|
||||
public void setBlocked(Recipient recipient, boolean blocked) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(BLOCK, blocked ? 1 : 0);
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setRingtone(Recipients recipients, @Nullable Uri notification) {
|
||||
public void setRingtone(Recipient recipient, @Nullable Uri notification) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NOTIFICATION, notification == null ? null : notification.toString());
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setVibrate(Recipients recipients, @NonNull VibrateState enabled) {
|
||||
public void setVibrate(Recipient recipient, @NonNull VibrateState enabled) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(VIBRATE, enabled.getId());
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setMuted(Recipients recipients, long until) {
|
||||
public void setMuted(Recipient recipient, long until) {
|
||||
Log.w(TAG, "Setting muted until: " + until);
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MUTE_UNTIL, until);
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setSeenInviteReminder(Recipients recipients, boolean seen) {
|
||||
public void setSeenInviteReminder(Recipient recipient, boolean seen) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0);
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
public void setExpireMessages(Recipients recipients, int expiration) {
|
||||
recipients.setExpireMessages(expiration);
|
||||
public void setExpireMessages(Recipient recipient, int expiration) {
|
||||
recipient.setExpireMessages(expiration);
|
||||
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(EXPIRE_MESSAGES, expiration);
|
||||
updateOrInsert(recipients, values);
|
||||
updateOrInsert(recipient, values);
|
||||
}
|
||||
|
||||
private void updateOrInsert(Recipients recipients, ContentValues contentValues) {
|
||||
private void updateOrInsert(Recipient recipient, ContentValues contentValues) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
database.beginTransaction();
|
||||
|
||||
List<Address> addresses = recipients.getAddressesList();
|
||||
String serializedAddresses = Address.toSerializedList(addresses, ' ');
|
||||
int updated = database.update(TABLE_NAME, contentValues, ADDRESSES + " = ?", new String[]{serializedAddresses});
|
||||
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ?",
|
||||
new String[] {recipient.getAddress().serialize()});
|
||||
|
||||
if (updated < 1) {
|
||||
contentValues.put(ADDRESSES, serializedAddresses);
|
||||
contentValues.put(ADDRESS, recipient.getAddress().serialize());
|
||||
database.insert(TABLE_NAME, null, contentValues);
|
||||
}
|
||||
|
||||
@@ -271,14 +266,12 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public @NonNull Recipients getCurrent() {
|
||||
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES));
|
||||
List<Address> addressList = Address.fromSerializedList(serialized, ' ');
|
||||
|
||||
return RecipientFactory.getRecipientsFor(context, addressList.toArray(new Address[0]), false);
|
||||
public @NonNull Recipient getCurrent() {
|
||||
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||
return RecipientFactory.getRecipientFor(context, Address.fromSerialized(serialized), false);
|
||||
}
|
||||
|
||||
public @Nullable Recipients getNext() {
|
||||
public @Nullable Recipient getNext() {
|
||||
if (!cursor.moveToNext()) {
|
||||
return null;
|
||||
}
|
||||
@@ -289,14 +282,14 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
|
||||
public static class RecipientPreferenceEvent {
|
||||
|
||||
private final Recipients recipients;
|
||||
private final Recipient recipient;
|
||||
|
||||
RecipientPreferenceEvent(Recipients recipients) {
|
||||
this.recipients = recipients;
|
||||
public RecipientPreferenceEvent(Recipient recipients) {
|
||||
this.recipient = recipients;
|
||||
}
|
||||
|
||||
public Recipients getRecipients() {
|
||||
return recipients;
|
||||
public Recipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
@@ -457,8 +457,8 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(ADDRESS, address.serialize());
|
||||
@@ -506,14 +506,14 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getSender()}, true);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, message.getSender(), true);
|
||||
|
||||
Recipients groupRecipients;
|
||||
Recipient groupRecipient;
|
||||
|
||||
if (message.getGroupId() == null) {
|
||||
groupRecipients = null;
|
||||
groupRecipient = null;
|
||||
} else {
|
||||
groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getGroupId()}, true);
|
||||
groupRecipient = RecipientFactory.getRecipientFor(context, message.getGroupId(), true);
|
||||
}
|
||||
|
||||
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
||||
@@ -522,8 +522,8 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
|
||||
long threadId;
|
||||
|
||||
if (groupRecipients == null) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
||||
if (groupRecipient == null) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(ADDRESS, message.getSender().serialize());
|
||||
@@ -560,7 +560,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
if (message.getSubscriptionId() != -1) {
|
||||
DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipients, message.getSubscriptionId());
|
||||
DatabaseFactory.getRecipientPreferenceDatabase(context).setDefaultSubscriptionId(recipient, message.getSubscriptionId());
|
||||
}
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
@@ -589,7 +589,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||
|
||||
Address address = message.getRecipients().getPrimaryRecipient().getAddress();
|
||||
Address address = message.getRecipient().getAddress();
|
||||
|
||||
ContentValues contentValues = new ContentValues(6);
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
@@ -783,7 +783,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
|
||||
public MessageRecord getCurrent() {
|
||||
return new SmsMessageRecord(context, id, new DisplayRecord.Body(message.getMessageBody(), true),
|
||||
message.getRecipients(), message.getRecipients().getPrimaryRecipient(),
|
||||
message.getRecipient(), message.getRecipient(),
|
||||
1, System.currentTimeMillis(), System.currentTimeMillis(),
|
||||
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
||||
@@ -828,21 +828,17 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
||||
|
||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||
Recipients recipients = getRecipientsFor(address);
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
|
||||
DisplayRecord.Body body = getBody(cursor);
|
||||
|
||||
return new SmsMessageRecord(context, messageId, body, recipients,
|
||||
recipients.getPrimaryRecipient(),
|
||||
return new SmsMessageRecord(context, messageId, body, recipient,
|
||||
recipient,
|
||||
addressDeviceId,
|
||||
dateSent, dateReceived, receiptCount, type,
|
||||
threadId, status, mismatches, subscriptionId,
|
||||
expiresIn, expireStarted);
|
||||
}
|
||||
|
||||
private Recipients getRecipientsFor(Address address) {
|
||||
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||
}
|
||||
|
||||
private List<IdentityKeyMismatch> getMismatches(String document) {
|
||||
try {
|
||||
if (!TextUtils.isEmpty(document)) {
|
||||
|
||||
@@ -22,16 +22,19 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class SmsMigrator {
|
||||
@@ -140,21 +143,21 @@ public class SmsMigrator {
|
||||
}
|
||||
}
|
||||
|
||||
private static Recipients getOurRecipients(Context context, String theirRecipients) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
||||
List<Address> addressList = new LinkedList<>();
|
||||
private static @Nullable Set<Recipient> getOurRecipients(Context context, String theirRecipients) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
||||
Set<Recipient> recipientList = new HashSet<>();
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String theirRecipientId = tokenizer.nextToken();
|
||||
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
||||
|
||||
if (address != null) {
|
||||
addressList.add(Address.fromExternal(context, address));
|
||||
recipientList.add(RecipientFactory.getRecipientFor(context, Address.fromExternal(context, address), true));
|
||||
}
|
||||
}
|
||||
|
||||
if (addressList.isEmpty()) return null;
|
||||
else return RecipientFactory.getRecipientsFor(context, addressList.toArray(new Address[0]), true);
|
||||
if (recipientList.isEmpty()) return null;
|
||||
else return recipientList;
|
||||
}
|
||||
|
||||
private static String encrypt(MasterSecret masterSecret, String body)
|
||||
@@ -221,16 +224,30 @@ public class SmsMigrator {
|
||||
cursor = context.getContentResolver().query(threadListUri, null, null, null, "date ASC");
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
|
||||
String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
Recipients ourRecipients = getOurRecipients(context, theirRecipients);
|
||||
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
|
||||
long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
|
||||
String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
|
||||
Set<Recipient> ourRecipients = getOurRecipients(context, theirRecipients);
|
||||
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
|
||||
|
||||
if (ourRecipients != null) {
|
||||
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients);
|
||||
migrateConversation(context, masterSecret,
|
||||
listener, progress,
|
||||
theirThreadId, ourThreadId);
|
||||
if (ourRecipients.size() == 1) {
|
||||
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients.iterator().next());
|
||||
migrateConversation(context, masterSecret, listener, progress, theirThreadId, ourThreadId);
|
||||
} else if (ourRecipients.size() > 1) {
|
||||
ourRecipients.add(RecipientFactory.getRecipientFor(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
|
||||
|
||||
List<Address> memberAddresses = new LinkedList<>();
|
||||
|
||||
for (Recipient recipient : ourRecipients) {
|
||||
memberAddresses.add(recipient.getAddress());
|
||||
}
|
||||
|
||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true);
|
||||
Recipient ourGroupRecipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(ourGroupId), true);
|
||||
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||
|
||||
migrateConversation(context, masterSecret, listener, progress, theirThreadId, ourThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
progress.incrementPrimaryComplete();
|
||||
|
||||
@@ -36,13 +36,12 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -55,7 +54,7 @@ public class ThreadDatabase extends Database {
|
||||
public static final String ID = "_id";
|
||||
public static final String DATE = "date";
|
||||
public static final String MESSAGE_COUNT = "message_count";
|
||||
public static final String ADDRESSES = "recipient_ids";
|
||||
public static final String ADDRESS = "recipient_ids";
|
||||
public static final String SNIPPET = "snippet";
|
||||
private static final String SNIPPET_CHARSET = "snippet_cs";
|
||||
public static final String READ = "read";
|
||||
@@ -71,7 +70,7 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
|
||||
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESSES + " TEXT, " + SNIPPET + " TEXT, " +
|
||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
|
||||
SNIPPET_CHARSET + " INTEGER DEFAULT 0, " + READ + " INTEGER DEFAULT 1, " +
|
||||
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
||||
@@ -80,7 +79,7 @@ public class ThreadDatabase extends Database {
|
||||
LAST_SEEN + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESSES + ");",
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");",
|
||||
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
|
||||
};
|
||||
|
||||
@@ -88,14 +87,14 @@ public class ThreadDatabase extends Database {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
private long createThreadForRecipients(Address[] addresses, int recipientCount, int distributionType) {
|
||||
private long createThreadForRecipient(Address address, boolean group, int distributionType) {
|
||||
ContentValues contentValues = new ContentValues(4);
|
||||
long date = System.currentTimeMillis();
|
||||
|
||||
contentValues.put(DATE, date - date % 1000);
|
||||
contentValues.put(ADDRESSES, Address.toSerializedList(Arrays.asList(addresses), ' '));
|
||||
contentValues.put(ADDRESS, address.serialize());
|
||||
|
||||
if (recipientCount > 1)
|
||||
if (group)
|
||||
contentValues.put(TYPE, distributionType);
|
||||
|
||||
contentValues.put(MESSAGE_COUNT, 0);
|
||||
@@ -272,6 +271,22 @@ public class ThreadDatabase extends Database {
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public int getDistributionType(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = db.query(TABLE_NAME, new String[]{TYPE}, ID_WHERE, new String[]{String.valueOf(threadId)}, null, null, null);
|
||||
|
||||
try {
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return cursor.getInt(cursor.getColumnIndexOrThrow(TYPE));
|
||||
}
|
||||
|
||||
return DistributionTypes.DEFAULT;
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Cursor getFilteredConversationList(List<Address> filter) {
|
||||
if (filter == null || filter.size() == 0)
|
||||
return null;
|
||||
@@ -281,11 +296,11 @@ public class ThreadDatabase extends Database {
|
||||
List<Cursor> cursors = new LinkedList<>();
|
||||
|
||||
for (List<Address> addresses : partitionedAddresses) {
|
||||
String selection = ADDRESSES + " = ?";
|
||||
String selection = ADDRESS + " = ?";
|
||||
String[] selectionArgs = new String[addresses.size()];
|
||||
|
||||
for (int i=0;i<addresses.size()-1;i++)
|
||||
selection += (" OR " + ADDRESSES + " = ?");
|
||||
selection += (" OR " + ADDRESS + " = ?");
|
||||
|
||||
int i= 0;
|
||||
for (Address address : addresses) {
|
||||
@@ -410,12 +425,11 @@ public class ThreadDatabase extends Database {
|
||||
deleteAllThreads();
|
||||
}
|
||||
|
||||
public long getThreadIdIfExistsFor(Recipients recipients) {
|
||||
List<Address> addresses = Arrays.asList(recipients.getAddresses());
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = ADDRESSES + " = ?";
|
||||
String[] recipientsArg = new String[]{Address.toSerializedList(addresses, ' ')};
|
||||
Cursor cursor = null;
|
||||
public long getThreadIdIfExistsFor(Recipient recipient) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = ADDRESS + " = ?";
|
||||
String[] recipientsArg = new String[] {recipient.getAddress().serialize()};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null);
|
||||
@@ -430,15 +444,14 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public long getThreadIdFor(Recipients recipients) {
|
||||
return getThreadIdFor(recipients, DistributionTypes.DEFAULT);
|
||||
public long getThreadIdFor(Recipient recipient) {
|
||||
return getThreadIdFor(recipient, DistributionTypes.DEFAULT);
|
||||
}
|
||||
|
||||
public long getThreadIdFor(Recipients recipients, int distributionType) {
|
||||
Address[] addresses = recipients.getAddresses();
|
||||
public long getThreadIdFor(Recipient recipient, int distributionType) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = ADDRESSES + " = ?";
|
||||
String[] recipientsArg = new String[]{Address.toSerializedList(Arrays.asList(addresses), ' ')};
|
||||
String where = ADDRESS + " = ?";
|
||||
String[] recipientsArg = new String[]{recipient.getAddress().serialize()};
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
@@ -447,7 +460,7 @@ public class ThreadDatabase extends Database {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
} else {
|
||||
return createThreadForRecipients(addresses, recipients.getRecipientsList().size(), distributionType);
|
||||
return createThreadForRecipient(recipient.getAddress(), recipient.isGroupRecipient(), distributionType);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
@@ -455,7 +468,7 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable Recipients getRecipientsForThreadId(long threadId) {
|
||||
public @Nullable Recipient getRecipientForThreadId(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
@@ -463,8 +476,8 @@ public class ThreadDatabase extends Database {
|
||||
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
List<Address> addresses = Address.fromSerializedList(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES)), ' ');
|
||||
return RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), false);
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
return RecipientFactory.getRecipientFor(context, address, false);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
@@ -561,9 +574,9 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
public ThreadRecord getCurrent() {
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||
List<Address> addresses = Address.fromSerializedList(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESSES)), ' ');
|
||||
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), true);
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESS)));
|
||||
Recipient recipient = RecipientFactory.getRecipientFor(context, address, true);
|
||||
|
||||
DisplayRecord.Body body = getPlaintextBody(cursor);
|
||||
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
||||
@@ -578,7 +591,7 @@ public class ThreadDatabase extends Database {
|
||||
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
||||
Uri snippetUri = getSnippetUri(cursor);
|
||||
|
||||
return new ThreadRecord(context, body, snippetUri, recipients, date, count, read == 1,
|
||||
return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
|
||||
threadId, receiptCount, status, type, distributionType, archived,
|
||||
expiresIn, lastSeen);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
||||
if (archivedCount > 0) {
|
||||
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
|
||||
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||
ThreadDatabase.ADDRESSES, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
|
||||
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.text.SpannableString;
|
||||
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
/**
|
||||
* The base class for all message record models. Encapsulates basic data
|
||||
@@ -36,7 +36,7 @@ public abstract class DisplayRecord {
|
||||
protected final Context context;
|
||||
protected final long type;
|
||||
|
||||
private final Recipients recipients;
|
||||
private final Recipient recipient;
|
||||
private final long dateSent;
|
||||
private final long dateReceived;
|
||||
private final long threadId;
|
||||
@@ -44,12 +44,12 @@ public abstract class DisplayRecord {
|
||||
private final int deliveryStatus;
|
||||
private final int receiptCount;
|
||||
|
||||
public DisplayRecord(Context context, Body body, Recipients recipients, long dateSent,
|
||||
public DisplayRecord(Context context, Body body, Recipient recipient, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int receiptCount, long type)
|
||||
{
|
||||
this.context = context.getApplicationContext();
|
||||
this.threadId = threadId;
|
||||
this.recipients = recipients;
|
||||
this.recipient = recipient;
|
||||
this.dateSent = dateSent;
|
||||
this.dateReceived = dateReceived;
|
||||
this.type = type;
|
||||
@@ -81,8 +81,8 @@ public abstract class DisplayRecord {
|
||||
|
||||
public abstract SpannableString getDisplayBody();
|
||||
|
||||
public Recipients getRecipients() {
|
||||
return recipients;
|
||||
public Recipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public long getDateSent() {
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,7 +44,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
private final Context context;
|
||||
private final int partCount;
|
||||
|
||||
public MediaMmsMessageRecord(Context context, long id, Recipients recipients,
|
||||
public MediaMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int receiptCount,
|
||||
long threadId, Body body,
|
||||
@@ -55,7 +54,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
List<NetworkFailure> failures, int subscriptionId,
|
||||
long expiresIn, long expireStarted)
|
||||
{
|
||||
super(context, id, body, recipients, individualRecipient, recipientDeviceId, dateSent,
|
||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, slideDeck);
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
|
||||
@@ -55,7 +54,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
private final long expiresIn;
|
||||
private final long expireStarted;
|
||||
|
||||
MessageRecord(Context context, long id, Body body, Recipients recipients,
|
||||
MessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, long threadId,
|
||||
int deliveryStatus, int receiptCount, long type,
|
||||
@@ -63,7 +62,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
List<NetworkFailure> networkFailures,
|
||||
int subscriptionId, long expiresIn, long expireStarted)
|
||||
{
|
||||
super(context, body, recipients, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
|
||||
super(context, body, conversationRecipient, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
|
||||
type);
|
||||
this.id = id;
|
||||
this.individualRecipient = individualRecipient;
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -17,14 +16,14 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
||||
|
||||
private final @NonNull SlideDeck slideDeck;
|
||||
|
||||
MmsMessageRecord(Context context, long id, Body body, Recipients recipients,
|
||||
MmsMessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int receiptCount,
|
||||
long type, List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||
long expireStarted, @NonNull SlideDeck slideDeck)
|
||||
{
|
||||
super(context, id, body, recipients, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, receiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, receiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||
this.slideDeck = slideDeck;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,12 @@ import android.content.Context;
|
||||
import android.text.SpannableString;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
@@ -46,14 +45,14 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
||||
private final int status;
|
||||
private final byte[] transactionId;
|
||||
|
||||
public NotificationMmsMessageRecord(Context context, long id, Recipients recipients,
|
||||
public NotificationMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int receiptCount,
|
||||
long threadId, byte[] contentLocation, long messageSize,
|
||||
long expiry, int status, byte[] transactionId, long mailbox,
|
||||
int subscriptionId, SlideDeck slideDeck)
|
||||
{
|
||||
super(context, id, new Body("", true), recipients, individualRecipient, recipientDeviceId,
|
||||
super(context, id, new Body("", true), conversationRecipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox,
|
||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
|
||||
0, 0, slideDeck);
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -41,7 +40,7 @@ import java.util.List;
|
||||
public class SmsMessageRecord extends MessageRecord {
|
||||
|
||||
public SmsMessageRecord(Context context, long id,
|
||||
Body body, Recipients recipients,
|
||||
Body body, Recipient recipient,
|
||||
Recipient individualRecipient,
|
||||
int recipientDeviceId,
|
||||
long dateSent, long dateReceived,
|
||||
@@ -50,7 +49,7 @@ public class SmsMessageRecord extends MessageRecord {
|
||||
int status, List<IdentityKeyMismatch> mismatches,
|
||||
int subscriptionId, long expiresIn, long expireStarted)
|
||||
{
|
||||
super(context, id, body, recipients, individualRecipient, recipientDeviceId,
|
||||
super(context, id, body, recipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, status, receiptCount, type,
|
||||
mismatches, new LinkedList<NetworkFailure>(), subscriptionId,
|
||||
expiresIn, expireStarted);
|
||||
|
||||
@@ -28,7 +28,7 @@ import android.text.style.StyleSpan;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||
|
||||
/**
|
||||
@@ -49,11 +49,11 @@ public class ThreadRecord extends DisplayRecord {
|
||||
private final long lastSeen;
|
||||
|
||||
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
||||
@NonNull Recipients recipients, long date, long count, boolean read,
|
||||
@NonNull Recipient recipient, long date, long count, boolean read,
|
||||
long threadId, int receiptCount, int status, long snippetType,
|
||||
int distributionType, boolean archived, long expiresIn, long lastSeen)
|
||||
{
|
||||
super(context, body, recipients, date, date, threadId, status, receiptCount, snippetType);
|
||||
super(context, body, recipient, date, date, threadId, status, receiptCount, snippetType);
|
||||
this.context = context.getApplicationContext();
|
||||
this.snippetUri = snippetUri;
|
||||
this.count = count;
|
||||
@@ -98,13 +98,13 @@ public class ThreadRecord extends DisplayRecord {
|
||||
} else if (SmsDatabase.Types.isMissedCall(type)) {
|
||||
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
|
||||
} else if (SmsDatabase.Types.isJoinedType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, getRecipients().getPrimaryRecipient().toShortString()));
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, getRecipient().toShortString()));
|
||||
} else if (SmsDatabase.Types.isExpirationTimerUpdate(type)) {
|
||||
String time = ExpirationUtil.getExpirationDisplayValue(context, (int) (getExpiresIn() / 1000));
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
||||
} else if (SmsDatabase.Types.isIdentityUpdate(type)) {
|
||||
if (getRecipients().isGroupRecipient()) return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
||||
else return emphasisAdded(context.getString(R.string.ThreadRecord_your_safety_number_with_s_has_changed, getRecipients().getPrimaryRecipient().toShortString()));
|
||||
if (getRecipient().isGroupRecipient()) return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
||||
else return emphasisAdded(context.getString(R.string.ThreadRecord_your_safety_number_with_s_has_changed, getRecipient().toShortString()));
|
||||
} else if (SmsDatabase.Types.isIdentityVerified(type)) {
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_verified));
|
||||
} else if (SmsDatabase.Types.isIdentityDefault(type)) {
|
||||
|
||||
Reference in New Issue
Block a user