Implement sending message quotes

Fixes #213
This commit is contained in:
AsamK 2021-11-21 19:18:17 +01:00
parent 415b65d208
commit d13d150fe1
6 changed files with 87 additions and 29 deletions

View file

@ -708,15 +708,27 @@ public class ManagerImpl implements Manager {
messageBuilder.withAttachments(attachmentHelper.uploadAttachments(attachments)); messageBuilder.withAttachments(attachmentHelper.uploadAttachments(attachments));
} }
if (message.mentions().size() > 0) { if (message.mentions().size() > 0) {
messageBuilder.withMentions(resolveMentions(message.mentions()));
}
if (message.quote().isPresent()) {
final var quote = message.quote().get();
messageBuilder.withQuote(new SignalServiceDataMessage.Quote(quote.timestamp(),
resolveSignalServiceAddress(resolveRecipient(quote.author())),
quote.message(),
List.of(),
resolveMentions(quote.mentions())));
}
}
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException {
final var mentions = new ArrayList<SignalServiceDataMessage.Mention>(); final var mentions = new ArrayList<SignalServiceDataMessage.Mention>();
for (final var m : message.mentions()) { for (final var m : mentionList) {
final var recipientId = resolveRecipient(m.recipient()); final var recipientId = resolveRecipient(m.recipient());
mentions.add(new SignalServiceDataMessage.Mention(resolveSignalServiceAddress(recipientId).getAci(), mentions.add(new SignalServiceDataMessage.Mention(resolveSignalServiceAddress(recipientId).getAci(),
m.start(), m.start(),
m.length())); m.length()));
} }
messageBuilder.withMentions(mentions); return mentions;
}
} }
@Override @Override

View file

@ -1,8 +1,11 @@
package org.asamk.signal.manager.api; package org.asamk.signal.manager.api;
import java.util.List; import java.util.List;
import java.util.Optional;
public record Message(String messageText, List<String> attachments, List<Mention> mentions) { public record Message(String messageText, List<String> attachments, List<Mention> mentions, Optional<Quote> quote) {
public record Mention(RecipientIdentifier.Single recipient, int start, int length) {} public record Mention(RecipientIdentifier.Single recipient, int start, int length) {}
public record Quote(long timestamp, RecipientIdentifier.Single author, String message, List<Mention> mentions) {}
} }

View file

@ -210,6 +210,19 @@ Mention another group member (syntax: start:length:recipientNumber)
In the apps the mention replaces part of the message text, which is specified by the start and length values. In the apps the mention replaces part of the message text, which is specified by the start and length values.
e.g.: `-m "Hi X!" --mention "3:1:+123456789"` e.g.: `-m "Hi X!" --mention "3:1:+123456789"`
*--quote-timestamp*::
Specify the timestamp of a previous message with the recipient or group to add a
quote to the new message.
*--quote-author*::
Specify the number of the author of the original message.
*--quote-message*::
Specify the message of the original message.
*--quote-mention*::
Specify the mentions of the original message (same format as `--mention`).
=== sendReaction === sendReaction
Send reaction to a previously received or sent message. Send reaction to a previously received or sent message.

View file

@ -28,6 +28,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -57,6 +58,14 @@ public class SendCommand implements JsonRpcLocalCommand {
subparser.addArgument("--mention") subparser.addArgument("--mention")
.nargs("*") .nargs("*")
.help("Mention another group member (syntax: start:length:recipientNumber)"); .help("Mention another group member (syntax: start:length:recipientNumber)");
subparser.addArgument("--quote-timestamp")
.type(long.class)
.help("Specify the timestamp of a previous message with the recipient or group to add a quote to the new message.");
subparser.addArgument("--quote-author").help("Specify the number of the author of the original message.");
subparser.addArgument("--quote-message").help("Specify the message of the original message.");
subparser.addArgument("--quote-mention")
.nargs("*")
.help("Quote with mention of another group member (syntax: start:length:recipientNumber)");
} }
@Override @Override
@ -108,10 +117,42 @@ public class SendCommand implements JsonRpcLocalCommand {
} }
List<String> mentionStrings = ns.getList("mention"); List<String> mentionStrings = ns.getList("mention");
List<Message.Mention> mentions; final var mentions = mentionStrings == null ? List.<Message.Mention>of() : parseMentions(m, mentionStrings);
if (mentionStrings == null) {
mentions = List.of(); final Message.Quote quote;
final var quoteTimestamp = ns.getLong("quote-timestamp");
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 quoteMentions = quoteMentionStrings == null
? List.<Message.Mention>of()
: parseMentions(m, quoteMentionStrings);
quote = new Message.Quote(quoteTimestamp,
CommandUtil.getSingleRecipientIdentifier(quoteAuthor, m.getSelfNumber()),
quoteMessage,
quoteMentions);
} else { } else {
quote = null;
}
try {
var results = m.sendMessage(new Message(messageText, attachments, mentions, Optional.ofNullable(quote)),
recipientIdentifiers);
outputResult(outputWriter, results.timestamp());
ErrorUtils.handleSendMessageResults(results.results());
} catch (AttachmentInvalidException | IOException e) {
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
.getSimpleName() + ")", e);
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
throw new UserErrorException(e.getMessage());
}
}
private List<Message.Mention> parseMentions(
final Manager m, final List<String> mentionStrings
) throws UserErrorException {
List<Message.Mention> mentions;
final Pattern mentionPattern = Pattern.compile("([0-9]+):([0-9]+):(.+)"); final Pattern mentionPattern = Pattern.compile("([0-9]+):([0-9]+):(.+)");
mentions = new ArrayList<>(); mentions = new ArrayList<>();
for (final var mention : mentionStrings) { for (final var mention : mentionStrings) {
@ -124,18 +165,7 @@ public class SendCommand implements JsonRpcLocalCommand {
mentions.add(new Message.Mention(CommandUtil.getSingleRecipientIdentifier(matcher.group(3), mentions.add(new Message.Mention(CommandUtil.getSingleRecipientIdentifier(matcher.group(3),
m.getSelfNumber()), Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)))); m.getSelfNumber()), Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2))));
} }
} return mentions;
try {
var results = m.sendMessage(new Message(messageText, attachments, mentions), recipientIdentifiers);
outputResult(outputWriter, results.timestamp());
ErrorUtils.handleSendMessageResults(results.results());
} catch (AttachmentInvalidException | IOException e) {
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
.getSimpleName() + ")", e);
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
throw new UserErrorException(e.getMessage());
}
} }
private void outputResult(final OutputWriter outputWriter, final long timestamp) { private void outputResult(final OutputWriter outputWriter, final long timestamp) {

View file

@ -199,7 +199,7 @@ public class DbusSignalImpl implements Signal {
@Override @Override
public long sendMessage(final String message, final List<String> attachments, final List<String> recipients) { public long sendMessage(final String message, final List<String> attachments, final List<String> recipients) {
try { try {
final var results = m.sendMessage(new Message(message, attachments, List.of()), final var results = m.sendMessage(new Message(message, attachments, List.of(), Optional.empty()),
getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
.map(RecipientIdentifier.class::cast) .map(RecipientIdentifier.class::cast)
.collect(Collectors.toSet())); .collect(Collectors.toSet()));
@ -364,7 +364,7 @@ public class DbusSignalImpl implements Signal {
final String message, final List<String> attachments final String message, final List<String> attachments
) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity { ) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity {
try { try {
final var results = m.sendMessage(new Message(message, attachments, List.of()), final var results = m.sendMessage(new Message(message, attachments, List.of(), Optional.empty()),
Set.of(RecipientIdentifier.NoteToSelf.INSTANCE)); Set.of(RecipientIdentifier.NoteToSelf.INSTANCE));
checkSendMessageResults(results.timestamp(), results.results()); checkSendMessageResults(results.timestamp(), results.results());
return results.timestamp(); return results.timestamp();
@ -390,7 +390,7 @@ public class DbusSignalImpl implements Signal {
@Override @Override
public long sendGroupMessage(final String message, final List<String> attachments, final byte[] groupId) { public long sendGroupMessage(final String message, final List<String> attachments, final byte[] groupId) {
try { try {
var results = m.sendMessage(new Message(message, attachments, List.of()), var results = m.sendMessage(new Message(message, attachments, List.of(), Optional.empty()),
Set.of(new RecipientIdentifier.Group(getGroupId(groupId)))); Set.of(new RecipientIdentifier.Group(getGroupId(groupId))));
checkSendMessageResults(results.timestamp(), results.results()); checkSendMessageResults(results.timestamp(), results.results());
return results.timestamp(); return results.timestamp();

View file

@ -93,7 +93,7 @@ public class CommandUtil {
try { try {
return RecipientIdentifier.Single.fromString(recipientString, localNumber); return RecipientIdentifier.Single.fromString(recipientString, localNumber);
} catch (InvalidNumberException e) { } catch (InvalidNumberException e) {
throw new UserErrorException("Invalid phone number '" + recipientString + "': " + e.getMessage()); throw new UserErrorException("Invalid phone number '" + recipientString + "': " + e.getMessage(), e);
} }
} }
} }