Reduce recipient resolves in MessageContentProcessor.

This commit is contained in:
Greyson Parrelli 2021-07-07 13:11:31 -04:00 committed by Alex Hart
parent ae4167ddae
commit 1bb87834d8

View file

@ -197,19 +197,23 @@ public final class MessageContentProcessor {
Optional<Long> optionalSmsMessageId = smsMessageId > 0 ? Optional.of(smsMessageId) : Optional.absent();
if (messageState == MessageState.DECRYPTED_OK) {
handleMessage(content, timestamp, optionalSmsMessageId);
if (content != null) {
Recipient senderRecipient = Recipient.externalHighTrustPush(context, content.getSender());
handleMessage(content, timestamp, senderRecipient, optionalSmsMessageId);
Optional<List<SignalServiceContent>> earlyContent = ApplicationDependencies.getEarlyMessageCache()
.retrieve(Recipient.externalPush(context, content.getSender()).getId(),
content.getTimestamp());
.retrieve(senderRecipient.getId(), content.getTimestamp());
if (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, Optional.absent());
handleMessage(earlyItem, timestamp, senderRecipient, Optional.absent());
}
}
} else {
warn("null", "Null content. Ignoring message.");
}
} else if (exceptionMetadata != null) {
handleExceptionMessage(messageState, exceptionMetadata, timestamp, optionalSmsMessageId);
@ -220,20 +224,19 @@ public final class MessageContentProcessor {
}
}
private void handleMessage(@Nullable SignalServiceContent content, long timestamp, @NonNull Optional<Long> smsMessageId)
private void handleMessage(@NonNull SignalServiceContent content, long timestamp, @NonNull Recipient senderRecipient, @NonNull Optional<Long> smsMessageId)
throws IOException, GroupChangeBusyException
{
try {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Recipient threadRecipient = getMessageDestination(content);
if (content == null || shouldIgnore(content)) {
log(content != null ? String.valueOf(content.getTimestamp()) : "null", "Ignoring message.");
if (shouldIgnore(content, senderRecipient, threadRecipient)) {
log(content.getTimestamp(), "Ignoring message.");
return;
}
RecipientId senderId = RecipientId.fromHighTrust(content.getSender());
PendingRetryReceiptModel pending = ApplicationDependencies.getPendingRetryReceiptCache().get(senderId, content.getTimestamp());
long receivedTime = handlePendingRetry(pending, content);
PendingRetryReceiptModel pending = ApplicationDependencies.getPendingRetryReceiptCache().get(senderRecipient.getId(), content.getTimestamp());
long receivedTime = handlePendingRetry(pending, content, threadRecipient);
log(String.valueOf(content.getTimestamp()), "Beginning message processing.");
@ -242,13 +245,14 @@ public final class MessageContentProcessor {
}
if (content.getDataMessage().isPresent()) {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
SignalServiceDataMessage message = content.getDataMessage().get();
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent() || message.getMentions().isPresent();
Optional<GroupId> groupId = GroupUtil.idFromGroupContext(message.getGroupContext());
boolean isGv2Message = groupId.isPresent() && groupId.get().isV2();
if (isGv2Message) {
if (handleGv2PreProcessing(groupId.orNull().requireV2(), content, content.getDataMessage().get().getGroupContext().get().getGroupV2().get())) {
if (handleGv2PreProcessing(groupId.orNull().requireV2(), content, content.getDataMessage().get().getGroupContext().get().getGroupV2().get(), senderRecipient)) {
return;
}
}
@ -256,41 +260,39 @@ public final class MessageContentProcessor {
MessageId messageId = null;
if (isInvalidMessage(message)) handleInvalidMessage(content.getSender(), content.getSenderDevice(), groupId, content.getTimestamp(), smsMessageId);
else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId);
else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId, groupId.get().requireV1(), receivedTime);
else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, receivedTime);
else if (message.getReaction().isPresent()) messageId = handleReaction(content, message);
else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message);
else if (message.getPayment().isPresent()) handlePayment(content, message);
else if (isMediaMessage) messageId = handleMediaMessage(content, message, smsMessageId, receivedTime);
else if (message.getBody().isPresent()) messageId = handleTextMessage(content, message, smsMessageId, groupId, receivedTime);
else if (Build.VERSION.SDK_INT > 19 && message.getGroupCallUpdate().isPresent()) handleGroupCallUpdateMessage(content, message, groupId);
else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId, senderRecipient);
else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId, groupId.get().requireV1(), senderRecipient, threadRecipient, receivedTime);
else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime);
else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient);
else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message, senderRecipient);
else if (message.getPayment().isPresent()) handlePayment(content, message, senderRecipient);
else if (isMediaMessage) messageId = handleMediaMessage(content, message, smsMessageId, senderRecipient, threadRecipient, receivedTime);
else if (message.getBody().isPresent()) messageId = handleTextMessage(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime);
else if (Build.VERSION.SDK_INT > 19 && message.getGroupCallUpdate().isPresent()) handleGroupCallUpdateMessage(content, message, groupId, senderRecipient);
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
handleUnknownGroupMessage(content, message.getGroupContext().get());
handleUnknownGroupMessage(content, message.getGroupContext().get(), senderRecipient);
}
if (message.getProfileKey().isPresent()) {
handleProfileKey(content, message.getProfileKey().get());
handleProfileKey(content, message.getProfileKey().get(), senderRecipient);
}
if (content.isNeedsReceipt() && messageId != null) {
handleNeedsDeliveryReceipt(content, message, messageId);
} else if (!content.isNeedsReceipt()) {
Recipient sender = getMessageDestination(content, message);
if (RecipientUtil.shouldHaveProfileKey(context, sender)) {
Log.w(TAG, "Received an unsealed sender message from " + sender.getId() + ", but they should already have our profile key. Correcting.");
if (RecipientUtil.shouldHaveProfileKey(context, threadRecipient)) {
Log.w(TAG, "Received an unsealed sender message from " + senderRecipient.getId() + ", but they should already have our profile key. Correcting.");
if (groupId.isPresent() && groupId.get().isV2()) {
Log.i(TAG, "Message was to a GV2 group. Ensuring our group profile keys are up to date.");
ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob(false))
.then(GroupV2UpdateSelfProfileKeyJob.withQueueLimits(groupId.get().requireV2()))
.enqueue();
} else if (!sender.isGroup()) {
} else if (!threadRecipient.isGroup()) {
Log.i(TAG, "Message was to a 1:1. Ensuring this user has our profile key.");
ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob(false))
.then(ProfileKeySendJob.create(context, DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender), true))
.then(ProfileKeySendJob.create(context, DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient), true))
.enqueue();
}
}
@ -300,9 +302,9 @@ public final class MessageContentProcessor {
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get(), senderRecipient);
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get());
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp());
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp(), senderRecipient);
else if (syncMessage.getViewed().isPresent()) handleSynchronizeViewedMessage(syncMessage.getViewed().get(), content.getTimestamp());
else if (syncMessage.getViewOnceOpen().isPresent()) handleSynchronizeViewOnceOpenMessage(syncMessage.getViewOnceOpen().get(), content.getTimestamp());
else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
@ -324,29 +326,29 @@ public final class MessageContentProcessor {
return;
}
if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId);
else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get());
else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(content, message.getIceUpdateMessages().get());
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(content, message.getHangupMessage().get(), smsMessageId);
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(content, message.getBusyMessage().get());
else if (message.getOpaqueMessage().isPresent()) handleCallOpaqueMessage(content, message.getOpaqueMessage().get());
if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId, senderRecipient);
else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get(), senderRecipient);
else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(content, message.getIceUpdateMessages().get(), senderRecipient);
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(content, message.getHangupMessage().get(), smsMessageId, senderRecipient);
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(content, message.getBusyMessage().get(), senderRecipient);
else if (message.getOpaqueMessage().isPresent()) handleCallOpaqueMessage(content, message.getOpaqueMessage().get(), senderRecipient);
} else if (content.getReceiptMessage().isPresent()) {
SignalServiceReceiptMessage message = content.getReceiptMessage().get();
if (message.isReadReceipt()) handleReadReceipt(content, message);
else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message);
else if (message.isViewedReceipt()) handleViewedReceipt(content, message);
if (message.isReadReceipt()) handleReadReceipt(content, message, senderRecipient);
else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message, senderRecipient);
else if (message.isViewedReceipt()) handleViewedReceipt(content, message, senderRecipient);
} else if (content.getTypingMessage().isPresent()) {
handleTypingMessage(content, content.getTypingMessage().get());
handleTypingMessage(content, content.getTypingMessage().get(), senderRecipient);
} else if (content.getDecryptionErrorMessage().isPresent()) {
handleRetryReceipt(content, content.getDecryptionErrorMessage().get());
handleRetryReceipt(content, content.getDecryptionErrorMessage().get(), senderRecipient);
} else if (content.getSenderKeyDistributionMessage().isPresent()) {
// Already handled, here in order to prevent unrecognized message log
} else {
warn(String.valueOf(content.getTimestamp()), "Got unrecognized message!");
}
resetRecipientToPush(Recipient.externalPush(context, content.getSender()));
resetRecipientToPush(senderRecipient);
if (pending != null) {
warn(content.getTimestamp(), "Pending retry was processed. Deleting.");
@ -360,14 +362,13 @@ public final class MessageContentProcessor {
}
}
private long handlePendingRetry(PendingRetryReceiptModel pending, SignalServiceContent content) throws BadGroupIdException {
private long handlePendingRetry(@Nullable PendingRetryReceiptModel pending, @NonNull SignalServiceContent content, @NonNull Recipient destination) throws BadGroupIdException {
long receivedTime = System.currentTimeMillis();
if (pending != null) {
warn(content.getTimestamp(), "Incoming message matches a pending retry we were expecting.");
Recipient destination = getMessageDestination(content);
Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(destination.getId());
Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(destination.getId());
if (threadId != null) {
ThreadDatabase.ConversationMetadata metadata = DatabaseFactory.getThreadDatabase(context).getConversationMetadata(threadId);
@ -387,32 +388,31 @@ public final class MessageContentProcessor {
return receivedTime;
}
private void handlePayment(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
private void handlePayment(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) {
if (!message.getPayment().isPresent()) {
throw new AssertionError();
}
if (!message.getPayment().get().getPaymentNotification().isPresent()) {
Log.w(TAG, "Ignoring payment message without notification");
warn(content.getTimestamp(), "Ignoring payment message without notification");
return;
}
SignalServiceDataMessage.PaymentNotification paymentNotification = message.getPayment().get().getPaymentNotification().get();
PaymentDatabase paymentDatabase = DatabaseFactory.getPaymentDatabase(context);
UUID uuid = UUID.randomUUID();
Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender());
String queue = "Payment_" + PushProcessMessageJob.getQueueName(recipient.getId());
String queue = "Payment_" + PushProcessMessageJob.getQueueName(senderRecipient.getId());
try {
paymentDatabase.createIncomingPayment(uuid,
recipient.getId(),
senderRecipient.getId(),
message.getTimestamp(),
paymentNotification.getNote(),
Money.MobileCoin.ZERO,
Money.MobileCoin.ZERO,
paymentNotification.getReceipt());
} catch (PaymentDatabase.PublicKeyConflictException e) {
Log.w(TAG, "Ignoring payment with public key already in database");
warn(content.getTimestamp(), "Ignoring payment with public key already in database");
return;
}
@ -425,7 +425,7 @@ public final class MessageContentProcessor {
/**
* @return True if the content should be ignored, otherwise false.
*/
private boolean handleGv2PreProcessing(GroupId.V2 groupId, SignalServiceContent content, SignalServiceGroupV2 groupV2)
private boolean handleGv2PreProcessing(@NonNull GroupId.V2 groupId, @NonNull SignalServiceContent content, @NonNull SignalServiceGroupV2 groupV2, @NonNull Recipient senderRecipient)
throws IOException, GroupChangeBusyException
{
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
@ -440,8 +440,7 @@ public final class MessageContentProcessor {
return true;
}
Recipient sender = Recipient.externalPush(context, content.getSender());
if (!groupDatabase.isCurrentMember(groupId, sender.getId())) {
if (!groupDatabase.isCurrentMember(groupId, senderRecipient.getId())) {
log(String.valueOf(content.getTimestamp()), "Ignoring GV2 message from member not in group " + groupId);
return true;
}
@ -516,7 +515,7 @@ public final class MessageContentProcessor {
case CORRUPT_MESSAGE:
case NO_SESSION:
warn(String.valueOf(timestamp), "Discovered old enqueued bad encrypted message. Scheduling reset.");
ApplicationDependencies.getJobManager().add(new AutomaticSessionResetJob(Recipient.external(context, e.sender).getId(), e.senderDevice, timestamp));
ApplicationDependencies.getJobManager().add(new AutomaticSessionResetJob(sender.getId(), e.senderDevice, timestamp));
break;
default:
@ -526,7 +525,8 @@ public final class MessageContentProcessor {
private void handleCallOfferMessage(@NonNull SignalServiceContent content,
@NonNull OfferMessage message,
@NonNull Optional<Long> smsMessageId)
@NonNull Optional<Long> smsMessageId,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content.getTimestamp()), "handleCallOfferMessage...");
@ -534,9 +534,8 @@ public final class MessageContentProcessor {
MessageDatabase database = DatabaseFactory.getSmsDatabase(context);
database.markAsMissedCall(smsMessageId.get(), message.getType() == OfferMessage.Type.VIDEO_CALL);
} else {
Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender());
RemotePeer remotePeer = new RemotePeer(recipient.getId());
byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull();
RemotePeer remotePeer = new RemotePeer(senderRecipient.getId());
byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull();
ApplicationDependencies.getSignalCallManager()
.receivedOffer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()),
@ -549,12 +548,12 @@ public final class MessageContentProcessor {
}
private void handleCallAnswerMessage(@NonNull SignalServiceContent content,
@NonNull AnswerMessage message)
@NonNull AnswerMessage message,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content), "handleCallAnswerMessage...");
Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender());
RemotePeer remotePeer = new RemotePeer(recipient.getId());
byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull();
RemotePeer remotePeer = new RemotePeer(senderRecipient.getId());
byte[] remoteIdentityKey = DatabaseFactory.getIdentityDatabase(context).getIdentity(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull();
ApplicationDependencies.getSignalCallManager()
.receivedAnswer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()),
@ -563,7 +562,8 @@ public final class MessageContentProcessor {
}
private void handleCallIceUpdateMessage(@NonNull SignalServiceContent content,
@NonNull List<IceUpdateMessage> messages)
@NonNull List<IceUpdateMessage> messages,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content), "handleCallIceUpdateMessage... " + messages.size());
@ -575,7 +575,7 @@ public final class MessageContentProcessor {
callId = iceMessage.getId();
}
RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId());
RemotePeer remotePeer = new RemotePeer(senderRecipient.getId());
ApplicationDependencies.getSignalCallManager()
.receivedIceCandidates(new WebRtcData.CallMetadata(remotePeer, new CallId(callId), content.getSenderDevice()),
@ -584,13 +584,14 @@ public final class MessageContentProcessor {
private void handleCallHangupMessage(@NonNull SignalServiceContent content,
@NonNull HangupMessage message,
@NonNull Optional<Long> smsMessageId)
@NonNull Optional<Long> smsMessageId,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content), "handleCallHangupMessage");
if (smsMessageId.isPresent()) {
DatabaseFactory.getSmsDatabase(context).markAsMissedCall(smsMessageId.get(), false);
} else {
RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId());
RemotePeer remotePeer = new RemotePeer(senderRecipient.getId());
ApplicationDependencies.getSignalCallManager()
.receivedCallHangup(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()),
@ -599,18 +600,20 @@ public final class MessageContentProcessor {
}
private void handleCallBusyMessage(@NonNull SignalServiceContent content,
@NonNull BusyMessage message)
@NonNull BusyMessage message,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content.getTimestamp()), "handleCallBusyMessage");
RemotePeer remotePeer = new RemotePeer(Recipient.externalHighTrustPush(context, content.getSender()).getId());
RemotePeer remotePeer = new RemotePeer(senderRecipient.getId());
ApplicationDependencies.getSignalCallManager()
.receivedCallBusy(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()));
}
private void handleCallOpaqueMessage(@NonNull SignalServiceContent content,
@NonNull OpaqueMessage message)
@NonNull OpaqueMessage message,
@NonNull Recipient senderRecipient)
{
log(String.valueOf(content.getTimestamp()), "handleCallOpaqueMessage");
@ -620,7 +623,7 @@ public final class MessageContentProcessor {
}
ApplicationDependencies.getSignalCallManager()
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(Recipient.externalHighTrustPush(context, content.getSender()).requireUuid(),
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireUuid(),
message.getOpaque(),
content.getSenderDevice(),
messageAgeSeconds));
@ -628,7 +631,8 @@ public final class MessageContentProcessor {
private void handleGroupCallUpdateMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<GroupId> groupId)
@NonNull Optional<GroupId> groupId,
@NonNull Recipient senderRecipient)
{
if (!groupId.isPresent() || !groupId.get().isV2()) {
Log.w(TAG, "Invalid group for group call update message");
@ -638,18 +642,19 @@ public final class MessageContentProcessor {
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromPossiblyMigratedGroupId(groupId.get());
DatabaseFactory.getSmsDatabase(context).insertOrUpdateGroupCall(groupRecipientId,
RecipientId.from(content.getSender()),
content.getServerReceivedTimestamp(),
message.getGroupCallUpdate().get().getEraId());
senderRecipient.getId(),
content.getServerReceivedTimestamp(),
message.getGroupCallUpdate().get().getEraId());
GroupCallPeekJob.enqueue(groupRecipientId);
}
private @Nullable MessageId handleEndSessionMessage(@NonNull SignalServiceContent content,
@NonNull Optional<Long> smsMessageId)
@NonNull Optional<Long> smsMessageId,
@NonNull Recipient senderRecipient)
{
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(),
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(senderRecipient.getId(),
content.getSenderDevice(),
content.getTimestamp(),
content.getServerReceivedTimestamp(),
@ -713,13 +718,15 @@ public final class MessageContentProcessor {
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId,
@NonNull GroupId.V1 groupId,
@NonNull Recipient senderRecipient,
@NonNull Recipient threadRecipient,
long receivedTime)
throws StorageFailedException, BadGroupIdException
{
GroupV1MessageProcessor.process(context, content, message, false);
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) {
handleExpirationUpdate(content, message, Optional.absent(), Optional.of(groupId), receivedTime);
if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != threadRecipient.getExpireMessages()) {
handleExpirationUpdate(content, message, Optional.absent(), Optional.of(groupId), senderRecipient, threadRecipient, receivedTime);
}
if (smsMessageId.isPresent()) {
@ -728,13 +735,14 @@ public final class MessageContentProcessor {
}
private void handleUnknownGroupMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceGroupContext group)
@NonNull SignalServiceGroupContext group,
@NonNull Recipient senderRecipient)
throws BadGroupIdException
{
if (group.getGroupV1().isPresent()) {
SignalServiceGroup groupV1 = group.getGroupV1().get();
if (groupV1.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalHighTrustPush(context, content.getSender()).getId(), GroupId.v1(groupV1.getGroupId())));
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(senderRecipient.getId(), GroupId.v1(groupV1.getGroupId())));
} else {
warn(content.getTimestamp(), "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
}
@ -750,8 +758,10 @@ public final class MessageContentProcessor {
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId,
@NonNull Optional<GroupId> groupId,
@NonNull Recipient senderRecipient,
@NonNull Recipient threadRecipient,
long receivedTime)
throws StorageFailedException, BadGroupIdException
throws StorageFailedException
{
if (groupId.isPresent() && groupId.get().isV2()) {
warn(String.valueOf(content.getTimestamp()), "Expiration update received for GV2. Ignoring.");
@ -760,17 +770,15 @@ public final class MessageContentProcessor {
int expiresInSeconds = message.getExpiresInSeconds();
Optional<SignalServiceGroupContext> groupContext = message.getGroupContext();
Recipient recipient = getMessageDestination(content, groupContext);
if (recipient.getExpireMessages() == expiresInSeconds) {
if (threadRecipient.getExpireMessages() == expiresInSeconds) {
log(String.valueOf(content.getTimestamp()), "No change in message expiry for group. Ignoring.");
return null;
}
try {
MessageDatabase database = DatabaseFactory.getMmsDatabase(context);
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(sender.getId(),
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(),
content.getTimestamp(),
content.getServerReceivedTimestamp(),
receivedTime,
@ -791,7 +799,7 @@ public final class MessageContentProcessor {
Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient.getId(), expiresInSeconds);
DatabaseFactory.getRecipientDatabase(context).setExpireMessages(threadRecipient.getId(), expiresInSeconds);
if (smsMessageId.isPresent()) {
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
@ -807,7 +815,7 @@ public final class MessageContentProcessor {
return null;
}
private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
private @Nullable MessageId handleReaction(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) {
SignalServiceDataMessage.Reaction reaction = message.getReaction().get();
if (!EmojiUtil.isEmoji(reaction.getEmoji())) {
@ -815,7 +823,6 @@ public final class MessageContentProcessor {
return null;
}
Recipient reactionAuthor = Recipient.externalHighTrustPush(context, content.getSender());
Recipient targetAuthor = Recipient.externalPush(context, reaction.getTargetAuthor());
MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(reaction.getTargetSentTimestamp(), targetAuthor.getId());
@ -839,12 +846,12 @@ public final class MessageContentProcessor {
Recipient threadRecipient = targetThread.getRecipient().resolve();
if (threadRecipient.isGroup() && !threadRecipient.getParticipants().contains(reactionAuthor)) {
if (threadRecipient.isGroup() && !threadRecipient.getParticipants().contains(senderRecipient)) {
warn(String.valueOf(content.getTimestamp()), "[handleReaction] Reaction author is not in the group! timestamp: " + reaction.getTargetSentTimestamp() + " author: " + targetAuthor.getId());
return null;
}
if (!threadRecipient.isGroup() && !reactionAuthor.equals(threadRecipient) && !reactionAuthor.isSelf()) {
if (!threadRecipient.isGroup() && !senderRecipient.equals(threadRecipient) && !senderRecipient.isSelf()) {
warn(String.valueOf(content.getTimestamp()), "[handleReaction] Reaction author is not a part of the 1:1 thread! timestamp: " + reaction.getTargetSentTimestamp() + " author: " + targetAuthor.getId());
return null;
}
@ -852,10 +859,10 @@ public final class MessageContentProcessor {
MessageDatabase db = targetMessage.isMms() ? DatabaseFactory.getMmsDatabase(context) : DatabaseFactory.getSmsDatabase(context);
if (reaction.isRemove()) {
db.deleteReaction(targetMessage.getId(), reactionAuthor.getId());
db.deleteReaction(targetMessage.getId(), senderRecipient.getId());
ApplicationDependencies.getMessageNotifier().updateNotification(context);
} else {
ReactionRecord reactionRecord = new ReactionRecord(reaction.getEmoji(), reactionAuthor.getId(), message.getTimestamp(), System.currentTimeMillis());
ReactionRecord reactionRecord = new ReactionRecord(reaction.getEmoji(), senderRecipient.getId(), message.getTimestamp(), System.currentTimeMillis());
db.addReaction(targetMessage.getId(), reactionRecord);
ApplicationDependencies.getMessageNotifier().updateNotification(context, targetMessage.getThreadId(), false);
}
@ -863,24 +870,23 @@ public final class MessageContentProcessor {
return new MessageId(targetMessage.getId(), targetMessage.isMms());
}
private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
private @Nullable MessageId handleRemoteDelete(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) {
SignalServiceDataMessage.RemoteDelete delete = message.getRemoteDelete().get();
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(delete.getTargetSentTimestamp(), sender.getId());
MessageRecord targetMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(delete.getTargetSentTimestamp(), senderRecipient.getId());
if (targetMessage != null && RemoteDeleteUtil.isValidReceive(targetMessage, sender, content.getServerReceivedTimestamp())) {
if (targetMessage != null && RemoteDeleteUtil.isValidReceive(targetMessage, senderRecipient, content.getServerReceivedTimestamp())) {
MessageDatabase db = targetMessage.isMms() ? DatabaseFactory.getMmsDatabase(context) : DatabaseFactory.getSmsDatabase(context);
db.markAsRemoteDelete(targetMessage.getId());
ApplicationDependencies.getMessageNotifier().updateNotification(context, targetMessage.getThreadId(), false);
return new MessageId(targetMessage.getId(), targetMessage.isMms());
} else if (targetMessage == null) {
warn(String.valueOf(content.getTimestamp()), "[handleRemoteDelete] Could not find matching message! timestamp: " + delete.getTargetSentTimestamp() + " author: " + sender.getId());
ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), delete.getTargetSentTimestamp(), content);
warn(String.valueOf(content.getTimestamp()), "[handleRemoteDelete] Could not find matching message! timestamp: " + delete.getTargetSentTimestamp() + " author: " + senderRecipient.getId());
ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), delete.getTargetSentTimestamp(), content);
return null;
} else {
warn(String.valueOf(content.getTimestamp()), String.format(Locale.ENGLISH, "[handleRemoteDelete] Invalid remote delete! deleteTime: %d, targetTime: %d, deleteAuthor: %s, targetAuthor: %s",
content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), sender.getId(), targetMessage.getRecipient().getId()));
content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), senderRecipient.getId(), targetMessage.getRecipient().getId()));
return null;
}
}
@ -952,7 +958,7 @@ public final class MessageContentProcessor {
throws BadGroupIdException
{
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
Recipient recipient;
@ -1025,7 +1031,8 @@ public final class MessageContentProcessor {
}
private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
@NonNull SentTranscriptMessage message)
@NonNull SentTranscriptMessage message,
@NonNull Recipient senderRecipient)
throws StorageFailedException, BadGroupIdException, IOException, GroupChangeBusyException
{
log(String.valueOf(content.getTimestamp()), "Processing sent transcript for message with ID " + message.getTimestamp());
@ -1035,7 +1042,7 @@ public final class MessageContentProcessor {
if (message.getMessage().isGroupV2Message()) {
GroupId.V2 groupId = GroupId.v2(message.getMessage().getGroupContext().get().getGroupV2().get().getMasterKey());
if (handleGv2PreProcessing(groupId, content, message.getMessage().getGroupContext().get().getGroupV2().get())) {
if (handleGv2PreProcessing(groupId, content, message.getMessage().getGroupContext().get().getGroupV2().get(), senderRecipient)) {
return;
}
}
@ -1053,16 +1060,16 @@ public final class MessageContentProcessor {
handleSynchronizeSentGv2Update(content, message);
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(getSyncMessageDestination(message));
} else if (Build.VERSION.SDK_INT > 19 && message.getMessage().getGroupCallUpdate().isPresent()) {
handleGroupCallUpdateMessage(content, message.getMessage(), GroupUtil.idFromGroupContext(message.getMessage().getGroupContext()));
handleGroupCallUpdateMessage(content, message.getMessage(), GroupUtil.idFromGroupContext(message.getMessage().getGroupContext()), senderRecipient);
} else if (message.getMessage().isEmptyGroupV2Message()) {
warn(content.getTimestamp(), "Empty GV2 message! Doing nothing.");
} else if (message.getMessage().isExpirationUpdate()) {
threadId = handleSynchronizeSentExpirationUpdate(message);
} else if (message.getMessage().getReaction().isPresent()) {
handleReaction(content, message.getMessage());
handleReaction(content, message.getMessage(), senderRecipient);
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(getSyncMessageDestination(message));
} else if (message.getMessage().getRemoteDelete().isPresent()) {
handleRemoteDelete(content, message.getMessage());
handleRemoteDelete(content, message.getMessage(), senderRecipient);
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent() || message.getMessage().getPreviews().isPresent() || message.getMessage().getSticker().isPresent() || message.getMessage().isViewOnce() || message.getMessage().getMentions().isPresent()) {
threadId = handleSynchronizeSentMediaMessage(message);
} else {
@ -1070,7 +1077,7 @@ public final class MessageContentProcessor {
}
if (message.getMessage().getGroupContext().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.idFromGroupContext(message.getMessage().getGroupContext().get()))) {
handleUnknownGroupMessage(content, message.getMessage().getGroupContext().get());
handleUnknownGroupMessage(content, message.getMessage().getGroupContext().get(), senderRecipient);
}
if (message.getMessage().getProfileKey().isPresent()) {
@ -1136,14 +1143,14 @@ public final class MessageContentProcessor {
}
}
private void handleSynchronizeReadMessage(@NonNull List<ReadMessage> readMessages, long envelopeTimestamp)
private void handleSynchronizeReadMessage(@NonNull List<ReadMessage> readMessages, long envelopeTimestamp, @NonNull Recipient senderRecipient)
{
Map<Long, Long> threadToLatestRead = new HashMap<>();
for (ReadMessage readMessage : readMessages) {
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()),
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()),
envelopeTimestamp,
threadToLatestRead);
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()),
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()),
envelopeTimestamp,
threadToLatestRead);
@ -1210,10 +1217,12 @@ public final class MessageContentProcessor {
private @Nullable MessageId handleMediaMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId,
@NonNull Recipient senderRecipient,
@NonNull Recipient threadRecipient,
long receivedTime)
throws StorageFailedException, BadGroupIdException
throws StorageFailedException
{
notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice());
notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient, content.getSenderDevice());
Optional<InsertResult> insertResult;
@ -1227,7 +1236,7 @@ public final class MessageContentProcessor {
Optional<List<Mention>> mentions = getMentions(message.getMentions());
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(RecipientId.fromHighTrust(content.getSender()),
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(),
message.getTimestamp(),
content.getServerReceivedTimestamp(),
receivedTime,
@ -1414,18 +1423,18 @@ public final class MessageContentProcessor {
}
private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, long messageId, @NonNull GroupId groupString) {
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
List<Recipient> messageRecipients = Stream.of(message.getRecipients()).map(address -> Recipient.externalPush(context, address)).toList();
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
Map<RecipientId, Integer> localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId))
.collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus));
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
List<RecipientId> messageRecipientIds = Stream.of(message.getRecipients()).map(RecipientId::from).toList();
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupString, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
Map<RecipientId, Integer> localReceipts = Stream.of(receiptDatabase.getGroupReceiptInfo(messageId))
.collect(Collectors.toMap(GroupReceiptInfo::getRecipientId, GroupReceiptInfo::getStatus));
for (Recipient messageRecipient : messageRecipients) {
for (RecipientId messageRecipientId : messageRecipientIds) {
//noinspection ConstantConditions
if (localReceipts.containsKey(messageRecipient.getId()) && localReceipts.get(messageRecipient.getId()) < GroupReceiptDatabase.STATUS_UNDELIVERED) {
receiptDatabase.update(messageRecipient.getId(), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
} else if (!localReceipts.containsKey(messageRecipient.getId())) {
receiptDatabase.insert(Collections.singletonList(messageRecipient.getId()), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
if (localReceipts.containsKey(messageRecipientId) && localReceipts.get(messageRecipientId) < GroupReceiptDatabase.STATUS_UNDELIVERED) {
receiptDatabase.update(messageRecipientId, messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
} else if (!localReceipts.containsKey(messageRecipientId)) {
receiptDatabase.insert(Collections.singletonList(messageRecipientId), messageId, GroupReceiptDatabase.STATUS_UNDELIVERED, message.getTimestamp());
}
}
@ -1439,15 +1448,16 @@ public final class MessageContentProcessor {
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId,
@NonNull Optional<GroupId> groupId,
@NonNull Recipient senderRecipient,
@NonNull Recipient threadRecipient,
long receivedTime)
throws StorageFailedException, BadGroupIdException
throws StorageFailedException
{
MessageDatabase database = DatabaseFactory.getSmsDatabase(context);
String body = message.getBody().isPresent() ? message.getBody().get() : "";
Recipient recipient = getMessageDestination(content, message);
MessageDatabase database = DatabaseFactory.getSmsDatabase(context);
String body = message.getBody().isPresent() ? message.getBody().get() : "";
if (message.getExpiresInSeconds() != recipient.getExpireMessages()) {
handleExpirationUpdate(content, message, Optional.absent(), groupId, receivedTime);
if (message.getExpiresInSeconds() != threadRecipient.getExpireMessages()) {
handleExpirationUpdate(content, message, Optional.absent(), groupId, senderRecipient, threadRecipient, receivedTime);
}
Optional<InsertResult> insertResult;
@ -1455,9 +1465,9 @@ public final class MessageContentProcessor {
if (smsMessageId.isPresent() && !message.getGroupContext().isPresent()) {
insertResult = Optional.of(database.updateBundleMessageBody(smsMessageId.get(), body));
} else {
notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice());
notifyTypingStoppedFromIncomingMessage(senderRecipient, threadRecipient, content.getSenderDevice());
IncomingTextMessage textMessage = new IncomingTextMessage(RecipientId.fromHighTrust(content.getSender()),
IncomingTextMessage textMessage = new IncomingTextMessage(senderRecipient.getId(),
content.getSenderDevice(),
message.getTimestamp(),
content.getServerReceivedTimestamp(),
@ -1635,15 +1645,15 @@ public final class MessageContentProcessor {
}
private void handleProfileKey(@NonNull SignalServiceContent content,
@NonNull byte[] messageProfileKeyBytes)
@NonNull byte[] messageProfileKeyBytes,
@NonNull Recipient senderRecipient)
{
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
Recipient recipient = Recipient.externalHighTrustPush(context, content.getSender());
ProfileKey messageProfileKey = ProfileKeyUtil.profileKeyOrNull(messageProfileKeyBytes);
ProfileKey messageProfileKey = ProfileKeyUtil.profileKeyOrNull(messageProfileKeyBytes);
if (messageProfileKey != null) {
if (database.setProfileKey(recipient.getId(), messageProfileKey)) {
ApplicationDependencies.getJobManager().add(RetrieveProfileJob.forRecipient(recipient.getId()));
if (database.setProfileKey(senderRecipient.getId(), messageProfileKey)) {
ApplicationDependencies.getJobManager().add(RetrieveProfileJob.forRecipient(senderRecipient.getId()));
}
} else {
warn(String.valueOf(content.getTimestamp()), "Ignored invalid profile key seen in message");
@ -1664,84 +1674,83 @@ public final class MessageContentProcessor {
}
private void handleViewedReceipt(@NonNull SignalServiceContent content,
@NonNull SignalServiceReceiptMessage message)
@NonNull SignalServiceReceiptMessage message,
@NonNull Recipient senderRecipient)
{
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
log("Ignoring viewed receipts for IDs: " + Util.join(message.getTimestamps(), ", "));
return;
}
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
log(TAG, "Processing viewed receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
log(TAG, "Processing viewed receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
List<SyncMessageId> ids = Stream.of(message.getTimestamps())
.map(t -> new SyncMessageId(sender.getId(), t))
.map(t -> new SyncMessageId(senderRecipient.getId(), t))
.toList();
Collection<SyncMessageId> unhandled = DatabaseFactory.getMmsSmsDatabase(context)
.incrementViewedReceiptCounts(ids, content.getTimestamp());
for (SyncMessageId id : unhandled) {
warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + sender.getId());
ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), id.getTimetamp(), content);
warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId());
ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), id.getTimetamp(), content);
}
}
@SuppressLint("DefaultLocale")
private void handleDeliveryReceipt(@NonNull SignalServiceContent content,
@NonNull SignalServiceReceiptMessage message)
@NonNull SignalServiceReceiptMessage message,
@NonNull Recipient senderRecipient)
{
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
log(TAG, "Processing delivery receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
log(TAG, "Processing delivery receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
List<SyncMessageId> ids = Stream.of(message.getTimestamps())
.map(t -> new SyncMessageId(sender.getId(), t))
.map(t -> new SyncMessageId(senderRecipient.getId(), t))
.toList();
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCounts(ids, System.currentTimeMillis());
DatabaseFactory.getMessageLogDatabase(context).deleteEntriesForRecipient(message.getTimestamps(), sender.getId(), content.getSenderDevice());
DatabaseFactory.getMessageLogDatabase(context).deleteEntriesForRecipient(message.getTimestamps(), senderRecipient.getId(), content.getSenderDevice());
}
@SuppressLint("DefaultLocale")
private void handleReadReceipt(@NonNull SignalServiceContent content,
@NonNull SignalServiceReceiptMessage message)
@NonNull SignalServiceReceiptMessage message,
@NonNull Recipient senderRecipient)
{
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
log("Ignoring read receipts for IDs: " + Util.join(message.getTimestamps(), ", "));
return;
}
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
log(TAG, "Processing read receipts. Sender: " + sender.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
log(TAG, "Processing read receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", "));
List<SyncMessageId> ids = Stream.of(message.getTimestamps())
.map(t -> new SyncMessageId(sender.getId(), t))
.map(t -> new SyncMessageId(senderRecipient.getId(), t))
.toList();
Collection<SyncMessageId> unhandled = DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCounts(ids, content.getTimestamp());
for (SyncMessageId id : unhandled) {
warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + sender.getId());
ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), id.getTimetamp(), content);
warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId());
ApplicationDependencies.getEarlyMessageCache().store(senderRecipient.getId(), id.getTimetamp(), content);
}
}
private void handleTypingMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceTypingMessage typingMessage)
@NonNull SignalServiceTypingMessage typingMessage,
@NonNull Recipient senderRecipient)
throws BadGroupIdException
{
if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
return;
}
Recipient author = Recipient.externalHighTrustPush(context, content.getSender());
long threadId;
if (typingMessage.getGroupId().isPresent()) {
GroupId.Push groupId = GroupId.push(typingMessage.getGroupId().get());
if (!DatabaseFactory.getGroupDatabase(context).isCurrentMember(groupId, author.getId())) {
if (!DatabaseFactory.getGroupDatabase(context).isCurrentMember(groupId, senderRecipient.getId())) {
warn(String.valueOf(content.getTimestamp()), "Seen typing indicator for non-member");
return;
}
@ -1750,7 +1759,7 @@ public final class MessageContentProcessor {
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
} else {
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(author);
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(senderRecipient);
}
if (threadId <= 0) {
@ -1760,35 +1769,34 @@ public final class MessageContentProcessor {
if (typingMessage.isTypingStarted()) {
Log.d(TAG, "Typing started on thread " + threadId);
ApplicationDependencies.getTypingStatusRepository().onTypingStarted(context,threadId, author, content.getSenderDevice());
ApplicationDependencies.getTypingStatusRepository().onTypingStarted(context,threadId, senderRecipient, content.getSenderDevice());
} else {
Log.d(TAG, "Typing stopped on thread " + threadId);
ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, author, content.getSenderDevice(), false);
ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, senderRecipient, content.getSenderDevice(), false);
}
}
private void handleRetryReceipt(@NonNull SignalServiceContent content, @NonNull DecryptionErrorMessage decryptionErrorMessage) {
private void handleRetryReceipt(@NonNull SignalServiceContent content, @NonNull DecryptionErrorMessage decryptionErrorMessage, @NonNull Recipient senderRecipient) {
if (!FeatureFlags.senderKey()) {
warn(String.valueOf(content.getTimestamp()), "[RetryReceipt] Sender key not enabled, skipping retry receipt.");
return;
}
Recipient requester = Recipient.externalHighTrustPush(context, content.getSender());
long sentTimestamp = decryptionErrorMessage.getTimestamp();
long sentTimestamp = decryptionErrorMessage.getTimestamp();
warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + requester.getId() + ", device " + decryptionErrorMessage.getDeviceId() + " for message with timestamp " + sentTimestamp + ".");
warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + senderRecipient.getId() + ", device " + decryptionErrorMessage.getDeviceId() + " for message with timestamp " + sentTimestamp + ".");
if (!requester.hasUuid()) {
warn(content.getTimestamp(), "[RetryReceipt] Requester " + requester.getId() + " somehow has no UUID! timestamp: " + sentTimestamp);
if (!senderRecipient.hasUuid()) {
warn(content.getTimestamp(), "[RetryReceipt] Requester " + senderRecipient.getId() + " somehow has no UUID! timestamp: " + sentTimestamp);
return;
}
MessageLogEntry messageLogEntry = DatabaseFactory.getMessageLogDatabase(context).getLogEntry(requester.getId(), content.getSenderDevice(), sentTimestamp);
MessageLogEntry messageLogEntry = DatabaseFactory.getMessageLogDatabase(context).getLogEntry(senderRecipient.getId(), content.getSenderDevice(), sentTimestamp);
if (decryptionErrorMessage.getRatchetKey().isPresent()) {
handleIndividualRetryReceipt(requester, messageLogEntry, content, decryptionErrorMessage);
handleIndividualRetryReceipt(senderRecipient, messageLogEntry, content, decryptionErrorMessage);
} else {
handleSenderKeyRetryReceipt(requester, messageLogEntry, content, decryptionErrorMessage);
handleSenderKeyRetryReceipt(senderRecipient, messageLogEntry, content, decryptionErrorMessage);
}
}
@ -2088,20 +2096,6 @@ public final class MessageContentProcessor {
return getGroupRecipient(message != null ? message.getGroupContext() : Optional.absent()).or(() -> Recipient.externalHighTrustPush(context, content.getSender()));
}
private Recipient getMessageDestination(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message)
throws BadGroupIdException
{
return getGroupRecipient(message.getGroupContext()).or(() -> Recipient.externalHighTrustPush(context, content.getSender()));
}
private Recipient getMessageDestination(@NonNull SignalServiceContent content,
@NonNull Optional<SignalServiceGroupContext> groupContext)
throws BadGroupIdException
{
return getGroupRecipient(groupContext).or(() -> Recipient.externalPush(context, content.getSender()));
}
private Optional<Recipient> getGroupRecipient(Optional<SignalServiceGroupContext> message)
throws BadGroupIdException
{
@ -2111,29 +2105,20 @@ public final class MessageContentProcessor {
return Optional.absent();
}
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull SignalServiceAddress sender, int device) {
Recipient author = Recipient.externalPush(context, sender);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient);
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient senderRecipient, @NonNull Recipient conversationRecipient, int device) {
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient);
if (threadId > 0 && TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
Log.d(TAG, "Typing stopped on thread " + threadId + " due to an incoming message.");
ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, author, device, true);
ApplicationDependencies.getTypingStatusRepository().onTypingStopped(context, threadId, senderRecipient, device, true);
}
}
private boolean shouldIgnore(@Nullable SignalServiceContent content)
private boolean shouldIgnore(@NonNull SignalServiceContent content, @NonNull Recipient sender, @NonNull Recipient conversation)
throws BadGroupIdException
{
if (content == null) {
warn("Got a message with null content.");
return true;
}
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
if (content.getDataMessage().isPresent()) {
SignalServiceDataMessage message = content.getDataMessage().get();
Recipient conversation = getMessageDestination(content, message);
SignalServiceDataMessage message = content.getDataMessage().get();
if (conversation.isGroup() && conversation.isBlocked()) {
return true;