From 3c41f2729863dd4f59f6e57a51a6cb7883f6fc5a Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Fri, 29 May 2015 16:23:47 -0700 Subject: [PATCH] Support for multi-device contact sync. // FREEBIE --- build.gradle | 4 +- .../securesms/ConfirmIdentityDialog.java | 7 +- .../securesms/ConversationActivity.java | 2 +- .../securesms/GroupCreateActivity.java | 10 +- .../securesms/database/DatabaseFactory.java | 41 ++-- .../securesms/database/PushDatabase.java | 37 ++- .../TextSecureCommunicationModule.java | 4 +- .../groups/GroupMessageProcessor.java | 8 +- .../jobs/MultiDeviceContactUpdateJob.java | 165 +++++++++++++ .../securesms/jobs/PushDecryptJob.java | 222 +++++++++--------- .../securesms/jobs/PushGroupSendJob.java | 20 +- .../securesms/jobs/PushMediaSendJob.java | 12 +- .../securesms/jobs/PushTextSendJob.java | 12 +- .../mms/OutgoingGroupMediaMessage.java | 3 +- .../securesms/sms/IncomingGroupMessage.java | 2 +- .../securesms/util/GroupUtil.java | 2 +- 16 files changed, 363 insertions(+), 188 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java diff --git a/build.gradle b/build.gradle index 0598447389..7b2d0ff2e9 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { compile 'org.whispersystems:jobmanager:0.11.0' compile 'org.whispersystems:libpastelog:1.0.6' compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' - compile 'org.whispersystems:textsecure-android:1.5.0' + compile 'org.whispersystems:textsecure-android:1.6.0-RC13' compile 'com.squareup.leakcanary:leakcanary-android:1.3.1' @@ -114,12 +114,10 @@ dependencyVerification { 'org.whispersystems:jobmanager:ea9cb943c4892fb90c1eea1be30efeb85cefca213d52c788419553b58d0ed70d', 'org.whispersystems:libpastelog:550d33c565380d90f4c671e7b8ed5f3a6da55a9fda468373177106b2eb5220b2', 'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb', - 'org.whispersystems:textsecure-android:b8001bd3c77fadcf84e0c3b21353f76d6db783bd17b28c5d7296d71198446d4b', 'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f', 'org.whispersystems:axolotl-android:40d3db5004a84749a73f68d2f0d01b2ae35a73c54df96d8c6c6723b96efb6fc0', - 'org.whispersystems:textsecure-java:b879094961f9ef0c851206223051e8478e6bbba0f039ea9340be20f40384bb20', 'org.whispersystems:axolotl-java:6daee739b89d8d7101de6d98f77132fee48495c6ea647d880e77def842f999ea', 'org.whispersystems:curve25519-android:3c29a4131a69b0d16baaa3d707678deb39602c3a3ffd75805ce7f9db252e5d0d', 'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab', diff --git a/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java b/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java index b30fb7cd2e..a31db4ece6 100644 --- a/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java +++ b/src/org/thoughtcrime/securesms/ConfirmIdentityDialog.java @@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.util.Base64; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; -import org.whispersystems.textsecure.internal.push.PushMessageProtos; +import org.whispersystems.textsecure.internal.push.TextSecureProtos; import java.io.IOException; @@ -162,11 +162,12 @@ public class ConfirmIdentityDialog extends AlertDialog { mismatch.getRecipientId(), mismatch.getIdentityKey()); - TextSecureEnvelope envelope = new TextSecureEnvelope(PushMessageProtos.IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE, + TextSecureEnvelope envelope = new TextSecureEnvelope(TextSecureProtos.Envelope.Type.PREKEY_BUNDLE_VALUE, messageRecord.getIndividualRecipient().getNumber(), messageRecord.getRecipientDeviceId(), "", messageRecord.getDateSent(), - Base64.decode(messageRecord.getBody().getBody())); + Base64.decode(messageRecord.getBody().getBody()), + null); long pushId = pushDatabase.insert(envelope); diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 04501b4ffa..46c89acccb 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -109,7 +109,7 @@ import java.util.List; import static org.thoughtcrime.securesms.TransportOption.Type; import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; +import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; /** * Activity for displaying a message thread, as well as diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index 9112650e21..991fd6b945 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -44,10 +44,12 @@ import com.google.protobuf.ByteString; import com.soundcloud.android.crop.Crop; import org.thoughtcrime.securesms.components.PushRecipientsPanel; -import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.RecipientsEditor; +import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; +import org.thoughtcrime.securesms.database.NotInDirectoryException; +import org.thoughtcrime.securesms.database.TextSecureDirectory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; @@ -63,10 +65,8 @@ import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.database.TextSecureDirectory; -import org.thoughtcrime.securesms.database.NotInDirectoryException; import org.whispersystems.textsecure.api.util.InvalidNumberException; +import org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; import java.io.ByteArrayOutputStream; import java.io.File; @@ -80,8 +80,6 @@ import java.util.Set; import ws.com.google.android.mms.MmsException; -import static org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; /** * Activity to create and update groups diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index 8f1c4c4eec..72c484acd6 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -45,24 +45,25 @@ import ws.com.google.android.mms.ContentType; public class DatabaseFactory { - private static final int INTRODUCED_IDENTITIES_VERSION = 2; - private static final int INTRODUCED_INDEXES_VERSION = 3; - private static final int INTRODUCED_DATE_SENT_VERSION = 4; - private static final int INTRODUCED_DRAFTS_VERSION = 5; - private static final int INTRODUCED_NEW_TYPES_VERSION = 6; - private static final int INTRODUCED_MMS_BODY_VERSION = 7; - private static final int INTRODUCED_MMS_FROM_VERSION = 8; - private static final int INTRODUCED_TOFU_IDENTITY_VERSION = 9; - private static final int INTRODUCED_PUSH_DATABASE_VERSION = 10; - private static final int INTRODUCED_GROUP_DATABASE_VERSION = 11; - private static final int INTRODUCED_PUSH_FIX_VERSION = 12; - private static final int INTRODUCED_DELIVERY_RECEIPTS = 13; - private static final int INTRODUCED_PART_DATA_SIZE_VERSION = 14; - private static final int INTRODUCED_THUMBNAILS_VERSION = 15; - private static final int INTRODUCED_IDENTITY_COLUMN_VERSION = 16; - private static final int INTRODUCED_UNIQUE_PART_IDS_VERSION = 17; - private static final int INTRODUCED_RECIPIENT_PREFS_DB = 18; - private static final int DATABASE_VERSION = 18; + private static final int INTRODUCED_IDENTITIES_VERSION = 2; + private static final int INTRODUCED_INDEXES_VERSION = 3; + private static final int INTRODUCED_DATE_SENT_VERSION = 4; + private static final int INTRODUCED_DRAFTS_VERSION = 5; + private static final int INTRODUCED_NEW_TYPES_VERSION = 6; + private static final int INTRODUCED_MMS_BODY_VERSION = 7; + private static final int INTRODUCED_MMS_FROM_VERSION = 8; + private static final int INTRODUCED_TOFU_IDENTITY_VERSION = 9; + private static final int INTRODUCED_PUSH_DATABASE_VERSION = 10; + private static final int INTRODUCED_GROUP_DATABASE_VERSION = 11; + private static final int INTRODUCED_PUSH_FIX_VERSION = 12; + private static final int INTRODUCED_DELIVERY_RECEIPTS = 13; + private static final int INTRODUCED_PART_DATA_SIZE_VERSION = 14; + private static final int INTRODUCED_THUMBNAILS_VERSION = 15; + private static final int INTRODUCED_IDENTITY_COLUMN_VERSION = 16; + private static final int INTRODUCED_UNIQUE_PART_IDS_VERSION = 17; + private static final int INTRODUCED_RECIPIENT_PREFS_DB = 18; + private static final int INTRODUCED_ENVELOPE_CONTENT_VERSION = 19; + private static final int DATABASE_VERSION = 19; private static final String DATABASE_NAME = "messages.db"; private static final Object lock = new Object(); @@ -737,6 +738,10 @@ public class DatabaseFactory { "notification TEXT DEFAULT NULL, vibrate INTEGER DEFAULT 0, mute_until INTEGER DEFAULT 0)"); } + if (oldVersion < INTRODUCED_ENVELOPE_CONTENT_VERSION) { + db.execSQL("ALTER TABLE push ADD COLUMN content TEXT"); + } + db.setTransactionSuccessful(); db.endTransaction(); } diff --git a/src/org/thoughtcrime/securesms/database/PushDatabase.java b/src/org/thoughtcrime/securesms/database/PushDatabase.java index 2e6854f05a..1328290b75 100644 --- a/src/org/thoughtcrime/securesms/database/PushDatabase.java +++ b/src/org/thoughtcrime/securesms/database/PushDatabase.java @@ -11,6 +11,7 @@ import android.util.Log; import org.thoughtcrime.securesms.util.Base64; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; +import org.whispersystems.textsecure.internal.util.Util; import java.io.IOException; @@ -23,11 +24,12 @@ public class PushDatabase extends Database { public static final String TYPE = "type"; public static final String SOURCE = "source"; public static final String DEVICE_ID = "device_id"; - public static final String BODY = "body"; + public static final String LEGACY_MSG = "body"; + public static final String CONTENT = "content"; public static final String TIMESTAMP = "timestamp"; public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + - TYPE + " INTEGER, " + SOURCE + " TEXT, " + DEVICE_ID + " INTEGER, " + BODY + " TEXT, " + TIMESTAMP + " INTEGER);"; + TYPE + " INTEGER, " + SOURCE + " TEXT, " + DEVICE_ID + " INTEGER, " + LEGACY_MSG + " TEXT, " + CONTENT + " TEXT, " + TIMESTAMP + " INTEGER);"; public PushDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); @@ -43,7 +45,8 @@ public class PushDatabase extends Database { values.put(TYPE, envelope.getType()); values.put(SOURCE, envelope.getSource()); values.put(DEVICE_ID, envelope.getSourceDevice()); - values.put(BODY, Base64.encodeBytes(envelope.getMessage())); + values.put(LEGACY_MSG, envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : ""); + values.put(CONTENT, envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : ""); values.put(TIMESTAMP, envelope.getTimestamp()); return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values); @@ -59,12 +62,16 @@ public class PushDatabase extends Database { null, null, null); if (cursor != null && cursor.moveToNext()) { + String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG)); + String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT)); + return new TextSecureEnvelope(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)), cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)), "", cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)), - Base64.decode(cursor.getString(cursor.getColumnIndexOrThrow(BODY)))); + Util.isEmpty(legacyMessage) ? null : Base64.decode(legacyMessage), + Util.isEmpty(content) ? null : Base64.decode(content)); } } catch (IOException e) { Log.w(TAG, e); @@ -95,12 +102,13 @@ public class PushDatabase extends Database { try { cursor = database.query(TABLE_NAME, null, TYPE + " = ? AND " + SOURCE + " = ? AND " + - DEVICE_ID + " = ? AND " + BODY + " = ? AND " + - TIMESTAMP + " = ?" , + DEVICE_ID + " = ? AND " + LEGACY_MSG + " = ? AND " + + CONTENT + " = ? AND " + TIMESTAMP + " = ?" , new String[] {String.valueOf(envelope.getType()), envelope.getSource(), String.valueOf(envelope.getSourceDevice()), - Base64.encodeBytes(envelope.getMessage()), + envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : "", + envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "", String.valueOf(envelope.getTimestamp())}, null, null, null); @@ -126,13 +134,16 @@ public class PushDatabase extends Database { if (cursor == null || !cursor.moveToNext()) return null; - int type = cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)); - String source = cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)); - int deviceId = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)); - byte[] body = Base64.decode(cursor.getString(cursor.getColumnIndexOrThrow(BODY))); - long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)); + int type = cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)); + String source = cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)); + int deviceId = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)); + String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG)); + String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT)); + long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)); - return new TextSecureEnvelope(type, source, deviceId, "", timestamp, body); + return new TextSecureEnvelope(type, source, deviceId, "", timestamp, + legacyMessage != null ? Base64.decode(legacyMessage) : null, + content != null ? Base64.decode(content) : null); } catch (IOException e) { throw new AssertionError(e); } diff --git a/src/org/thoughtcrime/securesms/dependencies/TextSecureCommunicationModule.java b/src/org/thoughtcrime/securesms/dependencies/TextSecureCommunicationModule.java index 8bf81112d9..c9a4e77d7a 100644 --- a/src/org/thoughtcrime/securesms/dependencies/TextSecureCommunicationModule.java +++ b/src/org/thoughtcrime/securesms/dependencies/TextSecureCommunicationModule.java @@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob; import org.thoughtcrime.securesms.jobs.CleanPreKeysJob; import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob; import org.thoughtcrime.securesms.jobs.DeliveryReceiptJob; +import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.PushMediaSendJob; import org.thoughtcrime.securesms.jobs.PushContentReceiveJob; @@ -37,7 +38,8 @@ import dagger.Provides; AttachmentDownloadJob.class, RefreshPreKeysJob.class, MessageRetrievalService.class, - PushNotificationReceiveJob.class}) + PushNotificationReceiveJob.class, + MultiDeviceContactUpdateJob.class}) public class TextSecureCommunicationModule { private final Context context; diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index e7a68bb56f..41a0d59d3c 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -21,7 +21,7 @@ import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; +import org.whispersystems.textsecure.api.messages.TextSecureDataMessage; import java.util.HashSet; import java.util.LinkedList; @@ -29,8 +29,8 @@ import java.util.List; import java.util.Set; import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.AttachmentPointer; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; +import static org.whispersystems.textsecure.internal.push.TextSecureProtos.AttachmentPointer; +import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; public class GroupMessageProcessor { @@ -39,7 +39,7 @@ public class GroupMessageProcessor { public static void process(Context context, MasterSecret masterSecret, TextSecureEnvelope envelope, - TextSecureMessage message) + TextSecureDataMessage message) { if (!message.getGroupInfo().isPresent() || message.getGroupInfo().get().getGroupId() == null) { Log.w(TAG, "Received group message with no id! Ignoring..."); diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java new file mode 100644 index 0000000000..9756362979 --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -0,0 +1,165 @@ +package org.thoughtcrime.securesms.jobs; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; +import android.util.Log; + +import org.thoughtcrime.securesms.contacts.ContactAccessor; +import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.dependencies.InjectableType; +import org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule.TextSecureMessageSenderFactory; +import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; +import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.jobqueue.JobParameters; +import org.whispersystems.jobqueue.requirements.NetworkRequirement; +import org.whispersystems.libaxolotl.util.guava.Optional; +import org.whispersystems.textsecure.api.TextSecureMessageSender; +import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; +import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream; +import org.whispersystems.textsecure.api.messages.multidevice.DeviceContact; +import org.whispersystems.textsecure.api.messages.multidevice.DeviceContactsOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; + +import javax.inject.Inject; + +public class MultiDeviceContactUpdateJob extends MasterSecretJob implements InjectableType { + + private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName(); + + @Inject transient TextSecureMessageSenderFactory messageSenderFactory; + + public MultiDeviceContactUpdateJob(Context context) { + super(context, JobParameters.newBuilder() + .withRequirement(new NetworkRequirement(context)) + .withRequirement(new MasterSecretRequirement(context)) + .withGroupId(MultiDeviceContactUpdateJob.class.getSimpleName()) + .withPersistence() + .create()); + } + + @Override + public void onRun(MasterSecret masterSecret) + throws IOException, UntrustedIdentityException, NetworkException + { + TextSecureMessageSender messageSender = messageSenderFactory.create(masterSecret); + File contactDataFile = createTempFile("multidevice-contact-update"); + + try { + DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile)); + Collection contacts = ContactAccessor.getInstance().getContactsWithPush(context); + + for (ContactData contactData : contacts) { + Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id)); + String number = contactData.numbers.get(0).number; + Optional name = Optional.fromNullable(contactData.name); + + out.write(new DeviceContact(number, name, getAvatar(contactUri))); + } + + out.close(); + sendUpdate(messageSender, contactDataFile); + + } finally { + if (contactDataFile != null) contactDataFile.delete(); + } + } + + @Override + public boolean onShouldRetryThrowable(Exception exception) { + if (exception instanceof NetworkException) return true; + return false; + } + + @Override + public void onAdded() { + + } + + @Override + public void onCanceled() { + + } + + private void sendUpdate(TextSecureMessageSender messageSender, File contactsFile) + throws IOException, UntrustedIdentityException, NetworkException + { + FileInputStream contactsFileStream = new FileInputStream(contactsFile); + TextSecureAttachmentStream attachmentStream = new TextSecureAttachmentStream(contactsFileStream, + "application/octet-stream", + contactsFile.length()); + + try { + messageSender.sendMultiDeviceContactsUpdate(attachmentStream); + } catch (IOException ioe) { + throw new NetworkException(ioe); + } + } + + private Optional getAvatar(Uri uri) throws IOException { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + try { + Uri displayPhotoUri = Uri.withAppendedPath(uri, ContactsContract.Contacts.Photo.DISPLAY_PHOTO); + AssetFileDescriptor fd = context.getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r"); + return Optional.of(new TextSecureAttachmentStream(fd.createInputStream(), "image/*", fd.getLength())); + } catch (IOException e) { + Log.w(TAG, e); + } + } + + Uri photoUri = Uri.withAppendedPath(uri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY); + + if (photoUri == null) { + return Optional.absent(); + } + + Cursor cursor = context.getContentResolver().query(photoUri, + new String[] { + ContactsContract.CommonDataKinds.Photo.PHOTO, + ContactsContract.CommonDataKinds.Phone.MIMETYPE + }, null, null, null); + + try { + if (cursor != null && cursor.moveToNext()) { + byte[] data = cursor.getBlob(0); + + if (data != null) { + return Optional.of(new TextSecureAttachmentStream(new ByteArrayInputStream(data), "image/*", data.length)); + } + } + + return Optional.absent(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + private File createTempFile(String prefix) throws IOException { + File file = File.createTempFile(prefix, "tmp", context.getCacheDir()); + file.deleteOnExit(); + + return file; + } + + private static class NetworkException extends Exception { + + public NetworkException(Exception ioe) { + super(ioe); + } + } + +} diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index ac1f503a65..a3f1c88ac9 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -46,10 +46,12 @@ import org.whispersystems.libaxolotl.state.AxolotlStore; import org.whispersystems.libaxolotl.state.SessionStore; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.crypto.TextSecureCipher; +import org.whispersystems.textsecure.api.messages.TextSecureContent; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; -import org.whispersystems.textsecure.api.messages.TextSecureSyncContext; +import org.whispersystems.textsecure.api.messages.TextSecureDataMessage; +import org.whispersystems.textsecure.api.messages.multidevice.SentTranscriptMessage; +import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage; import org.whispersystems.textsecure.api.push.TextSecureAddress; import java.util.concurrent.TimeUnit; @@ -112,12 +114,20 @@ public class PushDecryptJob extends MasterSecretJob { TextSecureAddress localAddress = new TextSecureAddress(TextSecurePreferences.getLocalNumber(context)); TextSecureCipher cipher = new TextSecureCipher(localAddress, axolotlStore); - TextSecureMessage message = cipher.decrypt(envelope); + TextSecureContent content = cipher.decrypt(envelope); - if (message.isEndSession()) handleEndSessionMessage(masterSecret, envelope, message, smsMessageId); - else if (message.isGroupUpdate()) handleGroupMessage(masterSecret, envelope, message, smsMessageId); - else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, envelope, message, smsMessageId); - else handleTextMessage(masterSecret, envelope, message, smsMessageId); + if (content.getDataMessage().isPresent()) { + TextSecureDataMessage message = content.getDataMessage().get(); + + if (message.isEndSession()) handleEndSessionMessage(masterSecret, envelope, message, smsMessageId); + else if (message.isGroupUpdate()) handleGroupMessage(masterSecret, envelope, message, smsMessageId); + else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, envelope, message, smsMessageId); + else handleTextMessage(masterSecret, envelope, message, smsMessageId); + } else if (content.getSyncMessage().isPresent()) { + TextSecureSyncMessage syncMessage = content.getSyncMessage().get(); + + if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(masterSecret, syncMessage.getSent().get(), smsMessageId); + } if (envelope.isPreKeyWhisperMessage()) { ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context)); @@ -144,7 +154,7 @@ public class PushDecryptJob extends MasterSecretJob { } private void handleEndSessionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, - TextSecureMessage message, Optional smsMessageId) + TextSecureDataMessage message, Optional smsMessageId) { EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context); IncomingTextMessage incomingTextMessage = new IncomingTextMessage(envelope.getSource(), @@ -170,7 +180,7 @@ public class PushDecryptJob extends MasterSecretJob { MessageNotifier.updateNotification(context, masterSecret, threadId); } - private void handleGroupMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureMessage message, Optional smsMessageId) { + private void handleGroupMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureDataMessage message, Optional smsMessageId) { GroupMessageProcessor.process(context, masterSecret, envelope, message); if (smsMessageId.isPresent()) { @@ -178,17 +188,30 @@ public class PushDecryptJob extends MasterSecretJob { } } - private void handleMediaMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, - TextSecureMessage message, Optional smsMessageId) + private void handleSynchronizeSentMessage(MasterSecret masterSecret, SentTranscriptMessage message, Optional smsMessageId) throws MmsException { - Pair messageAndThreadId; - - if (message.getSyncContext().isPresent()) { - messageAndThreadId = insertSyncMediaMessage(masterSecret, envelope, message); + if (message.getMessage().getAttachments().isPresent()) { + handleSynchronizeSentMediaMessage(masterSecret, message, smsMessageId); } else { - messageAndThreadId = insertStandardMediaMessage(masterSecret, envelope, message); + handleSynchronizeSentTextMessage(masterSecret, message, smsMessageId); } + } + + private void handleMediaMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, + TextSecureDataMessage message, Optional smsMessageId) + throws MmsException + { + MmsDatabase database = DatabaseFactory.getMmsDatabase(context); + String localNumber = TextSecurePreferences.getLocalNumber(context); + IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(), + localNumber, message.getTimestamp(), + Optional.fromNullable(envelope.getRelay()), + message.getBody(), + message.getGroupInfo(), + message.getAttachments()); + + Pair messageAndThreadId = database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1); ApplicationContext.getInstance(context) .getJobManager() @@ -201,20 +224,79 @@ public class PushDecryptJob extends MasterSecretJob { MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleTextMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, - TextSecureMessage message, Optional smsMessageId) + private void handleSynchronizeSentMediaMessage(MasterSecret masterSecret, + SentTranscriptMessage message, + Optional smsMessageId) + throws MmsException { + MmsDatabase database = DatabaseFactory.getMmsDatabase(context); + Recipients recipients = getSyncMessageDestination(message); + OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(context, masterSecret, recipients, + message.getMessage().getAttachments().get(), + message.getMessage().getBody().orNull()); + + mediaMessage = new OutgoingSecureMediaMessage(mediaMessage); + + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); + long messageId = database.insertMessageOutbox(masterSecret, mediaMessage, threadId, false, message.getTimestamp()); + + database.markAsSent(messageId, "push".getBytes(), 0); + database.markAsPush(messageId); + + ApplicationContext.getInstance(context) + .getJobManager() + .add(new AttachmentDownloadJob(context, messageId)); + + if (smsMessageId.isPresent()) { + DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get()); + } + } + + private void handleTextMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, + TextSecureDataMessage message, Optional smsMessageId) + { + EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); + String body = message.getBody().isPresent() ? message.getBody().get() : ""; + Pair messageAndThreadId; - if (message.getSyncContext().isPresent()) { - messageAndThreadId = insertSyncTextMessage(masterSecret, envelope, message, smsMessageId); + if (smsMessageId.isPresent()) { + messageAndThreadId = database.updateBundleMessageBody(masterSecret, smsMessageId.get(), body); } else { - messageAndThreadId = insertStandardTextMessage(masterSecret, envelope, message, smsMessageId); + IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), + envelope.getSourceDevice(), + message.getTimestamp(), body, + message.getGroupInfo()); + + textMessage = new IncomingEncryptedMessage(textMessage, body); + + messageAndThreadId = database.insertMessageInbox(masterSecret, textMessage); } MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } + private void handleSynchronizeSentTextMessage(MasterSecret masterSecret, + SentTranscriptMessage message, + Optional smsMessageId) + { + EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); + Recipients recipients = getSyncMessageDestination(message); + String body = message.getMessage().getBody().or(""); + OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body); + + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); + long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getTimestamp()); + + database.markAsSent(messageId); + database.markAsPush(messageId); + database.markAsSecure(messageId); + + if (smsMessageId.isPresent()) { + database.deleteMessage(smsMessageId.get()); + } + } + private void handleInvalidVersionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, Optional smsMessageId) { EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context); @@ -281,9 +363,9 @@ public class PushDecryptJob extends MasterSecretJob { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false); long recipientId = recipients.getPrimaryRecipient().getRecipientId(); - PreKeyWhisperMessage whisperMessage = new PreKeyWhisperMessage(envelope.getMessage()); + PreKeyWhisperMessage whisperMessage = new PreKeyWhisperMessage(envelope.getLegacyMessage()); IdentityKey identityKey = whisperMessage.getIdentityKey(); - String encoded = Base64.encodeBytes(envelope.getMessage()); + String encoded = Base64.encodeBytes(envelope.getLegacyMessage()); IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), encoded, Optional.absent()); @@ -316,97 +398,11 @@ public class PushDecryptJob extends MasterSecretJob { return database.insertMessageInbox(masterSecret, textMessage); } - private Pair insertSyncTextMessage(MasterSecret masterSecret, - TextSecureEnvelope envelope, - TextSecureMessage message, - Optional smsMessageId) - { - EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); - Recipients recipients = getSyncMessageDestination(message); - String body = message.getBody().or(""); - OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body); - - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); - long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getSyncContext().get().getTimestamp()); - - database.markAsSent(messageId); - database.markAsPush(messageId); - database.markAsSecure(messageId); - - if (smsMessageId.isPresent()) { - database.deleteMessage(smsMessageId.get()); - } - - return new Pair<>(messageId, threadId); - } - - private Pair insertStandardTextMessage(MasterSecret masterSecret, - TextSecureEnvelope envelope, - TextSecureMessage message, - Optional smsMessageId) - { - EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); - String body = message.getBody().isPresent() ? message.getBody().get() : ""; - - if (smsMessageId.isPresent()) { - return database.updateBundleMessageBody(masterSecret, smsMessageId.get(), body); + private Recipients getSyncMessageDestination(SentTranscriptMessage message) { + if (message.getMessage().getGroupInfo().isPresent()) { + return RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId()), false); } else { - IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), - envelope.getSourceDevice(), - message.getTimestamp(), body, - message.getGroupInfo()); - - textMessage = new IncomingEncryptedMessage(textMessage, body); - - return database.insertMessageInbox(masterSecret, textMessage); - } - } - - private Pair insertSyncMediaMessage(MasterSecret masterSecret, - TextSecureEnvelope envelope, - TextSecureMessage message) - throws MmsException - { - MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - TextSecureSyncContext syncContext = message.getSyncContext().get(); - Recipients recipients = getSyncMessageDestination(message); - OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(context, masterSecret, recipients, - message.getAttachments().get(), - message.getBody().orNull()); - - mediaMessage = new OutgoingSecureMediaMessage(mediaMessage); - - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); - long messageId = database.insertMessageOutbox(masterSecret, mediaMessage, threadId, false, syncContext.getTimestamp()); - - database.markAsSent(messageId, "push".getBytes(), 0); - database.markAsPush(messageId); - - return new Pair<>(messageId, threadId); - } - - private Pair insertStandardMediaMessage(MasterSecret masterSecret, - TextSecureEnvelope envelope, - TextSecureMessage message) - throws MmsException - { - MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - String localNumber = TextSecurePreferences.getLocalNumber(context); - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(), - localNumber, message.getTimestamp(), - Optional.fromNullable(envelope.getRelay()), - message.getBody(), - message.getGroupInfo(), - message.getAttachments()); - - return database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1); - } - - private Recipients getSyncMessageDestination(TextSecureMessage message) { - if (message.getGroupInfo().isPresent()) { - return RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId()), false); - } else { - return RecipientFactory.getRecipientsFromString(context, message.getSyncContext().get().getDestination(), false); + return RecipientFactory.getRecipientsFromString(context, message.getDestination().get(), false); } } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index b7e7746670..c5684f0bac 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -26,12 +26,12 @@ import org.whispersystems.textsecure.api.TextSecureMessageSender; import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; +import org.whispersystems.textsecure.api.messages.TextSecureDataMessage; import org.whispersystems.textsecure.api.push.TextSecureAddress; import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions; import org.whispersystems.textsecure.api.push.exceptions.NetworkFailureException; import org.whispersystems.textsecure.api.util.InvalidNumberException; -import org.whispersystems.textsecure.internal.push.PushMessageProtos; +import org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; import java.io.IOException; import java.util.LinkedList; @@ -148,18 +148,18 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { String content = PartParser.getMessageText(message.getBody()); if (content != null && !content.trim().isEmpty()) { - PushMessageProtos.PushMessageContent.GroupContext groupContext = PushMessageProtos.PushMessageContent.GroupContext.parseFrom(Base64.decode(content)); - TextSecureAttachment avatar = attachments.isEmpty() ? null : attachments.get(0); - TextSecureGroup.Type type = MmsSmsColumns.Types.isGroupQuit(message.getDatabaseMessageBox()) ? TextSecureGroup.Type.QUIT : TextSecureGroup.Type.UPDATE; - TextSecureGroup group = new TextSecureGroup(type, groupId, groupContext.getName(), groupContext.getMembersList(), avatar); - TextSecureMessage groupMessage = new TextSecureMessage(message.getSentTimestamp(), group, null, null); + GroupContext groupContext = GroupContext.parseFrom(Base64.decode(content)); + TextSecureAttachment avatar = attachments.isEmpty() ? null : attachments.get(0); + TextSecureGroup.Type type = MmsSmsColumns.Types.isGroupQuit(message.getDatabaseMessageBox()) ? TextSecureGroup.Type.QUIT : TextSecureGroup.Type.UPDATE; + TextSecureGroup group = new TextSecureGroup(type, groupId, groupContext.getName(), groupContext.getMembersList(), avatar); + TextSecureDataMessage groupMessage = new TextSecureDataMessage(message.getSentTimestamp(), group, null, null); messageSender.sendMessage(addresses, groupMessage); } } else { - String body = PartParser.getMessageText(message.getBody()); - TextSecureGroup group = new TextSecureGroup(groupId); - TextSecureMessage groupMessage = new TextSecureMessage(message.getSentTimestamp(), group, attachments, body); + String body = PartParser.getMessageText(message.getBody()); + TextSecureGroup group = new TextSecureGroup(groupId); + TextSecureDataMessage groupMessage = new TextSecureDataMessage(message.getSentTimestamp(), group, attachments, body); messageSender.sendMessage(addresses, groupMessage); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 38f171877d..467b9a059d 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -19,7 +19,7 @@ import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.whispersystems.textsecure.api.TextSecureMessageSender; import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; +import org.whispersystems.textsecure.api.messages.TextSecureDataMessage; import org.whispersystems.textsecure.api.push.TextSecureAddress; import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException; import org.whispersystems.textsecure.api.util.InvalidNumberException; @@ -109,11 +109,11 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { TextSecureAddress address = getPushAddress(destination); List attachments = getAttachments(masterSecret, message); String body = PartParser.getMessageText(message.getBody()); - TextSecureMessage mediaMessage = TextSecureMessage.newBuilder() - .withBody(body) - .withAttachments(attachments) - .withTimestamp(message.getSentTimestamp()) - .build(); + TextSecureDataMessage mediaMessage = TextSecureDataMessage.newBuilder() + .withBody(body) + .withAttachments(attachments) + .withTimestamp(message.getSentTimestamp()) + .build(); messageSender.sendMessage(address, mediaMessage); } catch (InvalidNumberException | UnregisteredUserException e) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 779630f238..1c2373d391 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.whispersystems.textsecure.api.TextSecureMessageSender; import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; +import org.whispersystems.textsecure.api.messages.TextSecureDataMessage; import org.whispersystems.textsecure.api.push.TextSecureAddress; import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException; import org.whispersystems.textsecure.api.util.InvalidNumberException; @@ -103,11 +103,11 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { try { TextSecureAddress address = getPushAddress(message.getIndividualRecipient().getNumber()); TextSecureMessageSender messageSender = messageSenderFactory.create(masterSecret); - TextSecureMessage textSecureMessage = TextSecureMessage.newBuilder() - .withTimestamp(message.getDateSent()) - .withBody(message.getBody().getBody()) - .asEndSessionMessage(message.isEndSession()) - .build(); + TextSecureDataMessage textSecureMessage = TextSecureDataMessage.newBuilder() + .withTimestamp(message.getDateSent()) + .withBody(message.getBody().getBody()) + .asEndSessionMessage(message.isEndSession()) + .build(); messageSender.sendMessage(address, textSecureMessage); diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java index 2033e788b5..37b50c3474 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java @@ -5,13 +5,12 @@ import android.content.Context; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.Base64; +import org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; import ws.com.google.android.mms.ContentType; import ws.com.google.android.mms.pdu.PduBody; import ws.com.google.android.mms.pdu.PduPart; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; - public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { private final GroupContext group; diff --git a/src/org/thoughtcrime/securesms/sms/IncomingGroupMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingGroupMessage.java index c9f971fda1..5fdcf9dcca 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingGroupMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingGroupMessage.java @@ -1,6 +1,6 @@ package org.thoughtcrime.securesms.sms; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; +import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; public class IncomingGroupMessage extends IncomingTextMessage { diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index d189f6a8e2..465e887f92 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -9,7 +9,7 @@ import java.io.IOException; import java.util.List; import org.thoughtcrime.securesms.R; -import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext; +import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext; public class GroupUtil {