Extend listContacts command with profiles and filtering

This commit is contained in:
AsamK 2022-05-20 11:46:03 +02:00
parent 496cd5e621
commit 5f941004f5
11 changed files with 196 additions and 83 deletions

View file

@ -28,9 +28,8 @@ import org.asamk.signal.manager.groups.GroupNotFoundException;
import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
import org.asamk.signal.manager.groups.LastGroupAdminException;
import org.asamk.signal.manager.groups.NotAGroupMemberException;
import org.asamk.signal.manager.storage.recipients.Contact;
import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.Recipient;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.io.Closeable;
@ -215,7 +214,12 @@ public interface Manager extends Closeable {
void sendContacts() throws IOException;
List<Pair<RecipientAddress, Contact>> getContacts();
List<Recipient> getRecipients(
boolean onlyContacts,
Optional<Boolean> blocked,
Collection<RecipientIdentifier.Single> address,
Optional<String> name
);
String getContactOrProfileName(RecipientIdentifier.Single recipient);

View file

@ -51,9 +51,8 @@ import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.identities.IdentityInfo;
import org.asamk.signal.manager.storage.recipients.Contact;
import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.Recipient;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack;
import org.asamk.signal.manager.storage.stickerPacks.StickerPackStore;
@ -84,6 +83,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@ -101,7 +101,6 @@ class ManagerImpl implements Manager {
private final static Logger logger = LoggerFactory.getLogger(ManagerImpl.class);
private SignalAccount account;
private AccountFileUpdater accountFileUpdater;
private final SignalDependencies dependencies;
private final Context context;
@ -123,7 +122,6 @@ class ManagerImpl implements Manager {
String userAgent
) {
this.account = account;
this.accountFileUpdater = accountFileUpdater;
final var sessionLock = new SignalSessionLock() {
private final ReentrantLock LEGACY_LOCK = new ReentrantLock();
@ -337,7 +335,7 @@ class ManagerImpl implements Manager {
}
@Override
public Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException {
public Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws UnregisteredRecipientException {
return context.getProfileHelper().getRecipientProfile(context.getRecipientHelper().resolveRecipient(recipient));
}
@ -495,7 +493,7 @@ class ManagerImpl implements Manager {
@Override
public SendMessageResults sendReadReceipt(
RecipientIdentifier.Single sender, List<Long> messageIds
) throws IOException {
) {
final var timestamp = System.currentTimeMillis();
var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ,
messageIds,
@ -507,7 +505,7 @@ class ManagerImpl implements Manager {
@Override
public SendMessageResults sendViewedReceipt(
RecipientIdentifier.Single sender, List<Long> messageIds
) throws IOException {
) {
final var timestamp = System.currentTimeMillis();
var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED,
messageIds,
@ -520,7 +518,7 @@ class ManagerImpl implements Manager {
final RecipientIdentifier.Single sender,
final long timestamp,
final SignalServiceReceiptMessage receiptMessage
) throws IOException {
) {
try {
final var result = context.getSendHelper()
.sendReceiptMessage(receiptMessage, context.getRecipientHelper().resolveRecipient(sender));
@ -592,7 +590,7 @@ class ManagerImpl implements Manager {
}
}
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException, UnregisteredRecipientException {
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws UnregisteredRecipientException {
final var mentions = new ArrayList<SignalServiceDataMessage.Mention>();
for (final var m : mentionList) {
final var recipientId = context.getRecipientHelper().resolveRecipient(m.recipient());
@ -676,7 +674,7 @@ class ManagerImpl implements Manager {
@Override
public void setContactName(
RecipientIdentifier.Single recipient, String name
) throws NotMasterDeviceException, IOException, UnregisteredRecipientException {
) throws NotMasterDeviceException, UnregisteredRecipientException {
if (!account.isMasterDevice()) {
throw new NotMasterDeviceException();
}
@ -932,7 +930,7 @@ class ManagerImpl implements Manager {
final RecipientId recipientId;
try {
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException | UnregisteredRecipientException e) {
} catch (UnregisteredRecipientException e) {
return false;
}
return context.getContactHelper().isContactBlocked(recipientId);
@ -944,12 +942,22 @@ class ManagerImpl implements Manager {
}
@Override
public List<Pair<RecipientAddress, Contact>> getContacts() {
return account.getContactStore()
.getContacts()
.stream()
.map(p -> new Pair<>(account.getRecipientStore().resolveRecipientAddress(p.first()), p.second()))
.toList();
public List<Recipient> getRecipients(
boolean onlyContacts,
Optional<Boolean> blocked,
Collection<RecipientIdentifier.Single> recipients,
Optional<String> name
) {
final var recipientIds = recipients.stream().map(a -> {
try {
return context.getRecipientHelper().resolveRecipient(a);
} catch (UnregisteredRecipientException e) {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toSet());
// refresh profiles of explicitly given recipients
context.getProfileHelper().refreshRecipientProfiles(recipientIds);
return account.getRecipientStore().getRecipients(onlyContacts, blocked, recipientIds, name);
}
@Override
@ -957,7 +965,7 @@ class ManagerImpl implements Manager {
final RecipientId recipientId;
try {
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException | UnregisteredRecipientException e) {
} catch (UnregisteredRecipientException e) {
return null;
}
@ -1007,7 +1015,7 @@ class ManagerImpl implements Manager {
try {
identity = account.getIdentityKeyStore()
.getIdentity(context.getRecipientHelper().resolveRecipient(recipient));
} catch (IOException | UnregisteredRecipientException e) {
} catch (UnregisteredRecipientException e) {
identity = null;
}
return identity == null ? List.of() : List.of(toIdentity(identity));
@ -1044,12 +1052,7 @@ class ManagerImpl implements Manager {
private boolean trustIdentity(
RecipientIdentifier.Single recipient, Function<RecipientId, Boolean> trustMethod
) throws UnregisteredRecipientException {
RecipientId recipientId;
try {
recipientId = context.getRecipientHelper().resolveRecipient(recipient);
} catch (IOException e) {
return false;
}
final var recipientId = context.getRecipientHelper().resolveRecipient(recipient);
final var updated = trustMethod.apply(recipientId);
if (updated && this.isReceiving()) {
context.getReceiveHelper().setNeedsToRetryFailedMessages(true);

View file

@ -36,6 +36,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Base64;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@ -94,10 +95,18 @@ public final class ProfileHelper {
return getRecipientProfile(recipientId, false);
}
public List<Profile> getRecipientProfiles(Collection<RecipientId> recipientIds) {
return getRecipientProfiles(recipientIds, false);
}
public void refreshRecipientProfile(RecipientId recipientId) {
getRecipientProfile(recipientId, true);
}
public void refreshRecipientProfiles(Collection<RecipientId> recipientIds) {
getRecipientProfiles(recipientIds, true);
}
public List<ProfileKeyCredential> getRecipientProfileKeyCredential(List<RecipientId> recipientIds) {
try {
account.getRecipientStore().setBulkUpdating(true);
@ -216,11 +225,12 @@ public final class ProfileHelper {
return getRecipientProfile(account.getSelfRecipientId());
}
public List<Profile> getRecipientProfile(List<RecipientId> recipientIds) {
private List<Profile> getRecipientProfiles(Collection<RecipientId> recipientIds, boolean force) {
final var profileStore = account.getProfileStore();
try {
account.getRecipientStore().setBulkUpdating(true);
final var profileFetches = Flowable.fromIterable(recipientIds)
.filter(recipientId -> isProfileRefreshRequired(account.getProfileStore().getProfile(recipientId)))
.filter(recipientId -> force || isProfileRefreshRequired(profileStore.getProfile(recipientId)))
.map(recipientId -> retrieveProfile(recipientId,
SignalServiceProfile.RequestType.PROFILE).onErrorComplete());
Maybe.merge(profileFetches, 10).blockingSubscribe();
@ -228,7 +238,7 @@ public final class ProfileHelper {
account.getRecipientStore().setBulkUpdating(false);
}
return recipientIds.stream().map(r -> account.getProfileStore().getProfile(r)).toList();
return recipientIds.stream().map(profileStore::getProfile).toList();
}
private Profile getRecipientProfile(RecipientId recipientId, boolean force) {

View file

@ -69,7 +69,7 @@ public class RecipientHelper {
return account.getRecipientStore().resolveRecipient(address);
}
public Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws IOException, UnregisteredRecipientException {
public Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredRecipientException {
final var recipientIds = new HashSet<RecipientId>(recipients.size());
for (var number : recipients) {
final var recipientId = resolveRecipient(number);
@ -78,7 +78,7 @@ public class RecipientHelper {
return recipientIds;
}
public RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException {
public RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) throws UnregisteredRecipientException {
if (recipient instanceof RecipientIdentifier.Uuid uuidRecipient) {
return account.getRecipientStore().resolveRecipient(ServiceId.from(uuidRecipient.uuid()));
} else {

View file

@ -475,7 +475,7 @@ public class SendHelper {
final var senderKeyTargets = new HashSet<RecipientId>();
final var recipientList = new ArrayList<>(recipientIds);
final var profiles = context.getProfileHelper().getRecipientProfile(recipientList).iterator();
final var profiles = context.getProfileHelper().getRecipientProfiles(recipientList).iterator();
for (final var recipientId : recipientList) {
final var profile = profiles.next();
if (profile == null || !profile.getCapabilities().contains(Profile.Capability.senderKey)) {

View file

@ -277,6 +277,24 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
.toList();
}
public List<Recipient> getRecipients(
boolean onlyContacts, Optional<Boolean> blocked, Set<RecipientId> recipientIds, Optional<String> name
) {
return recipients.values()
.stream()
.filter(r -> !onlyContacts || r.getContact() != null)
.filter(r -> blocked.isEmpty() || (
blocked.get() == (
r.getContact() != null && r.getContact().isBlocked()
)
))
.filter(r -> recipientIds.isEmpty() || (recipientIds.contains(r.getRecipientId())))
.filter(r -> name.isEmpty()
|| (r.getContact() != null && name.get().equals(r.getContact().getName()))
|| (r.getProfile() != null && name.get().equals(r.getProfile().getDisplayName())))
.toList();
}
@Override
public void deleteContact(RecipientId recipientId) {
synchronized (recipients) {