diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessEarlyMessagesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessEarlyMessagesJob.kt index 26622aa95e..8decf6a735 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessEarlyMessagesJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessEarlyMessagesJob.kt @@ -48,7 +48,7 @@ class PushProcessEarlyMessagesJob private constructor(parameters: Parameters) : if (contents.isPresent) { for (content: SignalServiceContent in contents.get()) { Log.i(TAG, "[${id.sentTimestamp}] Processing early content for $id") - MessageContentProcessor.forEarlyContent(context).process(MessageContentProcessor.MessageState.DECRYPTED_OK, content, null, id.sentTimestamp, -1) + MessageContentProcessor.create(context).processEarlyContent(MessageContentProcessor.MessageState.DECRYPTED_OK, content, null, id.sentTimestamp, -1) } } else { Log.w(TAG, "[${id.sentTimestamp}] Saw $id in the cache, but when we went to retrieve it, it was already gone.") diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.java index fab5ed9541..48f1f111ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushProcessMessageJob.java @@ -9,7 +9,6 @@ import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.groups.BadGroupIdException; import org.thoughtcrime.securesms.groups.GroupChangeBusyException; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Data; @@ -185,7 +184,7 @@ public final class PushProcessMessageJob extends BaseJob { @Override public void onRun() throws Exception { - MessageContentProcessor processor = MessageContentProcessor.forNormalContent(context); + MessageContentProcessor processor = MessageContentProcessor.create(context); processor.process(messageState, content, exceptionMetadata, timestamp, smsMessageId); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java index 51491b8212..f425e00c5d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageProcessor.java @@ -138,7 +138,7 @@ public class IncomingMessageProcessor { stopwatch.split("group-check"); try { - MessageContentProcessor processor = MessageContentProcessor.forNormalContent(context); + MessageContentProcessor processor = MessageContentProcessor.create(context); processor.process(result.getState(), result.getContent(), result.getException(), envelope.getTimestamp(), -1); return null; } catch (IOException | GroupChangeBusyException e) { 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 2922014d2d..9c9ab4122b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -203,19 +203,13 @@ public final class MessageContentProcessor { private static final String TAG = Log.tag(MessageContentProcessor.class); private final Context context; - private final boolean processingEarlyContent; - public static MessageContentProcessor forNormalContent(@NonNull Context context) { - return new MessageContentProcessor(context, false); + public static MessageContentProcessor create(@NonNull Context context) { + return new MessageContentProcessor(context); } - public static MessageContentProcessor forEarlyContent(@NonNull Context context) { - return new MessageContentProcessor(context, true); - } - - private MessageContentProcessor(@NonNull Context context, boolean processingEarlyContent) { - this.context = context; - this.processingEarlyContent = processingEarlyContent; + private MessageContentProcessor(@NonNull Context context) { + this.context = context; } /** @@ -225,7 +219,24 @@ public final class MessageContentProcessor { * This is super-stateful, and it's recommended that this be run in a transaction so that no * intermediate results are persisted to the database if the app were to crash. */ - public void process(MessageState messageState, @Nullable SignalServiceContent content, @Nullable ExceptionMetadata exceptionMetadata, long timestamp, long smsMessageId) + public void process(MessageState messageState, @Nullable SignalServiceContent content, @Nullable ExceptionMetadata exceptionMetadata, long envelopeTimestamp, long smsMessageId) + throws IOException, GroupChangeBusyException + { + process(messageState, content, exceptionMetadata, envelopeTimestamp, smsMessageId, false); + } + + /** + * The same as {@link #process(MessageState, SignalServiceContent, ExceptionMetadata, long, long)}, except specifically targeted at early content. + * Using this method will *not* store or enqueue early content jobs if we detect this as being early, to avoid recursive scenarios. + */ + public void processEarlyContent(MessageState messageState, @Nullable SignalServiceContent content, @Nullable ExceptionMetadata exceptionMetadata, long envelopeTimestamp, long smsMessageId) + throws IOException, GroupChangeBusyException + { + process(messageState, content, exceptionMetadata, envelopeTimestamp, smsMessageId, true); + } + + + private void process(MessageState messageState, @Nullable SignalServiceContent content, @Nullable ExceptionMetadata exceptionMetadata, long envelopeTimestamp, long smsMessageId, boolean processingEarlyContent) throws IOException, GroupChangeBusyException { Optional optionalSmsMessageId = smsMessageId > 0 ? Optional.of(smsMessageId) : Optional.empty(); @@ -235,22 +246,22 @@ public final class MessageContentProcessor { if (content != null) { Recipient senderRecipient = Recipient.externalPush(content.getSender()); - handleMessage(content, timestamp, senderRecipient, optionalSmsMessageId); + handleMessage(content, senderRecipient, optionalSmsMessageId, processingEarlyContent); Optional> earlyContent = ApplicationDependencies.getEarlyMessageCache() .retrieve(senderRecipient.getId(), content.getTimestamp()); - if (earlyContent.isPresent()) { + if (!processingEarlyContent && earlyContent.isPresent()) { log(String.valueOf(content.getTimestamp()), "Found " + earlyContent.get().size() + " dependent item(s) that were retrieved earlier. Processing."); for (SignalServiceContent earlyItem : earlyContent.get()) { - handleMessage(earlyItem, timestamp, senderRecipient, Optional.empty()); + handleMessage(earlyItem, senderRecipient, Optional.empty(), true); } } } else { warn("null", "Null content. Ignoring message."); } } else if (exceptionMetadata != null) { - handleExceptionMessage(messageState, exceptionMetadata, timestamp, optionalSmsMessageId); + handleExceptionMessage(messageState, exceptionMetadata, envelopeTimestamp, optionalSmsMessageId); } else if (messageState == MessageState.NOOP) { Log.d(TAG, "Nothing to do: " + messageState.name()); } else { @@ -258,7 +269,7 @@ public final class MessageContentProcessor { } } - private void handleMessage(@NonNull SignalServiceContent content, long timestamp, @NonNull Recipient senderRecipient, @NonNull Optional smsMessageId) + private void handleMessage(@NonNull SignalServiceContent content, @NonNull Recipient senderRecipient, @NonNull Optional smsMessageId, boolean processingEarlyContent) throws IOException, GroupChangeBusyException { try { @@ -293,8 +304,8 @@ public final class MessageContentProcessor { else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId, senderRecipient); else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime, false); else if (message.getReaction().isPresent() && message.getStoryContext().isPresent()) messageId = handleStoryReaction(content, message, senderRecipient); - else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient); - else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message, senderRecipient); + else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient, processingEarlyContent); + else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message, senderRecipient, processingEarlyContent); else if (message.isActivatePaymentsRequest()) messageId = handlePaymentActivation(content, message, smsMessageId, senderRecipient, receivedTime, true, false); else if (message.isPaymentsActivated()) messageId = handlePaymentActivation(content, message, smsMessageId, senderRecipient, receivedTime, false, true); else if (message.getPayment().isPresent()) messageId = handlePayment(content, message, smsMessageId, senderRecipient, receivedTime); @@ -341,11 +352,11 @@ public final class MessageContentProcessor { SignalServiceSyncMessage syncMessage = content.getSyncMessage().get(); - if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get(), senderRecipient); + if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get(), senderRecipient, processingEarlyContent); else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get(), content.getTimestamp()); - else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(content, syncMessage.getRead().get(), content.getTimestamp()); + else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(content, syncMessage.getRead().get(), content.getTimestamp(), processingEarlyContent); else if (syncMessage.getViewed().isPresent()) handleSynchronizeViewedMessage(syncMessage.getViewed().get(), content.getTimestamp()); - else if (syncMessage.getViewOnceOpen().isPresent()) handleSynchronizeViewOnceOpenMessage(content, syncMessage.getViewOnceOpen().get(), content.getTimestamp()); + else if (syncMessage.getViewOnceOpen().isPresent()) handleSynchronizeViewOnceOpenMessage(content, syncMessage.getViewOnceOpen().get(), content.getTimestamp(), processingEarlyContent); else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get()); else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get(), content.getTimestamp()); else if (syncMessage.getConfiguration().isPresent()) handleSynchronizeConfigurationMessage(syncMessage.getConfiguration().get(), content.getTimestamp()); @@ -377,9 +388,9 @@ public final class MessageContentProcessor { } else if (content.getReceiptMessage().isPresent()) { SignalServiceReceiptMessage message = content.getReceiptMessage().get(); - if (message.isReadReceipt()) handleReadReceipt(content, message, senderRecipient); + if (message.isReadReceipt()) handleReadReceipt(content, message, senderRecipient, processingEarlyContent); else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message, senderRecipient); - else if (message.isViewedReceipt()) handleViewedReceipt(content, message, senderRecipient); + else if (message.isViewedReceipt()) handleViewedReceipt(content, message, senderRecipient, processingEarlyContent); } else if (content.getTypingMessage().isPresent()) { handleTypingMessage(content, content.getTypingMessage().get(), senderRecipient); } else if (content.getStoryMessage().isPresent()) { @@ -402,7 +413,7 @@ public final class MessageContentProcessor { } } catch (StorageFailedException e) { warn(String.valueOf(content.getTimestamp()), e); - handleCorruptMessage(e.getSender(), e.getSenderDevice(), timestamp, smsMessageId); + handleCorruptMessage(e.getSender(), e.getSenderDevice(), content.getTimestamp(), smsMessageId); } catch (BadGroupIdException e) { warn(String.valueOf(content.getTimestamp()), "Ignoring message with bad group id", e); } @@ -963,7 +974,7 @@ public final class MessageContentProcessor { return null; } - private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) throws StorageFailedException { + private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient, boolean processingEarlyContent) throws StorageFailedException { log(content.getTimestamp(), "Handle reaction for message " + message.getReaction().get().getTargetSentTimestamp()); SignalServiceDataMessage.Reaction reaction = message.getReaction().get(); @@ -1023,7 +1034,7 @@ public final class MessageContentProcessor { return new MessageId(targetMessage.getId()); } - private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) { + private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient, boolean processingEarlyContent) { log(content.getTimestamp(), "Remote delete for message " + message.getRemoteDelete().get().getTargetSentTimestamp()); SignalServiceDataMessage.RemoteDelete delete = message.getRemoteDelete().get(); @@ -1275,7 +1286,8 @@ public final class MessageContentProcessor { private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content, @NonNull SentTranscriptMessage message, - @NonNull Recipient senderRecipient) + @NonNull Recipient senderRecipient, + boolean processingEarlyContent) throws StorageFailedException, BadGroupIdException, IOException, GroupChangeBusyException { log(String.valueOf(content.getTimestamp()), "Processing sent transcript for message with ID " + message.getTimestamp()); @@ -1314,10 +1326,10 @@ public final class MessageContentProcessor { } else if (dataMessage.getStoryContext().isPresent()) { threadId = handleSynchronizeSentStoryReply(message, content.getTimestamp()); } else if (dataMessage.getReaction().isPresent()) { - handleReaction(content, dataMessage, senderRecipient); + handleReaction(content, dataMessage, senderRecipient, processingEarlyContent); threadId = SignalDatabase.threads().getOrCreateThreadIdFor(getSyncMessageDestination(message)); } else if (dataMessage.getRemoteDelete().isPresent()) { - handleRemoteDelete(content, dataMessage, senderRecipient); + handleRemoteDelete(content, dataMessage, senderRecipient, processingEarlyContent); } else if (dataMessage.getAttachments().isPresent() || dataMessage.getQuote().isPresent() || dataMessage.getPreviews().isPresent() || dataMessage.getSticker().isPresent() || dataMessage.isViewOnce() || dataMessage.getMentions().isPresent()) { threadId = handleSynchronizeSentMediaMessage(message, content.getTimestamp()); } else { @@ -1407,7 +1419,8 @@ public final class MessageContentProcessor { private void handleSynchronizeReadMessage(@NonNull SignalServiceContent content, @NonNull List readMessages, - long envelopeTimestamp) + long envelopeTimestamp, + boolean processingEarlyContent) { log(envelopeTimestamp, "Synchronize read message. Count: " + readMessages.size() + ", Timestamps: " + Stream.of(readMessages).map(ReadMessage::getTimestamp).toList()); @@ -1473,7 +1486,7 @@ public final class MessageContentProcessor { messageNotifier.updateNotification(context); } - private void handleSynchronizeViewOnceOpenMessage(@NonNull SignalServiceContent content, @NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) { + private void handleSynchronizeViewOnceOpenMessage(@NonNull SignalServiceContent content, @NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp, boolean processingEarlyContent) { log(envelopeTimestamp, "Handling a view-once open for message: " + openMessage.getTimestamp()); RecipientId author = Recipient.externalPush(openMessage.getSender()).getId(); @@ -2700,7 +2713,8 @@ public final class MessageContentProcessor { private void handleViewedReceipt(@NonNull SignalServiceContent content, @NonNull SignalServiceReceiptMessage message, - @NonNull Recipient senderRecipient) + @NonNull Recipient senderRecipient, + boolean processingEarlyContent) { boolean readReceipts = TextSecurePreferences.isReadReceiptsEnabled(context); boolean storyViewedReceipts = SignalStore.storyValues().getViewedReceiptsEnabled(); @@ -2775,7 +2789,8 @@ public final class MessageContentProcessor { @SuppressLint("DefaultLocale") private void handleReadReceipt(@NonNull SignalServiceContent content, @NonNull SignalServiceReceiptMessage message, - @NonNull Recipient senderRecipient) + @NonNull Recipient senderRecipient, + boolean processingEarlyContent) { if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { log("Ignoring read receipts for IDs: " + Util.join(message.getTimestamps(), ", "));