From 8a31b7f2c153e89532010b9ab58eb045ddfe43fe Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 11 May 2023 19:10:29 +0200 Subject: [PATCH] Implement editing of previous messages --- graalvm-config-dir/reflect-config.json | 43 ++++++++++++--- .../org/asamk/signal/manager/Manager.java | 4 ++ .../org/asamk/signal/manager/ManagerImpl.java | 25 +++++++-- .../signal/manager/api/MessageEnvelope.java | 22 ++++++++ .../signal/manager/helper/GroupHelper.java | 2 +- .../signal/manager/helper/SendHelper.java | 53 ++++++++++++------- man/signal-cli.1.adoc | 3 ++ .../asamk/signal/ReceiveMessageHandler.java | 11 ++++ .../asamk/signal/commands/SendCommand.java | 9 +++- .../asamk/signal/dbus/DbusManagerImpl.java | 13 +++++ .../asamk/signal/json/JsonEditMessage.java | 10 ++++ .../signal/json/JsonMessageEnvelope.java | 3 ++ .../signal/json/JsonSyncDataMessage.java | 23 ++++---- 13 files changed, 179 insertions(+), 42 deletions(-) create mode 100644 src/main/java/org/asamk/signal/json/JsonEditMessage.java diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 70b26757..3bab701f 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -288,7 +288,8 @@ "name":"java.lang.Long", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }] }, { "name":"java.lang.Number", @@ -838,11 +839,25 @@ {"name":"viewOnce","parameterTypes":[] } ] }, +{ + "name":"org.asamk.signal.json.JsonEditMessage", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[ + {"name":"dataMessage","parameterTypes":[] }, + {"name":"targetSentTimestamp","parameterTypes":[] } + ] +}, { "name":"org.asamk.signal.json.JsonError", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[ + {"name":"message","parameterTypes":[] }, + {"name":"type","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.json.JsonGroupInfo", @@ -875,6 +890,7 @@ "methods":[ {"name":"callMessage","parameterTypes":[] }, {"name":"dataMessage","parameterTypes":[] }, + {"name":"editMessage","parameterTypes":[] }, {"name":"receiptMessage","parameterTypes":[] }, {"name":"source","parameterTypes":[] }, {"name":"sourceDevice","parameterTypes":[] }, @@ -1007,7 +1023,11 @@ "name":"org.asamk.signal.json.JsonSticker", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[ + {"name":"packId","parameterTypes":[] }, + {"name":"stickerId","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.json.JsonStoryContext", @@ -1069,7 +1089,8 @@ {"name":"dataMessage","parameterTypes":[] }, {"name":"destination","parameterTypes":[] }, {"name":"destinationNumber","parameterTypes":[] }, - {"name":"destinationUuid","parameterTypes":[] } + {"name":"destinationUuid","parameterTypes":[] }, + {"name":"editMessage","parameterTypes":[] } ] }, { @@ -2417,13 +2438,15 @@ "name":"org.whispersystems.signalservice.api.groupsv2.CredentialResponse", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }] }, { "name":"org.whispersystems.signalservice.api.groupsv2.TemporalCredential", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }] }, { "name":"org.whispersystems.signalservice.api.groupsv2.TemporalCredential[]" @@ -3236,6 +3259,14 @@ {"name":"sentTimestamp_"} ] }, +{ + "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$EditMessage", + "fields":[ + {"name":"bitField0_"}, + {"name":"dataMessage_"}, + {"name":"targetSentTimestamp_"} + ] +}, { "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$Envelope", "fields":[ diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index bcb8f348..b6602f57 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -142,6 +142,10 @@ public interface Manager extends Closeable { Message message, Set recipients ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; + SendMessageResults sendEditMessage( + Message message, Set recipients, long editTargetTimestamp + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; + SendMessageResults sendRemoteDeleteMessage( long targetSentTimestamp, Set recipients ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException; diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index 9696d956..1cc0629b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -466,6 +466,14 @@ class ManagerImpl implements Manager { private SendMessageResults sendMessage( SignalServiceDataMessage.Builder messageBuilder, Set recipients + ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { + return sendMessage(messageBuilder, recipients, Optional.empty()); + } + + private SendMessageResults sendMessage( + SignalServiceDataMessage.Builder messageBuilder, + Set recipients, + Optional editTargetTimestamp ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var results = new HashMap>(); long timestamp = System.currentTimeMillis(); @@ -474,17 +482,19 @@ class ManagerImpl implements Manager { if (recipient instanceof RecipientIdentifier.Single single) { try { final var recipientId = context.getRecipientHelper().resolveRecipient(single); - final var result = context.getSendHelper().sendMessage(messageBuilder, recipientId); + final var result = context.getSendHelper() + .sendMessage(messageBuilder, recipientId, editTargetTimestamp); results.put(recipient, List.of(toSendMessageResult(result))); } catch (UnregisteredRecipientException e) { results.put(recipient, List.of(SendMessageResult.unregisteredFailure(single.toPartialRecipientAddress()))); } } else if (recipient instanceof RecipientIdentifier.NoteToSelf) { - final var result = context.getSendHelper().sendSelfMessage(messageBuilder); + final var result = context.getSendHelper().sendSelfMessage(messageBuilder, editTargetTimestamp); results.put(recipient, List.of(toSendMessageResult(result))); } else if (recipient instanceof RecipientIdentifier.Group group) { - final var result = context.getSendHelper().sendAsGroupMessage(messageBuilder, group.groupId()); + final var result = context.getSendHelper() + .sendAsGroupMessage(messageBuilder, group.groupId(), editTargetTimestamp); results.put(recipient, result.stream().map(this::toSendMessageResult).toList()); } } @@ -581,6 +591,15 @@ class ManagerImpl implements Manager { return sendMessage(messageBuilder, recipients); } + @Override + public SendMessageResults sendEditMessage( + Message message, Set recipients, long editTargetTimestamp + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { + final var messageBuilder = SignalServiceDataMessage.newBuilder(); + applyMessage(messageBuilder, message); + return sendMessage(messageBuilder, recipients, Optional.of(editTargetTimestamp)); + } + private void applyMessage( final SignalServiceDataMessage.Builder messageBuilder, final Message message ) throws AttachmentInvalidException, IOException, UnregisteredRecipientException, InvalidStickerException { diff --git a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java index c1726c1a..a8f00875 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java @@ -9,6 +9,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; +import org.whispersystems.signalservice.api.messages.SignalServiceEditMessage; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceGroup; import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext; @@ -51,6 +52,7 @@ public record MessageEnvelope( Optional receipt, Optional typing, Optional data, + Optional edit, Optional sync, Optional call, Optional story @@ -541,6 +543,19 @@ public record MessageEnvelope( } } + public record Edit(long targetSentTimestamp, Data dataMessage) { + + public static Edit from( + final SignalServiceEditMessage editMessage, + RecipientResolver recipientResolver, + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider + ) { + return new Edit(editMessage.getTargetSentTimestamp(), + Data.from(editMessage.getDataMessage(), recipientResolver, addressResolver, fileProvider)); + } + } + public record Sync( Optional sent, Optional blocked, @@ -582,6 +597,7 @@ public record MessageEnvelope( Optional destination, Set recipients, Optional message, + Optional editMessage, Optional story ) { @@ -603,6 +619,8 @@ public record MessageEnvelope( .collect(Collectors.toSet()), sentMessage.getDataMessage() .map(message -> Data.from(message, recipientResolver, addressResolver, fileProvider)), + sentMessage.getEditMessage() + .map(message -> Edit.from(message, recipientResolver, addressResolver, fileProvider)), sentMessage.getStoryMessage().map(s -> Story.from(s, fileProvider))); } } @@ -920,6 +938,7 @@ public record MessageEnvelope( Optional receipt; Optional typing; Optional data; + Optional edit; Optional sync; Optional call; Optional story; @@ -928,6 +947,7 @@ public record MessageEnvelope( typing = content.getTypingMessage().map(Typing::from); data = content.getDataMessage() .map(dataMessage -> Data.from(dataMessage, recipientResolver, addressResolver, fileProvider)); + edit = content.getEditMessage().map(s -> Edit.from(s, recipientResolver, addressResolver, fileProvider)); sync = content.getSyncMessage().map(s -> Sync.from(s, recipientResolver, addressResolver, fileProvider)); call = content.getCallMessage().map(Call::from); story = content.getStoryMessage().map(s -> Story.from(s, fileProvider)); @@ -937,6 +957,7 @@ public record MessageEnvelope( List.of(envelope.getTimestamp()))) : Optional.empty(); typing = Optional.empty(); data = Optional.empty(); + edit = Optional.empty(); sync = Optional.empty(); call = Optional.empty(); story = Optional.empty(); @@ -953,6 +974,7 @@ public record MessageEnvelope( receipt, typing, data, + edit, sync, call, story); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index bb9a3ea4..5658dc25 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -563,7 +563,7 @@ public class GroupHelper { private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); - context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId); + context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId, Optional.empty()); } private SendGroupMessageResults updateGroupV2( diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java index 3dd99d3a..a410c2c9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java @@ -29,6 +29,7 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; +import org.whispersystems.signalservice.api.messages.SignalServiceEditMessage; import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage; import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage; import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage; @@ -71,8 +72,10 @@ public class SendHelper { * The message is extended with the current expiration timer. */ public SendMessageResult sendMessage( - final SignalServiceDataMessage.Builder messageBuilder, final RecipientId recipientId - ) throws IOException { + final SignalServiceDataMessage.Builder messageBuilder, + final RecipientId recipientId, + Optional editTargetTimestamp + ) { var contact = account.getContactStore().getContact(recipientId); if (contact == null || !contact.isProfileSharingEnabled()) { final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); @@ -89,7 +92,7 @@ public class SendHelper { } final var message = messageBuilder.build(); - return sendMessage(message, recipientId); + return sendMessage(message, recipientId, editTargetTimestamp); } /** @@ -97,10 +100,10 @@ public class SendHelper { * The message is extended with the current expiration timer for the group and the group context. */ public List sendAsGroupMessage( - SignalServiceDataMessage.Builder messageBuilder, GroupId groupId + SignalServiceDataMessage.Builder messageBuilder, GroupId groupId, Optional editTargetTimestamp ) throws IOException, GroupNotFoundException, NotAGroupMemberException, GroupSendingNotAllowedException { final var g = getGroupForSending(groupId); - return sendAsGroupMessage(messageBuilder, g); + return sendAsGroupMessage(messageBuilder, g, editTargetTimestamp); } /** @@ -112,7 +115,7 @@ public class SendHelper { final Set recipientIds, final DistributionId distributionId ) throws IOException { - return sendGroupMessage(message, recipientIds, distributionId, ContentHint.IMPLICIT); + return sendGroupMessage(message, recipientIds, distributionId, ContentHint.IMPLICIT, Optional.empty()); } public SendMessageResult sendReceiptMessage( @@ -169,7 +172,7 @@ public class SendHelper { } public SendMessageResult sendSelfMessage( - SignalServiceDataMessage.Builder messageBuilder + SignalServiceDataMessage.Builder messageBuilder, Optional editTargetTimestamp ) { final var recipientId = account.getSelfRecipientId(); final var contact = account.getContactStore().getContact(recipientId); @@ -177,7 +180,7 @@ public class SendHelper { messageBuilder.withExpiration(expirationTime); var message = messageBuilder.build(); - return sendSelfMessage(message); + return sendSelfMessage(message, editTargetTimestamp); } public SendMessageResult sendSyncMessage(SignalServiceSyncMessage message) { @@ -289,7 +292,7 @@ public class SendHelper { } private List sendAsGroupMessage( - final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g + final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g, Optional editTargetTimestamp ) throws IOException, GroupSendingNotAllowedException { GroupUtils.setGroupContext(messageBuilder, g); messageBuilder.withExpiration(g.getMessageExpirationTimer()); @@ -308,14 +311,19 @@ public class SendHelper { } } - return sendGroupMessage(message, recipients, g.getDistributionId(), ContentHint.RESENDABLE); + return sendGroupMessage(message, + recipients, + g.getDistributionId(), + ContentHint.RESENDABLE, + editTargetTimestamp); } private List sendGroupMessage( final SignalServiceDataMessage message, final Set recipientIds, final DistributionId distributionId, - final ContentHint contentHint + final ContentHint contentHint, + final Optional editTargetTimestamp ) throws IOException { final var messageSender = dependencies.getMessageSender(); final var messageSendLogStore = account.getMessageSendLogStore(); @@ -355,7 +363,7 @@ public class SendHelper { SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY, urgent, false, - null, + editTargetTimestamp.map(timestamp -> new SignalServiceEditMessage(timestamp, message)).orElse(null), sendResult -> { logger.trace("Partial message send results: {}", sendResult.size()); synchronized (entryId) { @@ -613,18 +621,27 @@ public class SendHelper { } private SendMessageResult sendMessage( - SignalServiceDataMessage message, RecipientId recipientId + SignalServiceDataMessage message, RecipientId recipientId, Optional editTargetTimestamp ) { final var messageSendLogStore = account.getMessageSendLogStore(); final var urgent = true; + final var includePniSignature = false; final var result = handleSendMessage(recipientId, - (messageSender, address, unidentifiedAccess) -> messageSender.sendDataMessage(address, + editTargetTimestamp.isEmpty() + ? (messageSender, address, unidentifiedAccess) -> messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, message, SignalServiceMessageSender.IndividualSendEvents.EMPTY, urgent, - false)); + includePniSignature) + : (messageSender, address, unidentifiedAccess) -> messageSender.sendEditMessage(address, + unidentifiedAccess, + ContentHint.RESENDABLE, + message, + SignalServiceMessageSender.IndividualSendEvents.EMPTY, + urgent, + editTargetTimestamp.get())); messageSendLogStore.insertIfPossible(message.getTimestamp(), result, ContentHint.RESENDABLE, urgent); handleSendMessageResult(result); return result; @@ -665,17 +682,17 @@ public class SendHelper { } } - private SendMessageResult sendSelfMessage(SignalServiceDataMessage message) { + private SendMessageResult sendSelfMessage(SignalServiceDataMessage message, Optional editTargetTimestamp) { var address = account.getSelfAddress(); var transcript = new SentTranscriptMessage(Optional.of(address), message.getTimestamp(), - Optional.of(message), + editTargetTimestamp.isEmpty() ? Optional.of(message) : Optional.empty(), message.getExpiresInSeconds(), Map.of(address.getServiceId(), true), false, Optional.empty(), Set.of(), - Optional.empty()); + editTargetTimestamp.map((timestamp) -> new SignalServiceEditMessage(timestamp, message))); var syncMessage = SignalServiceSyncMessage.forSentTranscript(transcript); return sendSyncMessage(syncMessage); diff --git a/man/signal-cli.1.adoc b/man/signal-cli.1.adoc index a9ccbad4..57a10e5a 100644 --- a/man/signal-cli.1.adoc +++ b/man/signal-cli.1.adoc @@ -285,6 +285,9 @@ Specify the number of the author of the story. *-e*, *--end-session*:: Clear session state and send end session message. +*--edit-timestamp*:: +Specify the timestamp of a previous message with the recipient or group to send an edited message. + === sendPaymentNotification Send a payment notification. diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java index c5270030..1f4253ac 100644 --- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java @@ -69,6 +69,10 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { var message = envelope.data().get(); printDataMessage(writer, message); } + if (envelope.edit().isPresent()) { + var message = envelope.edit().get(); + printEditMessage(writer, message); + } if (envelope.story().isPresent()) { var message = envelope.story().get(); printStoryMessage(writer.indentedWriter(), message); @@ -192,6 +196,13 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { } } + private void printEditMessage( + PlainTextWriter writer, MessageEnvelope.Edit message + ) { + writer.println("Edit: Target message timestamp: {}", DateUtils.formatTimestamp(message.targetSentTimestamp())); + printDataMessage(writer.indentedWriter(), message.dataMessage()); + } + private void printStoryMessage( PlainTextWriter writer, MessageEnvelope.Story message ) { diff --git a/src/main/java/org/asamk/signal/commands/SendCommand.java b/src/main/java/org/asamk/signal/commands/SendCommand.java index 2a47ab8d..9534f182 100644 --- a/src/main/java/org/asamk/signal/commands/SendCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendCommand.java @@ -84,6 +84,9 @@ public class SendCommand implements JsonRpcLocalCommand { .type(long.class) .help("Specify the timestamp of a story to reply to."); subparser.addArgument("--story-author").help("Specify the number of the author of the story."); + subparser.addArgument("--edit-timestamp") + .type(long.class) + .help("Specify the timestamp of a previous message with the recipient or group to send an edited message."); } @Override @@ -189,6 +192,8 @@ public class SendCommand implements JsonRpcLocalCommand { "Sending empty message is not allowed, either a message, attachment or sticker must be given."); } + final var editTimestamp = ns.getLong("edit-timestamp"); + try { final var message = new Message(messageText, attachments, @@ -197,7 +202,9 @@ public class SendCommand implements JsonRpcLocalCommand { Optional.ofNullable(sticker), previews, Optional.ofNullable((storyReply))); - var results = m.sendMessage(message, recipientIdentifiers); + var results = editTimestamp != null + ? m.sendEditMessage(message, recipientIdentifiers, editTimestamp) + : m.sendMessage(message, recipientIdentifiers); outputResult(outputWriter, results); } catch (AttachmentInvalidException | IOException e) { throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass() diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index cefb7a82..7eca1f20 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -10,6 +10,7 @@ import org.asamk.signal.manager.api.Group; import org.asamk.signal.manager.api.Identity; import org.asamk.signal.manager.api.InactiveGroupLinkException; import org.asamk.signal.manager.api.InvalidDeviceLinkException; +import org.asamk.signal.manager.api.InvalidStickerException; import org.asamk.signal.manager.api.InvalidUsernameException; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.MessageEnvelope; @@ -25,6 +26,7 @@ import org.asamk.signal.manager.api.StickerPack; import org.asamk.signal.manager.api.StickerPackInvalidException; import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; +import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.api.UpdateProfile; import org.asamk.signal.manager.api.UserStatus; @@ -369,6 +371,13 @@ public class DbusManagerImpl implements Manager { groupId -> signal.sendGroupMessage(message.messageText(), message.attachments(), groupId)); } + @Override + public SendMessageResults sendEditMessage( + final Message message, final Set recipients, final long editTargetTimestamp + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { + throw new UnsupportedOperationException(); + } + @Override public SendMessageResults sendRemoteDeleteMessage( final long targetSentTimestamp, final Set recipients @@ -801,6 +810,7 @@ public class DbusManagerImpl implements Manager { List.of())), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.empty()); notifyMessageHandlers(envelope); }; @@ -827,6 +837,7 @@ public class DbusManagerImpl implements Manager { Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.empty()); notifyMessageHandlers(envelope); }; @@ -844,6 +855,7 @@ public class DbusManagerImpl implements Manager { Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.of(new MessageEnvelope.Sync(Optional.of(new MessageEnvelope.Sync.Sent(syncReceived.getTimestamp(), syncReceived.getTimestamp(), syncReceived.getDestination().isEmpty() @@ -874,6 +886,7 @@ public class DbusManagerImpl implements Manager { List.of(), List.of(), List.of())), + Optional.empty(), Optional.empty())), Optional.empty(), List.of(), diff --git a/src/main/java/org/asamk/signal/json/JsonEditMessage.java b/src/main/java/org/asamk/signal/json/JsonEditMessage.java new file mode 100644 index 00000000..193bd16a --- /dev/null +++ b/src/main/java/org/asamk/signal/json/JsonEditMessage.java @@ -0,0 +1,10 @@ +package org.asamk.signal.json; + +import org.asamk.signal.manager.api.MessageEnvelope; + +record JsonEditMessage(long targetSentTimestamp, JsonDataMessage dataMessage) { + + static JsonEditMessage from(MessageEnvelope.Edit editMessage) { + return new JsonEditMessage(editMessage.targetSentTimestamp(), JsonDataMessage.from(editMessage.dataMessage())); + } +} diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index c32de61a..bafa97e7 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -18,6 +18,7 @@ public record JsonMessageEnvelope( Integer sourceDevice, long timestamp, @JsonInclude(JsonInclude.Include.NON_NULL) JsonDataMessage dataMessage, + @JsonInclude(JsonInclude.Include.NON_NULL) JsonEditMessage editMessage, @JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryMessage storyMessage, @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessage syncMessage, @JsonInclude(JsonInclude.Include.NON_NULL) JsonCallMessage callMessage, @@ -61,6 +62,7 @@ public record JsonMessageEnvelope( final var typingMessage = envelope.typing().map(JsonTypingMessage::from).orElse(null); final var dataMessage = envelope.data().map(JsonDataMessage::from).orElse(null); + final var editMessage = envelope.edit().map(JsonEditMessage::from).orElse(null); final var storyMessage = envelope.story().map(JsonStoryMessage::from).orElse(null); final var syncMessage = envelope.sync().map(JsonSyncMessage::from).orElse(null); final var callMessage = envelope.call().map(JsonCallMessage::from).orElse(null); @@ -72,6 +74,7 @@ public record JsonMessageEnvelope( sourceDevice, timestamp, dataMessage, + editMessage, storyMessage, syncMessage, callMessage, diff --git a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java index fc84b088..fe427ef1 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java @@ -1,8 +1,10 @@ package org.asamk.signal.json; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonUnwrapped; import org.asamk.signal.manager.api.MessageEnvelope; +import org.asamk.signal.manager.api.RecipientAddress; import java.util.UUID; @@ -10,22 +12,17 @@ record JsonSyncDataMessage( @Deprecated String destination, String destinationNumber, String destinationUuid, + @JsonInclude(JsonInclude.Include.NON_NULL) JsonEditMessage editMessage, @JsonUnwrapped JsonDataMessage dataMessage ) { static JsonSyncDataMessage from(MessageEnvelope.Sync.Sent transcriptMessage) { - if (transcriptMessage.destination().isPresent()) { - final var address = transcriptMessage.destination().get(); - return new JsonSyncDataMessage(address.getLegacyIdentifier(), - address.number().orElse(null), - address.uuid().map(UUID::toString).orElse(null), - transcriptMessage.message().map(JsonDataMessage::from).orElse(null)); - - } else { - return new JsonSyncDataMessage(null, - null, - null, - transcriptMessage.message().map(JsonDataMessage::from).orElse(null)); - } + return new JsonSyncDataMessage(transcriptMessage.destination() + .map(RecipientAddress::getLegacyIdentifier) + .orElse(null), + transcriptMessage.destination().flatMap(RecipientAddress::number).orElse(null), + transcriptMessage.destination().flatMap(address -> address.uuid().map(UUID::toString)).orElse(null), + transcriptMessage.editMessage().map(JsonEditMessage::from).orElse(null), + transcriptMessage.message().map(JsonDataMessage::from).orElse(null)); } } -- 2.50.1