]> nmode's Git Repositories - signal-cli/commitdiff
Add --quote-attachment paramter to send command
authorAsamK <asamk@gmx.de>
Tue, 10 Oct 2023 17:54:45 +0000 (19:54 +0200)
committerAsamK <asamk@gmx.de>
Tue, 10 Oct 2023 17:54:45 +0000 (19:54 +0200)
Fixes #1318

client/src/cli.rs
client/src/jsonrpc.rs
client/src/main.rs
graalvm-config-dir/reflect-config.json
lib/src/main/java/org/asamk/signal/manager/api/Message.java
lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java
src/main/java/org/asamk/signal/commands/SendCommand.java

index 6a8dd3613dedaad0cb8f571884b37548700f32a0..0b513268eabd9a8e4d0739485b0442092df33d97 100644 (file)
@@ -164,6 +164,9 @@ pub enum CliCommands {
         #[arg(long)]
         quote_mention: Vec<String>,
 
         #[arg(long)]
         quote_mention: Vec<String>,
 
+        #[arg(long)]
+        quote_attachment: Vec<String>,
+
         #[arg(long)]
         sticker: Option<String>,
 
         #[arg(long)]
         sticker: Option<String>,
 
index cd2573053218abbdd27a194baa8d42cf77cc8bd3..e3031bf39ae403cfeb3d2375f6f1156e5eab4c73 100644 (file)
@@ -143,6 +143,7 @@ pub trait Rpc {
         #[allow(non_snake_case)] quoteAuthor: Option<String>,
         #[allow(non_snake_case)] quoteMessage: Option<String>,
         #[allow(non_snake_case)] quoteMention: Vec<String>,
         #[allow(non_snake_case)] quoteAuthor: Option<String>,
         #[allow(non_snake_case)] quoteMessage: Option<String>,
         #[allow(non_snake_case)] quoteMention: Vec<String>,
+        #[allow(non_snake_case)] quoteAttachment: Vec<String>,
         sticker: Option<String>,
         #[allow(non_snake_case)] storyTimestamp: Option<u64>,
         #[allow(non_snake_case)] storyAuthor: Option<String>,
         sticker: Option<String>,
         #[allow(non_snake_case)] storyTimestamp: Option<u64>,
         #[allow(non_snake_case)] storyAuthor: Option<String>,
index c840fd5ea9ce861fdb1cada7e4219a3ca968df8e..958d9d9fd036caa6586edc8e1a3ebba3fe346a9d 100644 (file)
@@ -140,6 +140,7 @@ async fn handle_command(
             quote_author,
             quote_message,
             quote_mention,
             quote_author,
             quote_message,
             quote_mention,
+            quote_attachment,
             sticker,
             story_timestamp,
             story_author,
             sticker,
             story_timestamp,
             story_author,
@@ -158,6 +159,7 @@ async fn handle_command(
                     quote_author,
                     quote_message,
                     quote_mention,
                     quote_author,
                     quote_message,
                     quote_mention,
+                    quote_attachment,
                     sticker,
                     story_timestamp,
                     story_author,
                     sticker,
                     story_timestamp,
                     story_author,
index 75d452539c630974ab0aecd1263b2b7268acb11f..6aec194b1a56ef9e470764dfa3d8d0eaca60e5fb 100644 (file)
 {
   "name":"org.asamk.Signal",
   "allDeclaredMethods":true,
 {
   "name":"org.asamk.Signal",
   "allDeclaredMethods":true,
-  "allDeclaredClasses":true
+  "allDeclaredClasses":true,
+  "methods":[{"name":"getSelfNumber","parameterTypes":[] }, {"name":"sendGroupMessageReaction","parameterTypes":["java.lang.String","boolean","java.lang.String","long","byte[]"] }, {"name":"sendMessage","parameterTypes":["java.lang.String","java.util.List","java.lang.String"] }, {"name":"sendMessageReaction","parameterTypes":["java.lang.String","boolean","java.lang.String","long","java.util.List"] }]
 },
 {
   "name":"org.asamk.Signal$Configuration",
 },
 {
   "name":"org.asamk.Signal$Configuration",
 {
   "name":"org.freedesktop.dbus.interfaces.Introspectable",
   "allDeclaredMethods":true,
 {
   "name":"org.freedesktop.dbus.interfaces.Introspectable",
   "allDeclaredMethods":true,
-  "allDeclaredClasses":true
+  "allDeclaredClasses":true,
+  "methods":[{"name":"Introspect","parameterTypes":[] }]
 },
 {
   "name":"org.freedesktop.dbus.interfaces.Peer",
 },
 {
   "name":"org.freedesktop.dbus.interfaces.Peer",
index ac9e4999b6b717bd99987fe2e15f8081207969fa..48277e6dc9d277821ce2bb79d3de7d604dc5b6ac 100644 (file)
@@ -21,8 +21,12 @@ public record Message(
             RecipientIdentifier.Single author,
             String message,
             List<Mention> mentions,
             RecipientIdentifier.Single author,
             String message,
             List<Mention> mentions,
-            List<TextStyle> textStyles
-    ) {}
+            List<TextStyle> textStyles,
+            List<Attachment> attachments
+    ) {
+
+        public record Attachment(String contentType, String filename, String preview) {}
+    }
 
     public record Sticker(byte[] packId, int stickerId) {}
 
 
     public record Sticker(byte[] packId, int stickerId) {}
 
index d1e96026a4511fb5e623e350b794f148042ec3fa..bfb52ebfd13aa013ce1efbe8d6e1623f6dfc488d 100644 (file)
@@ -627,12 +627,19 @@ public class ManagerImpl implements Manager {
         }
         if (message.quote().isPresent()) {
             final var quote = message.quote().get();
         }
         if (message.quote().isPresent()) {
             final var quote = message.quote().get();
+            final var quotedAttachments = new ArrayList<SignalServiceDataMessage.Quote.QuotedAttachment>();
+            for (final var a : quote.attachments()) {
+                final var quotedAttachment = new SignalServiceDataMessage.Quote.QuotedAttachment(a.contentType(),
+                        a.filename(),
+                        a.preview() == null ? null : context.getAttachmentHelper().uploadAttachment(a.preview()));
+                quotedAttachments.add(quotedAttachment);
+            }
             messageBuilder.withQuote(new SignalServiceDataMessage.Quote(quote.timestamp(),
                     context.getRecipientHelper()
                             .resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author()))
                             .getServiceId(),
                     quote.message(),
             messageBuilder.withQuote(new SignalServiceDataMessage.Quote(quote.timestamp(),
                     context.getRecipientHelper()
                             .resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author()))
                             .getServiceId(),
                     quote.message(),
-                    List.of(),
+                    quotedAttachments,
                     resolveMentions(quote.mentions()),
                     SignalServiceDataMessage.Quote.Type.NORMAL,
                     quote.textStyles().stream().map(TextStyle::toBodyRange).toList()));
                     resolveMentions(quote.mentions()),
                     SignalServiceDataMessage.Quote.Type.NORMAL,
                     quote.textStyles().stream().map(TextStyle::toBodyRange).toList()));
index 56a26253081b58c0b741e14dcc25a93d45a4f7ed..1c3d91baa346293d2ccd75349d88f85ce5938f55 100644 (file)
@@ -78,6 +78,9 @@ public class SendCommand implements JsonRpcLocalCommand {
         subparser.addArgument("--quote-mention")
                 .nargs("*")
                 .help("Quote with mention of another group member (syntax: start:length:recipientNumber)");
         subparser.addArgument("--quote-mention")
                 .nargs("*")
                 .help("Quote with mention of another group member (syntax: start:length:recipientNumber)");
+        subparser.addArgument("--quote-attachment")
+                .nargs("*")
+                .help("Specify the attachments of the original message (syntax: contentType[:filename[:previewFile]], e.g. 'audio/aac' or 'image/png:test.png:/tmp/preview.jpg'.");
         subparser.addArgument("--quote-text-style")
                 .nargs("*")
                 .help("Quote with style parts of the message text (syntax: start:length:STYLE)");
         subparser.addArgument("--quote-text-style")
                 .nargs("*")
                 .help("Quote with style parts of the message text (syntax: start:length:STYLE)");
@@ -145,19 +148,19 @@ public class SendCommand implements JsonRpcLocalCommand {
             messageText = "";
         }
 
             messageText = "";
         }
 
-        List<String> attachments = ns.getList("attachment");
+        var attachments = ns.<String>getList("attachment");
         if (attachments == null) {
             attachments = List.of();
         }
 
         final var selfNumber = m.getSelfNumber();
 
         if (attachments == null) {
             attachments = List.of();
         }
 
         final var selfNumber = m.getSelfNumber();
 
-        List<String> mentionStrings = ns.getList("mention");
+        final var mentionStrings = ns.<String>getList("mention");
         final var mentions = mentionStrings == null
                 ? List.<Message.Mention>of()
                 : parseMentions(selfNumber, mentionStrings);
 
         final var mentions = mentionStrings == null
                 ? List.<Message.Mention>of()
                 : parseMentions(selfNumber, mentionStrings);
 
-        List<String> textStyleStrings = ns.getList("text-style");
+        final var textStyleStrings = ns.<String>getList("text-style");
         final var textStyles = textStyleStrings == null ? List.<TextStyle>of() : parseTextStyles(textStyleStrings);
 
         final Message.Quote quote;
         final var textStyles = textStyleStrings == null ? List.<TextStyle>of() : parseTextStyles(textStyleStrings);
 
         final Message.Quote quote;
@@ -165,29 +168,34 @@ public class SendCommand implements JsonRpcLocalCommand {
         if (quoteTimestamp != null) {
             final var quoteAuthor = ns.getString("quote-author");
             final var quoteMessage = ns.getString("quote-message");
         if (quoteTimestamp != null) {
             final var quoteAuthor = ns.getString("quote-author");
             final var quoteMessage = ns.getString("quote-message");
-            List<String> quoteMentionStrings = ns.getList("quote-mention");
+            final var quoteMentionStrings = ns.<String>getList("quote-mention");
             final var quoteMentions = quoteMentionStrings == null
                     ? List.<Message.Mention>of()
                     : parseMentions(selfNumber, quoteMentionStrings);
             final var quoteMentions = quoteMentionStrings == null
                     ? List.<Message.Mention>of()
                     : parseMentions(selfNumber, quoteMentionStrings);
-            List<String> quoteTextStyleStrings = ns.getList("quote-text-style");
+            final var quoteTextStyleStrings = ns.<String>getList("quote-text-style");
+            final var quoteAttachmentStrings = ns.<String>getList("quote-attachment");
             final var quoteTextStyles = quoteTextStyleStrings == null
                     ? List.<TextStyle>of()
                     : parseTextStyles(quoteTextStyleStrings);
             final var quoteTextStyles = quoteTextStyleStrings == null
                     ? List.<TextStyle>of()
                     : parseTextStyles(quoteTextStyleStrings);
+            final var quoteAttachments = quoteAttachmentStrings == null
+                    ? List.<Message.Quote.Attachment>of()
+                    : parseQuoteAttachments(quoteAttachmentStrings);
             quote = new Message.Quote(quoteTimestamp,
                     CommandUtil.getSingleRecipientIdentifier(quoteAuthor, selfNumber),
                     quoteMessage == null ? "" : quoteMessage,
                     quoteMentions,
             quote = new Message.Quote(quoteTimestamp,
                     CommandUtil.getSingleRecipientIdentifier(quoteAuthor, selfNumber),
                     quoteMessage == null ? "" : quoteMessage,
                     quoteMentions,
-                    quoteTextStyles);
+                    quoteTextStyles,
+                    quoteAttachments);
         } else {
             quote = null;
         }
 
         final List<Message.Preview> previews;
         } else {
             quote = null;
         }
 
         final List<Message.Preview> previews;
-        String previewUrl = ns.getString("preview-url");
+        final var previewUrl = ns.getString("preview-url");
         if (previewUrl != null) {
         if (previewUrl != null) {
-            String previewTitle = ns.getString("preview-title");
-            String previewDescription = ns.getString("preview-description");
-            String previewImage = ns.getString("preview-image");
+            final var previewTitle = ns.getString("preview-title");
+            final var previewDescription = ns.getString("preview-description");
+            final var previewImage = ns.getString("preview-image");
             previews = List.of(new Message.Preview(previewUrl,
                     Optional.ofNullable(previewTitle).orElse(""),
                     Optional.ofNullable(previewDescription).orElse(""),
             previews = List.of(new Message.Preview(previewUrl,
                     Optional.ofNullable(previewTitle).orElse(""),
                     Optional.ofNullable(previewDescription).orElse(""),
@@ -241,9 +249,8 @@ public class SendCommand implements JsonRpcLocalCommand {
     private List<Message.Mention> parseMentions(
             final String selfNumber, final List<String> mentionStrings
     ) throws UserErrorException {
     private List<Message.Mention> parseMentions(
             final String selfNumber, final List<String> mentionStrings
     ) throws UserErrorException {
-        List<Message.Mention> mentions;
-        final Pattern mentionPattern = Pattern.compile("(\\d+):(\\d+):(.+)");
-        mentions = new ArrayList<>();
+        final var mentionPattern = Pattern.compile("(\\d+):(\\d+):(.+)");
+        final var mentions = new ArrayList<Message.Mention>();
         for (final var mention : mentionStrings) {
             final var matcher = mentionPattern.matcher(mention);
             if (!matcher.matches()) {
         for (final var mention : mentionStrings) {
             final var matcher = mentionPattern.matcher(mention);
             if (!matcher.matches()) {
@@ -261,9 +268,8 @@ public class SendCommand implements JsonRpcLocalCommand {
     private List<TextStyle> parseTextStyles(
             final List<String> textStylesStrings
     ) throws UserErrorException {
     private List<TextStyle> parseTextStyles(
             final List<String> textStylesStrings
     ) throws UserErrorException {
-        List<TextStyle> textStyles;
-        final Pattern textStylePattern = Pattern.compile("(\\d+):(\\d+):(.+)");
-        textStyles = new ArrayList<>();
+        final var textStylePattern = Pattern.compile("(\\d+):(\\d+):(.+)");
+        final var textStyles = new ArrayList<TextStyle>();
         for (final var textStyle : textStylesStrings) {
             final var matcher = textStylePattern.matcher(textStyle);
             if (!matcher.matches()) {
         for (final var textStyle : textStylesStrings) {
             final var matcher = textStylePattern.matcher(textStyle);
             if (!matcher.matches()) {
@@ -283,7 +289,7 @@ public class SendCommand implements JsonRpcLocalCommand {
     }
 
     private Message.Sticker parseSticker(final String stickerString) throws UserErrorException {
     }
 
     private Message.Sticker parseSticker(final String stickerString) throws UserErrorException {
-        final Pattern stickerPattern = Pattern.compile("([\\da-f]+):(\\d+)");
+        final var stickerPattern = Pattern.compile("([\\da-f]+):(\\d+)");
         final var matcher = stickerPattern.matcher(stickerString);
         if (!matcher.matches() || matcher.group(1).length() % 2 != 0) {
             throw new UserErrorException("Invalid sticker syntax ("
         final var matcher = stickerPattern.matcher(stickerString);
         if (!matcher.matches() || matcher.group(1).length() % 2 != 0) {
             throw new UserErrorException("Invalid sticker syntax ("
@@ -292,4 +298,21 @@ public class SendCommand implements JsonRpcLocalCommand {
         }
         return new Message.Sticker(Hex.toByteArray(matcher.group(1)), Integer.parseInt(matcher.group(2)));
     }
         }
         return new Message.Sticker(Hex.toByteArray(matcher.group(1)), Integer.parseInt(matcher.group(2)));
     }
+
+    private List<Message.Quote.Attachment> parseQuoteAttachments(
+            final List<String> attachmentStrings
+    ) throws UserErrorException {
+        final var attachmentPattern = Pattern.compile("([^:]+)(:([^:]+)(:(.+))?)?");
+        final var attachments = new ArrayList<Message.Quote.Attachment>();
+        for (final var attachment : attachmentStrings) {
+            final var matcher = attachmentPattern.matcher(attachment);
+            if (!matcher.matches()) {
+                throw new UserErrorException("Invalid attachment syntax ("
+                        + attachment
+                        + ") expected 'contentType[:filename[:previewFile]]'");
+            }
+            attachments.add(new Message.Quote.Attachment(matcher.group(1), matcher.group(3), matcher.group(5)));
+        }
+        return attachments;
+    }
 }
 }