Implement editing of previous messages
This commit is contained in:
		
							parent
							
								
									72390e595d
								
							
						
					
					
						commit
						8a31b7f2c1
					
				| @ -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":"<init>","parameterTypes":[] }] | ||||
| }, | ||||
| { | ||||
|   "name":"org.whispersystems.signalservice.api.groupsv2.TemporalCredential", | ||||
|   "allDeclaredFields":true, | ||||
|   "allDeclaredMethods":true, | ||||
|   "allDeclaredConstructors":true | ||||
|   "allDeclaredConstructors":true, | ||||
|   "methods":[{"name":"<init>","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":[ | ||||
|  | ||||
| @ -142,6 +142,10 @@ public interface Manager extends Closeable { | ||||
|             Message message, Set<RecipientIdentifier> recipients | ||||
|     ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; | ||||
| 
 | ||||
|     SendMessageResults sendEditMessage( | ||||
|             Message message, Set<RecipientIdentifier> recipients, long editTargetTimestamp | ||||
|     ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; | ||||
| 
 | ||||
|     SendMessageResults sendRemoteDeleteMessage( | ||||
|             long targetSentTimestamp, Set<RecipientIdentifier> recipients | ||||
|     ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException; | ||||
|  | ||||
| @ -466,6 +466,14 @@ class ManagerImpl implements Manager { | ||||
| 
 | ||||
|     private SendMessageResults sendMessage( | ||||
|             SignalServiceDataMessage.Builder messageBuilder, Set<RecipientIdentifier> recipients | ||||
|     ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { | ||||
|         return sendMessage(messageBuilder, recipients, Optional.empty()); | ||||
|     } | ||||
| 
 | ||||
|     private SendMessageResults sendMessage( | ||||
|             SignalServiceDataMessage.Builder messageBuilder, | ||||
|             Set<RecipientIdentifier> recipients, | ||||
|             Optional<Long> editTargetTimestamp | ||||
|     ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { | ||||
|         var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>(); | ||||
|         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<RecipientIdentifier> 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 { | ||||
|  | ||||
| @ -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> receipt, | ||||
|         Optional<Typing> typing, | ||||
|         Optional<Data> data, | ||||
|         Optional<Edit> edit, | ||||
|         Optional<Sync> sync, | ||||
|         Optional<Call> call, | ||||
|         Optional<Story> 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> sent, | ||||
|             Optional<Blocked> blocked, | ||||
| @ -582,6 +597,7 @@ public record MessageEnvelope( | ||||
|                 Optional<RecipientAddress> destination, | ||||
|                 Set<RecipientAddress> recipients, | ||||
|                 Optional<Data> message, | ||||
|                 Optional<Edit> editMessage, | ||||
|                 Optional<Story> 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> receipt; | ||||
|         Optional<Typing> typing; | ||||
|         Optional<Data> data; | ||||
|         Optional<Edit> edit; | ||||
|         Optional<Sync> sync; | ||||
|         Optional<Call> call; | ||||
|         Optional<Story> 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); | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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<Long> 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<SendMessageResult> sendAsGroupMessage( | ||||
|             SignalServiceDataMessage.Builder messageBuilder, GroupId groupId | ||||
|             SignalServiceDataMessage.Builder messageBuilder, GroupId groupId, Optional<Long> 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<RecipientId> 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<Long> 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<SendMessageResult> sendAsGroupMessage( | ||||
|             final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g | ||||
|             final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g, Optional<Long> 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<SendMessageResult> sendGroupMessage( | ||||
|             final SignalServiceDataMessage message, | ||||
|             final Set<RecipientId> recipientIds, | ||||
|             final DistributionId distributionId, | ||||
|             final ContentHint contentHint | ||||
|             final ContentHint contentHint, | ||||
|             final Optional<Long> 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<Long> 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<Long> 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); | ||||
|  | ||||
| @ -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. | ||||
|  | ||||
| @ -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 | ||||
|     ) { | ||||
|  | ||||
| @ -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() | ||||
|  | ||||
| @ -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<RecipientIdentifier> recipients, final long editTargetTimestamp | ||||
|     ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { | ||||
|         throw new UnsupportedOperationException(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SendMessageResults sendRemoteDeleteMessage( | ||||
|             final long targetSentTimestamp, final Set<RecipientIdentifier> 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(), | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/main/java/org/asamk/signal/json/JsonEditMessage.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/main/java/org/asamk/signal/json/JsonEditMessage.java
									
									
									
									
									
										Normal file
									
								
							| @ -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())); | ||||
|     } | ||||
| } | ||||
| @ -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, | ||||
|  | ||||
| @ -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)); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 AsamK
						AsamK