Signal-Android/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java

233 lines
9.9 KiB
Java

package org.thoughtcrime.securesms.messagerequests;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.core.util.Consumer;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor;
final class MessageRequestRepository {
private static final String TAG = Log.tag(MessageRequestRepository.class);
private final Context context;
private final Executor executor;
MessageRequestRepository(@NonNull Context context) {
this.context = context.getApplicationContext();
this.executor = SignalExecutors.BOUNDED;
}
void getGroups(@NonNull RecipientId recipientId, @NonNull Consumer<List<String>> onGroupsLoaded) {
executor.execute(() -> {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
onGroupsLoaded.accept(groupDatabase.getPushGroupNamesContainingMember(recipientId));
});
}
void getMemberCount(@NonNull RecipientId recipientId, @NonNull Consumer<GroupMemberCount> onMemberCountLoaded) {
executor.execute(() -> {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Optional<GroupDatabase.GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
onMemberCountLoaded.accept(groupRecord.transform(record -> {
if (record.isV2Group()) {
DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup();
return new GroupMemberCount(decryptedGroup.getMembersCount(), decryptedGroup.getPendingMembersCount());
} else {
return new GroupMemberCount(record.getMembers().size(), 0);
}
}).or(GroupMemberCount.ZERO));
});
}
void getMessageRequestState(@NonNull Recipient recipient, long threadId, @NonNull Consumer<MessageRequestState> state) {
executor.execute(() -> {
if (recipient.isPushV2Group()) {
boolean pendingMember = DatabaseFactory.getGroupDatabase(context)
.isPendingMember(recipient.requireGroupId().requireV2(), Recipient.self());
state.accept(pendingMember ? MessageRequestState.UNACCEPTED
: MessageRequestState.ACCEPTED);
} else if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) {
state.accept(MessageRequestState.UNACCEPTED);
} else if (RecipientUtil.isPreMessageRequestThread(context, threadId) && !RecipientUtil.isLegacyProfileSharingAccepted(recipient)) {
state.accept(MessageRequestState.LEGACY);
} else {
state.accept(MessageRequestState.ACCEPTED);
}
});
}
void acceptMessageRequest(@NonNull LiveRecipient liveRecipient,
long threadId,
@NonNull Runnable onMessageRequestAccepted,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(()-> {
if (liveRecipient.get().isPushV2Group()) {
try {
Log.i(TAG, "GV2 accepting invite");
GroupManager.acceptInvite(context, liveRecipient.get().requireGroupId().requireV2());
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
recipientDatabase.setProfileSharing(liveRecipient.getId(), true);
onMessageRequestAccepted.run();
} catch (GroupInsufficientRightsException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeBusyException | GroupChangeFailedException | GroupNotAMemberException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
}
} else {
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
recipientDatabase.setProfileSharing(liveRecipient.getId(), true);
MessageSender.sendProfileKey(context, threadId);
List<MessagingDatabase.MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context)
.setEntireThreadRead(threadId);
ApplicationDependencies.getMessageNotifier().updateNotification(context);
MarkReadReceiver.process(context, messageIds);
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(liveRecipient.getId()));
}
onMessageRequestAccepted.run();
}
});
}
void deleteMessageRequest(@NonNull LiveRecipient recipient,
long threadId,
@NonNull Runnable onMessageRequestDeleted,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
Recipient resolved = recipient.resolve();
if (resolved.isGroup() && resolved.requireGroupId().isPush()) {
try {
GroupManager.leaveGroupFromBlockOrMessageRequest(context, resolved.requireGroupId().requirePush());
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
return;
}
}
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forDelete(recipient.getId()));
}
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
threadDatabase.deleteConversation(threadId);
onMessageRequestDeleted.run();
});
}
void blockMessageRequest(@NonNull LiveRecipient liveRecipient,
@NonNull Runnable onMessageRequestBlocked,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
Recipient recipient = liveRecipient.resolve();
try {
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
return;
}
liveRecipient.refresh();
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forBlock(liveRecipient.getId()));
}
onMessageRequestBlocked.run();
});
}
void blockAndDeleteMessageRequest(@NonNull LiveRecipient liveRecipient,
long threadId,
@NonNull Runnable onMessageRequestBlocked,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
Recipient recipient = liveRecipient.resolve();
try{
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
return;
}
liveRecipient.refresh();
DatabaseFactory.getThreadDatabase(context).deleteConversation(threadId);
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forBlockAndDelete(liveRecipient.getId()));
}
onMessageRequestBlocked.run();
});
}
void unblockAndAccept(@NonNull LiveRecipient liveRecipient, long threadId, @NonNull Runnable onMessageRequestUnblocked) {
executor.execute(() -> {
Recipient recipient = liveRecipient.resolve();
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
RecipientUtil.unblock(context, recipient);
recipientDatabase.setProfileSharing(liveRecipient.getId(), true);
liveRecipient.refresh();
List<MessagingDatabase.MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context)
.setEntireThreadRead(threadId);
ApplicationDependencies.getMessageNotifier().updateNotification(context);
MarkReadReceiver.process(context, messageIds);
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(liveRecipient.getId()));
}
onMessageRequestUnblocked.run();
});
}
enum MessageRequestState {
ACCEPTED, UNACCEPTED, LEGACY
}
}