]> nmode's Git Repositories - signal-cli/commitdiff
Add command sendReaction for emoji reactions
authorAsamK <asamk@gmx.de>
Sat, 22 Feb 2020 10:29:17 +0000 (11:29 +0100)
committerAsamK <asamk@gmx.de>
Sat, 22 Feb 2020 10:29:17 +0000 (11:29 +0100)
man/signal-cli.1.adoc
src/main/java/org/asamk/signal/commands/Commands.java
src/main/java/org/asamk/signal/commands/SendReactionCommand.java [new file with mode: 0644]
src/main/java/org/asamk/signal/manager/Manager.java

index 35a578f420f48334317f9ec973efaa6c0ed06f89..4101986f0b13078a258aa5893b4e39ad8465d58b 100644 (file)
@@ -140,6 +140,28 @@ RECIPIENT::
 *-e*, *--endsession*::
        Clear session state and send end session message.
 
+sendReaction
+~~~~~~~~~~~~
+Send reaction to a previously received or sent message.
+
+RECIPIENT::
+       Specify the recipients’ phone number.
+
+*-g* GROUP, *--group* GROUP::
+       Specify the recipient group ID in base64 encoding.
+
+*-e* EMOJI, *--emoji* EMOJI::
+       Specify the emoji, should be a single unicode grapheme cluster.
+
+*-a* NUMBER, *--target-author* NUMBER::
+       Specify the number of the author of the message to which to react.
+
+*-t* TIMESTAMP, *--target-timestamp* TIMESTAMP::
+       Specify the timestamp of the message to which to react.
+
+*-r*, *--remove*::
+       Remove a reaction.
+
 receive
 ~~~~~~~
 Query the server for new messages. New messages are printed on standardoutput and
index 1ad0987a373be22e569eef5304bac87e8fda2bc2..24a03e3fa4fedef88989417755109d0f5a74450c 100644 (file)
@@ -22,6 +22,7 @@ public class Commands {
         addCommand("removeDevice", new RemoveDeviceCommand());
         addCommand("removePin", new RemovePinCommand());
         addCommand("send", new SendCommand());
+        addCommand("sendReaction", new SendReactionCommand());
         addCommand("sendContacts", new SendContactsCommand());
         addCommand("updateContact", new UpdateContactCommand());
         addCommand("setPin", new SetPinCommand());
diff --git a/src/main/java/org/asamk/signal/commands/SendReactionCommand.java b/src/main/java/org/asamk/signal/commands/SendReactionCommand.java
new file mode 100644 (file)
index 0000000..3856064
--- /dev/null
@@ -0,0 +1,95 @@
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+
+import org.asamk.signal.GroupIdFormatException;
+import org.asamk.signal.GroupNotFoundException;
+import org.asamk.signal.NotAGroupMemberException;
+import org.asamk.signal.manager.Manager;
+import org.asamk.signal.util.Util;
+import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions;
+
+import java.io.IOException;
+
+import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
+import static org.asamk.signal.util.ErrorUtils.handleEncapsulatedExceptions;
+import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
+import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
+import static org.asamk.signal.util.ErrorUtils.handleIOException;
+import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
+
+public class SendReactionCommand implements LocalCommand {
+
+    @Override
+    public void attachToSubparser(final Subparser subparser) {
+        subparser.help("Send reaction to a previously received or sent message.");
+        subparser.addArgument("-g", "--group")
+                .help("Specify the recipient group ID.");
+        subparser.addArgument("recipient")
+                .help("Specify the recipients' phone number.")
+                .nargs("*");
+        subparser.addArgument("-e", "--emoji")
+                .required(true)
+                .help("Specify the emoji, should be a single unicode grapheme cluster.");
+        subparser.addArgument("-a", "--target-author")
+                .required(true)
+                .help("Specify the number of the author of the message to which to react.");
+        subparser.addArgument("-t", "--target-timestamp")
+                .required(true)
+                .type(long.class)
+                .help("Specify the timestamp of the message to which to react.");
+        subparser.addArgument("-r", "--remove")
+                .help("Remove a reaction.")
+                .action(Arguments.storeTrue());
+    }
+
+    @Override
+    public int handleCommand(final Namespace ns, final Manager m) {
+        if (!m.isRegistered()) {
+            System.err.println("User is not registered.");
+            return 1;
+        }
+
+        if ((ns.getList("recipient") == null || ns.getList("recipient").size() == 0) && ns.getString("group") == null) {
+            System.err.println("No recipients given");
+            System.err.println("Aborting sending.");
+            return 1;
+        }
+
+        String emoji = ns.getString("emoji");
+        boolean isRemove = ns.getBoolean("remove");
+        SignalServiceAddress targetAuthor = new SignalServiceAddress(null, ns.getString("target_author"));
+        long targetTimestamp = ns.getLong("target_timestamp");
+
+        try {
+            if (ns.getString("group") != null) {
+                byte[] groupId = Util.decodeGroupId(ns.getString("group"));
+                m.sendGroupMessageReaction(emoji, isRemove, targetAuthor, targetTimestamp, groupId);
+            } else {
+                m.sendMessageReaction(emoji, isRemove, targetAuthor, targetTimestamp, ns.<String>getList("recipient"));
+            }
+            return 0;
+        } catch (IOException e) {
+            handleIOException(e);
+            return 3;
+        } catch (EncapsulatedExceptions e) {
+            handleEncapsulatedExceptions(e);
+            return 3;
+        } catch (AssertionError e) {
+            handleAssertionError(e);
+            return 1;
+        } catch (GroupNotFoundException e) {
+            handleGroupNotFoundException(e);
+            return 1;
+        } catch (NotAGroupMemberException e) {
+            handleNotAGroupMemberException(e);
+            return 1;
+        } catch (GroupIdFormatException e) {
+            handleGroupIdFormatException(e);
+            return 1;
+        }
+    }
+}
index 0847e4840290f738b7157ec61134c9dd9541cb93..8d0d46c88bc7054768104fed9bbb971a0ad7a50a 100644 (file)
@@ -496,6 +496,26 @@ public class Manager implements Signal {
         sendMessageLegacy(messageBuilder, membersSend);
     }
 
+    public void sendGroupMessageReaction(String emoji, boolean remove, SignalServiceAddress targetAuthor,
+                                         long targetSentTimestamp, byte[] groupId)
+            throws IOException, EncapsulatedExceptions, AttachmentInvalidException {
+        SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
+        final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
+                .withReaction(reaction)
+                .withProfileKey(account.getProfileKey());
+        if (groupId != null) {
+            SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
+                    .withId(groupId)
+                    .build();
+            messageBuilder.asGroupMessage(group);
+        }
+        final GroupInfo g = getGroupForSending(groupId);
+        // Don't send group message to ourself
+        final List<String> membersSend = new ArrayList<>(g.members);
+        membersSend.remove(this.username);
+        sendMessageLegacy(messageBuilder, membersSend);
+    }
+
     public void sendQuitGroupMessage(byte[] groupId) throws GroupNotFoundException, IOException, EncapsulatedExceptions {
         SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.QUIT)
                 .withId(groupId)
@@ -669,6 +689,16 @@ public class Manager implements Signal {
         sendMessageLegacy(messageBuilder, recipients);
     }
 
+    public void sendMessageReaction(String emoji, boolean remove, SignalServiceAddress targetAuthor,
+                                    long targetSentTimestamp, List<String> recipients)
+            throws IOException, EncapsulatedExceptions, AttachmentInvalidException {
+        SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
+        final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
+                .withReaction(reaction)
+                .withProfileKey(account.getProfileKey());
+        sendMessageLegacy(messageBuilder, recipients);
+    }
+
     @Override
     public void sendEndSessionMessage(List<String> recipients) throws IOException, EncapsulatedExceptions {
         SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()