diff --git a/man/signal-cli-dbus.5.adoc b/man/signal-cli-dbus.5.adoc index 6e0003cc..b9279416 100755 --- a/man/signal-cli-dbus.5.adoc +++ b/man/signal-cli-dbus.5.adoc @@ -195,6 +195,15 @@ Depending on the type of the recipient(s) field this deletes a message with one Exceptions: Failure, InvalidNumber +sendTyping(typingAction, base64GroupId, recipients) -> <> +* typingAction : true = start typing, false = stop typing +* base64GroupId : String representing the internal group identifier in Base64 format +* recipients : List of phone numbers + +Note that you must specify either the base64GroupId or the list of recipients, but not both. + +Exceptions: Failure, UntrustedIdentity + getContactName(number) -> name:: * number : Phone number * name : Contact's name in local storage (from the primary device for a linked account, or the one set with setContactName); if not set, contact's profile name is used diff --git a/src/main/java/org/asamk/Signal.java b/src/main/java/org/asamk/Signal.java index 0d281c6f..7a5aaea1 100644 --- a/src/main/java/org/asamk/Signal.java +++ b/src/main/java/org/asamk/Signal.java @@ -3,14 +3,22 @@ package org.asamk; import org.asamk.SignalControl; import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.commands.exceptions.UnexpectedErrorException; +import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.manager.AvatarStore; +import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.groups.GroupId; +import org.asamk.signal.manager.groups.GroupIdFormatException; +import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.NotAGroupMemberException; +import org.asamk.signal.util.Util; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.freedesktop.dbus.interfaces.DBusInterface; import org.freedesktop.dbus.messages.DBusSignal; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.util.guava.Optional; +import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; +import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; import java.io.File; @@ -19,6 +27,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Base64; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -70,6 +79,8 @@ public interface Signal extends DBusInterface { String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, byte[] groupId ) throws Error.GroupNotFound, Error.Failure, Error.InvalidNumber; + void sendTyping(boolean typingAction, String base64GroupId, Listrecipients) throws Error.Failure, Error.UntrustedIdentity; + String getContactName(String number) throws Error.InvalidNumber; void setContactName(String number, String name) throws Error.InvalidNumber; diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 904029e4..9c88e266 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -9,6 +9,8 @@ import org.asamk.signal.PlainTextWriter; import org.asamk.signal.PlainTextWriterImpl; import org.asamk.signal.commands.GetUserStatusCommand; import org.asamk.signal.commands.UpdateGroupCommand; +import org.asamk.signal.OutputWriter; +import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.commands.exceptions.UnexpectedErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; @@ -17,7 +19,9 @@ import org.asamk.signal.manager.AvatarStore; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.NotMasterDeviceException; import org.asamk.signal.manager.api.Device; +import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.groups.GroupId; +import org.asamk.signal.manager.groups.GroupIdFormatException; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; import org.asamk.signal.manager.groups.GroupLinkState; import org.asamk.signal.manager.groups.GroupNotFoundException; @@ -29,14 +33,17 @@ import org.asamk.signal.util.DateUtils; import org.asamk.signal.util.ErrorUtils; import org.asamk.signal.util.Hex; import org.asamk.signal.util.Util; + import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; +import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException; import org.whispersystems.signalservice.api.messages.SendMessageResult; +import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; @@ -342,6 +349,45 @@ public class DbusSignalImpl implements Signal { return sendGroupMessageReaction(emoji, remove, targetAuthor, targetSentTimestamp, groupId); } + @Override + public void sendTyping(boolean typingAction, String base64GroupId, Listrecipients) { + final var noRecipients = recipients == null || recipients.isEmpty(); + final var noGroup = base64GroupId == null || base64GroupId.isEmpty(); + if (noRecipients && noGroup) { + throw new Error.Failure("No recipients given"); + } + if (!noRecipients && !noGroup) { + throw new Error.Failure("You cannot specify recipients by phone number and groups at the same time"); + } + + final TypingAction action = typingAction ? TypingAction.START : TypingAction.STOP; + + GroupId groupId = null; + if (!noGroup) { + try { + groupId = Util.decodeGroupId(base64GroupId); + } catch (GroupIdFormatException e) { + throw new Error.Failure("Invalid group id: " + e.getMessage()); + } + } + + try { + if (groupId != null) { + m.sendGroupTypingMessage(action, groupId); + } else { + m.sendTypingMessage(action, new HashSet(recipients)); + } + } catch (UntrustedIdentityException e) { + throw new Error.UntrustedIdentity("Failed to send message: " + e.getMessage()); + } catch (IOException e) { + throw new Error.Failure("Failed to send message: " + e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException e) { + throw new Error.Failure("Failed to send to group: " + e.getMessage()); + } catch (InvalidNumberException e) { + throw new Error.Failure("Invalid number: " + e.getMessage()); + } + } + // Since contact names might be empty if not defined, also potentially return // the profile name @Override @@ -786,13 +832,13 @@ public class DbusSignalImpl implements Signal { @Override public void unregister() { - try { + try { m.unregister(); logger.info("Unregister succeeded, exiting.\n"); System.exit(0); - } catch (IOException e) { + } catch (IOException e) { throw new Error.Failure(e.getClass().getSimpleName() + "Unregister error: " + e.getMessage()); - } + } } @Override