mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-22 02:36:55 +00:00
Additional work on not sending to blocked recipients.
This commit is contained in:
committed by
Alex Hart
parent
eb12395b8e
commit
83215bb98f
@@ -97,7 +97,7 @@ public class GroupReceiptDatabase extends Database {
|
||||
}
|
||||
|
||||
public void setSkipped(Collection<RecipientId> recipients, long mmsId) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
|
||||
@@ -167,7 +167,7 @@ public class GroupCallUpdateSendJob extends BaseJob {
|
||||
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));
|
||||
}
|
||||
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results);
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<GroupCallUpdateSendJob> {
|
||||
|
||||
@@ -4,11 +4,14 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class GroupSendJobHelper {
|
||||
@@ -18,9 +21,10 @@ final class GroupSendJobHelper {
|
||||
private GroupSendJobHelper() {
|
||||
}
|
||||
|
||||
static List<Recipient> getCompletedSends(@NonNull List<Recipient> possibleRecipients, @NonNull Collection<SendMessageResult> results) {
|
||||
static @NonNull SendResult getCompletedSends(@NonNull List<Recipient> possibleRecipients, @NonNull Collection<SendMessageResult> results) {
|
||||
RecipientAccessList accessList = new RecipientAccessList(possibleRecipients);
|
||||
List<Recipient> completions = new ArrayList<>(results.size());
|
||||
List<RecipientId> skipped = new ArrayList<>();
|
||||
|
||||
for (SendMessageResult sendMessageResult : results) {
|
||||
Recipient recipient = accessList.requireByAddress(sendMessageResult.getAddress());
|
||||
@@ -31,6 +35,7 @@ final class GroupSendJobHelper {
|
||||
|
||||
if (sendMessageResult.isUnregisteredFailure()) {
|
||||
Log.w(TAG, "Unregistered failure for " + recipient.getId());
|
||||
skipped.add(recipient.getId());
|
||||
}
|
||||
|
||||
if (sendMessageResult.getSuccess() != null ||
|
||||
@@ -41,6 +46,16 @@ final class GroupSendJobHelper {
|
||||
}
|
||||
}
|
||||
|
||||
return completions;
|
||||
return new SendResult(completions, skipped);
|
||||
}
|
||||
|
||||
public static class SendResult {
|
||||
public final List<Recipient> completed;
|
||||
public final List<RecipientId> skipped;
|
||||
|
||||
public SendResult(@NonNull List<Recipient> completed, @NonNull List<RecipientId> skipped) {
|
||||
this.completed = completed;
|
||||
this.skipped = skipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public class ProfileKeySendJob extends BaseJob {
|
||||
|
||||
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, null, destinations, false, ContentHint.IMPLICIT, dataMessage.build());
|
||||
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results);
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<ProfileKeySendJob> {
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -151,7 +152,7 @@ public final class PushDistributionListSendJob extends PushSendJob {
|
||||
List<SendMessageResult> results = deliver(message, target);
|
||||
Log.i(TAG, JobLogger.format(this, "Finished send."));
|
||||
|
||||
PushGroupSendJob.processGroupMessageResults(context, messageId, -1, null, message, results, target, existingNetworkFailures, existingIdentityMismatches);
|
||||
PushGroupSendJob.processGroupMessageResults(context, messageId, -1, null, message, results, target, Collections.emptyList(), existingNetworkFailures, existingIdentityMismatches);
|
||||
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
|
||||
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
|
||||
database.markAsSentFailed(messageId);
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||
import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -60,6 +61,7 @@ import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedExcept
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -183,14 +185,22 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
RecipientUtil.shareProfileIfFirstSecureMessage(context, groupRecipient);
|
||||
}
|
||||
|
||||
List<Recipient> target;
|
||||
List<Recipient> target;
|
||||
List<RecipientId> skipped = new ArrayList<>();
|
||||
|
||||
if (filterRecipient != null) target = Collections.singletonList(Recipient.resolved(filterRecipient));
|
||||
else if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
||||
else target = Stream.of(getGroupMessageRecipients(groupRecipient.requireGroupId(), messageId)).distinctBy(Recipient::getId).toList();
|
||||
if (filterRecipient != null) {
|
||||
target = Collections.singletonList(Recipient.resolved(filterRecipient));
|
||||
} else if (!existingNetworkFailures.isEmpty()) {
|
||||
target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
|
||||
} else {
|
||||
GroupRecipientResult result = getGroupMessageRecipients(groupRecipient.requireGroupId(), messageId);
|
||||
|
||||
target = result.target;
|
||||
skipped = result.skipped;
|
||||
}
|
||||
|
||||
List<SendMessageResult> results = deliver(message, groupRecipient, target);
|
||||
processGroupMessageResults(context, messageId, threadId, groupRecipient, message, results, target, existingNetworkFailures, existingIdentityMismatches);
|
||||
processGroupMessageResults(context, messageId, threadId, groupRecipient, message, results, target, skipped, existingNetworkFailures, existingIdentityMismatches);
|
||||
Log.i(TAG, JobLogger.format(this, "Finished send."));
|
||||
|
||||
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
|
||||
@@ -334,6 +344,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
@NonNull OutgoingMediaMessage message,
|
||||
@NonNull List<SendMessageResult> results,
|
||||
@NonNull List<Recipient> target,
|
||||
@NonNull List<RecipientId> skipped,
|
||||
@NonNull Set<NetworkFailure> existingNetworkFailures,
|
||||
@NonNull Set<IdentityKeyMismatch> existingIdentityMismatches)
|
||||
throws RetryLaterException, ProofRequiredException
|
||||
@@ -350,6 +361,9 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
List<NetworkFailure> resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
|
||||
List<IdentityKeyMismatch> resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
|
||||
List<RecipientId> unregisteredRecipients = Stream.of(results).filter(SendMessageResult::isUnregisteredFailure).map(result -> RecipientId.from(result.getAddress())).toList();
|
||||
List<RecipientId> skippedRecipients = new ArrayList<>(unregisteredRecipients);
|
||||
|
||||
skippedRecipients.addAll(skipped);
|
||||
|
||||
if (networkFailures.size() > 0 || identityMismatches.size() > 0 || proofRequired != null || unregisteredRecipients.size() > 0) {
|
||||
Log.w(TAG, String.format(Locale.US, "Failed to send to some recipients. Network: %d, Identity: %d, ProofRequired: %s, Unregistered: %d",
|
||||
@@ -380,6 +394,10 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
|
||||
markAttachmentsUploaded(messageId, message);
|
||||
|
||||
if (skippedRecipients.size() > 0) {
|
||||
SignalDatabase.groupReceipts().setSkipped(skippedRecipients, messageId);
|
||||
}
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
database.markExpireStarted(messageId);
|
||||
ApplicationDependencies.getExpiringMessageManager()
|
||||
@@ -414,25 +432,40 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||
}
|
||||
}
|
||||
|
||||
private static @NonNull List<Recipient> getGroupMessageRecipients(@NonNull GroupId groupId, long messageId) {
|
||||
private static @NonNull GroupRecipientResult getGroupMessageRecipients(@NonNull GroupId groupId, long messageId) {
|
||||
List<GroupReceiptInfo> destinations = SignalDatabase.groupReceipts().getGroupReceiptInfo(messageId);
|
||||
|
||||
List<Recipient> possible;
|
||||
|
||||
if (!destinations.isEmpty()) {
|
||||
return RecipientUtil.getEligibleForSending(Stream.of(destinations)
|
||||
.map(GroupReceiptInfo::getRecipientId)
|
||||
.map(Recipient::resolved)
|
||||
.toList());
|
||||
}
|
||||
|
||||
List<Recipient> members = Stream.of(SignalDatabase.groups().getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF))
|
||||
.map(Recipient::resolve)
|
||||
.toList();
|
||||
|
||||
if (members.size() > 0) {
|
||||
possible = Stream.of(destinations)
|
||||
.map(GroupReceiptInfo::getRecipientId)
|
||||
.map(Recipient::resolved)
|
||||
.distinctBy(Recipient::getId)
|
||||
.toList();
|
||||
} else {
|
||||
Log.w(TAG, "No destinations found for group message " + groupId + " using current group membership");
|
||||
possible = Stream.of(SignalDatabase.groups()
|
||||
.getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF))
|
||||
.map(Recipient::resolve)
|
||||
.distinctBy(Recipient::getId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
return RecipientUtil.getEligibleForSending(members);
|
||||
List<Recipient> eligible = RecipientUtil.getEligibleForSending(possible);
|
||||
List<RecipientId> skipped = Stream.of(SetUtil.difference(possible, eligible)).map(Recipient::getId).toList();
|
||||
|
||||
return new GroupRecipientResult(eligible, skipped);
|
||||
}
|
||||
|
||||
private static class GroupRecipientResult {
|
||||
private final List<Recipient> target;
|
||||
private final List<RecipientId> skipped;
|
||||
|
||||
private GroupRecipientResult(@NonNull List<Recipient> target, @NonNull List<RecipientId> skipped) {
|
||||
this.target = target;
|
||||
this.skipped = skipped;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<PushGroupSendJob> {
|
||||
|
||||
@@ -178,7 +178,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
|
||||
|
||||
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, groupId, destinations, false, ContentHint.IMPLICIT, groupDataMessage);
|
||||
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results);
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<PushGroupSilentUpdateSendJob> {
|
||||
|
||||
@@ -248,7 +248,7 @@ public class ReactionSendJob extends BaseJob {
|
||||
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));
|
||||
}
|
||||
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results);
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
|
||||
}
|
||||
|
||||
private static SignalServiceDataMessage.Reaction buildReaction(@NonNull Context context,
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
@@ -65,7 +67,7 @@ public class RemoteDeleteSendJob extends BaseJob {
|
||||
throw new AssertionError("We have a message, but couldn't find the thread!");
|
||||
}
|
||||
|
||||
List<RecipientId> recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList()
|
||||
List<RecipientId> recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList()
|
||||
: Stream.of(conversationRecipient.getId()).toList();
|
||||
|
||||
recipients.remove(Recipient.self().getId());
|
||||
@@ -137,14 +139,27 @@ public class RemoteDeleteSendJob extends BaseJob {
|
||||
throw new IllegalStateException("Cannot delete a message that isn't yours!");
|
||||
}
|
||||
|
||||
List<Recipient> destinations = Stream.of(recipients).map(Recipient::resolved).toList();
|
||||
List<Recipient> completions = deliver(conversationRecipient, destinations, targetSentTimestamp);
|
||||
List<Recipient> possible = Stream.of(recipients).map(Recipient::resolved).toList();
|
||||
List<Recipient> eligible = RecipientUtil.getEligibleForSending(Stream.of(recipients).map(Recipient::resolved).toList());
|
||||
List<RecipientId> skipped = Stream.of(SetUtil.difference(possible, eligible)).map(Recipient::getId).toList();
|
||||
|
||||
for (Recipient completion : completions) {
|
||||
GroupSendJobHelper.SendResult sendResult = deliver(conversationRecipient, eligible, targetSentTimestamp);
|
||||
|
||||
for (Recipient completion : sendResult.completed) {
|
||||
recipients.remove(completion.getId());
|
||||
}
|
||||
|
||||
Log.i(TAG, "Completed now: " + completions.size() + ", Remaining: " + recipients.size());
|
||||
for (RecipientId skip : skipped) {
|
||||
recipients.remove(skip);
|
||||
}
|
||||
|
||||
List<RecipientId> totalSkips = Util.join(skipped, sendResult.skipped);
|
||||
|
||||
Log.i(TAG, "Completed now: " + sendResult.completed.size() + ", Skipped: " + totalSkips.size() + ", Remaining: " + recipients.size());
|
||||
|
||||
if (totalSkips.size() > 0 && isMms && message.getRecipient().isGroup()) {
|
||||
SignalDatabase.groupReceipts().setSkipped(totalSkips, messageId);
|
||||
}
|
||||
|
||||
if (recipients.isEmpty()) {
|
||||
db.markAsSent(messageId, true);
|
||||
@@ -167,7 +182,7 @@ public class RemoteDeleteSendJob extends BaseJob {
|
||||
Log.w(TAG, "Failed to send remote delete to all recipients! (" + (initialRecipientCount - recipients.size() + "/" + initialRecipientCount + ")") );
|
||||
}
|
||||
|
||||
private @NonNull List<Recipient> deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations, long targetSentTimestamp)
|
||||
private @NonNull GroupSendJobHelper.SendResult deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations, long targetSentTimestamp)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder()
|
||||
@@ -187,9 +202,6 @@ public class RemoteDeleteSendJob extends BaseJob {
|
||||
new MessageId(messageId, isMms),
|
||||
dataMessage);
|
||||
|
||||
List<RecipientId> blockedIds = Stream.of(conversationRecipient.getParticipants()).filter(Recipient::isBlocked).map(Recipient::getId).toList();
|
||||
SignalDatabase.groupReceipts().setSkipped(blockedIds, messageId);
|
||||
|
||||
return GroupSendJobHelper.getCompletedSends(destinations, results);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ final class MessageDetails {
|
||||
break;
|
||||
case SKIPPED:
|
||||
skipped.add(status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user