Add --quote-attachment paramter to send command

Fixes #1318
This commit is contained in:
AsamK 2023-10-10 19:54:45 +02:00
parent 91ab0b12b0
commit 7b5b5776f0
7 changed files with 64 additions and 22 deletions

View file

@ -164,6 +164,9 @@ pub enum CliCommands {
#[arg(long)] #[arg(long)]
quote_mention: Vec<String>, quote_mention: Vec<String>,
#[arg(long)]
quote_attachment: Vec<String>,
#[arg(long)] #[arg(long)]
sticker: Option<String>, sticker: Option<String>,

View file

@ -143,6 +143,7 @@ pub trait Rpc {
#[allow(non_snake_case)] quoteAuthor: Option<String>, #[allow(non_snake_case)] quoteAuthor: Option<String>,
#[allow(non_snake_case)] quoteMessage: Option<String>, #[allow(non_snake_case)] quoteMessage: Option<String>,
#[allow(non_snake_case)] quoteMention: Vec<String>, #[allow(non_snake_case)] quoteMention: Vec<String>,
#[allow(non_snake_case)] quoteAttachment: Vec<String>,
sticker: Option<String>, sticker: Option<String>,
#[allow(non_snake_case)] storyTimestamp: Option<u64>, #[allow(non_snake_case)] storyTimestamp: Option<u64>,
#[allow(non_snake_case)] storyAuthor: Option<String>, #[allow(non_snake_case)] storyAuthor: Option<String>,

View file

@ -140,6 +140,7 @@ async fn handle_command(
quote_author, quote_author,
quote_message, quote_message,
quote_mention, quote_mention,
quote_attachment,
sticker, sticker,
story_timestamp, story_timestamp,
story_author, story_author,
@ -158,6 +159,7 @@ async fn handle_command(
quote_author, quote_author,
quote_message, quote_message,
quote_mention, quote_mention,
quote_attachment,
sticker, sticker,
story_timestamp, story_timestamp,
story_author, story_author,

View file

@ -544,7 +544,8 @@
{ {
"name":"org.asamk.Signal", "name":"org.asamk.Signal",
"allDeclaredMethods":true, "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",
@ -1747,7 +1748,8 @@
{ {
"name":"org.freedesktop.dbus.interfaces.Introspectable", "name":"org.freedesktop.dbus.interfaces.Introspectable",
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredClasses":true "allDeclaredClasses":true,
"methods":[{"name":"Introspect","parameterTypes":[] }]
}, },
{ {
"name":"org.freedesktop.dbus.interfaces.Peer", "name":"org.freedesktop.dbus.interfaces.Peer",

View file

@ -21,8 +21,12 @@ public record Message(
RecipientIdentifier.Single author, RecipientIdentifier.Single author,
String message, String message,
List<Mention> mentions, 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) {}

View file

@ -627,12 +627,19 @@ public class ManagerImpl implements Manager {
} }
if (message.quote().isPresent()) { if (message.quote().isPresent()) {
final var quote = message.quote().get(); 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(), messageBuilder.withQuote(new SignalServiceDataMessage.Quote(quote.timestamp(),
context.getRecipientHelper() context.getRecipientHelper()
.resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author())) .resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author()))
.getServiceId(), .getServiceId(),
quote.message(), quote.message(),
List.of(), quotedAttachments,
resolveMentions(quote.mentions()), resolveMentions(quote.mentions()),
SignalServiceDataMessage.Quote.Type.NORMAL, SignalServiceDataMessage.Quote.Type.NORMAL,
quote.textStyles().stream().map(TextStyle::toBodyRange).toList())); quote.textStyles().stream().map(TextStyle::toBodyRange).toList()));

View file

@ -78,6 +78,9 @@ public class SendCommand implements JsonRpcLocalCommand {
subparser.addArgument("--quote-mention") subparser.addArgument("--quote-mention")
.nargs("*") .nargs("*")
.help("Quote with mention of another group member (syntax: start:length:recipientNumber)"); .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") subparser.addArgument("--quote-text-style")
.nargs("*") .nargs("*")
.help("Quote with style parts of the message text (syntax: start:length:STYLE)"); .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) { if (attachments == null) {
attachments = List.of(); attachments = List.of();
} }
final var selfNumber = m.getSelfNumber(); final var selfNumber = m.getSelfNumber();
List<String> mentionStrings = ns.getList("mention"); final var mentionStrings = ns.<String>getList("mention");
final var mentions = mentionStrings == null final var mentions = mentionStrings == null
? List.<Message.Mention>of() ? List.<Message.Mention>of()
: parseMentions(selfNumber, mentionStrings); : 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 var textStyles = textStyleStrings == null ? List.<TextStyle>of() : parseTextStyles(textStyleStrings);
final Message.Quote quote; final Message.Quote quote;
@ -165,29 +168,34 @@ public class SendCommand implements JsonRpcLocalCommand {
if (quoteTimestamp != null) { if (quoteTimestamp != null) {
final var quoteAuthor = ns.getString("quote-author"); final var quoteAuthor = ns.getString("quote-author");
final var quoteMessage = ns.getString("quote-message"); 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 final var quoteMentions = quoteMentionStrings == null
? List.<Message.Mention>of() ? List.<Message.Mention>of()
: parseMentions(selfNumber, quoteMentionStrings); : 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 final var quoteTextStyles = quoteTextStyleStrings == null
? List.<TextStyle>of() ? List.<TextStyle>of()
: parseTextStyles(quoteTextStyleStrings); : parseTextStyles(quoteTextStyleStrings);
final var quoteAttachments = quoteAttachmentStrings == null
? List.<Message.Quote.Attachment>of()
: parseQuoteAttachments(quoteAttachmentStrings);
quote = new Message.Quote(quoteTimestamp, quote = new Message.Quote(quoteTimestamp,
CommandUtil.getSingleRecipientIdentifier(quoteAuthor, selfNumber), CommandUtil.getSingleRecipientIdentifier(quoteAuthor, selfNumber),
quoteMessage == null ? "" : quoteMessage, quoteMessage == null ? "" : quoteMessage,
quoteMentions, quoteMentions,
quoteTextStyles); quoteTextStyles,
quoteAttachments);
} else { } else {
quote = null; quote = null;
} }
final List<Message.Preview> previews; 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"); final var previewTitle = ns.getString("preview-title");
String previewDescription = ns.getString("preview-description"); final var previewDescription = ns.getString("preview-description");
String previewImage = ns.getString("preview-image"); final var previewImage = ns.getString("preview-image");
previews = List.of(new Message.Preview(previewUrl, previews = List.of(new Message.Preview(previewUrl,
Optional.ofNullable(previewTitle).orElse(""), Optional.ofNullable(previewTitle).orElse(""),
Optional.ofNullable(previewDescription).orElse(""), Optional.ofNullable(previewDescription).orElse(""),
@ -241,9 +249,8 @@ public class SendCommand implements JsonRpcLocalCommand {
private List<Message.Mention> parseMentions( private List<Message.Mention> parseMentions(
final String selfNumber, final List<String> mentionStrings final String selfNumber, final List<String> mentionStrings
) throws UserErrorException { ) throws UserErrorException {
List<Message.Mention> mentions; final var mentionPattern = Pattern.compile("(\\d+):(\\d+):(.+)");
final Pattern mentionPattern = Pattern.compile("(\\d+):(\\d+):(.+)"); final var mentions = new ArrayList<Message.Mention>();
mentions = new ArrayList<>();
for (final var mention : mentionStrings) { for (final var mention : mentionStrings) {
final var matcher = mentionPattern.matcher(mention); final var matcher = mentionPattern.matcher(mention);
if (!matcher.matches()) { if (!matcher.matches()) {
@ -261,9 +268,8 @@ public class SendCommand implements JsonRpcLocalCommand {
private List<TextStyle> parseTextStyles( private List<TextStyle> parseTextStyles(
final List<String> textStylesStrings final List<String> textStylesStrings
) throws UserErrorException { ) throws UserErrorException {
List<TextStyle> textStyles; final var textStylePattern = Pattern.compile("(\\d+):(\\d+):(.+)");
final Pattern textStylePattern = Pattern.compile("(\\d+):(\\d+):(.+)"); final var textStyles = new ArrayList<TextStyle>();
textStyles = new ArrayList<>();
for (final var textStyle : textStylesStrings) { for (final var textStyle : textStylesStrings) {
final var matcher = textStylePattern.matcher(textStyle); final var matcher = textStylePattern.matcher(textStyle);
if (!matcher.matches()) { 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); final var matcher = stickerPattern.matcher(stickerString);
if (!matcher.matches() || matcher.group(1).length() % 2 != 0) { if (!matcher.matches() || matcher.group(1).length() % 2 != 0) {
throw new UserErrorException("Invalid sticker syntax (" 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;
}
} }