Add sendMessageRequestResponse command
This commit is contained in:
		
							parent
							
								
									2c0ad7feb7
								
							
						
					
					
						commit
						d84362eb0f
					
				| @ -277,6 +277,14 @@ pub enum CliCommands { | ||||
|         #[arg(short = 's', long)] | ||||
|         stop: bool, | ||||
|     }, | ||||
|     SendMessageRequestResponse { | ||||
|         recipient: Vec<String>, | ||||
| 
 | ||||
|         #[arg(short = 'g', long = "group-id")] | ||||
|         group_id: Vec<String>, | ||||
| 
 | ||||
|         r#type: MessageRequestResponseType, | ||||
|     }, | ||||
|     SetPin { | ||||
|         pin: String, | ||||
|     }, | ||||
| @ -447,3 +455,10 @@ pub enum GroupPermission { | ||||
|     EveryMember, | ||||
|     OnlyAdmins, | ||||
| } | ||||
| 
 | ||||
| #[derive(ValueEnum, Clone, Debug)] | ||||
| #[value(rename_all = "kebab-case")] | ||||
| pub enum MessageRequestResponseType { | ||||
|     Accept, | ||||
|     Delete, | ||||
| } | ||||
|  | ||||
| @ -247,6 +247,15 @@ pub trait Rpc { | ||||
|         stop: bool, | ||||
|     ) -> Result<Value, ErrorObjectOwned>; | ||||
| 
 | ||||
|     #[method(name = "sendMessageRequestResponse", param_kind = map)] | ||||
|     fn send_message_request_response( | ||||
|         &self, | ||||
|         account: Option<String>, | ||||
|         recipients: Vec<String>, | ||||
|         #[allow(non_snake_case)] groupIds: Vec<String>, | ||||
|         r#type: String, | ||||
|     ) -> Result<Value, ErrorObjectOwned>; | ||||
| 
 | ||||
|     #[method(name = "setPin", param_kind = map)] | ||||
|     fn set_pin(&self, account: Option<String>, pin: String) -> Result<Value, ErrorObjectOwned>; | ||||
| 
 | ||||
|  | ||||
| @ -437,6 +437,23 @@ async fn handle_command( | ||||
|                 .start_change_number(cli.account, number, voice, captcha) | ||||
|                 .await | ||||
|         } | ||||
|         CliCommands::SendMessageRequestResponse { | ||||
|             recipient, | ||||
|             group_id, | ||||
|             r#type, | ||||
|         } => { | ||||
|             client | ||||
|                 .send_message_request_response( | ||||
|                     cli.account, | ||||
|                     recipient, | ||||
|                     group_id, | ||||
|                     match r#type { | ||||
|                         cli::MessageRequestResponseType::Accept => "accept".to_owned(), | ||||
|                         cli::MessageRequestResponseType::Delete => "delete".to_owned(), | ||||
|                     }, | ||||
|                 ) | ||||
|                 .await | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -204,6 +204,10 @@ public interface Manager extends Closeable { | ||||
| 
 | ||||
|     SendMessageResults sendEndSessionMessage(Set<RecipientIdentifier.Single> recipients) throws IOException; | ||||
| 
 | ||||
|     SendMessageResults sendMessageRequestResponse( | ||||
|             MessageEnvelope.Sync.MessageRequestResponse.Type type, Set<RecipientIdentifier> recipientIdentifiers | ||||
|     ); | ||||
| 
 | ||||
|     void hideRecipient(RecipientIdentifier.Single recipient); | ||||
| 
 | ||||
|     void deleteRecipient(RecipientIdentifier.Single recipient); | ||||
|  | ||||
| @ -2,6 +2,7 @@ package org.asamk.signal.manager.helper; | ||||
| 
 | ||||
| import org.asamk.signal.manager.api.Contact; | ||||
| import org.asamk.signal.manager.api.GroupId; | ||||
| import org.asamk.signal.manager.api.MessageEnvelope; | ||||
| import org.asamk.signal.manager.api.TrustLevel; | ||||
| import org.asamk.signal.manager.storage.SignalAccount; | ||||
| import org.asamk.signal.manager.storage.groups.GroupInfoV1; | ||||
| @ -28,6 +29,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.KeysMessage; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; | ||||
| import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage; | ||||
| @ -365,6 +367,25 @@ public class SyncHelper { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public SendMessageResult sendMessageRequestResponse( | ||||
|             final MessageEnvelope.Sync.MessageRequestResponse.Type type, final GroupId groupId | ||||
|     ) { | ||||
|         final var response = MessageRequestResponseMessage.forGroup(groupId.serialize(), localToRemoteType(type)); | ||||
|         return context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forMessageRequestResponse(response)); | ||||
|     } | ||||
| 
 | ||||
|     public SendMessageResult sendMessageRequestResponse( | ||||
|             final MessageEnvelope.Sync.MessageRequestResponse.Type type, final RecipientId recipientId | ||||
|     ) { | ||||
|         final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId); | ||||
|         if (address.serviceId().isEmpty()) { | ||||
|             return null; | ||||
|         } | ||||
|         final var response = MessageRequestResponseMessage.forIndividual(address.serviceId().get(), | ||||
|                 localToRemoteType(type)); | ||||
|         return context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forMessageRequestResponse(response)); | ||||
|     } | ||||
| 
 | ||||
|     private SendMessageResult requestSyncData(final SyncMessage.Request.Type type) { | ||||
|         var r = new SyncMessage.Request.Builder().type(type).build(); | ||||
|         var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r)); | ||||
| @ -389,4 +410,17 @@ public class SyncHelper { | ||||
|             logger.warn("Failed to download avatar for contact {}, ignoring: {}", address, e.getMessage()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private MessageRequestResponseMessage.Type localToRemoteType(final MessageEnvelope.Sync.MessageRequestResponse.Type type) { | ||||
|         return switch (type) { | ||||
|             case UNKNOWN -> MessageRequestResponseMessage.Type.UNKNOWN; | ||||
|             case ACCEPT -> MessageRequestResponseMessage.Type.ACCEPT; | ||||
|             case DELETE -> MessageRequestResponseMessage.Type.DELETE; | ||||
|             case BLOCK -> MessageRequestResponseMessage.Type.BLOCK; | ||||
|             case BLOCK_AND_DELETE -> MessageRequestResponseMessage.Type.BLOCK_AND_DELETE; | ||||
|             case UNBLOCK_AND_ACCEPT -> MessageRequestResponseMessage.Type.UNBLOCK_AND_ACCEPT; | ||||
|             case SPAM -> MessageRequestResponseMessage.Type.SPAM; | ||||
|             case BLOCK_AND_SPAM -> MessageRequestResponseMessage.Type.BLOCK_AND_SPAM; | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -38,6 +38,7 @@ import org.asamk.signal.manager.api.InvalidUsernameException; | ||||
| import org.asamk.signal.manager.api.LastGroupAdminException; | ||||
| import org.asamk.signal.manager.api.Message; | ||||
| import org.asamk.signal.manager.api.MessageEnvelope; | ||||
| import org.asamk.signal.manager.api.MessageEnvelope.Sync.MessageRequestResponse; | ||||
| import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException; | ||||
| import org.asamk.signal.manager.api.NotAGroupMemberException; | ||||
| import org.asamk.signal.manager.api.NotPrimaryDeviceException; | ||||
| @ -874,6 +875,41 @@ public class ManagerImpl implements Manager { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SendMessageResults sendMessageRequestResponse( | ||||
|             final MessageRequestResponse.Type type, final Set<RecipientIdentifier> recipients | ||||
|     ) { | ||||
|         var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>(); | ||||
|         for (final var recipient : recipients) { | ||||
|             if (recipient instanceof RecipientIdentifier.NoteToSelf || ( | ||||
|                     recipient instanceof RecipientIdentifier.Single single | ||||
|                             && new RecipientAddress(single.toPartialRecipientAddress()).matches(account.getSelfRecipientAddress()) | ||||
|             )) { | ||||
|                 final var result = context.getSyncHelper() | ||||
|                         .sendMessageRequestResponse(type, account.getSelfRecipientId()); | ||||
|                 if (result != null) { | ||||
|                     results.put(recipient, List.of(toSendMessageResult(result))); | ||||
|                 } | ||||
|                 results.put(recipient, List.of(toSendMessageResult(result))); | ||||
|             } else if (recipient instanceof RecipientIdentifier.Single single) { | ||||
|                 try { | ||||
|                     final var recipientId = context.getRecipientHelper().resolveRecipient(single); | ||||
|                     final var result = context.getSyncHelper().sendMessageRequestResponse(type, recipientId); | ||||
|                     if (result != null) { | ||||
|                         results.put(recipient, List.of(toSendMessageResult(result))); | ||||
|                     } | ||||
|                 } catch (UnregisteredRecipientException e) { | ||||
|                     results.put(recipient, | ||||
|                             List.of(SendMessageResult.unregisteredFailure(single.toPartialRecipientAddress()))); | ||||
|                 } | ||||
|             } else if (recipient instanceof RecipientIdentifier.Group group) { | ||||
|                 final var result = context.getSyncHelper().sendMessageRequestResponse(type, group.groupId()); | ||||
|                 results.put(recipient, List.of(toSendMessageResult(result))); | ||||
|             } | ||||
|         } | ||||
|         return new SendMessageResults(0, results); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void hideRecipient(final RecipientIdentifier.Single recipient) { | ||||
|         final var recipientIdOptional = context.getRecipientHelper().resolveRecipientOptional(recipient); | ||||
| @ -929,6 +965,10 @@ public class ManagerImpl implements Manager { | ||||
|                 continue; | ||||
|             } | ||||
|             context.getContactHelper().setContactBlocked(recipientId, blocked); | ||||
|             context.getSyncHelper() | ||||
|                     .sendMessageRequestResponse(blocked | ||||
|                             ? MessageRequestResponse.Type.BLOCK | ||||
|                             : MessageRequestResponse.Type.UNBLOCK_AND_ACCEPT, recipientId); | ||||
|             // if we don't have a common group with the blocked contact we need to rotate the profile key | ||||
|             shouldRotateProfileKey = blocked && ( | ||||
|                     shouldRotateProfileKey || account.getGroupStore() | ||||
| @ -957,6 +997,10 @@ public class ManagerImpl implements Manager { | ||||
|                 continue; | ||||
|             } | ||||
|             context.getGroupHelper().setGroupBlocked(groupId, blocked); | ||||
|             context.getSyncHelper() | ||||
|                     .sendMessageRequestResponse(blocked | ||||
|                             ? MessageRequestResponse.Type.BLOCK | ||||
|                             : MessageRequestResponse.Type.UNBLOCK_AND_ACCEPT, groupId); | ||||
|             shouldRotateProfileKey = blocked; | ||||
|         } | ||||
|         if (shouldRotateProfileKey) { | ||||
|  | ||||
| @ -346,6 +346,19 @@ 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. | ||||
| 
 | ||||
| === sendMessageRequestResponse | ||||
| 
 | ||||
| Send response to a message request to linked devices. | ||||
| 
 | ||||
| RECIPIENT:: | ||||
| Specify the recipients’ phone number. | ||||
| 
 | ||||
| *-g* GROUP, *--group-id* GROUP:: | ||||
| Specify the recipient group ID in base64 encoding. | ||||
| 
 | ||||
| *--type* TYPE:: | ||||
| Type of message request response (accept, delete) | ||||
| 
 | ||||
| === sendPaymentNotification | ||||
| 
 | ||||
| Send a payment notification. | ||||
|  | ||||
| @ -39,6 +39,7 @@ public class Commands { | ||||
|         addCommand(new RemoteDeleteCommand()); | ||||
|         addCommand(new SendCommand()); | ||||
|         addCommand(new SendContactsCommand()); | ||||
|         addCommand(new SendMessageRequestResponseCommand()); | ||||
|         addCommand(new SendPaymentNotificationCommand()); | ||||
|         addCommand(new SendReactionCommand()); | ||||
|         addCommand(new SendReceiptCommand()); | ||||
|  | ||||
| @ -0,0 +1,16 @@ | ||||
| package org.asamk.signal.commands; | ||||
| 
 | ||||
| enum MessageRequestResponseType { | ||||
|     ACCEPT { | ||||
|         @Override | ||||
|         public String toString() { | ||||
|             return "accept"; | ||||
|         } | ||||
|     }, | ||||
|     DELETE { | ||||
|         @Override | ||||
|         public String toString() { | ||||
|             return "delete"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| package org.asamk.signal.commands; | ||||
| 
 | ||||
| import net.sourceforge.argparse4j.impl.Arguments; | ||||
| import net.sourceforge.argparse4j.inf.Namespace; | ||||
| import net.sourceforge.argparse4j.inf.Subparser; | ||||
| 
 | ||||
| import org.asamk.signal.commands.exceptions.CommandException; | ||||
| import org.asamk.signal.manager.Manager; | ||||
| import org.asamk.signal.manager.api.MessageEnvelope.Sync.MessageRequestResponse.Type; | ||||
| import org.asamk.signal.output.OutputWriter; | ||||
| import org.asamk.signal.util.CommandUtil; | ||||
| 
 | ||||
| public class SendMessageRequestResponseCommand implements JsonRpcLocalCommand { | ||||
| 
 | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return "sendMessageRequestResponse"; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void attachToSubparser(final Subparser subparser) { | ||||
|         subparser.help("Send response to a message request to linked devices."); | ||||
|         subparser.addArgument("-g", "--group-id", "--group").help("Specify the recipient group ID.").nargs("*"); | ||||
|         subparser.addArgument("recipient").help("Specify the recipients' phone number.").nargs("*"); | ||||
|         subparser.addArgument("-u", "--username").help("Specify the recipient username or username link.").nargs("*"); | ||||
|         subparser.addArgument("--type") | ||||
|                 .help("Type of message request response") | ||||
|                 .type(Arguments.enumStringType(MessageRequestResponseType.class)) | ||||
|                 .required(true); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void handleCommand( | ||||
|             final Namespace ns, final Manager m, final OutputWriter outputWriter | ||||
|     ) throws CommandException { | ||||
|         final var recipientStrings = ns.<String>getList("recipient"); | ||||
|         final var groupIdStrings = ns.<String>getList("group-id"); | ||||
|         final var usernameStrings = ns.<String>getList("username"); | ||||
|         final var type = ns.<MessageRequestResponseType>get("type"); | ||||
| 
 | ||||
|         final var recipientIdentifiers = CommandUtil.getRecipientIdentifiers(m, | ||||
|                 false, | ||||
|                 recipientStrings, | ||||
|                 groupIdStrings, | ||||
|                 usernameStrings); | ||||
|         m.sendMessageRequestResponse(type == MessageRequestResponseType.ACCEPT ? Type.ACCEPT : Type.DELETE, | ||||
|                 recipientIdentifiers); | ||||
|     } | ||||
| } | ||||
| @ -472,6 +472,14 @@ public class DbusManagerImpl implements Manager { | ||||
|         return new SendMessageResults(0, Map.of()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SendMessageResults sendMessageRequestResponse( | ||||
|             final MessageEnvelope.Sync.MessageRequestResponse.Type type, | ||||
|             final Set<RecipientIdentifier> recipientIdentifiers | ||||
|     ) { | ||||
|         throw new UnsupportedOperationException(); | ||||
|     } | ||||
| 
 | ||||
|     public void hideRecipient(final RecipientIdentifier.Single recipient) { | ||||
|         throw new UnsupportedOperationException(); | ||||
|     } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 AsamK
						AsamK