diff --git a/app/src/main/java/org/thoughtcrime/securesms/InviteActivity.java b/app/src/main/java/org/thoughtcrime/securesms/InviteActivity.java index 850431c458..28c0907082 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/InviteActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/InviteActivity.java @@ -28,10 +28,10 @@ import org.thoughtcrime.securesms.contacts.SelectedContact; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.groups.SelectionLimits; import org.thoughtcrime.securesms.keyvalue.SignalStore; +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.DynamicNoActionBarInviteTheme; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Util; @@ -254,7 +254,7 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac Recipient recipient = Recipient.resolved(recipientId); int subscriptionId = recipient.getDefaultSubscriptionId().orElse(-1); - MessageSender.send(context, new OutgoingTextMessage(recipient, message, subscriptionId), -1L, true, null, null); + MessageSender.send(context, OutgoingMediaMessage.sms(recipient, message, subscriptionId), -1L, true, null, null); if (recipient.getContactUri() != null) { SignalDatabase.recipients().setHasSentInvite(recipient.getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt index 737861e116..a5075cd281 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt @@ -20,10 +20,10 @@ import org.thoughtcrime.securesms.database.model.RecipientRecord import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientForeverObserver import org.thoughtcrime.securesms.recipients.RecipientId -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage import org.thoughtcrime.securesms.subscription.Subscriber import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.FeatureFlags @@ -243,10 +243,9 @@ class InternalConversationSettingsFragment : DSLSettingsFragment( val splitThreadId: Long = SignalDatabase.threads.getOrCreateThreadIdFor(splitRecipient) val messageId: Long = SignalDatabase.sms.insertMessageOutbox( + OutgoingMediaMessage.text(splitRecipient, "Test Message ${System.currentTimeMillis()}", 0), splitThreadId, - OutgoingEncryptedMessage(splitRecipient, "Test Message ${System.currentTimeMillis()}", 0), false, - System.currentTimeMillis(), null ) SignalDatabase.sms.markAsSent(messageId, true) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index eafbab58ce..e4d3fe8c9e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -163,7 +163,6 @@ import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity; import org.thoughtcrime.securesms.revealable.ViewOnceUtil; import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.stickers.StickerPackPreviewActivity; import org.thoughtcrime.securesms.stories.Stories; @@ -1206,17 +1205,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect return messageRecord.getId(); } - public long stageOutgoingMessage(OutgoingTextMessage message, long messageId) { - MessageRecord messageRecord = MessageTable.readerFor(message, threadId, messageId).getCurrent(); - - if (getListAdapter() != null) { - setLastSeen(0); - list.post(() -> list.scrollToPosition(0)); - } - - return messageRecord.getId(); - } - private void presentConversationMetadata(@NonNull ConversationData conversation) { if (conversationData != null && conversationData.getThreadId() == conversation.getThreadId()) { Log.d(TAG, "Already presented conversation data for thread " + threadId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index 56a6bec30d..f3a23640c2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -266,8 +266,6 @@ import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet; import org.thoughtcrime.securesms.search.MessageResult; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stickers.StickerEventListener; import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.stickers.StickerManagementActivity; @@ -3139,13 +3137,13 @@ public class ConversationParentFragment extends Fragment final String messageBody = getMessage(); final boolean sendPush = sendType.usesSignalTransport(); - OutgoingTextMessage message; + OutgoingMediaMessage message; if (sendPush) { - message = new OutgoingEncryptedMessage(recipient.get(), messageBody, expiresIn); + message = OutgoingMediaMessage.text(recipient.get(), messageBody, expiresIn, System.currentTimeMillis()); ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread); } else { - message = new OutgoingTextMessage(recipient.get(), messageBody, 0, sendType.getSimSubscriptionIdOr(-1)); + message = OutgoingMediaMessage.sms(recipient.get(), messageBody, sendType.getSimSubscriptionIdOr(-1)); } Permissions.with(this) @@ -3153,13 +3151,12 @@ public class ConversationParentFragment extends Fragment .ifNecessary(!sendPush) .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_sms_permission_in_order_to_send_an_sms)) .onAllGranted(() -> { - final long id = new SecureRandom().nextLong(); SimpleTask.run(() -> { return MessageSender.send(context, message, thread, sendType.usesSmsTransport(), metricId, null); }, this::sendComplete); silentlySetComposeText(""); - fragment.stageOutgoingMessage(message, id); + fragment.stageOutgoingMessage(message); }) .execute(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java index e56c584bcd..5a17bfa417 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java @@ -89,7 +89,6 @@ import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo; import org.thoughtcrime.securesms.revealable.ViewOnceUtil; import org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.JsonUtils; @@ -933,57 +932,6 @@ public class MessageTable extends DatabaseTable implements MmsSmsColumns, Recipi return insertMessageInbox(message, Types.BASE_INBOX_TYPE); } - public long insertMessageOutbox(long threadId, OutgoingTextMessage message, boolean forceSms, long date, InsertListener insertListener) { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - - long type = Types.BASE_SENDING_TYPE; - - if (message.isKeyExchange()) type |= Types.KEY_EXCHANGE_BIT; - else if (message.isSecureMessage()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); - else if (message.isEndSession()) type |= Types.END_SESSION_BIT; - if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; - - if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT; - else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT; - - RecipientId recipientId = message.getRecipient().getId(); - Map earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(date); - - ContentValues contentValues = new ContentValues(6); - contentValues.put(RECIPIENT_ID, recipientId.serialize()); - contentValues.put(THREAD_ID, threadId); - contentValues.put(BODY, message.getMessageBody()); - contentValues.put(DATE_RECEIVED, System.currentTimeMillis()); - contentValues.put(DATE_SENT, date); - contentValues.put(READ, 1); - contentValues.put(TYPE, type); - contentValues.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId()); - contentValues.put(EXPIRES_IN, message.getExpiresIn()); - contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum()); - contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1)); - - long messageId = db.insert(TABLE_NAME, null, contentValues); - - if (insertListener != null) { - insertListener.onComplete(); - } - - if (!message.isIdentityVerified() && !message.isIdentityDefault()) { - SignalDatabase.threads().setLastScrolled(threadId, 0); - SignalDatabase.threads().setLastSeenSilently(threadId); - } - - SignalDatabase.threads().setHasSentSilently(threadId, true); - - ApplicationDependencies.getDatabaseObserver().notifyMessageInsertObservers(threadId, new MessageId(messageId, false)); - - if (!message.isIdentityVerified() && !message.isIdentityDefault()) { - TrimThreadJob.enqueueAsync(threadId); - } - - return messageId; - } - public void insertProfileNameChangeMessages(@NonNull Recipient recipient, @NonNull String newProfileName, @NonNull String previousProfileName) { ThreadTable threadTable = SignalDatabase.threads(); List groupRecords = SignalDatabase.groups().getGroupsContainingMember(recipient.getId(), false); @@ -2776,6 +2724,12 @@ public class MessageTable extends DatabaseTable implements MmsSmsColumns, Recipi if (message.isSecure()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; + if (message.isSecure()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); + else if (message.isEndSession()) type |= Types.END_SESSION_BIT; + + if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT; + else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT; + if (message.isGroup()) { if (message.isV2Group()) { type |= Types.GROUP_V2_BIT | Types.GROUP_UPDATE_BIT; @@ -2919,7 +2873,9 @@ public class MessageTable extends DatabaseTable implements MmsSmsColumns, Recipi notifyConversationListListeners(); - TrimThreadJob.enqueueAsync(threadId); + if (!message.isIdentityVerified() && !message.isIdentityDefault()) { + TrimThreadJob.enqueueAsync(threadId); + } return messageId; } @@ -4296,48 +4252,6 @@ public class MessageTable extends DatabaseTable implements MmsSmsColumns, Recipi } } - public static OutgoingSmsReader readerFor(OutgoingTextMessage message, long threadId, long messageId) { - return new OutgoingSmsReader(message, threadId, messageId); - } - - public static class OutgoingSmsReader { - - private final OutgoingTextMessage message; - private final long id; - private final long threadId; - - public OutgoingSmsReader(OutgoingTextMessage message, long threadId, long messageId) { - this.message = message; - this.threadId = threadId; - this.id = messageId; - } - - public MessageRecord getCurrent() { - return new SmsMessageRecord(id, - message.getMessageBody(), - message.getRecipient(), - message.getRecipient(), - 1, - System.currentTimeMillis(), - System.currentTimeMillis(), - -1, - 0, - message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(), - threadId, - 0, - new HashSet<>(), - message.getSubscriptionId(), - message.getExpiresIn(), - System.currentTimeMillis(), - 0, - false, - Collections.emptyList(), - false, - 0, - -1); - } - } - public static class MmsStatus { public static final int DOWNLOAD_INITIALIZED = 1; public static final int DOWNLOAD_NO_CONNECTIVITY = 2; diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index 8a09899070..7bd3e0af85 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.jobs.PushDecryptMessageJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.PushMediaSendJob; import org.thoughtcrime.securesms.jobs.PushProcessMessageJob; -import org.thoughtcrime.securesms.jobs.PushTextSendJob; import org.thoughtcrime.securesms.jobs.ReactionSendJob; import org.thoughtcrime.securesms.jobs.TypingSendJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; @@ -181,7 +180,7 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr .setJobStorage(new FastJobStorage(JobDatabase.getInstance(context))) .setJobMigrator(new JobMigrator(TextSecurePreferences.getJobManagerVersion(context), JobManager.CURRENT_VERSION, JobManagerFactories.getJobMigrations(context))) .addReservedJobRunner(new FactoryJobPredicate(PushDecryptMessageJob.KEY, PushProcessMessageJob.KEY, MarkerJob.KEY)) - .addReservedJobRunner(new FactoryJobPredicate(PushTextSendJob.KEY, PushMediaSendJob.KEY, PushGroupSendJob.KEY, ReactionSendJob.KEY, TypingSendJob.KEY, GroupCallUpdateSendJob.KEY)) + .addReservedJobRunner(new FactoryJobPredicate(PushMediaSendJob.KEY, PushGroupSendJob.KEY, ReactionSendJob.KEY, TypingSendJob.KEY, GroupCallUpdateSendJob.KEY)) .build(); return new JobManager(context, config); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/insights/InsightsRepository.java b/app/src/main/java/org/thoughtcrime/securesms/insights/InsightsRepository.java index e710dc90a6..a63a6f30d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/insights/InsightsRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/insights/InsightsRepository.java @@ -13,10 +13,10 @@ import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto; import org.thoughtcrime.securesms.database.MmsSmsTable; import org.thoughtcrime.securesms.database.RecipientTable; import org.thoughtcrime.securesms.database.SignalDatabase; +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.Util; import org.signal.core.util.concurrent.SimpleTask; @@ -36,7 +36,7 @@ public class InsightsRepository implements InsightsDashboardViewModel.Repository SimpleTask.run(() -> { MmsSmsTable mmsSmsDatabase = SignalDatabase.mmsSms(); int insecure = mmsSmsDatabase.getInsecureMessageCountForInsights(); - int secure = mmsSmsDatabase.getSecureMessageCountForInsights(); + int secure = mmsSmsDatabase.getSecureMessageCountForInsights(); if (insecure + secure == 0) { return new InsightsData(false, 0); @@ -78,7 +78,7 @@ public class InsightsRepository implements InsightsDashboardViewModel.Repository int subscriptionId = resolved.getDefaultSubscriptionId().orElse(-1); String message = context.getString(R.string.InviteActivity_lets_switch_to_signal, context.getString(R.string.install_url)); - MessageSender.send(context, new OutgoingTextMessage(resolved, message, subscriptionId), -1L, true, null, null); + MessageSender.send(context, OutgoingMediaMessage.sms(resolved, message, subscriptionId), -1L, true, null, null); RecipientTable database = SignalDatabase.recipients(); database.setHasSentInvite(recipient.getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 8adf9731a5..40372a2347 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -155,7 +155,6 @@ public final class JobManagerFactories { put(PushNotificationReceiveJob.KEY, new PushNotificationReceiveJob.Factory()); put(PushProcessEarlyMessagesJob.KEY, new PushProcessEarlyMessagesJob.Factory()); put(PushProcessMessageJob.KEY, new PushProcessMessageJob.Factory()); - put(PushTextSendJob.KEY, new PushTextSendJob.Factory()); put(ReactionSendJob.KEY, new ReactionSendJob.Factory()); put(RefreshAttributesJob.KEY, new RefreshAttributesJob.Factory()); put(RefreshOwnProfileJob.KEY, new RefreshOwnProfileJob.Factory()); @@ -254,6 +253,7 @@ public final class JobManagerFactories { put("CreateSignedPreKeyJob", new PreKeysSyncJob.Factory()); put("RefreshPreKeysJob", new PreKeysSyncJob.Factory()); put("RecipientChangedNumberJob", new FailingJob.Factory()); + put("PushTextSendJob", new PushMediaSendJob.Factory()); }}; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 28b7b32c73..458bc754ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -229,6 +229,7 @@ public class PushMediaSendJob extends PushSendJob { .withPreviews(previews) .withGiftBadge(giftBadge) .asExpirationUpdate(message.isExpirationUpdate()) + .asEndSessionMessage(message.isEndSession()) .withPayment(payment); if (message.getParentStoryId() != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java deleted file mode 100644 index 616a5bf2bb..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ /dev/null @@ -1,252 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - -import androidx.annotation.NonNull; - -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; -import org.thoughtcrime.securesms.database.MessageTable; -import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId; -import org.thoughtcrime.securesms.database.NoSuchMessageException; -import org.thoughtcrime.securesms.database.RecipientTable.UnidentifiedAccessMode; -import org.thoughtcrime.securesms.database.SignalDatabase; -import org.thoughtcrime.securesms.database.model.MessageId; -import org.thoughtcrime.securesms.database.model.SmsMessageRecord; -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.Data; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.thoughtcrime.securesms.notifications.v2.ConversationId; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientId; -import org.thoughtcrime.securesms.recipients.RecipientUtil; -import org.thoughtcrime.securesms.service.ExpiringMessageManager; -import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; -import org.thoughtcrime.securesms.transport.RetryLaterException; -import org.thoughtcrime.securesms.transport.UndeliverableMessageException; -import org.thoughtcrime.securesms.util.SignalLocalMetrics; -import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.signalservice.api.SignalServiceMessageSender; -import org.whispersystems.signalservice.api.crypto.ContentHint; -import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; -import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; -import org.whispersystems.signalservice.api.messages.SendMessageResult; -import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; -import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; - -import java.io.IOException; -import java.util.Optional; - -public class PushTextSendJob extends PushSendJob { - - public static final String KEY = "PushTextSendJob"; - - private static final String TAG = Log.tag(PushTextSendJob.class); - - private static final String KEY_MESSAGE_ID = "message_id"; - - private final long messageId; - - public PushTextSendJob(long messageId, @NonNull Recipient recipient) { - this(constructParameters(recipient, false), messageId); - } - - private PushTextSendJob(@NonNull Job.Parameters parameters, long messageId) { - super(parameters); - this.messageId = messageId; - } - - @Override - public @NonNull Data serialize() { - return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId).build(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onAdded() { - SignalDatabase.sms().markAsSending(messageId); - } - - @Override - public void onPushSend() throws IOException, NoSuchMessageException, UndeliverableMessageException, RetryLaterException { - SignalLocalMetrics.IndividualMessageSend.onJobStarted(messageId); - - ExpiringMessageManager expirationManager = ApplicationDependencies.getExpiringMessageManager(); - MessageTable database = SignalDatabase.sms(); - SmsMessageRecord record = database.getSmsMessage(messageId); - - if (!record.isPending() && !record.isFailed()) { - warn(TAG, String.valueOf(record.getDateSent()), "Message " + messageId + " was already sent. Ignoring."); - return; - } - - try { - log(TAG, String.valueOf(record.getDateSent()), "Sending message: " + messageId + ", Recipient: " + record.getRecipient().getId() + ", Thread: " + record.getThreadId()); - - RecipientUtil.shareProfileIfFirstSecureMessage(record.getRecipient()); - - Recipient recipient = record.getRecipient().resolve(); - byte[] profileKey = recipient.getProfileKey(); - UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode(); - - boolean unidentified = deliver(record); - - database.markAsSent(messageId, true); - database.markUnidentified(messageId, unidentified); - - if (recipient.isSelf()) { - SyncMessageId id = new SyncMessageId(recipient.getId(), record.getDateSent()); - SignalDatabase.mmsSms().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.mmsSms().incrementReadReceiptCount(id, System.currentTimeMillis()); - } - - if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { - log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-unrestricted following a UD send."); - SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.UNRESTRICTED); - } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) { - log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-enabled following a UD send."); - SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.ENABLED); - } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) { - log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-disabled following a non-UD send."); - SignalDatabase.recipients().setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.DISABLED); - } - - if (record.getExpiresIn() > 0) { - database.markExpireStarted(messageId); - expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn()); - } - - log(TAG, String.valueOf(record.getDateSent()), "Sent message: " + messageId); - - } catch (InsecureFallbackApprovalException e) { - warn(TAG, String.valueOf(record.getDateSent()), "Failure", e); - database.markAsPendingInsecureSmsFallback(record.getId()); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getRecipient(), ConversationId.forConversation(record.getThreadId())); - ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(false)); - } catch (UntrustedIdentityException e) { - warn(TAG, String.valueOf(record.getDateSent()), "Failure", e); - RecipientId recipientId = Recipient.external(context, e.getIdentifier()).getId(); - database.addMismatchedIdentity(record.getId(), recipientId, e.getIdentityKey()); - database.markAsSentFailed(record.getId()); - database.markAsPush(record.getId()); - RetrieveProfileJob.enqueue(recipientId); - } catch (ProofRequiredException e) { - handleProofRequiredException(context, e, record.getRecipient(), record.getThreadId(), messageId, false); - } - - SignalLocalMetrics.IndividualMessageSend.onJobFinished(messageId); - } - - @Override - public void onRetry() { - SignalLocalMetrics.IndividualMessageSend.cancel(messageId); - super.onRetry(); - } - - @Override - public void onFailure() { - SignalDatabase.sms().markAsSentFailed(messageId); - - long threadId = SignalDatabase.sms().getThreadIdForMessage(messageId); - Recipient recipient = SignalDatabase.threads().getRecipientForThreadId(threadId); - - if (threadId != -1 && recipient != null) { - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, recipient, ConversationId.forConversation(threadId)); - } - } - - private boolean deliver(SmsMessageRecord message) - throws UntrustedIdentityException, InsecureFallbackApprovalException, UndeliverableMessageException, IOException - { - try { - rotateSenderCertificateIfNecessary(); - - Recipient messageRecipient = message.getIndividualRecipient().resolve(); - - if (messageRecipient.isUnregistered()) { - throw new UndeliverableMessageException(messageRecipient.getId() + " not registered!"); - } - - SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender(); - SignalServiceAddress address = RecipientUtil.toSignalServiceAddress(context, messageRecipient); - Optional profileKey = getProfileKey(messageRecipient); - Optional unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, messageRecipient); - - log(TAG, String.valueOf(message.getDateSent()), "Have access key to use: " + unidentifiedAccess.isPresent()); - - SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder() - .withTimestamp(message.getDateSent()) - .withBody(message.getBody()) - .withExpiration((int)(message.getExpiresIn() / 1000)) - .withProfileKey(profileKey.orElse(null)) - .asEndSessionMessage(message.isEndSession()) - .build(); - - if (Util.equals(SignalStore.account().getAci(), address.getServiceId())) { - Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); - - SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId); - SendMessageResult result = messageSender.sendSyncMessage(textSecureMessage); - - SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false), false); - return syncAccess.isPresent(); - } else { - SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId); - SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage, new MetricEventListener(messageId), true, messageRecipient.needsPniSignature()); - - SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false), true); - - if (messageRecipient.needsPniSignature()) { - SignalDatabase.pendingPniSignatureMessages().insertIfNecessary(messageRecipient.getId(), message.getDateSent(), result); - } - - return result.getSuccess().isUnidentified(); - } - } catch (UnregisteredUserException e) { - warn(TAG, "Failure", e); - throw new InsecureFallbackApprovalException(e); - } catch (ServerRejectedException e) { - throw new UndeliverableMessageException(e); - } - } - - public static long getMessageId(@NonNull Data data) { - return data.getLong(KEY_MESSAGE_ID); - } - - private static class MetricEventListener implements SignalServiceMessageSender.IndividualSendEvents { - private final long messageId; - - private MetricEventListener(long messageId) { - this.messageId = messageId; - } - - @Override - public void onMessageEncrypted() { - SignalLocalMetrics.IndividualMessageSend.onMessageEncrypted(messageId); - } - - @Override - public void onMessageSent() { - SignalLocalMetrics.IndividualMessageSend.onMessageSent(messageId); - } - - @Override - public void onSyncMessageSent() { - SignalLocalMetrics.IndividualMessageSend.onSyncMessageSent(messageId); - } - } - - public static class Factory implements Job.Factory { - @Override - public @NonNull PushTextSendJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new PushTextSendJob(parameters, data.getLong(KEY_MESSAGE_ID)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index a0208b02c7..11316c05eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -120,9 +120,6 @@ import org.thoughtcrime.securesms.service.webrtc.WebRtcData; import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage; import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; -import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.storage.StorageSyncHelper; import org.thoughtcrime.securesms.stories.Stories; @@ -772,14 +769,13 @@ public final class MessageContentProcessor { } private long handleSynchronizeSentEndSessionMessage(@NonNull SentTranscriptMessage message, long envelopeTimestamp) - throws BadGroupIdException + throws MmsException { log(envelopeTimestamp, "Synchronize end session message."); - MessageTable database = SignalDatabase.sms(); - Recipient recipient = getSyncMessageDestination(message); - OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, "", -1); - OutgoingEndSessionMessage outgoingEndSessionMessage = new OutgoingEndSessionMessage(outgoingTextMessage); + MessageTable database = SignalDatabase.sms(); + Recipient recipient = getSyncMessageDestination(message); + OutgoingMediaMessage outgoingEndSessionMessage = OutgoingMediaMessage.endSessionMessage(recipient, message.getTimestamp()); long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient); @@ -788,10 +784,9 @@ public final class MessageContentProcessor { SecurityEvent.broadcastSecurityUpdateEvent(context); - long messageId = database.insertMessageOutbox(threadId, - outgoingEndSessionMessage, + long messageId = database.insertMessageOutbox(outgoingEndSessionMessage, + threadId, false, - message.getTimestamp(), null); database.markAsSent(messageId, true); SignalDatabase.threads().update(threadId, true); @@ -2448,9 +2443,9 @@ public final class MessageContentProcessor { updateGroupReceiptStatus(message, messageId, recipient.requireGroupId()); } else { - OutgoingTextMessage outgoingTextMessage = new OutgoingEncryptedMessage(recipient, body, expiresInMillis); + OutgoingMediaMessage outgoingTextMessage = OutgoingMediaMessage.text(recipient, body, expiresInMillis, message.getTimestamp()); - messageId = SignalDatabase.sms().insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null); + messageId = SignalDatabase.sms().insertMessageOutbox(outgoingTextMessage, threadId, false, null); database = SignalDatabase.sms(); database.markUnidentified(messageId, isUnidentified(message, recipient)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.kt b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.kt index 7db7167fdc..7b9334dfd4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.kt @@ -45,6 +45,9 @@ data class OutgoingMediaMessage( val isUrgent: Boolean = true, val networkFailures: Set = emptySet(), val identityKeyMismatches: Set = emptySet(), + val isEndSession: Boolean = false, + val isIdentityVerified: Boolean = false, + val isIdentityDefault: Boolean = false, ) { val isV2Group: Boolean = messageGroupContext != null && GroupV2UpdateMessageUtil.isGroupV2(messageGroupContext) @@ -145,6 +148,36 @@ data class OutgoingMediaMessage( } companion object { + + /** + * A literal, insecure SMS message. + */ + @JvmStatic + fun sms(recipient: Recipient, body: String, subscriptionId: Int): OutgoingMediaMessage { + return OutgoingMediaMessage( + recipient = recipient, + sentTimeMillis = System.currentTimeMillis(), + body = body, + subscriptionId = subscriptionId, + isSecure = false + ) + } + + /** + * A secure message that only contains text. + */ + @JvmStatic + fun text(recipient: Recipient, body: String, expiresIn: Long, sentTimeMillis: Long = System.currentTimeMillis()): OutgoingMediaMessage { + return OutgoingMediaMessage( + recipient = recipient, + sentTimeMillis = sentTimeMillis, + body = body, + expiresIn = expiresIn, + isUrgent = true, + isSecure = true + ) + } + /** * Helper for creating a group update message when a state change occurs and needs to be sent to others. */ @@ -279,6 +312,49 @@ data class OutgoingMediaMessage( ) } + /** + * Message for when you have verified the identity of a contact. + */ + @JvmStatic + fun identityVerifiedMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMediaMessage { + return OutgoingMediaMessage( + recipient = recipient, + sentTimeMillis = sentTimeMillis, + isIdentityVerified = true, + isUrgent = false, + isSecure = true, + ) + } + + /** + * Message for when the verification status of an identity is getting set to the default. + */ + @JvmStatic + fun identityDefaultMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMediaMessage { + return OutgoingMediaMessage( + recipient = recipient, + sentTimeMillis = sentTimeMillis, + isIdentityDefault = true, + isUrgent = false, + isSecure = true, + ) + } + + /** + * A legacy message that represented that the user manually reset the session. We don't send these anymore, and could probably get rid of them, + * but it doesn't hurt to support receiving them in sync messages. + */ + @JvmStatic + fun endSessionMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMediaMessage { + return OutgoingMediaMessage( + recipient = recipient, + sentTimeMillis = sentTimeMillis, + isEndSession = true, + isUrgent = false, + isSecure = true, + ) + } + @JvmStatic fun buildMessage(slideDeck: SlideDeck, message: String): String { return if (message.isNotEmpty() && slideDeck.body.isNotEmpty()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java index fc847bbf5b..d2f6207a68 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java @@ -37,8 +37,6 @@ import org.thoughtcrime.securesms.notifications.v2.ConversationId; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import java.util.Collections; import java.util.LinkedList; @@ -107,12 +105,12 @@ public class RemoteReplyReceiver extends BroadcastReceiver { break; } case SecureMessage: { - OutgoingEncryptedMessage reply = new OutgoingEncryptedMessage(recipient, responseText.toString(), expiresIn); + OutgoingMediaMessage reply = OutgoingMediaMessage.text(recipient, responseText.toString(), expiresIn, System.currentTimeMillis()); threadId = MessageSender.send(context, reply, -1, false, null, null); break; } case UnsecuredSmsMessage: { - OutgoingTextMessage reply = new OutgoingTextMessage(recipient, responseText.toString(), expiresIn, subscriptionId); + OutgoingMediaMessage reply = OutgoingMediaMessage.sms(recipient, responseText.toString(), subscriptionId); threadId = MessageSender.send(context, reply, -1, true, null, null); break; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ratelimit/RateLimitUtil.java b/app/src/main/java/org/thoughtcrime/securesms/ratelimit/RateLimitUtil.java index 5154a2f55a..b3baab936f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ratelimit/RateLimitUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ratelimit/RateLimitUtil.java @@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.PushMediaSendJob; -import org.thoughtcrime.securesms.jobs.PushTextSendJob; import java.util.Set; @@ -26,26 +25,22 @@ public final class RateLimitUtil { */ @WorkerThread public static void retryAllRateLimitedMessages(@NonNull Context context) { - Set sms = SignalDatabase.sms().getAllRateLimitedMessageIds(); - Set mms = SignalDatabase.mms().getAllRateLimitedMessageIds(); + Set messageIds = SignalDatabase.mms().getAllRateLimitedMessageIds(); - if (sms.isEmpty() && mms.isEmpty()) { + if (messageIds.isEmpty()) { return; } - Log.i(TAG, "Retrying " + sms.size() + " sms records and " + mms.size() + " mms records."); + Log.i(TAG, "Retrying " + messageIds.size() + " message records."); - SignalDatabase.sms().clearRateLimitStatus(sms); - SignalDatabase.mms().clearRateLimitStatus(mms); + SignalDatabase.mms().clearRateLimitStatus(messageIds); ApplicationDependencies.getJobManager().update((job, serializer) -> { Data data = serializer.deserialize(job.getSerializedData()); - if (job.getFactoryKey().equals(PushTextSendJob.KEY) && sms.contains(PushTextSendJob.getMessageId(data))) { + if (job.getFactoryKey().equals(PushMediaSendJob.KEY) && messageIds.contains(PushMediaSendJob.getMessageId(data))) { return job.withNextRunAttemptTime(System.currentTimeMillis()); - } else if (job.getFactoryKey().equals(PushMediaSendJob.KEY) && mms.contains(PushMediaSendJob.getMessageId(data))) { - return job.withNextRunAttemptTime(System.currentTimeMillis()); - } else if (job.getFactoryKey().equals(PushGroupSendJob.KEY) && mms.contains(PushGroupSendJob.getMessageId(data))) { + } else if (job.getFactoryKey().equals(PushGroupSendJob.KEY) && messageIds.contains(PushGroupSendJob.getMessageId(data))) { return job.withNextRunAttemptTime(System.currentTimeMillis()); } else { return job; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/QuickResponseService.java b/app/src/main/java/org/thoughtcrime/securesms/service/QuickResponseService.java index 62e50a09e2..3ff782e218 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/QuickResponseService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/QuickResponseService.java @@ -8,14 +8,13 @@ import android.widget.Toast; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.Rfc5724Uri; import java.net.URISyntaxException; import java.net.URLDecoder; -import java.util.concurrent.TimeUnit; public class QuickResponseService extends IntentService { @@ -49,10 +48,9 @@ public class QuickResponseService extends IntentService { Recipient recipient = Recipient.external(this, number); int subscriptionId = recipient.getDefaultSubscriptionId().orElse(-1); - long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds()); if (!TextUtils.isEmpty(content)) { - MessageSender.send(this, new OutgoingTextMessage(recipient, content, expiresIn, subscriptionId), -1, false, null, null); + MessageSender.send(this, OutgoingMediaMessage.sms(recipient, content, subscriptionId), -1, false, null, null); } } catch (URISyntaxException e) { Toast.makeText(this, R.string.QuickResponseService_problem_sending_message, Toast.LENGTH_LONG).show(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java index 8c70584491..56665ec0d2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java @@ -43,8 +43,6 @@ import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.MediaUtil; @@ -386,15 +384,16 @@ public final class MultiShareSender { long expiresIn, int subscriptionId) { + String body = multiShareArgs.getDraftText() == null ? "" : multiShareArgs.getDraftText(); - final OutgoingTextMessage outgoingTextMessage; + OutgoingMediaMessage outgoingMessage; if (shouldSendAsPush(recipient, forceSms)) { - outgoingTextMessage = new OutgoingEncryptedMessage(recipient, multiShareArgs.getDraftText(), expiresIn); + outgoingMessage = OutgoingMediaMessage.text(recipient, body, expiresIn, System.currentTimeMillis()); } else { - outgoingTextMessage = new OutgoingTextMessage(recipient, multiShareArgs.getDraftText(), expiresIn, subscriptionId); + outgoingMessage = OutgoingMediaMessage.sms(recipient, body, subscriptionId); } - MessageSender.send(context, outgoingTextMessage, threadId, forceSms, null, null); + MessageSender.send(context, outgoingMessage, threadId, forceSms, null, null); } private static @NonNull OutgoingMediaMessage generateTextStory(@NonNull Context context, diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java index 9e568c32a7..916c3c5cae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java @@ -59,7 +59,6 @@ import org.thoughtcrime.securesms.jobs.ProfileKeySendJob; import org.thoughtcrime.securesms.jobs.PushDistributionListSendJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.PushMediaSendJob; -import org.thoughtcrime.securesms.jobs.PushTextSendJob; import org.thoughtcrime.securesms.jobs.ReactionSendJob; import org.thoughtcrime.securesms.jobs.RemoteDeleteSendJob; import org.thoughtcrime.securesms.jobs.ResumableUploadSpecJob; @@ -107,34 +106,6 @@ public class MessageSender { } } - public static long send(final Context context, - final OutgoingTextMessage message, - final long threadId, - final boolean forceSms, - @Nullable final String metricId, - final MessageTable.InsertListener insertListener) - { - Log.i(TAG, "Sending text message to " + message.getRecipient().getId() + ", thread: " + threadId); - MessageTable database = SignalDatabase.sms(); - Recipient recipient = message.getRecipient(); - boolean keyExchange = message.isKeyExchange(); - - long allocatedThreadId = SignalDatabase.threads().getOrCreateValidThreadId(recipient, threadId); - long messageId = database.insertMessageOutbox(allocatedThreadId, - applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), - forceSms, - System.currentTimeMillis(), - insertListener); - - SignalLocalMetrics.IndividualMessageSend.onInsertedIntoDatabase(messageId, metricId); - - sendTextMessage(context, recipient, forceSms, keyExchange, messageId); - onMessageSent(); - SignalDatabase.threads().update(threadId, true); - - return allocatedThreadId; - } - public static void sendStories(@NonNull final Context context, @NonNull final List messages, @Nullable final String metricId, @@ -525,14 +496,9 @@ public class MessageSender { public static void resend(Context context, MessageRecord messageRecord) { long messageId = messageRecord.getId(); boolean forceSms = messageRecord.isForcedSms(); - boolean keyExchange = messageRecord.isKeyExchange(); Recipient recipient = messageRecord.getRecipient(); - if (messageRecord.isMms()) { - sendMediaMessage(context, recipient, forceSms, messageId, Collections.emptyList()); - } else { - sendTextMessage(context, recipient, forceSms, keyExchange, messageId); - } + sendMediaMessage(context, recipient, forceSms, messageId, Collections.emptyList()); onMessageSent(); } @@ -541,13 +507,6 @@ public class MessageSender { EventBus.getDefault().postSticky(MessageSentEvent.INSTANCE); } - private static @NonNull OutgoingTextMessage applyUniversalExpireTimerIfNecessary(@NonNull Context context, @NonNull Recipient recipient, @NonNull OutgoingTextMessage outgoingTextMessage, long threadId) { - if (outgoingTextMessage.getExpiresIn() == 0 && RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, recipient, threadId)) { - return outgoingTextMessage.withExpiry(TimeUnit.SECONDS.toMillis(SignalStore.settings().getUniversalExpireTimer())); - } - return outgoingTextMessage; - } - private static @NonNull OutgoingMediaMessage applyUniversalExpireTimerIfNecessary(@NonNull Context context, @NonNull Recipient recipient, @NonNull OutgoingMediaMessage outgoingMediaMessage, long threadId) { if (!outgoingMediaMessage.isExpirationUpdate() && outgoingMediaMessage.getExpiresIn() == 0 && RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, recipient, threadId)) { return outgoingMediaMessage.withExpiry(TimeUnit.SECONDS.toMillis(SignalStore.settings().getUniversalExpireTimer())); @@ -570,23 +529,6 @@ public class MessageSender { } } - private static void sendTextMessage(Context context, Recipient recipient, - boolean forceSms, boolean keyExchange, - long messageId) - { - if (isLocalSelfSend(context, recipient, forceSms)) { - sendLocalTextSelf(context, messageId); - } else if (!forceSms && isPushTextSend(context, recipient, keyExchange)) { - sendTextPush(recipient, messageId); - } else { - sendSms(recipient, messageId); - } - } - - private static void sendTextPush(Recipient recipient, long messageId) { - ApplicationDependencies.getJobManager().add(new PushTextSendJob(messageId, recipient)); - } - private static void sendMediaPush(Context context, Recipient recipient, long messageId, @NonNull Collection uploadJobIds) { JobManager jobManager = ApplicationDependencies.getJobManager(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java deleted file mode 100644 index fd9c3cc554..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEncryptedMessage.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.thoughtcrime.securesms.sms; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.recipients.Recipient; - -public class OutgoingEncryptedMessage extends OutgoingTextMessage { - - public OutgoingEncryptedMessage(Recipient recipient, String body, long expiresIn) { - super(recipient, body, expiresIn, -1); - } - - private OutgoingEncryptedMessage(OutgoingEncryptedMessage base, String body) { - super(base, body); - } - - @Override - public boolean isSecureMessage() { - return true; - } - - @Override - public @NonNull OutgoingTextMessage withExpiry(long expiresIn) { - return new OutgoingEncryptedMessage(getRecipient(), getMessageBody(), expiresIn); - }; - - @Override - public OutgoingTextMessage withBody(String body) { - return new OutgoingEncryptedMessage(this, body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEndSessionMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEndSessionMessage.java deleted file mode 100644 index cbba047507..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingEndSessionMessage.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.thoughtcrime.securesms.sms; - -public class OutgoingEndSessionMessage extends OutgoingTextMessage { - - public OutgoingEndSessionMessage(OutgoingTextMessage base) { - this(base, base.getMessageBody()); - } - - public OutgoingEndSessionMessage(OutgoingTextMessage message, String body) { - super(message, body); - } - - @Override - public boolean isEndSession() { - return true; - } - - @Override - public OutgoingTextMessage withBody(String body) { - return new OutgoingEndSessionMessage(this, body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java deleted file mode 100644 index 30bc27a27c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityDefaultMessage.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.thoughtcrime.securesms.sms; - - -import org.thoughtcrime.securesms.recipients.Recipient; - -public class OutgoingIdentityDefaultMessage extends OutgoingTextMessage { - - public OutgoingIdentityDefaultMessage(Recipient recipient) { - this(recipient, ""); - } - - private OutgoingIdentityDefaultMessage(Recipient recipient, String body) { - super(recipient, body, -1); - } - - @Override - public boolean isIdentityDefault() { - return true; - } - - public OutgoingTextMessage withBody(String body) { - return new OutgoingIdentityDefaultMessage(getRecipient()); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java deleted file mode 100644 index 23d83334c1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingIdentityVerifiedMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.thoughtcrime.securesms.sms; - - -import org.thoughtcrime.securesms.recipients.Recipient; - -public class OutgoingIdentityVerifiedMessage extends OutgoingTextMessage { - - public OutgoingIdentityVerifiedMessage(Recipient recipient) { - this(recipient, ""); - } - - private OutgoingIdentityVerifiedMessage(Recipient recipient, String body) { - super(recipient, body, -1); - } - - @Override - public boolean isIdentityVerified() { - return true; - } - - @Override - public OutgoingTextMessage withBody(String body) { - return new OutgoingIdentityVerifiedMessage(getRecipient(), body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java deleted file mode 100644 index 557814c89f..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingKeyExchangeMessage.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.thoughtcrime.securesms.sms; - -import org.thoughtcrime.securesms.recipients.Recipient; - -public class OutgoingKeyExchangeMessage extends OutgoingTextMessage { - - public OutgoingKeyExchangeMessage(Recipient recipient, String message) { - super(recipient, message, -1); - } - - private OutgoingKeyExchangeMessage(OutgoingKeyExchangeMessage base, String body) { - super(base, body); - } - - @Override - public boolean isKeyExchange() { - return true; - } - - @Override - public OutgoingTextMessage withBody(String body) { - return new OutgoingKeyExchangeMessage(this, body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingPrekeyBundleMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingPrekeyBundleMessage.java deleted file mode 100644 index ae7f9329a4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingPrekeyBundleMessage.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.thoughtcrime.securesms.sms; - - -public class OutgoingPrekeyBundleMessage extends OutgoingTextMessage { - - public OutgoingPrekeyBundleMessage(OutgoingTextMessage message, String body) { - super(message, body); - } - - @Override - public boolean isPreKeyBundle() { - return true; - } - - @Override - public OutgoingTextMessage withBody(String body) { - return new OutgoingPrekeyBundleMessage(this, body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java deleted file mode 100644 index dcdfb02383..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.thoughtcrime.securesms.sms; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.database.model.SmsMessageRecord; -import org.thoughtcrime.securesms.recipients.Recipient; - -public class OutgoingTextMessage { - - private final Recipient recipient; - private final String message; - private final int subscriptionId; - private final long expiresIn; - - public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) { - this(recipient, message, 0, subscriptionId); - } - - public OutgoingTextMessage(Recipient recipient, String message, long expiresIn, int subscriptionId) { - this.recipient = recipient; - this.message = message; - this.expiresIn = expiresIn; - this.subscriptionId = subscriptionId; - } - - protected OutgoingTextMessage(OutgoingTextMessage base, String body) { - this.recipient = base.getRecipient(); - this.subscriptionId = base.getSubscriptionId(); - this.expiresIn = base.getExpiresIn(); - this.message = body; - } - - public @NonNull OutgoingTextMessage withExpiry(long expiresIn) { - return new OutgoingTextMessage(recipient, message, expiresIn, subscriptionId); - } - - public long getExpiresIn() { - return expiresIn; - } - - public int getSubscriptionId() { - return subscriptionId; - } - - public String getMessageBody() { - return message; - } - - public Recipient getRecipient() { - return recipient; - } - - public boolean isKeyExchange() { - return false; - } - - public boolean isSecureMessage() { - return false; - } - - public boolean isEndSession() { - return false; - } - - public boolean isPreKeyBundle() { - return false; - } - - public boolean isIdentityVerified() { - return false; - } - - public boolean isIdentityDefault() { - return false; - } - - public static OutgoingTextMessage from(SmsMessageRecord record) { - if (record.isSecure()) { - return new OutgoingEncryptedMessage(record.getRecipient(), record.getBody(), record.getExpiresIn()); - } else if (record.isKeyExchange()) { - return new OutgoingKeyExchangeMessage(record.getRecipient(), record.getBody()); - } else if (record.isEndSession()) { - return new OutgoingEndSessionMessage(new OutgoingTextMessage(record.getRecipient(), record.getBody(), 0, -1)); - } else { - return new OutgoingTextMessage(record.getRecipient(), record.getBody(), record.getExpiresIn(), record.getSubscriptionId()); - } - } - - public OutgoingTextMessage withBody(String body) { - return new OutgoingTextMessage(this, body); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java index d171325812..5c160a02c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java @@ -23,6 +23,8 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.IdentityRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.keyvalue.SignalStore; +import org.thoughtcrime.securesms.mms.MmsException; +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.notifications.v2.ConversationId; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; @@ -30,9 +32,6 @@ import org.thoughtcrime.securesms.sms.IncomingIdentityDefaultMessage; import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage; import org.thoughtcrime.securesms.sms.IncomingIdentityVerifiedMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; -import org.thoughtcrime.securesms.sms.OutgoingIdentityDefaultMessage; -import org.thoughtcrime.securesms.sms.OutgoingIdentityVerifiedMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.signal.core.util.concurrent.SimpleTask; @@ -81,15 +80,22 @@ public final class IdentityUtil { smsDatabase.insertMessageInbox(incoming); } else { - RecipientId recipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupRecord.getId()); - Recipient groupRecipient = Recipient.resolved(recipientId); - long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(groupRecipient); - OutgoingTextMessage outgoing ; + RecipientId recipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupRecord.getId()); + Recipient groupRecipient = Recipient.resolved(recipientId); + long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(groupRecipient); - if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient); - else outgoing = new OutgoingIdentityDefaultMessage(recipient); + OutgoingMediaMessage outgoing; + if (verified) { + outgoing = OutgoingMediaMessage.identityVerifiedMessage(recipient, time); + } else { + outgoing = OutgoingMediaMessage.identityDefaultMessage(recipient, time); + } - SignalDatabase.sms().insertMessageOutbox(threadId, outgoing, false, time, null); + try { + SignalDatabase.sms().insertMessageOutbox(outgoing, threadId, false, null); + } catch (MmsException e) { + throw new AssertionError(e); + } SignalDatabase.threads().update(threadId, true); } } @@ -104,15 +110,21 @@ public final class IdentityUtil { smsDatabase.insertMessageInbox(incoming); } else { - OutgoingTextMessage outgoing; - - if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient); - else outgoing = new OutgoingIdentityDefaultMessage(recipient); + OutgoingMediaMessage outgoing; + if (verified) { + outgoing = OutgoingMediaMessage.identityVerifiedMessage(recipient, time); + } else { + outgoing = OutgoingMediaMessage.identityDefaultMessage(recipient, time); + } long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient); Log.i(TAG, "Inserting verified outbox..."); - SignalDatabase.sms().insertMessageOutbox(threadId, outgoing, false, time, null); + try { + SignalDatabase.sms().insertMessageOutbox(outgoing, threadId, false, null); + } catch (MmsException e) { + throw new AssertionError(); + } boolean keepThreadArchived = SignalStore.settings().shouldKeepMutedChatsArchived() && recipient.isMuted(); SignalDatabase.threads().update(threadId, !keepThreadArchived); } diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobmanager/migrations/RecipientIdJobMigrationTest.java b/app/src/test/java/org/thoughtcrime/securesms/jobmanager/migrations/RecipientIdJobMigrationTest.java index 53271ea10f..275fda8a82 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/jobmanager/migrations/RecipientIdJobMigrationTest.java +++ b/app/src/test/java/org/thoughtcrime/securesms/jobmanager/migrations/RecipientIdJobMigrationTest.java @@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.PushMediaSendJob; -import org.thoughtcrime.securesms.jobs.PushTextSendJob; import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob; import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob; import org.thoughtcrime.securesms.jobs.SmsSendJob; @@ -247,21 +246,6 @@ public class RecipientIdJobMigrationTest { new MultiDeviceReadUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData()); } - @Test - public void migrate_pushTextSendJob() throws Exception { - JobData testData = new JobData("PushTextSendJob", "+16101234567", new Data.Builder().putLong("message_id", 1).build()); - mockRecipientResolve("+16101234567", 1); - - RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class)); - JobData converted = subject.migrate(testData); - - assertEquals("PushTextSendJob", converted.getFactoryKey()); - assertEquals(RecipientId.from(1).toQueueKey(), converted.getQueueKey()); - assertEquals(1, converted.getData().getLong("message_id")); - - new PushTextSendJob.Factory().create(mock(Job.Parameters.class), converted.getData()); - } - @Test public void migrate_pushMediaSendJob() throws Exception { JobData testData = new JobData("PushMediaSendJob", "+16101234567", new Data.Builder().putLong("message_id", 1).build());