X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/cd7172ee57049d292e7916ef58886d74bc82fcf7..8bee08fd96571f0f08ffa713b7bd20a2b251d277:/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index ab2bcda0..4a478f13 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -5,10 +5,15 @@ import org.asamk.signal.BaseConfig; import org.asamk.signal.manager.AttachmentInvalidException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.NotMasterDeviceException; +import org.asamk.signal.manager.StickerPackInvalidException; +import org.asamk.signal.manager.UntrustedIdentityException; import org.asamk.signal.manager.api.Message; +import org.asamk.signal.manager.api.RecipientIdentifier; +import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; 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.identities.IdentityInfo; @@ -19,12 +24,17 @@ import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException; import org.whispersystems.signalservice.api.messages.SendMessageResult; +import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.api.util.InvalidNumberException; +import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -59,57 +69,22 @@ public class DbusSignalImpl implements Signal { return sendMessage(message, attachments, recipients); } - private static void checkSendMessageResult(long timestamp, SendMessageResult result) throws DBusExecutionException { - var error = ErrorUtils.getErrorMessageFromSendMessageResult(result); - - if (error == null) { - return; - } - - final var message = timestamp + "\nFailed to send message:\n" + error + '\n'; - - if (result.getIdentityFailure() != null) { - throw new Error.UntrustedIdentity(message); - } else { - throw new Error.Failure(message); - } - } - - private static void checkSendMessageResults( - long timestamp, List results - ) throws DBusExecutionException { - if (results.size() == 1) { - checkSendMessageResult(timestamp, results.get(0)); - return; - } - - var errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results); - if (errors.size() == 0) { - return; - } - - var message = new StringBuilder(); - message.append(timestamp).append('\n'); - message.append("Failed to send (some) messages:\n"); - for (var error : errors) { - message.append(error).append('\n'); - } - - throw new Error.Failure(message.toString()); - } - @Override public long sendMessage(final String message, final List attachments, final List recipients) { try { - final var results = m.sendMessage(new Message(message, attachments), recipients); - checkSendMessageResults(results.first(), results.second()); - return results.first(); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); + final var results = m.sendMessage(new Message(message, attachments), + getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + .map(RecipientIdentifier.class::cast) + .collect(Collectors.toSet())); + + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); } } @@ -127,13 +102,16 @@ public class DbusSignalImpl implements Signal { final long targetSentTimestamp, final List recipients ) { try { - final var results = m.sendRemoteDeleteMessage(targetSentTimestamp, recipients); - checkSendMessageResults(results.first(), results.second()); - return results.first(); + final var results = m.sendRemoteDeleteMessage(targetSentTimestamp, + getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + .map(RecipientIdentifier.class::cast) + .collect(Collectors.toSet())); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); } } @@ -142,12 +120,13 @@ public class DbusSignalImpl implements Signal { final long targetSentTimestamp, final byte[] groupId ) { try { - final var results = m.sendGroupRemoteDeleteMessage(targetSentTimestamp, GroupId.unknownVersion(groupId)); - checkSendMessageResults(results.first(), results.second()); - return results.first(); + final var results = m.sendRemoteDeleteMessage(targetSentTimestamp, + Set.of(new RecipientIdentifier.Group(getGroupId(groupId)))); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -174,13 +153,70 @@ public class DbusSignalImpl implements Signal { final List recipients ) { try { - final var results = m.sendMessageReaction(emoji, remove, targetAuthor, targetSentTimestamp, recipients); - checkSendMessageResults(results.first(), results.second()); - return results.first(); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); + final var results = m.sendMessageReaction(emoji, + remove, + getSingleRecipientIdentifier(targetAuthor, m.getUsername()), + targetSentTimestamp, + getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + .map(RecipientIdentifier.class::cast) + .collect(Collectors.toSet())); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); + } + } + + @Override + public void sendTyping( + final String recipient, final boolean stop + ) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity { + try { + var recipients = new ArrayList(1); + recipients.add(recipient); + m.sendTypingMessage(stop ? TypingAction.STOP : TypingAction.START, + getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + .map(RecipientIdentifier.class::cast) + .collect(Collectors.toSet())); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); + } catch (UntrustedIdentityException e) { + throw new Error.UntrustedIdentity(e.getMessage()); + } + } + + @Override + public void sendReadReceipt( + final String recipient, final List timestamps + ) throws Error.Failure, Error.UntrustedIdentity { + try { + m.sendReadReceipt(getSingleRecipientIdentifier(recipient, m.getUsername()), timestamps); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); + } catch (UntrustedIdentityException e) { + throw new Error.UntrustedIdentity(e.getMessage()); + } + } + + @Override + public void sendContacts() { + try { + m.sendContacts(); + } catch (IOException e) { + throw new Error.Failure("SendContacts error: " + e.getMessage()); + } + } + + @Override + public void sendSyncRequest() { + try { + m.requestAllSyncData(); + } catch (IOException e) { + throw new Error.Failure("Request sync data error: " + e.getMessage()); } } @@ -189,37 +225,39 @@ public class DbusSignalImpl implements Signal { final String message, final List attachments ) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity { try { - final var results = m.sendSelfMessage(new Message(message, attachments)); - checkSendMessageResult(results.first(), results.second()); - return results.first(); + final var results = m.sendMessage(new Message(message, attachments), + Set.of(new RecipientIdentifier.NoteToSelf())); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); } } @Override public void sendEndSessionMessage(final List recipients) { try { - final var results = m.sendEndSessionMessage(recipients); - checkSendMessageResults(results.first(), results.second()); + final var results = m.sendEndSessionMessage(getSingleRecipientIdentifiers(recipients, m.getUsername())); + checkSendMessageResults(results.getTimestamp(), results.getResults()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); } } @Override public long sendGroupMessage(final String message, final List attachments, final byte[] groupId) { try { - var results = m.sendGroupMessage(new Message(message, attachments), GroupId.unknownVersion(groupId)); - checkSendMessageResults(results.first(), results.second()); - return results.first(); + var results = m.sendMessage(new Message(message, attachments), + Set.of(new RecipientIdentifier.Group(getGroupId(groupId)))); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); @@ -235,18 +273,16 @@ public class DbusSignalImpl implements Signal { final byte[] groupId ) { try { - final var results = m.sendGroupMessageReaction(emoji, + final var results = m.sendMessageReaction(emoji, remove, - targetAuthor, + getSingleRecipientIdentifier(targetAuthor, m.getUsername()), targetSentTimestamp, - GroupId.unknownVersion(groupId)); - checkSendMessageResults(results.first(), results.second()); - return results.first(); + Set.of(new RecipientIdentifier.Group(getGroupId(groupId)))); + checkSendMessageResults(results.getTimestamp(), results.getResults()); + return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -255,41 +291,39 @@ public class DbusSignalImpl implements Signal { // the profile name @Override public String getContactName(final String number) { - try { - return m.getContactOrProfileName(number); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); - } + return m.getContactOrProfileName(getSingleRecipientIdentifier(number, m.getUsername())); } @Override public void setContactName(final String number, final String name) { try { - m.setContactName(number, name); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); + m.setContactName(getSingleRecipientIdentifier(number, m.getUsername()), name); } catch (NotMasterDeviceException e) { throw new Error.Failure("This command doesn't work on linked devices."); + } catch (UnregisteredUserException e) { + throw new Error.Failure("Contact is not registered."); } } @Override public void setContactBlocked(final String number, final boolean blocked) { try { - m.setContactBlocked(number, blocked); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); + m.setContactBlocked(getSingleRecipientIdentifier(number, m.getUsername()), blocked); } catch (NotMasterDeviceException e) { throw new Error.Failure("This command doesn't work on linked devices."); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); } } @Override public void setGroupBlocked(final byte[] groupId, final boolean blocked) { try { - m.setGroupBlocked(GroupId.unknownVersion(groupId), blocked); + m.setGroupBlocked(getGroupId(groupId), blocked); } catch (GroupNotFoundException e) { throw new Error.GroupNotFound(e.getMessage()); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); } } @@ -305,7 +339,7 @@ public class DbusSignalImpl implements Signal { @Override public String getGroupName(final byte[] groupId) { - var group = m.getGroup(GroupId.unknownVersion(groupId)); + var group = m.getGroup(getGroupId(groupId)); if (group == null) { return ""; } else { @@ -315,7 +349,7 @@ public class DbusSignalImpl implements Signal { @Override public List getGroupMembers(final byte[] groupId) { - var group = m.getGroup(GroupId.unknownVersion(groupId)); + var group = m.getGroup(getGroupId(groupId)); if (group == null) { return List.of(); } else { @@ -336,21 +370,19 @@ public class DbusSignalImpl implements Signal { if (name.isEmpty()) { name = null; } - if (members.isEmpty()) { - members = null; - } if (avatar.isEmpty()) { avatar = null; } + final var memberIdentifiers = getSingleRecipientIdentifiers(members, m.getUsername()); if (groupId == null) { - final var results = m.createGroup(name, members, avatar == null ? null : new File(avatar)); - checkSendMessageResults(0, results.second()); + final var results = m.createGroup(name, memberIdentifiers, avatar == null ? null : new File(avatar)); + checkSendMessageResults(results.second().getTimestamp(), results.second().getResults()); return results.first().serialize(); } else { - final var results = m.updateGroup(GroupId.unknownVersion(groupId), + final var results = m.updateGroup(getGroupId(groupId), name, null, - members, + memberIdentifiers, null, null, null, @@ -362,16 +394,14 @@ public class DbusSignalImpl implements Signal { null, null); if (results != null) { - checkSendMessageResults(results.first(), results.second()); + checkSendMessageResults(results.getTimestamp(), results.getResults()); } return groupId; } } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); } @@ -403,6 +433,28 @@ public class DbusSignalImpl implements Signal { } } + @Override + public void removePin() { + try { + m.setRegistrationLockPin(Optional.absent()); + } catch (UnauthenticatedResponseException e) { + throw new Error.Failure("Remove pin failed with unauthenticated response: " + e.getMessage()); + } catch (IOException e) { + throw new Error.Failure("Remove pin error: " + e.getMessage()); + } + } + + @Override + public void setPin(String registrationLockPin) { + try { + m.setRegistrationLockPin(Optional.of(registrationLockPin)); + } catch (UnauthenticatedResponseException e) { + throw new Error.Failure("Set pin error failed with unauthenticated response: " + e.getMessage()); + } catch (IOException e) { + throw new Error.Failure("Set pin error: " + e.getMessage()); + } + } + // Provide option to query a version string in order to react on potential // future interface changes @Override @@ -450,26 +502,25 @@ public class DbusSignalImpl implements Signal { @Override public void quitGroup(final byte[] groupId) { - var group = GroupId.unknownVersion(groupId); + var group = getGroupId(groupId); try { - m.sendQuitGroupMessage(group, Set.of()); + m.quitGroup(group, Set.of()); } catch (GroupNotFoundException | NotAGroupMemberException e) { throw new Error.GroupNotFound(e.getMessage()); } catch (IOException | LastGroupAdminException e) { throw new Error.Failure(e.getMessage()); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); } } @Override - public void joinGroup(final String groupLink) { + public byte[] joinGroup(final String groupLink) { try { final var linkUrl = GroupInviteLinkUrl.fromUri(groupLink); if (linkUrl == null) { throw new Error.Failure("Group link is invalid:"); } - m.joinGroup(linkUrl); + final var result = m.joinGroup(linkUrl); + return result.first().serialize(); } catch (GroupInviteLinkUrl.InvalidGroupLinkException | GroupLinkNotActiveException e) { throw new Error.Failure("Group link is invalid: " + e.getMessage()); } catch (GroupInviteLinkUrl.UnknownGroupLinkVersionException e) { @@ -481,16 +532,12 @@ public class DbusSignalImpl implements Signal { @Override public boolean isContactBlocked(final String number) { - try { - return m.isContactBlocked(number); - } catch (InvalidNumberException e) { - throw new Error.InvalidNumber(e.getMessage()); - } + return m.isContactBlocked(getSingleRecipientIdentifier(number, m.getUsername())); } @Override public boolean isGroupBlocked(final byte[] groupId) { - var group = m.getGroup(GroupId.unknownVersion(groupId)); + var group = m.getGroup(getGroupId(groupId)); if (group == null) { return false; } else { @@ -500,11 +547,114 @@ public class DbusSignalImpl implements Signal { @Override public boolean isMember(final byte[] groupId) { - var group = m.getGroup(GroupId.unknownVersion(groupId)); + var group = m.getGroup(getGroupId(groupId)); if (group == null) { return false; } else { return group.isMember(m.getSelfRecipientId()); } } + + @Override + public String uploadStickerPack(String stickerPackPath) { + File path = new File(stickerPackPath); + try { + return m.uploadStickerPack(path).toString(); + } catch (IOException e) { + throw new Error.Failure("Upload error (maybe image size is too large):" + e.getMessage()); + } catch (StickerPackInvalidException e) { + throw new Error.Failure("Invalid sticker pack: " + e.getMessage()); + } + } + + private static void checkSendMessageResult(long timestamp, SendMessageResult result) throws DBusExecutionException { + var error = ErrorUtils.getErrorMessageFromSendMessageResult(result); + + if (error == null) { + return; + } + + final var message = timestamp + "\nFailed to send message:\n" + error + '\n'; + + if (result.getIdentityFailure() != null) { + throw new Error.UntrustedIdentity(message); + } else { + throw new Error.Failure(message); + } + } + + private static void checkSendMessageResults( + long timestamp, Map> results + ) throws DBusExecutionException { + final var sendMessageResults = results.values().stream().findFirst(); + if (results.size() == 1 && sendMessageResults.get().size() == 1) { + checkSendMessageResult(timestamp, sendMessageResults.get().stream().findFirst().get()); + return; + } + + var errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results); + if (errors.size() == 0) { + return; + } + + var message = new StringBuilder(); + message.append(timestamp).append('\n'); + message.append("Failed to send (some) messages:\n"); + for (var error : errors) { + message.append(error).append('\n'); + } + + throw new Error.Failure(message.toString()); + } + + private static void checkSendMessageResults( + long timestamp, Collection results + ) throws DBusExecutionException { + if (results.size() == 1) { + checkSendMessageResult(timestamp, results.stream().findFirst().get()); + return; + } + + var errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results); + if (errors.size() == 0) { + return; + } + + var message = new StringBuilder(); + message.append(timestamp).append('\n'); + message.append("Failed to send (some) messages:\n"); + for (var error : errors) { + message.append(error).append('\n'); + } + + throw new Error.Failure(message.toString()); + } + + private static Set getSingleRecipientIdentifiers( + final Collection recipientStrings, final String localNumber + ) throws DBusExecutionException { + final var identifiers = new HashSet(); + for (var recipientString : recipientStrings) { + identifiers.add(getSingleRecipientIdentifier(recipientString, localNumber)); + } + return identifiers; + } + + private static RecipientIdentifier.Single getSingleRecipientIdentifier( + final String recipientString, final String localNumber + ) throws DBusExecutionException { + try { + return RecipientIdentifier.Single.fromString(recipientString, localNumber); + } catch (InvalidNumberException e) { + throw new Error.InvalidNumber(e.getMessage()); + } + } + + private static GroupId getGroupId(byte[] groupId) throws DBusExecutionException { + try { + return GroupId.unknownVersion(groupId); + } catch (Throwable e) { + throw new Error.InvalidGroupId("Invalid group id: " + e.getMessage()); + } + } }