From 4c08b94b8825fdfbecf46365813256d843519818 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 8 Jun 2026 12:34:34 -0400 Subject: [PATCH] Reduce Recipient usage in group-related jobs. --- .../securesms/jobs/AdminDeleteSendJob.kt | 31 ++++++++----- .../jobs/GroupCallUpdateSendJob.java | 24 ++++++----- .../securesms/jobs/PollVoteJob.kt | 34 +++++++++------ .../securesms/jobs/ProfileKeySendJob.java | 26 +++++------ .../securesms/jobs/PushGroupSendJob.java | 9 ++-- .../securesms/jobs/ReactionSendJob.java | 39 +++++++++-------- .../securesms/jobs/RemoteDeleteSendJob.java | 43 +++++++++++-------- .../securesms/jobs/UnpinMessageJob.kt | 32 ++++++++------ 8 files changed, 139 insertions(+), 99 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AdminDeleteSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/AdminDeleteSendJob.kt index d32107f517..0d17d2567c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AdminDeleteSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AdminDeleteSendJob.kt @@ -3,9 +3,11 @@ package org.thoughtcrime.securesms.jobs import org.signal.core.models.ServiceId import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log.tag +import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.documents.NetworkFailure import org.thoughtcrime.securesms.database.model.MessageId +import org.thoughtcrime.securesms.database.model.RecipientRecord import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint @@ -20,7 +22,6 @@ import org.thoughtcrime.securesms.util.GroupUtil import org.whispersystems.signalservice.api.crypto.ContentHint import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Companion.newBuilder -import kotlin.jvm.optionals.getOrNull import kotlin.time.Duration.Companion.days /** @@ -45,13 +46,17 @@ class AdminDeleteSendJob private constructor( return null } - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) - if (conversationRecipient == null) { + if (conversationRecipientId == null) { return null } - val recipientIds = filterRecipients.ifEmpty { conversationRecipient.participantIds }.map { it.toLong() }.toMutableList() + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val groupId = conversationRecipient.groupId + val members = if (groupId != null) SignalDatabase.groups.getGroupMemberIds(groupId, GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF) else emptyList() + + val recipientIds = filterRecipients.ifEmpty { members }.map { it.toLong() }.toMutableList() return AdminDeleteSendJob( messageId = messageId, @@ -96,18 +101,21 @@ class AdminDeleteSendJob private constructor( val targetSentTimestamp = message.dateSent val targetAuthor = message.fromRecipient.requireServiceId() - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) - if (conversationRecipient == null) { + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) + if (conversationRecipientId == null) { Log.w(TAG, "We have a message, but couldn't find the thread!") return Result.failure() } - if (!conversationRecipient.isPushV2Group) { + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val groupId = conversationRecipient.groupId + + if (groupId == null || !groupId.isV2) { Log.w(TAG, "Cannot admin delete in a non V2 group.") return Result.failure() } - val groupRecord = SignalDatabase.groups.getGroup(conversationRecipient.requireGroupId()) + val groupRecord = SignalDatabase.groups.getGroup(groupId) if (groupRecord.isPresent && groupRecord.get().isTerminated) { Log.w(TAG, "Cannot admin delete in a terminated group.") return Result.failure() @@ -175,7 +183,7 @@ class AdminDeleteSendJob private constructor( } private fun deliver( - conversationRecipient: Recipient, + conversationRecipient: RecipientRecord, destinations: MutableList, targetAuthor: ServiceId, targetSentTimestamp: Long @@ -184,7 +192,8 @@ class AdminDeleteSendJob private constructor( .withTimestamp(System.currentTimeMillis()) .withAdminDelete(SignalServiceDataMessage.AdminDelete(targetAuthor, targetSentTimestamp)) - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()) + val groupId = conversationRecipient.groupId!! + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, groupId.requirePush()) val nonSelfDestinations = destinations.filterNot { it.isSelf } val includeSelf = destinations.size != nonSelfDestinations.size @@ -193,7 +202,7 @@ class AdminDeleteSendJob private constructor( val results = GroupSendUtil.sendResendableDataMessage( context, - conversationRecipient.groupId.map { it.requireV2() }.getOrNull(), + groupId.requireV2(), null, nonSelfDestinations, false, diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java index f15ec56932..bfe094b885 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java @@ -6,8 +6,11 @@ import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.SignalDatabase; +import org.thoughtcrime.securesms.database.model.RecipientRecord; import org.thoughtcrime.securesms.dependencies.AppDependencies; +import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint; @@ -54,14 +57,13 @@ public class GroupCallUpdateSendJob extends BaseJob { @WorkerThread public static @NonNull GroupCallUpdateSendJob create(@NonNull RecipientId recipientId, @Nullable String eraId) { - Recipient conversationRecipient = Recipient.resolved(recipientId); + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(recipientId); - if (!conversationRecipient.isPushV2Group()) { + if (conversationRecipient.getGroupId() == null || !conversationRecipient.getGroupId().isV2()) { throw new AssertionError("We have a recipient, but it's not a V2 Group"); } - List recipientIds = RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())).stream() - .filter(recipient -> !recipient.isSelf()) + List recipientIds = RecipientUtil.getEligibleForSending(Recipient.resolvedList(SignalDatabase.groups().getGroupMemberIds(conversationRecipient.getGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF))).stream() .map(Recipient::getId).collect(Collectors.toList()); return new GroupCallUpdateSendJob(recipientId, @@ -114,19 +116,19 @@ public class GroupCallUpdateSendJob extends BaseJob { throw new NotPushRegisteredException(); } - Recipient conversationRecipient = Recipient.resolved(recipientId); + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(recipientId); - if (!conversationRecipient.isPushV2Group()) { + if (conversationRecipient.getGroupId() == null || !conversationRecipient.getGroupId().isV2()) { throw new AssertionError("We have a recipient, but it's not a V2 Group"); } - if (!SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) { + if (!SignalDatabase.groups().isActive(conversationRecipient.getGroupId())) { Log.w(TAG, "Not sending group call update to terminated or inactive group."); return; } List destinations = recipients.stream().map(Recipient::resolved).collect(Collectors.toList()); - List completions = deliver(conversationRecipient, destinations); + List completions = deliver(conversationRecipient.getGroupId(), destinations); for (Recipient completion : completions) { recipients.remove(completion.getId()); @@ -166,20 +168,20 @@ public class GroupCallUpdateSendJob extends BaseJob { Log.w(TAG, "Failed to send the group update to all recipients!"); } - private @NonNull List deliver(@NonNull Recipient conversationRecipient, @NonNull List destinations) + private @NonNull List deliver(@NonNull GroupId groupId, @NonNull List destinations) throws IOException, UntrustedIdentityException { SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder() .withTimestamp(System.currentTimeMillis()) .withGroupCallUpdate(new SignalServiceDataMessage.GroupCallUpdate(eraId)); - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()); + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, groupId.requirePush()); SignalServiceDataMessage dataMessage = dataMessageBuilder.build(); List nonSelfDestinations = destinations.stream().filter(r -> !r.isSelf()).collect(Collectors.toList()); boolean includesSelf = nonSelfDestinations.size() != destinations.size(); List results = GroupSendUtil.sendUnresendableDataMessage(context, - conversationRecipient.requireGroupId().requireV2(), + groupId.requireV2(), nonSelfDestinations, false, ContentHint.DEFAULT, diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PollVoteJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/PollVoteJob.kt index 4f66e03e56..2ecb9028c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PollVoteJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PollVoteJob.kt @@ -1,10 +1,11 @@ package org.thoughtcrime.securesms.jobs import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.MessageId +import org.thoughtcrime.securesms.database.model.RecipientRecord import org.thoughtcrime.securesms.dependencies.AppDependencies -import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint @@ -45,14 +46,17 @@ class PollVoteJob( return null } - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) - if (conversationRecipient == null) { + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) + if (conversationRecipientId == null) { Log.w(TAG, "We have a message, but couldn't find the thread!") return null } - val recipients = if (conversationRecipient.isGroup) { - conversationRecipient.participantIds.filter { it != Recipient.self().id }.map { it.toLong() } + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val groupId = conversationRecipient.groupId + + val recipients = if (groupId != null) { + SignalDatabase.groups.getGroupMemberIds(groupId, GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF).map { it.toLong() } } else { listOf(conversationRecipient.id.toLong()) } @@ -95,13 +99,16 @@ class PollVoteJob( return Result.failure() } - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) - if (conversationRecipient == null) { + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) + if (conversationRecipientId == null) { Log.w(TAG, "We have a message, but couldn't find the thread!") return Result.failure() } - if (conversationRecipient.isPushV2Group && !SignalDatabase.groups.isActive(conversationRecipient.requireGroupId())) { + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val groupId = conversationRecipient.groupId + + if (groupId != null && groupId.isV2 && !SignalDatabase.groups.isActive(groupId)) { Log.w(TAG, "Cannot send poll vote to terminated or inactive group.") return Result.failure() } @@ -138,7 +145,7 @@ class PollVoteJob( return Result.success() } - private fun deliver(conversationRecipient: Recipient, destinations: List, targetAuthor: Recipient, targetSentTimestamp: Long, poll: PollRecord): List { + private fun deliver(conversationRecipient: RecipientRecord, destinations: List, targetAuthor: Recipient, targetSentTimestamp: Long, poll: PollRecord): List { val votes = SignalDatabase.polls.getVotes(poll.id, poll.allowMultipleVotes, voteCount) val dataMessageBuilder = newBuilder() @@ -152,8 +159,9 @@ class PollVoteJob( ) ) - if (conversationRecipient.isPushV2Group) { - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()) + val groupId = conversationRecipient.groupId + if (groupId != null && groupId.isV2) { + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, groupId.requirePush()) } val dataMessage = dataMessageBuilder.build() @@ -161,7 +169,7 @@ class PollVoteJob( val results = GroupSendUtil.sendResendableDataMessage( context, - conversationRecipient.groupId.map { obj: GroupId -> obj.requireV2() }.orElse(null), + groupId?.requireV2(), null, nonSelfDestinations, false, @@ -174,7 +182,7 @@ class PollVoteJob( null ) - if (conversationRecipient.isSelf) { + if (conversationRecipient.id == Recipient.self().id) { results.add(AppDependencies.signalServiceMessageSender.sendSyncMessage(dataMessage)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java index 1b9de07525..519bb00f61 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java @@ -5,7 +5,9 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.SignalDatabase; +import org.thoughtcrime.securesms.database.model.RecipientRecord; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.DecryptionsDrainedConstraint; @@ -81,22 +83,24 @@ public class ProfileKeySendJob extends BaseJob { */ @WorkerThread public static @Nullable ProfileKeySendJob create(long threadId, boolean queueLimits) { - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(threadId); + RecipientId conversationRecipientId = SignalDatabase.threads().getRecipientIdForThreadId(threadId); - if (conversationRecipient == null) { + if (conversationRecipientId == null) { Log.w(TAG, "Thread no longer valid! Aborting."); return null; } - if (conversationRecipient.isPushV2Group()) { + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(conversationRecipientId); + + if (conversationRecipient.getGroupId() != null && conversationRecipient.getGroupId().isV2()) { throw new AssertionError("Do not send profile keys directly for GV2"); } - List recipients = conversationRecipient.isGroup() - ? RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())) + List recipients = conversationRecipient.getGroupId() != null + ? RecipientUtil.getEligibleForSending(Recipient.resolvedList(SignalDatabase.groups().getGroupMemberIds(conversationRecipient.getGroupId(), GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF))) .stream() .map(Recipient::getId).collect(Collectors.toList()) - : Stream.of(conversationRecipient.getId()).collect(Collectors.toList()); + : Stream.of(conversationRecipient.getId()).collect(Collectors.toList()); recipients.remove(Recipient.self().getId()); @@ -133,13 +137,9 @@ public class ProfileKeySendJob extends BaseJob { throw new NotPushRegisteredException(); } - if (threadId > 0) { - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(threadId); - - if (conversationRecipient == null) { - Log.w(TAG, "Thread no longer present"); - return; - } + if (threadId > 0 && SignalDatabase.threads().getRecipientIdForThreadId(threadId) == null) { + Log.w(TAG, "Thread no longer present"); + return; } List destinations = recipients.stream().map(Recipient::resolved).collect(Collectors.toList()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 757070c3dc..753aba39b1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.database.model.GroupRecord; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.database.model.RecipientRecord; import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.groups.GroupAccessControl; import org.thoughtcrime.securesms.groups.GroupId; @@ -119,12 +120,12 @@ public final class PushGroupSendJob extends PushSendJob { boolean isScheduledSend) { try { - Recipient group = Recipient.resolved(destination); - if (!group.isPushGroup()) { + RecipientRecord group = SignalDatabase.recipients().getRecord(destination); + if (group.getGroupId() == null || !group.getGroupId().isPush()) { throw new AssertionError("Not a group!"); } - if (group.isPushV1Group()) { + if (group.getGroupId().isV1()) { throw new MmsException("Cannot send to GV1 groups"); } @@ -145,7 +146,7 @@ public final class PushGroupSendJob extends PushSendJob { throw new MmsException("Cannot send a gift badge to a group!"); } - if (!SignalDatabase.groups().isActive(group.requireGroupId()) && !isGv2UpdateMessage(message)) { + if (!SignalDatabase.groups().isActive(group.getGroupId()) && !isGv2UpdateMessage(message)) { throw new MmsException("Inactive group!"); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java index 67680ebcf5..9bd0d5a94d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java @@ -7,14 +7,15 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.ReactionTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.ReactionRecord; +import org.thoughtcrime.securesms.database.model.RecipientRecord; import org.thoughtcrime.securesms.dependencies.AppDependencies; -import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; @@ -70,19 +71,19 @@ public class ReactionSendJob extends BaseJob { { MessageRecord message = SignalDatabase.messages().getMessageRecord(messageId.getId()); - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId()); + RecipientId conversationRecipientId = SignalDatabase.threads().getRecipientIdForThreadId(message.getThreadId()); - if (conversationRecipient == null) { + if (conversationRecipientId == null) { throw new AssertionError("We have a message, but couldn't find the thread!"); } - RecipientId selfId = Recipient.self().getId(); - List recipients = conversationRecipient.isGroup() ? RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())) - .stream() - .map(Recipient::getId) - .filter(r -> !r.equals(selfId)) - .collect(Collectors.toList()) - : Collections.singletonList(conversationRecipient.getId()); + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(conversationRecipientId); + + List recipients = conversationRecipient.getGroupId() != null ? RecipientUtil.getEligibleForSending(Recipient.resolvedList(SignalDatabase.groups().getGroupMemberIds(conversationRecipient.getGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF))) + .stream() + .map(Recipient::getId) + .collect(Collectors.toList()) + : Collections.singletonList(conversationRecipient.getId()); return new ReactionSendJob(messageId, recipients, @@ -158,18 +159,20 @@ public class ReactionSendJob extends BaseJob { return; } - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId()); + RecipientId conversationRecipientId = SignalDatabase.threads().getRecipientIdForThreadId(message.getThreadId()); - if (conversationRecipient == null) { + if (conversationRecipientId == null) { throw new AssertionError("We have a message, but couldn't find the thread!"); } - if (conversationRecipient.isPushV1Group() || conversationRecipient.isMmsGroup()) { + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(conversationRecipientId); + + if (conversationRecipient.getGroupId() != null && (conversationRecipient.getGroupId().isV1() || conversationRecipient.getGroupId().isMms())) { Log.w(TAG, "Cannot send reactions to legacy groups."); return; } - if (conversationRecipient.isPushV2Group() && !SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) { + if (conversationRecipient.getGroupId() != null && conversationRecipient.getGroupId().isV2() && !SignalDatabase.groups().isActive(conversationRecipient.getGroupId())) { Log.w(TAG, "Cannot send reactions to terminated or inactive groups."); return; } @@ -225,22 +228,22 @@ public class ReactionSendJob extends BaseJob { } } - private @NonNull List deliver(@NonNull Recipient conversationRecipient, @NonNull List destinations, @NonNull Recipient targetAuthor, long targetSentTimestamp) + private @NonNull List deliver(@NonNull RecipientRecord conversationRecipient, @NonNull List destinations, @NonNull Recipient targetAuthor, long targetSentTimestamp) throws IOException, UntrustedIdentityException { SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder() .withTimestamp(System.currentTimeMillis()) .withReaction(buildReaction(reaction, remove, targetAuthor, targetSentTimestamp)); - if (conversationRecipient.isGroup()) { - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()); + if (conversationRecipient.getGroupId() != null) { + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.getGroupId().requirePush()); } SignalServiceDataMessage dataMessage = dataMessageBuilder.build(); List nonSelfDestinations = destinations.stream().filter(r -> !r.isSelf()).collect(Collectors.toList()); boolean includesSelf = nonSelfDestinations.size() != destinations.size(); List results = GroupSendUtil.sendResendableDataMessage(context, - conversationRecipient.getGroupId().map(GroupId::requireV2).orElse(null), + conversationRecipient.getGroupId() != null ? conversationRecipient.getGroupId().requireV2() : null, null, nonSelfDestinations, false, diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java index 7b998f4487..e06a12a665 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java @@ -7,15 +7,17 @@ import androidx.annotation.WorkerThread; import org.signal.core.util.SetUtil; import org.signal.core.util.Util; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.NoSuchMessageException; +import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.DistributionListId; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; +import org.thoughtcrime.securesms.database.model.RecipientRecord; import org.thoughtcrime.securesms.dependencies.AppDependencies; -import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobmanager.JsonJobData; @@ -60,21 +62,23 @@ public class RemoteDeleteSendJob extends BaseJob { { MessageRecord message = SignalDatabase.messages().getMessageRecord(messageId); - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId()); + RecipientId conversationRecipientId = SignalDatabase.threads().getRecipientIdForThreadId(message.getThreadId()); - if (conversationRecipient == null) { + if (conversationRecipientId == null) { throw new AssertionError("We have a message, but couldn't find the thread!"); } + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(conversationRecipientId); + List recipients; - if (conversationRecipient.isDistributionList()) { + if (conversationRecipient.getDistributionListId() != null) { recipients = SignalDatabase.storySends().getRemoteDeleteRecipients(message.getId(), message.getTimestamp()); if (recipients.isEmpty()) { return AppDependencies.getJobManager().startChain(MultiDeviceStorySendSyncJob.create(message.getDateSent(), messageId)); } } else { - recipients = conversationRecipient.isGroup() - ? conversationRecipient.getParticipantIds().stream().collect(Collectors.toList()) + recipients = conversationRecipient.getGroupId() != null + ? SignalDatabase.groups().getGroupMemberIds(conversationRecipient.getGroupId(), GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF).stream().collect(Collectors.toList()) : Stream.of(conversationRecipient.getId()).collect(Collectors.toList()); } @@ -90,7 +94,7 @@ public class RemoteDeleteSendJob extends BaseJob { .setMaxAttempts(Parameters.UNLIMITED) .build()); - if (conversationRecipient.isDistributionList()) { + if (conversationRecipient.getDistributionListId() != null) { return AppDependencies.getJobManager() .startChain(sendJob) .then(MultiDeviceStorySendSyncJob.create(message.getDateSent(), messageId)); @@ -134,27 +138,32 @@ public class RemoteDeleteSendJob extends BaseJob { MessageRecord message = SignalDatabase.messages().getMessageRecord(messageId); long targetSentTimestamp = message.getDateSent(); - Recipient conversationRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId()); + RecipientId conversationRecipientId = SignalDatabase.threads().getRecipientIdForThreadId(message.getThreadId()); - if (conversationRecipient == null) { + if (conversationRecipientId == null) { throw new AssertionError("We have a message, but couldn't find the thread!"); } + RecipientRecord conversationRecipient = SignalDatabase.recipients().getRecord(conversationRecipientId); + if (!message.isOutgoing()) { throw new IllegalStateException("Cannot delete a message that isn't yours!"); } - if (!conversationRecipient.isRegistered() || conversationRecipient.isMmsGroup()) { + boolean isRegistered = conversationRecipient.getGroupId() != null ? !conversationRecipient.getGroupId().isMms() + : (conversationRecipient.getDistributionListId() != null || conversationRecipient.getRegistered() == RegisteredState.REGISTERED); + + if (!isRegistered) { Log.w(TAG, "Unable to remote delete non-push messages"); return; } - if (conversationRecipient.isPushV1Group()) { + if (conversationRecipient.getGroupId() != null && conversationRecipient.getGroupId().isV1()) { Log.w(TAG, "Unable to remote delete messages in GV1 groups"); return; } - if (conversationRecipient.isPushV2Group() && !SignalDatabase.groups().isActive(conversationRecipient.requireGroupId())) { + if (conversationRecipient.getGroupId() != null && conversationRecipient.getGroupId().isV2() && !SignalDatabase.groups().isActive(conversationRecipient.getGroupId())) { Log.w(TAG, "Unable to remote delete messages in terminated or inactive groups"); return; } @@ -214,7 +223,7 @@ public class RemoteDeleteSendJob extends BaseJob { Log.w(TAG, "Failed to send remote delete to all recipients! (" + (initialRecipientCount - recipients.size() + "/" + initialRecipientCount + ")") ); } - private @NonNull GroupSendJobHelper.SendResult deliver(@NonNull Recipient conversationRecipient, + private @NonNull GroupSendJobHelper.SendResult deliver(@NonNull RecipientRecord conversationRecipient, @NonNull List destinations, long targetSentTimestamp, boolean isForStory, @@ -225,13 +234,13 @@ public class RemoteDeleteSendJob extends BaseJob { .withTimestamp(System.currentTimeMillis()) .withRemoteDelete(new SignalServiceDataMessage.RemoteDelete(targetSentTimestamp)); - if (conversationRecipient.isGroup()) { - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()); + if (conversationRecipient.getGroupId() != null) { + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.getGroupId().requirePush()); } SignalServiceDataMessage dataMessage = dataMessageBuilder.build(); List results = GroupSendUtil.sendResendableDataMessage(context, - conversationRecipient.getGroupId().map(GroupId::requireV2).orElse(null), + conversationRecipient.getGroupId() != null ? conversationRecipient.getGroupId().requireV2() : null, distributionListId, destinations, false, @@ -243,7 +252,7 @@ public class RemoteDeleteSendJob extends BaseJob { null, null); - if (conversationRecipient.isSelf()) { + if (conversationRecipient.getId().equals(Recipient.self().getId())) { AppDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/UnpinMessageJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/UnpinMessageJob.kt index 9f503afdd6..c7ffb6d2b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/UnpinMessageJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/UnpinMessageJob.kt @@ -1,11 +1,12 @@ package org.thoughtcrime.securesms.jobs import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.MessageId +import org.thoughtcrime.securesms.database.model.RecipientRecord import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.groups.GroupAccessControl -import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.jobmanager.Job import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint @@ -46,16 +47,19 @@ class UnpinMessageJob( return null } - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) - if (conversationRecipient == null) { + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) + if (conversationRecipientId == null) { Log.w(TAG, "We have a message, but couldn't find the thread!") return null } + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val groupId = conversationRecipient.groupId + val recipients = if (initialRecipientIds.isNotEmpty()) { initialRecipientIds.map { it.toLong() } - } else if (conversationRecipient.isGroup) { - conversationRecipient.participantIds.filter { it != Recipient.self().id }.map { it.toLong() } + } else if (groupId != null) { + SignalDatabase.groups.getGroupMemberIds(groupId, GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF).map { it.toLong() } } else { listOf(conversationRecipient.id.toLong()) } @@ -95,19 +99,22 @@ class UnpinMessageJob( return Result.failure() } - val conversationRecipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId) - if (conversationRecipient == null) { + val conversationRecipientId = SignalDatabase.threads.getRecipientIdForThreadId(message.threadId) + if (conversationRecipientId == null) { Log.w(TAG, "We have a message, but couldn't find the thread!") return Result.failure() } + val conversationRecipient = SignalDatabase.recipients.getRecord(conversationRecipientId) + val targetAuthor = message.fromRecipient if (targetAuthor == null || !targetAuthor.hasServiceId) { Log.w(TAG, "Unable to find target author") return Result.failure() } - if (conversationRecipient.isPushV2Group) { + val groupId = conversationRecipient.groupId + if (groupId != null && groupId.isV2) { val groupRecord = SignalDatabase.groups.getGroup(conversationRecipient.id) if (groupRecord.isPresent && groupRecord.get().isTerminated) { Log.w(TAG, "Cannot send unpin messages to terminated group.") @@ -139,7 +146,7 @@ class UnpinMessageJob( return Result.success() } - private fun deliver(conversationRecipient: Recipient, destinations: List, threadId: Long, targetAuthor: Recipient, targetSentTimestamp: Long): List { + private fun deliver(conversationRecipient: RecipientRecord, destinations: List, threadId: Long, targetAuthor: Recipient, targetSentTimestamp: Long): List { val dataMessageBuilder = newBuilder() .withTimestamp(System.currentTimeMillis()) .withUnpinnedMessage( @@ -149,8 +156,9 @@ class UnpinMessageJob( ) ) - if (conversationRecipient.isGroup) { - GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush()) + val groupId = conversationRecipient.groupId + if (groupId != null) { + GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, groupId.requirePush()) } val dataMessage = dataMessageBuilder.build() @@ -160,7 +168,7 @@ class UnpinMessageJob( val results = GroupSendUtil.sendResendableDataMessage( context, - conversationRecipient.groupId.map { obj: GroupId -> obj.requireV2() }.orElse(null), + groupId?.requireV2(), null, nonSelfRecipients, false,