Reduce Recipient usage in group-related jobs.

This commit is contained in:
Greyson Parrelli 2026-06-08 12:34:34 -04:00 committed by Cody Henthorne
parent 135bc6e560
commit 4c08b94b88
8 changed files with 139 additions and 99 deletions

View File

@ -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<Recipient>,
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,

View File

@ -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<RecipientId> recipientIds = RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())).stream()
.filter(recipient -> !recipient.isSelf())
List<RecipientId> 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<Recipient> destinations = recipients.stream().map(Recipient::resolved).collect(Collectors.toList());
List<Recipient> completions = deliver(conversationRecipient, destinations);
List<Recipient> 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<Recipient> deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations)
private @NonNull List<Recipient> deliver(@NonNull GroupId groupId, @NonNull List<Recipient> 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<Recipient> nonSelfDestinations = destinations.stream().filter(r -> !r.isSelf()).collect(Collectors.toList());
boolean includesSelf = nonSelfDestinations.size() != destinations.size();
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context,
conversationRecipient.requireGroupId().requireV2(),
groupId.requireV2(),
nonSelfDestinations,
false,
ContentHint.DEFAULT,

View File

@ -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<Recipient>, targetAuthor: Recipient, targetSentTimestamp: Long, poll: PollRecord): List<Recipient> {
private fun deliver(conversationRecipient: RecipientRecord, destinations: List<Recipient>, targetAuthor: Recipient, targetSentTimestamp: Long, poll: PollRecord): List<Recipient> {
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))
}

View File

@ -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<RecipientId> recipients = conversationRecipient.isGroup()
? RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds()))
List<RecipientId> 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<Recipient> destinations = recipients.stream().map(Recipient::resolved).collect(Collectors.toList());

View File

@ -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!");
}

View File

@ -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<RecipientId> 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<RecipientId> 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<Recipient> deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations, @NonNull Recipient targetAuthor, long targetSentTimestamp)
private @NonNull List<Recipient> deliver(@NonNull RecipientRecord conversationRecipient, @NonNull List<Recipient> 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<Recipient> nonSelfDestinations = destinations.stream().filter(r -> !r.isSelf()).collect(Collectors.toList());
boolean includesSelf = nonSelfDestinations.size() != destinations.size();
List<SendMessageResult> results = GroupSendUtil.sendResendableDataMessage(context,
conversationRecipient.getGroupId().map(GroupId::requireV2).orElse(null),
conversationRecipient.getGroupId() != null ? conversationRecipient.getGroupId().requireV2() : null,
null,
nonSelfDestinations,
false,

View File

@ -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<RecipientId> 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<Recipient> 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<SendMessageResult> 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);
}

View File

@ -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<Recipient>, threadId: Long, targetAuthor: Recipient, targetSentTimestamp: Long): List<Recipient> {
private fun deliver(conversationRecipient: RecipientRecord, destinations: List<Recipient>, threadId: Long, targetAuthor: Recipient, targetSentTimestamp: Long): List<Recipient> {
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,