Fix resend after safety number change in groups or distribution lists.
This commit is contained in:
parent
2253e25ae1
commit
c56ef33833
6 changed files with 123 additions and 59 deletions
|
@ -32,7 +32,9 @@ import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
final class SafetyNumberChangeRepository {
|
final class SafetyNumberChangeRepository {
|
||||||
|
|
||||||
|
@ -153,6 +155,7 @@ final class SafetyNumberChangeRepository {
|
||||||
Log.d(TAG, "processOutgoingMessageRecord");
|
Log.d(TAG, "processOutgoingMessageRecord");
|
||||||
MessageDatabase smsDatabase = SignalDatabase.sms();
|
MessageDatabase smsDatabase = SignalDatabase.sms();
|
||||||
MessageDatabase mmsDatabase = SignalDatabase.mms();
|
MessageDatabase mmsDatabase = SignalDatabase.mms();
|
||||||
|
Set<RecipientId> resendIds = new HashSet<>();
|
||||||
|
|
||||||
for (ChangedRecipient changedRecipient : changedRecipients) {
|
for (ChangedRecipient changedRecipient : changedRecipients) {
|
||||||
RecipientId id = changedRecipient.getRecipient().getId();
|
RecipientId id = changedRecipient.getRecipient().getId();
|
||||||
|
@ -161,8 +164,8 @@ final class SafetyNumberChangeRepository {
|
||||||
if (messageRecord.isMms()) {
|
if (messageRecord.isMms()) {
|
||||||
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(), id, identityKey);
|
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(), id, identityKey);
|
||||||
|
|
||||||
if (messageRecord.getRecipient().isPushGroup()) {
|
if (messageRecord.getRecipient().isDistributionList() || messageRecord.getRecipient().isPushGroup()) {
|
||||||
MessageSender.resendGroupMessage(context, messageRecord, id);
|
resendIds.add(id);
|
||||||
} else {
|
} else {
|
||||||
MessageSender.resend(context, messageRecord);
|
MessageSender.resend(context, messageRecord);
|
||||||
}
|
}
|
||||||
|
@ -172,6 +175,14 @@ final class SafetyNumberChangeRepository {
|
||||||
MessageSender.resend(context, messageRecord);
|
MessageSender.resend(context, messageRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Util.hasItems(resendIds)) {
|
||||||
|
if (messageRecord.getRecipient().isPushGroup()) {
|
||||||
|
MessageSender.resendGroupMessage(context, messageRecord, resendIds);
|
||||||
|
} else {
|
||||||
|
MessageSender.resendDistributionList(context, messageRecord, resendIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class SafetyNumberChangeState {
|
static final class SafetyNumberChangeState {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.stories.Stories;
|
import org.thoughtcrime.securesms.stories.Stories;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
|
@ -37,10 +38,13 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
|
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A job that lets us send a message to a distribution list. Currently the only supported message type is a story.
|
* A job that lets us send a message to a distribution list. Currently the only supported message type is a story.
|
||||||
|
@ -52,30 +56,35 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||||
private static final String TAG = Log.tag(PushDistributionListSendJob.class);
|
private static final String TAG = Log.tag(PushDistributionListSendJob.class);
|
||||||
|
|
||||||
private static final String KEY_MESSAGE_ID = "message_id";
|
private static final String KEY_MESSAGE_ID = "message_id";
|
||||||
|
private static final String KEY_FILTERED_RECIPIENT_IDS = "filtered_recipient_ids";
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
private final Set<RecipientId> filterRecipientIds;
|
||||||
|
|
||||||
public PushDistributionListSendJob(long messageId, @NonNull RecipientId destination, boolean hasMedia) {
|
public PushDistributionListSendJob(long messageId, @NonNull RecipientId destination, boolean hasMedia, @NonNull Set<RecipientId> filterRecipientIds) {
|
||||||
this(new Parameters.Builder()
|
this(new Parameters.Builder()
|
||||||
.setQueue(destination.toQueueKey(hasMedia))
|
.setQueue(destination.toQueueKey(hasMedia))
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(Parameters.UNLIMITED)
|
.setMaxAttempts(Parameters.UNLIMITED)
|
||||||
.build(),
|
.build(),
|
||||||
messageId);
|
messageId,
|
||||||
|
filterRecipientIds
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PushDistributionListSendJob(@NonNull Parameters parameters, long messageId) {
|
private PushDistributionListSendJob(@NonNull Parameters parameters, long messageId, @NonNull Set<RecipientId> filterRecipientIds) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
|
this.filterRecipientIds = filterRecipientIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static void enqueue(@NonNull Context context,
|
public static void enqueue(@NonNull Context context,
|
||||||
@NonNull JobManager jobManager,
|
@NonNull JobManager jobManager,
|
||||||
long messageId,
|
long messageId,
|
||||||
@NonNull RecipientId destination)
|
@NonNull RecipientId destination,
|
||||||
|
@NonNull Set<RecipientId> filterRecipientIds)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Recipient listRecipient = Recipient.resolved(destination);
|
Recipient listRecipient = Recipient.resolved(destination);
|
||||||
|
@ -92,7 +101,7 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||||
|
|
||||||
Set<String> attachmentUploadIds = enqueueCompressingAndUploadAttachmentsChains(jobManager, message);
|
Set<String> attachmentUploadIds = enqueueCompressingAndUploadAttachmentsChains(jobManager, message);
|
||||||
|
|
||||||
jobManager.add(new PushDistributionListSendJob(messageId, destination, !attachmentUploadIds.isEmpty()), attachmentUploadIds, attachmentUploadIds.isEmpty() ? null : destination.toQueueKey());
|
jobManager.add(new PushDistributionListSendJob(messageId, destination, !attachmentUploadIds.isEmpty(), filterRecipientIds), attachmentUploadIds, attachmentUploadIds.isEmpty() ? null : destination.toQueueKey());
|
||||||
} catch (NoSuchMessageException | MmsException e) {
|
} catch (NoSuchMessageException | MmsException e) {
|
||||||
Log.w(TAG, "Failed to enqueue message.", e);
|
Log.w(TAG, "Failed to enqueue message.", e);
|
||||||
SignalDatabase.mms().markAsSentFailed(messageId);
|
SignalDatabase.mms().markAsSentFailed(messageId);
|
||||||
|
@ -102,7 +111,9 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId).build();
|
return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId)
|
||||||
|
.putString(KEY_FILTERED_RECIPIENT_IDS, RecipientId.toSerializedList(filterRecipientIds))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -142,15 +153,22 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||||
try {
|
try {
|
||||||
log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Attachments: " + buildAttachmentString(message.getAttachments()));
|
log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Attachments: " + buildAttachmentString(message.getAttachments()));
|
||||||
|
|
||||||
List<Recipient> target;
|
List<Recipient> targets;
|
||||||
|
|
||||||
if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
if (Util.hasItems(filterRecipientIds)) {
|
||||||
else target = Stream.of(Stories.getRecipientsToSendTo(messageId, message.getSentTimeMillis(), message.getStoryType().isStoryWithReplies())).distinctBy(Recipient::getId).toList();
|
targets = new ArrayList<>(filterRecipientIds.size() + existingNetworkFailures.size());
|
||||||
|
targets.addAll(filterRecipientIds.stream().map(Recipient::resolved).collect(Collectors.toList()));
|
||||||
|
targets.addAll(existingNetworkFailures.stream().map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).collect(Collectors.toList()));
|
||||||
|
} else if (!existingNetworkFailures.isEmpty()) {
|
||||||
|
targets = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
||||||
|
} else {
|
||||||
|
targets = Stream.of(Stories.getRecipientsToSendTo(messageId, message.getSentTimeMillis(), message.getStoryType().isStoryWithReplies())).distinctBy(Recipient::getId).toList();
|
||||||
|
}
|
||||||
|
|
||||||
List<SendMessageResult> results = deliver(message, target);
|
List<SendMessageResult> results = deliver(message, targets);
|
||||||
Log.i(TAG, JobLogger.format(this, "Finished send."));
|
Log.i(TAG, JobLogger.format(this, "Finished send."));
|
||||||
|
|
||||||
PushGroupSendJob.processGroupMessageResults(context, messageId, -1, null, message, results, target, Collections.emptyList(), existingNetworkFailures, existingIdentityMismatches);
|
PushGroupSendJob.processGroupMessageResults(context, messageId, -1, null, message, results, targets, Collections.emptyList(), existingNetworkFailures, existingIdentityMismatches);
|
||||||
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
|
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
|
||||||
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
|
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
|
@ -191,7 +209,8 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||||
public static class Factory implements Job.Factory<PushDistributionListSendJob> {
|
public static class Factory implements Job.Factory<PushDistributionListSendJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PushDistributionListSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull PushDistributionListSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
return new PushDistributionListSendJob(parameters, data.getLong(KEY_MESSAGE_ID));
|
Set<RecipientId> recipientIds = new HashSet<>(RecipientId.fromSerializedList(data.getStringOrDefault(KEY_FILTERED_RECIPIENT_IDS, "")));
|
||||||
|
return new PushDistributionListSendJob(parameters, data.getLong(KEY_MESSAGE_ID), recipientIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||||
import org.signal.core.util.SetUtil;
|
import org.signal.core.util.SetUtil;
|
||||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||||
|
@ -63,6 +64,8 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupC
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -76,27 +79,27 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
private static final String TAG = Log.tag(PushGroupSendJob.class);
|
private static final String TAG = Log.tag(PushGroupSendJob.class);
|
||||||
|
|
||||||
private static final String KEY_MESSAGE_ID = "message_id";
|
private static final String KEY_MESSAGE_ID = "message_id";
|
||||||
private static final String KEY_FILTER_RECIPIENT = "filter_recipient";
|
private static final String KEY_FILTER_RECIPIENTS = "filter_recipient";
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
private final RecipientId filterRecipient;
|
private final Set<RecipientId> filterRecipients;
|
||||||
|
|
||||||
public PushGroupSendJob(long messageId, @NonNull RecipientId destination, @Nullable RecipientId filterRecipient, boolean hasMedia) {
|
public PushGroupSendJob(long messageId, @NonNull RecipientId destination, @NonNull Set<RecipientId> filterRecipients, boolean hasMedia) {
|
||||||
this(new Job.Parameters.Builder()
|
this(new Job.Parameters.Builder()
|
||||||
.setQueue(destination.toQueueKey(hasMedia))
|
.setQueue(destination.toQueueKey(hasMedia))
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(Parameters.UNLIMITED)
|
.setMaxAttempts(Parameters.UNLIMITED)
|
||||||
.build(),
|
.build(),
|
||||||
messageId, filterRecipient);
|
messageId, filterRecipients);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PushGroupSendJob(@NonNull Job.Parameters parameters, long messageId, @Nullable RecipientId filterRecipient) {
|
private PushGroupSendJob(@NonNull Job.Parameters parameters, long messageId, @NonNull Set<RecipientId> filterRecipients) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
|
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.filterRecipient = filterRecipient;
|
this.filterRecipients = filterRecipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
@ -104,7 +107,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
@NonNull JobManager jobManager,
|
@NonNull JobManager jobManager,
|
||||||
long messageId,
|
long messageId,
|
||||||
@NonNull RecipientId destination,
|
@NonNull RecipientId destination,
|
||||||
@Nullable RecipientId filterAddress)
|
@NonNull Set<RecipientId> filterAddresses)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Recipient group = Recipient.resolved(destination);
|
Recipient group = Recipient.resolved(destination);
|
||||||
|
@ -120,7 +123,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
throw new MmsException("Inactive group!");
|
throw new MmsException("Inactive group!");
|
||||||
}
|
}
|
||||||
|
|
||||||
jobManager.add(new PushGroupSendJob(messageId, destination, filterAddress, !attachmentUploadIds.isEmpty()), attachmentUploadIds, attachmentUploadIds.isEmpty() ? null : destination.toQueueKey());
|
jobManager.add(new PushGroupSendJob(messageId, destination, filterAddresses, !attachmentUploadIds.isEmpty()), attachmentUploadIds, attachmentUploadIds.isEmpty() ? null : destination.toQueueKey());
|
||||||
|
|
||||||
} catch (NoSuchMessageException | MmsException e) {
|
} catch (NoSuchMessageException | MmsException e) {
|
||||||
Log.w(TAG, "Failed to enqueue message.", e);
|
Log.w(TAG, "Failed to enqueue message.", e);
|
||||||
|
@ -132,7 +135,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId)
|
return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId)
|
||||||
.putString(KEY_FILTER_RECIPIENT, filterRecipient != null ? filterRecipient.serialize() : null)
|
.putString(KEY_FILTER_RECIPIENTS, RecipientId.toSerializedList(filterRecipients))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +192,10 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
List<Recipient> target;
|
List<Recipient> target;
|
||||||
List<RecipientId> skipped = new ArrayList<>();
|
List<RecipientId> skipped = new ArrayList<>();
|
||||||
|
|
||||||
if (filterRecipient != null) {
|
if (Util.hasItems(filterRecipients)) {
|
||||||
target = Collections.singletonList(Recipient.resolved(filterRecipient));
|
target = new ArrayList<>(filterRecipients.size() + existingNetworkFailures.size());
|
||||||
|
target.addAll(Stream.of(filterRecipients).map(Recipient::resolved).toList());
|
||||||
|
target.addAll(Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList());
|
||||||
} else if (!existingNetworkFailures.isEmpty()) {
|
} else if (!existingNetworkFailures.isEmpty()) {
|
||||||
target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
||||||
} else {
|
} else {
|
||||||
|
@ -407,7 +412,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
handleProofRequiredException(context, proofRequired, groupRecipient, threadId, messageId, true);
|
handleProofRequiredException(context, proofRequired, groupRecipient, threadId, messageId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
|
if (existingNetworkFailures.isEmpty() && existingIdentityMismatches.isEmpty()) {
|
||||||
database.markAsSent(messageId, true);
|
database.markAsSent(messageId, true);
|
||||||
|
|
||||||
markAttachmentsUploaded(messageId, message);
|
markAttachmentsUploaded(messageId, message);
|
||||||
|
@ -429,12 +434,12 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
if (message.getStoryType().isStory()) {
|
if (message.getStoryType().isStory()) {
|
||||||
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary();
|
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary();
|
||||||
}
|
}
|
||||||
} else if (!identityMismatches.isEmpty()) {
|
} else if (!existingIdentityMismatches.isEmpty()) {
|
||||||
Log.w(TAG, "Failing because there were " + identityMismatches.size() + " identity mismatches.");
|
Log.w(TAG, "Failing because there were " + existingIdentityMismatches.size() + " identity mismatches.");
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
notifyMediaMessageDeliveryFailed(context, messageId);
|
notifyMediaMessageDeliveryFailed(context, messageId);
|
||||||
|
|
||||||
Set<RecipientId> mismatchRecipientIds = Stream.of(identityMismatches)
|
Set<RecipientId> mismatchRecipientIds = Stream.of(existingIdentityMismatches)
|
||||||
.map(mismatch -> mismatch.getRecipientId(context))
|
.map(mismatch -> mismatch.getRecipientId(context))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
@ -489,10 +494,10 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
public @NonNull PushGroupSendJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
|
||||||
String raw = data.getString(KEY_FILTER_RECIPIENT);
|
String raw = data.getStringOrDefault(KEY_FILTER_RECIPIENTS, "");
|
||||||
RecipientId filter = raw != null ? RecipientId.from(raw) : null;
|
Set<RecipientId> filters = raw != null ? new HashSet<>(RecipientId.fromSerializedList(raw)) : Collections.emptySet();
|
||||||
|
|
||||||
return new PushGroupSendJob(parameters, data.getLong(KEY_MESSAGE_ID), filter);
|
return new PushGroupSendJob(parameters, data.getLong(KEY_MESSAGE_ID), filters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,10 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.StoryType;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||||
|
@ -86,6 +88,7 @@ import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MessageSender {
|
public class MessageSender {
|
||||||
|
@ -327,9 +330,9 @@ public class MessageSender {
|
||||||
if (isLocalSelfSend(context, recipient, false)) {
|
if (isLocalSelfSend(context, recipient, false)) {
|
||||||
sendLocalMediaSelf(context, messageId);
|
sendLocalMediaSelf(context, messageId);
|
||||||
} else if (recipient.isPushGroup()) {
|
} else if (recipient.isPushGroup()) {
|
||||||
jobManager.add(new PushGroupSendJob(messageId, recipient.getId(), null, true), messageDependsOnIds, recipient.getId().toQueueKey());
|
jobManager.add(new PushGroupSendJob(messageId, recipient.getId(), Collections.emptySet(), true), messageDependsOnIds, recipient.getId().toQueueKey());
|
||||||
} else if (recipient.isDistributionList()) {
|
} else if (recipient.isDistributionList()) {
|
||||||
jobManager.add(new PushDistributionListSendJob(messageId, recipient.getId(), true), messageDependsOnIds, recipient.getId().toQueueKey());
|
jobManager.add(new PushDistributionListSendJob(messageId, recipient.getId(), true, Collections.emptySet()), messageDependsOnIds, recipient.getId().toQueueKey());
|
||||||
} else {
|
} else {
|
||||||
jobManager.add(new PushMediaSendJob(messageId, recipient, true), messageDependsOnIds, recipient.getId().toQueueKey());
|
jobManager.add(new PushMediaSendJob(messageId, recipient, true), messageDependsOnIds, recipient.getId().toQueueKey());
|
||||||
}
|
}
|
||||||
|
@ -403,9 +406,17 @@ public class MessageSender {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resendGroupMessage(Context context, MessageRecord messageRecord, RecipientId filterRecipientId) {
|
public static void resendGroupMessage(@NonNull Context context, @NonNull MessageRecord messageRecord, @NonNull Set<RecipientId> filterRecipientIds) {
|
||||||
if (!messageRecord.isMms()) throw new AssertionError("Not Group");
|
if (!messageRecord.isMms()) throw new AssertionError("Not Group");
|
||||||
sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterRecipientId, Collections.emptyList());
|
sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList());
|
||||||
|
onMessageSent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resendDistributionList(@NonNull Context context, @NonNull MessageRecord messageRecord, @NonNull Set<RecipientId> filterRecipientIds) {
|
||||||
|
if (!messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getStoryType().isStory()) {
|
||||||
|
throw new AssertionError("Not a story");
|
||||||
|
}
|
||||||
|
sendDistributionList(context, messageRecord.getRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList());
|
||||||
onMessageSent();
|
onMessageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,9 +458,9 @@ public class MessageSender {
|
||||||
if (isLocalSelfSend(context, recipient, forceSms)) {
|
if (isLocalSelfSend(context, recipient, forceSms)) {
|
||||||
sendLocalMediaSelf(context, messageId);
|
sendLocalMediaSelf(context, messageId);
|
||||||
} else if (recipient.isPushGroup()) {
|
} else if (recipient.isPushGroup()) {
|
||||||
sendGroupPush(context, recipient, messageId, null, uploadJobIds);
|
sendGroupPush(context, recipient, messageId, Collections.emptySet(), uploadJobIds);
|
||||||
} else if (recipient.isDistributionList()) {
|
} else if (recipient.isDistributionList()) {
|
||||||
sendDistributionList(context, recipient, messageId, uploadJobIds);
|
sendDistributionList(context, recipient, messageId, Collections.emptySet(), uploadJobIds);
|
||||||
} else if (!forceSms && isPushMediaSend(context, recipient)) {
|
} else if (!forceSms && isPushMediaSend(context, recipient)) {
|
||||||
sendMediaPush(context, recipient, messageId, uploadJobIds);
|
sendMediaPush(context, recipient, messageId, uploadJobIds);
|
||||||
} else {
|
} else {
|
||||||
|
@ -485,25 +496,25 @@ public class MessageSender {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendGroupPush(Context context, Recipient recipient, long messageId, RecipientId filterRecipientId, @NonNull Collection<String> uploadJobIds) {
|
private static void sendGroupPush(@NonNull Context context, @NonNull Recipient recipient, long messageId, @NonNull Set<RecipientId> filterRecipientIds, @NonNull Collection<String> uploadJobIds) {
|
||||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||||
|
|
||||||
if (uploadJobIds.size() > 0) {
|
if (uploadJobIds.size() > 0) {
|
||||||
Job groupSend = new PushGroupSendJob(messageId, recipient.getId(), filterRecipientId, !uploadJobIds.isEmpty());
|
Job groupSend = new PushGroupSendJob(messageId, recipient.getId(), filterRecipientIds, !uploadJobIds.isEmpty());
|
||||||
jobManager.add(groupSend, uploadJobIds, uploadJobIds.isEmpty() ? null : recipient.getId().toQueueKey());
|
jobManager.add(groupSend, uploadJobIds, uploadJobIds.isEmpty() ? null : recipient.getId().toQueueKey());
|
||||||
} else {
|
} else {
|
||||||
PushGroupSendJob.enqueue(context, jobManager, messageId, recipient.getId(), filterRecipientId);
|
PushGroupSendJob.enqueue(context, jobManager, messageId, recipient.getId(), filterRecipientIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendDistributionList(Context context, Recipient recipient, long messageId, @NonNull Collection<String> uploadJobIds) {
|
private static void sendDistributionList(@NonNull Context context, @NonNull Recipient recipient, long messageId, @NonNull Set<RecipientId> filterRecipientIds, @NonNull Collection<String> uploadJobIds) {
|
||||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||||
|
|
||||||
if (uploadJobIds.size() > 0) {
|
if (uploadJobIds.size() > 0) {
|
||||||
Job groupSend = new PushDistributionListSendJob(messageId, recipient.getId(), !uploadJobIds.isEmpty());
|
Job groupSend = new PushDistributionListSendJob(messageId, recipient.getId(), !uploadJobIds.isEmpty(), filterRecipientIds);
|
||||||
jobManager.add(groupSend, uploadJobIds, uploadJobIds.isEmpty() ? null : recipient.getId().toQueueKey());
|
jobManager.add(groupSend, uploadJobIds, uploadJobIds.isEmpty() ? null : recipient.getId().toQueueKey());
|
||||||
} else {
|
} else {
|
||||||
PushDistributionListSendJob.enqueue(context, jobManager, messageId, recipient.getId());
|
PushDistributionListSendJob.enqueue(context, jobManager, messageId, recipient.getId(), filterRecipientIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||||
import org.thoughtcrime.securesms.components.settings.configure
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||||
|
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||||
|
@ -73,8 +74,12 @@ class MyStoriesFragment : DSLSettingsFragment(
|
||||||
distributionStory = conversationMessage,
|
distributionStory = conversationMessage,
|
||||||
onClick = { it, preview ->
|
onClick = { it, preview ->
|
||||||
if (it.distributionStory.messageRecord.isOutgoing && it.distributionStory.messageRecord.isFailed) {
|
if (it.distributionStory.messageRecord.isOutgoing && it.distributionStory.messageRecord.isFailed) {
|
||||||
|
if (it.distributionStory.messageRecord.isIdentityMismatchFailure) {
|
||||||
|
SafetyNumberChangeDialog.show(requireContext(), childFragmentManager, it.distributionStory.messageRecord)
|
||||||
|
} else {
|
||||||
lifecycleDisposable += viewModel.resend(it.distributionStory.messageRecord).subscribe()
|
lifecycleDisposable += viewModel.resend(it.distributionStory.messageRecord).subscribe()
|
||||||
Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val recipientId = if (it.distributionStory.messageRecord.recipient.isGroup) {
|
val recipientId = if (it.distributionStory.messageRecord.recipient.isGroup) {
|
||||||
it.distributionStory.messageRecord.recipient.id
|
it.distributionStory.messageRecord.recipient.id
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
package org.thoughtcrime.securesms.recipients;
|
package org.thoughtcrime.securesms.recipients;
|
||||||
|
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
|
@ -43,6 +49,13 @@ public final class RecipientIdSerializationTest {
|
||||||
assertThat(RecipientId.fromSerializedList("123,456"), is(asList(RecipientId.from(123), RecipientId.from(456))));
|
assertThat(RecipientId.fromSerializedList("123,456"), is(asList(RecipientId.from(123), RecipientId.from(456))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromSerializedList_recipient_serialize() {
|
||||||
|
List<RecipientId> recipientIds = RecipientId.fromSerializedList(RecipientId.from(123).serialize());
|
||||||
|
assertThat(recipientIds, hasSize(1));
|
||||||
|
assertThat(recipientIds, contains(RecipientId.from(123)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializedListContains_empty_list_does_not_contain_item() {
|
public void serializedListContains_empty_list_does_not_contain_item() {
|
||||||
assertFalse(RecipientId.serializedListContains("", RecipientId.from(456)));
|
assertFalse(RecipientId.serializedListContains("", RecipientId.from(456)));
|
||||||
|
|
Loading…
Add table
Reference in a new issue