mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Add support for sending stickers
This commit is contained in:
parent
5d83e149b3
commit
404063a080
11 changed files with 141 additions and 35 deletions
|
@ -730,6 +730,7 @@
|
||||||
"queryAllDeclaredMethods":true,
|
"queryAllDeclaredMethods":true,
|
||||||
"queryAllDeclaredConstructors":true,
|
"queryAllDeclaredConstructors":true,
|
||||||
"methods":[
|
"methods":[
|
||||||
|
{"name":"<init>","parameterTypes":["java.lang.String","java.lang.String","org.asamk.signal.manager.JsonStickerPack$JsonSticker","java.util.List"] },
|
||||||
{"name":"author","parameterTypes":[] },
|
{"name":"author","parameterTypes":[] },
|
||||||
{"name":"cover","parameterTypes":[] },
|
{"name":"cover","parameterTypes":[] },
|
||||||
{"name":"stickers","parameterTypes":[] },
|
{"name":"stickers","parameterTypes":[] },
|
||||||
|
@ -742,6 +743,7 @@
|
||||||
"queryAllDeclaredMethods":true,
|
"queryAllDeclaredMethods":true,
|
||||||
"queryAllDeclaredConstructors":true,
|
"queryAllDeclaredConstructors":true,
|
||||||
"methods":[
|
"methods":[
|
||||||
|
{"name":"<init>","parameterTypes":["java.lang.String","java.lang.String","java.lang.String"] },
|
||||||
{"name":"contentType","parameterTypes":[] },
|
{"name":"contentType","parameterTypes":[] },
|
||||||
{"name":"emoji","parameterTypes":[] },
|
{"name":"emoji","parameterTypes":[] },
|
||||||
{"name":"file","parameterTypes":[] }
|
{"name":"file","parameterTypes":[] }
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.asamk.signal.manager.api.Group;
|
||||||
import org.asamk.signal.manager.api.Identity;
|
import org.asamk.signal.manager.api.Identity;
|
||||||
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
||||||
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
||||||
|
import org.asamk.signal.manager.api.InvalidStickerException;
|
||||||
import org.asamk.signal.manager.api.Message;
|
import org.asamk.signal.manager.api.Message;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.manager.api.Pair;
|
import org.asamk.signal.manager.api.Pair;
|
||||||
|
@ -173,7 +174,7 @@ public interface Manager extends Closeable {
|
||||||
|
|
||||||
SendMessageResults sendMessage(
|
SendMessageResults sendMessage(
|
||||||
Message message, Set<RecipientIdentifier> recipients
|
Message message, Set<RecipientIdentifier> recipients
|
||||||
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException;
|
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException;
|
||||||
|
|
||||||
SendMessageResults sendRemoteDeleteMessage(
|
SendMessageResults sendRemoteDeleteMessage(
|
||||||
long targetSentTimestamp, Set<RecipientIdentifier> recipients
|
long targetSentTimestamp, Set<RecipientIdentifier> recipients
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.asamk.signal.manager.api.Group;
|
||||||
import org.asamk.signal.manager.api.Identity;
|
import org.asamk.signal.manager.api.Identity;
|
||||||
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
||||||
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
||||||
|
import org.asamk.signal.manager.api.InvalidStickerException;
|
||||||
import org.asamk.signal.manager.api.Message;
|
import org.asamk.signal.manager.api.Message;
|
||||||
import org.asamk.signal.manager.api.Pair;
|
import org.asamk.signal.manager.api.Pair;
|
||||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
|
@ -48,6 +49,7 @@ import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||||
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
||||||
import org.asamk.signal.manager.storage.stickers.Sticker;
|
import org.asamk.signal.manager.storage.stickers.Sticker;
|
||||||
import org.asamk.signal.manager.storage.stickers.StickerPackId;
|
import org.asamk.signal.manager.storage.stickers.StickerPackId;
|
||||||
|
import org.asamk.signal.manager.util.AttachmentUtils;
|
||||||
import org.asamk.signal.manager.util.KeyUtils;
|
import org.asamk.signal.manager.util.KeyUtils;
|
||||||
import org.asamk.signal.manager.util.StickerUtils;
|
import org.asamk.signal.manager.util.StickerUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -484,7 +486,7 @@ public class ManagerImpl implements Manager {
|
||||||
@Override
|
@Override
|
||||||
public SendMessageResults sendMessage(
|
public SendMessageResults sendMessage(
|
||||||
Message message, Set<RecipientIdentifier> recipients
|
Message message, Set<RecipientIdentifier> recipients
|
||||||
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException {
|
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
|
||||||
final var messageBuilder = SignalServiceDataMessage.newBuilder();
|
final var messageBuilder = SignalServiceDataMessage.newBuilder();
|
||||||
applyMessage(messageBuilder, message);
|
applyMessage(messageBuilder, message);
|
||||||
return sendMessage(messageBuilder, recipients);
|
return sendMessage(messageBuilder, recipients);
|
||||||
|
@ -492,7 +494,7 @@ public class ManagerImpl implements Manager {
|
||||||
|
|
||||||
private void applyMessage(
|
private void applyMessage(
|
||||||
final SignalServiceDataMessage.Builder messageBuilder, final Message message
|
final SignalServiceDataMessage.Builder messageBuilder, final Message message
|
||||||
) throws AttachmentInvalidException, IOException, UnregisteredRecipientException {
|
) throws AttachmentInvalidException, IOException, UnregisteredRecipientException, InvalidStickerException {
|
||||||
messageBuilder.withBody(message.messageText());
|
messageBuilder.withBody(message.messageText());
|
||||||
final var attachments = message.attachments();
|
final var attachments = message.attachments();
|
||||||
if (attachments != null) {
|
if (attachments != null) {
|
||||||
|
@ -510,6 +512,30 @@ public class ManagerImpl implements Manager {
|
||||||
List.of(),
|
List.of(),
|
||||||
resolveMentions(quote.mentions())));
|
resolveMentions(quote.mentions())));
|
||||||
}
|
}
|
||||||
|
if (message.sticker().isPresent()) {
|
||||||
|
final var sticker = message.sticker().get();
|
||||||
|
final var packId = StickerPackId.deserialize(sticker.packId());
|
||||||
|
final var stickerId = sticker.stickerId();
|
||||||
|
|
||||||
|
final var stickerPack = context.getAccount().getStickerStore().getStickerPack(packId);
|
||||||
|
if (stickerPack == null || !context.getStickerPackStore().existsStickerPack(packId)) {
|
||||||
|
throw new InvalidStickerException("Sticker pack not found");
|
||||||
|
}
|
||||||
|
final var manifest = context.getStickerPackStore().retrieveManifest(packId);
|
||||||
|
if (manifest.stickers().size() <= stickerId) {
|
||||||
|
throw new InvalidStickerException("Sticker id not part of this pack");
|
||||||
|
}
|
||||||
|
final var manifestSticker = manifest.stickers().get(stickerId);
|
||||||
|
final var streamDetails = context.getStickerPackStore().retrieveSticker(packId, stickerId);
|
||||||
|
if (streamDetails == null) {
|
||||||
|
throw new InvalidStickerException("Missing local sticker file");
|
||||||
|
}
|
||||||
|
messageBuilder.withSticker(new SignalServiceDataMessage.Sticker(packId.serialize(),
|
||||||
|
stickerPack.getPackKey(),
|
||||||
|
stickerId,
|
||||||
|
manifestSticker.emoji(),
|
||||||
|
AttachmentUtils.createAttachment(streamDetails, Optional.absent())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException, UnregisteredRecipientException {
|
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException, UnregisteredRecipientException {
|
||||||
|
|
|
@ -4,10 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.asamk.signal.manager.storage.stickers.StickerPackId;
|
import org.asamk.signal.manager.storage.stickers.StickerPackId;
|
||||||
import org.asamk.signal.manager.util.IOUtils;
|
import org.asamk.signal.manager.util.IOUtils;
|
||||||
|
import org.asamk.signal.manager.util.Utils;
|
||||||
|
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||||
import org.whispersystems.signalservice.internal.util.Hex;
|
import org.whispersystems.signalservice.internal.util.Hex;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -26,8 +29,22 @@ public class StickerPackStore {
|
||||||
return getStickerPackManifestFile(stickerPackId).exists();
|
return getStickerPackManifestFile(stickerPackId).exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonStickerPack retrieveManifest(StickerPackId stickerPackId) throws IOException {
|
||||||
|
try (final var inputStream = new FileInputStream(getStickerPackManifestFile(stickerPackId))) {
|
||||||
|
return new ObjectMapper().readValue(inputStream, JsonStickerPack.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamDetails retrieveSticker(final StickerPackId stickerPackId, final int stickerId) throws IOException {
|
||||||
|
final var stickerFile = getStickerPackStickerFile(stickerPackId, stickerId);
|
||||||
|
if (!stickerFile.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Utils.createStreamDetailsFromFile(stickerFile);
|
||||||
|
}
|
||||||
|
|
||||||
public void storeManifest(StickerPackId stickerPackId, JsonStickerPack manifest) throws IOException {
|
public void storeManifest(StickerPackId stickerPackId, JsonStickerPack manifest) throws IOException {
|
||||||
try (OutputStream output = new FileOutputStream(getStickerPackManifestFile(stickerPackId))) {
|
try (final var output = new FileOutputStream(getStickerPackManifestFile(stickerPackId))) {
|
||||||
try (var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) {
|
try (var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) {
|
||||||
new ObjectMapper().writeValue(writer, manifest);
|
new ObjectMapper().writeValue(writer, manifest);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +53,7 @@ public class StickerPackStore {
|
||||||
|
|
||||||
public void storeSticker(StickerPackId stickerPackId, int stickerId, StickerStorer storer) throws IOException {
|
public void storeSticker(StickerPackId stickerPackId, int stickerId, StickerStorer storer) throws IOException {
|
||||||
createStickerPackDir(stickerPackId);
|
createStickerPackDir(stickerPackId);
|
||||||
try (OutputStream output = new FileOutputStream(getStickerPackStickerFile(stickerPackId, stickerId))) {
|
try (final var output = new FileOutputStream(getStickerPackStickerFile(stickerPackId, stickerId))) {
|
||||||
storer.store(output);
|
storer.store(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.asamk.signal.manager.api;
|
||||||
|
|
||||||
|
public class InvalidStickerException extends Exception {
|
||||||
|
|
||||||
|
public InvalidStickerException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidStickerException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,17 @@ package org.asamk.signal.manager.api;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record Message(String messageText, List<String> attachments, List<Mention> mentions, Optional<Quote> quote) {
|
public record Message(
|
||||||
|
String messageText,
|
||||||
|
List<String> attachments,
|
||||||
|
List<Mention> mentions,
|
||||||
|
Optional<Quote> quote,
|
||||||
|
Optional<Sticker> sticker
|
||||||
|
) {
|
||||||
|
|
||||||
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) {}
|
public record Quote(long timestamp, RecipientIdentifier.Single author, String message, List<Mention> mentions) {}
|
||||||
|
|
||||||
|
public record Sticker(byte[] packId, int stickerId) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,7 +327,7 @@ public final class IncomingMessageHandler {
|
||||||
final var installed = !m.getType().isPresent()
|
final var installed = !m.getType().isPresent()
|
||||||
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
|
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
|
||||||
|
|
||||||
var sticker = account.getStickerStore().getSticker(stickerPackId);
|
var sticker = account.getStickerStore().getStickerPack(stickerPackId);
|
||||||
if (m.getPackKey().isPresent()) {
|
if (m.getPackKey().isPresent()) {
|
||||||
if (sticker == null) {
|
if (sticker == null) {
|
||||||
sticker = new Sticker(stickerPackId, m.getPackKey().get());
|
sticker = new Sticker(stickerPackId, m.getPackKey().get());
|
||||||
|
@ -598,7 +598,7 @@ public final class IncomingMessageHandler {
|
||||||
if (message.getSticker().isPresent()) {
|
if (message.getSticker().isPresent()) {
|
||||||
final var messageSticker = message.getSticker().get();
|
final var messageSticker = message.getSticker().get();
|
||||||
final var stickerPackId = StickerPackId.deserialize(messageSticker.getPackId());
|
final var stickerPackId = StickerPackId.deserialize(messageSticker.getPackId());
|
||||||
var sticker = account.getStickerStore().getSticker(stickerPackId);
|
var sticker = account.getStickerStore().getStickerPack(stickerPackId);
|
||||||
if (sticker == null) {
|
if (sticker == null) {
|
||||||
sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
|
sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
|
||||||
account.getStickerStore().updateSticker(sticker);
|
account.getStickerStore().updateSticker(sticker);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class StickerStore {
|
||||||
return new StickerStore(stickers, saver);
|
return new StickerStore(stickers, saver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sticker getSticker(StickerPackId packId) {
|
public Sticker getStickerPack(StickerPackId packId) {
|
||||||
synchronized (stickers) {
|
synchronized (stickers) {
|
||||||
return stickers.get(packId);
|
return stickers.get(packId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,11 +73,9 @@ Choose when to trust new identities:
|
||||||
Register a phone number with SMS or voice verification.
|
Register a phone number with SMS or voice verification.
|
||||||
Use the verify command to complete the verification.
|
Use the verify command to complete the verification.
|
||||||
|
|
||||||
If the account is just deactivated, the register command will just reactivate
|
If the account is just deactivated, the register command will just reactivate account, without requiring an SMS verification.
|
||||||
account, without requiring an SMS verification. By default the unregister command
|
By default the unregister command just deactivates the account, in which case it can be reactivated without sms verification if the local data is still available.
|
||||||
just deactivates the account, in which case it can be reactivated without sms
|
If the account was deleted (with --delete-account) it cannot be reactivated.
|
||||||
verification if the local data is still available. If the account was deleted
|
|
||||||
(with --delete-account) it cannot be reactivated.
|
|
||||||
|
|
||||||
*-v*, *--voice*::
|
*-v*, *--voice*::
|
||||||
The verification should be done over voice, not SMS.
|
The verification should be done over voice, not SMS.
|
||||||
|
@ -197,6 +195,9 @@ Send a message to another user or group.
|
||||||
RECIPIENT::
|
RECIPIENT::
|
||||||
Specify the recipients’ phone number.
|
Specify the recipients’ phone number.
|
||||||
|
|
||||||
|
*--note-to-self*::
|
||||||
|
Send the message to self without notification.
|
||||||
|
|
||||||
*-g* GROUP, *--group-id* GROUP::
|
*-g* GROUP, *--group-id* GROUP::
|
||||||
Specify the recipient group ID in base64 encoding.
|
Specify the recipient group ID in base64 encoding.
|
||||||
|
|
||||||
|
@ -206,11 +207,10 @@ Specify the message, if missing, standard input is used.
|
||||||
*-a* [ATTACHMENT [ATTACHMENT ...]], *--attachment* [ATTACHMENT [ATTACHMENT ...]]::
|
*-a* [ATTACHMENT [ATTACHMENT ...]], *--attachment* [ATTACHMENT [ATTACHMENT ...]]::
|
||||||
Add one or more files as attachment.
|
Add one or more files as attachment.
|
||||||
|
|
||||||
*--note-to-self*::
|
*--sticker* STICKER::
|
||||||
Send the message to self without notification.
|
Send a sticker of a locally known sticker pack (syntax: stickerPackId:stickerId).
|
||||||
|
Shouldn't be used together with `-m` as the official clients don't support this.
|
||||||
*-e*, *--end-session*::
|
e.g.: `--sticker 00abac3bc18d7f599bff2325dc306d43:2`
|
||||||
Clear session state and send end session message.
|
|
||||||
|
|
||||||
*--mention*::
|
*--mention*::
|
||||||
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.
|
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.
|
||||||
|
@ -228,6 +228,9 @@ Specify the message of the original message.
|
||||||
*--quote-mention*::
|
*--quote-mention*::
|
||||||
Specify the mentions of the original message (same format as `--mention`).
|
Specify the mentions of the original message (same format as `--mention`).
|
||||||
|
|
||||||
|
*-e*, *--end-session*::
|
||||||
|
Clear session state and send end session message.
|
||||||
|
|
||||||
=== sendReaction
|
=== sendReaction
|
||||||
|
|
||||||
Send reaction to a previously received or sent message.
|
Send reaction to a previously received or sent message.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||||
import org.asamk.signal.manager.AttachmentInvalidException;
|
import org.asamk.signal.manager.AttachmentInvalidException;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.api.InvalidStickerException;
|
||||||
import org.asamk.signal.manager.api.Message;
|
import org.asamk.signal.manager.api.Message;
|
||||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
||||||
|
@ -17,6 +18,7 @@ import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
|
||||||
import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
||||||
import org.asamk.signal.output.OutputWriter;
|
import org.asamk.signal.output.OutputWriter;
|
||||||
import org.asamk.signal.util.CommandUtil;
|
import org.asamk.signal.util.CommandUtil;
|
||||||
|
import org.asamk.signal.util.Hex;
|
||||||
import org.asamk.signal.util.IOUtils;
|
import org.asamk.signal.util.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -65,6 +67,7 @@ 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("--sticker").help("Send a sticker (syntax: stickerPackId:stickerId)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -100,13 +103,20 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final var stickerString = ns.getString("sticker");
|
||||||
|
final var sticker = stickerString == null ? null : parseSticker(stickerString);
|
||||||
|
|
||||||
var messageText = ns.getString("message");
|
var messageText = ns.getString("message");
|
||||||
if (messageText == null) {
|
if (messageText == null) {
|
||||||
logger.debug("Reading message from stdin...");
|
if (sticker != null) {
|
||||||
try {
|
messageText = "";
|
||||||
messageText = IOUtils.readAll(System.in, Charset.defaultCharset());
|
} else {
|
||||||
} catch (IOException e) {
|
logger.debug("Reading message from stdin...");
|
||||||
throw new UserErrorException("Failed to read message from stdin: " + e.getMessage());
|
try {
|
||||||
|
messageText = IOUtils.readAll(System.in, Charset.defaultCharset());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UserErrorException("Failed to read message from stdin: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,15 +139,18 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||||
: parseMentions(m, quoteMentionStrings);
|
: parseMentions(m, quoteMentionStrings);
|
||||||
quote = new Message.Quote(quoteTimestamp,
|
quote = new Message.Quote(quoteTimestamp,
|
||||||
CommandUtil.getSingleRecipientIdentifier(quoteAuthor, m.getSelfNumber()),
|
CommandUtil.getSingleRecipientIdentifier(quoteAuthor, m.getSelfNumber()),
|
||||||
quoteMessage,
|
quoteMessage == null ? "" : quoteMessage,
|
||||||
quoteMentions);
|
quoteMentions);
|
||||||
} else {
|
} else {
|
||||||
quote = null;
|
quote = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var results = m.sendMessage(new Message(messageText, attachments, mentions, Optional.ofNullable(quote)),
|
var results = m.sendMessage(new Message(messageText,
|
||||||
recipientIdentifiers);
|
attachments,
|
||||||
|
mentions,
|
||||||
|
Optional.ofNullable(quote),
|
||||||
|
Optional.ofNullable(sticker)), recipientIdentifiers);
|
||||||
outputResult(outputWriter, results);
|
outputResult(outputWriter, results);
|
||||||
} catch (AttachmentInvalidException | IOException e) {
|
} catch (AttachmentInvalidException | IOException e) {
|
||||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||||
|
@ -146,6 +159,8 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||||
throw new UserErrorException(e.getMessage());
|
throw new UserErrorException(e.getMessage());
|
||||||
} catch (UnregisteredRecipientException e) {
|
} catch (UnregisteredRecipientException e) {
|
||||||
throw new UserErrorException("The user " + e.getSender().getIdentifier() + " is not registered.");
|
throw new UserErrorException("The user " + e.getSender().getIdentifier() + " is not registered.");
|
||||||
|
} catch (InvalidStickerException e) {
|
||||||
|
throw new UserErrorException("Failed to send sticker: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,4 +182,15 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||||
}
|
}
|
||||||
return mentions;
|
return mentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Message.Sticker parseSticker(final String stickerString) throws UserErrorException {
|
||||||
|
final Pattern stickerPattern = Pattern.compile("([0-9a-f]+):([0-9]+)");
|
||||||
|
final var matcher = stickerPattern.matcher(stickerString);
|
||||||
|
if (!matcher.matches() || matcher.group(1).length() % 2 != 0) {
|
||||||
|
throw new UserErrorException("Invalid sticker syntax ("
|
||||||
|
+ stickerString
|
||||||
|
+ ") expected 'stickerPackId:stickerId'");
|
||||||
|
}
|
||||||
|
return new Message.Sticker(Hex.toByteArray(matcher.group(1)), Integer.parseInt(matcher.group(2)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.asamk.signal.manager.api.Identity;
|
||||||
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
import org.asamk.signal.manager.api.InactiveGroupLinkException;
|
||||||
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
||||||
import org.asamk.signal.manager.api.InvalidNumberException;
|
import org.asamk.signal.manager.api.InvalidNumberException;
|
||||||
|
import org.asamk.signal.manager.api.InvalidStickerException;
|
||||||
import org.asamk.signal.manager.api.Message;
|
import org.asamk.signal.manager.api.Message;
|
||||||
import org.asamk.signal.manager.api.Pair;
|
import org.asamk.signal.manager.api.Pair;
|
||||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
|
@ -199,7 +200,11 @@ 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(), Optional.empty()),
|
final var results = m.sendMessage(new Message(message,
|
||||||
|
attachments,
|
||||||
|
List.of(),
|
||||||
|
Optional.empty(),
|
||||||
|
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()));
|
||||||
|
@ -208,7 +213,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
return results.timestamp();
|
return results.timestamp();
|
||||||
} catch (AttachmentInvalidException e) {
|
} catch (AttachmentInvalidException e) {
|
||||||
throw new Error.AttachmentInvalid(e.getMessage());
|
throw new Error.AttachmentInvalid(e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException | InvalidStickerException e) {
|
||||||
throw new Error.Failure(e);
|
throw new Error.Failure(e);
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||||
throw new Error.GroupNotFound(e.getMessage());
|
throw new Error.GroupNotFound(e.getMessage());
|
||||||
|
@ -346,13 +351,16 @@ 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(), Optional.empty()),
|
final var results = m.sendMessage(new Message(message,
|
||||||
Set.of(RecipientIdentifier.NoteToSelf.INSTANCE));
|
attachments,
|
||||||
|
List.of(),
|
||||||
|
Optional.empty(),
|
||||||
|
Optional.empty()), Set.of(RecipientIdentifier.NoteToSelf.INSTANCE));
|
||||||
checkSendMessageResults(results);
|
checkSendMessageResults(results);
|
||||||
return results.timestamp();
|
return results.timestamp();
|
||||||
} catch (AttachmentInvalidException e) {
|
} catch (AttachmentInvalidException e) {
|
||||||
throw new Error.AttachmentInvalid(e.getMessage());
|
throw new Error.AttachmentInvalid(e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException | InvalidStickerException e) {
|
||||||
throw new Error.Failure(e.getMessage());
|
throw new Error.Failure(e.getMessage());
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||||
throw new Error.GroupNotFound(e.getMessage());
|
throw new Error.GroupNotFound(e.getMessage());
|
||||||
|
@ -384,11 +392,14 @@ 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(), Optional.empty()),
|
var results = m.sendMessage(new Message(message,
|
||||||
Set.of(getGroupRecipientIdentifier(groupId)));
|
attachments,
|
||||||
|
List.of(),
|
||||||
|
Optional.empty(),
|
||||||
|
Optional.empty()), Set.of(getGroupRecipientIdentifier(groupId)));
|
||||||
checkSendMessageResults(results);
|
checkSendMessageResults(results);
|
||||||
return results.timestamp();
|
return results.timestamp();
|
||||||
} catch (IOException e) {
|
} catch (IOException | InvalidStickerException e) {
|
||||||
throw new Error.Failure(e.getMessage());
|
throw new Error.Failure(e.getMessage());
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||||
throw new Error.GroupNotFound(e.getMessage());
|
throw new Error.GroupNotFound(e.getMessage());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue