X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/73e137137d272811b01ed053f57e0161e476d90a..0a5e836ab69d52c262ea792ed4b84a82dd8a34ca:/lib/src/main/java/org/asamk/signal/manager/Manager.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 9d0c355b..cde2714f 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -327,16 +327,32 @@ public class Manager implements Closeable { * This is used for checking a set of phone numbers for registration on Signal * * @param numbers The set of phone number in question - * @return A map of numbers to booleans. True if registered, false otherwise. Should never be null + * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null. * @throws IOException if its unable to get the contacts to check if they're registered */ - public Map areUsersRegistered(Set numbers) throws IOException { + public Map> areUsersRegistered(Set numbers) throws IOException { + Map canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> { + try { + return canonicalizePhoneNumber(n); + } catch (InvalidNumberException e) { + return ""; + } + })); + // Note "contactDetails" has no optionals. It only gives us info on users who are registered - var contactDetails = getRegisteredUsers(numbers); + var contactDetails = getRegisteredUsers(canonicalizedNumbers.values() + .stream() + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet())); - var registeredUsers = contactDetails.keySet(); + // Store numbers as recipients so we have the number/uuid association + contactDetails.forEach((number, uuid) -> resolveRecipientTrusted(new SignalServiceAddress(uuid, number))); - return numbers.stream().collect(Collectors.toMap(x -> x, registeredUsers::contains)); + return numbers.stream().collect(Collectors.toMap(n -> n, n -> { + final var number = canonicalizedNumbers.get(n); + final var uuid = contactDetails.get(number); + return new Pair<>(number.isEmpty() ? null : number, uuid); + })); } public void updateAccountAttributes() throws IOException { @@ -1175,11 +1191,31 @@ public class Manager implements Closeable { return sendHelper.sendGroupMessage(messageBuilder.build(), Set.of(resolveRecipient(recipient))); } - void sendReceipt( - SignalServiceAddress remoteAddress, long messageId + public void sendReadReceipt( + String sender, List messageIds + ) throws IOException, UntrustedIdentityException, InvalidNumberException { + var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, + messageIds, + System.currentTimeMillis()); + + sendHelper.sendReceiptMessage(receiptMessage, canonicalizeAndResolveRecipient(sender)); + } + + public void sendViewedReceipt( + String sender, List messageIds + ) throws IOException, UntrustedIdentityException, InvalidNumberException { + var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED, + messageIds, + System.currentTimeMillis()); + + sendHelper.sendReceiptMessage(receiptMessage, canonicalizeAndResolveRecipient(sender)); + } + + void sendDeliveryReceipt( + SignalServiceAddress remoteAddress, List messageIds ) throws IOException, UntrustedIdentityException { var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.DELIVERY, - List.of(messageId), + messageIds, System.currentTimeMillis()); sendHelper.sendReceiptMessage(receiptMessage, resolveRecipient(remoteAddress)); @@ -1807,7 +1843,7 @@ public class Manager implements Closeable { ) throws IOException, InterruptedException { retryFailedReceivedMessages(handler, ignoreAttachments); - Set queuedActions = null; + Set queuedActions = new HashSet<>(); final var signalWebSocket = dependencies.getSignalWebSocket(); signalWebSocket.connect(); @@ -1836,20 +1872,17 @@ public class Manager implements Closeable { // Received indicator that server queue is empty hasCaughtUpWithOldMessages = true; - if (queuedActions != null) { - for (var action : queuedActions) { - try { - action.execute(this); - } catch (Throwable e) { - if (e instanceof AssertionError && e.getCause() instanceof InterruptedException) { - Thread.currentThread().interrupt(); - } - logger.warn("Message action failed.", e); + for (var action : queuedActions) { + try { + action.execute(this); + } catch (Throwable e) { + if (e instanceof AssertionError && e.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); } + logger.warn("Message action failed.", e); } - queuedActions.clear(); - queuedActions = null; } + queuedActions.clear(); // Continue to wait another timeout for new messages continue; @@ -1903,9 +1936,6 @@ public class Manager implements Closeable { } } } else { - if (queuedActions == null) { - queuedActions = new HashSet<>(); - } queuedActions.addAll(actions); } } @@ -2724,14 +2754,16 @@ public class Manager implements Closeable { return account.getRecipientStore().resolveServiceAddress(recipientId); } - public RecipientId canonicalizeAndResolveRecipient(String identifier) throws InvalidNumberException { - var canonicalizedNumber = UuidUtil.isUuid(identifier) - ? identifier - : PhoneNumberFormatter.formatNumber(identifier, account.getUsername()); + private RecipientId canonicalizeAndResolveRecipient(String identifier) throws InvalidNumberException { + var canonicalizedNumber = UuidUtil.isUuid(identifier) ? identifier : canonicalizePhoneNumber(identifier); return resolveRecipient(canonicalizedNumber); } + private String canonicalizePhoneNumber(final String number) throws InvalidNumberException { + return PhoneNumberFormatter.formatNumber(number, account.getUsername()); + } + private RecipientId resolveRecipient(final String identifier) { var address = Utils.getSignalServiceAddressFromIdentifier(identifier);