From: Adaptive Garage Date: Mon, 5 Apr 2021 17:49:45 +0000 (+0200) Subject: Send remote delete (#593) X-Git-Tag: v0.8.2~56 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/05abb3f9f6294677d2de97a9d88c8e9de04c10ec Send remote delete (#593) * Implementation of remoteDelete command, iteration 1 * Implementation of remoteDelete command, iteration 2 * Implementation of remoteDelete command, iteration 3 * Implementation of remoteDelete command, iteration 4 * Implementation of remoteDelete command, iteration 5 * Implementation of remoteDelete command, iteration 6 * Renaming dbus methods remoteGroupDelete -> sendGroupRemoteDeleteMessage, remoteDelete -> sendRemoteDeleteMessage --- 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 99099e92..5d0e7d3d 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -992,6 +992,22 @@ public class Manager implements Closeable { return sendSelfMessage(messageBuilder); } + public Pair> sendRemoteDeleteMessage( + long targetSentTimestamp, List recipients + ) throws IOException, InvalidNumberException { + var delete = new SignalServiceDataMessage.RemoteDelete(targetSentTimestamp); + final var messageBuilder = SignalServiceDataMessage.newBuilder().withRemoteDelete(delete); + return sendMessage(messageBuilder, getSignalServiceAddresses(recipients)); + } + + public Pair> sendGroupRemoteDeleteMessage( + long targetSentTimestamp, GroupId groupId + ) throws IOException, NotAGroupMemberException, GroupNotFoundException { + var delete = new SignalServiceDataMessage.RemoteDelete(targetSentTimestamp); + final var messageBuilder = SignalServiceDataMessage.newBuilder().withRemoteDelete(delete); + return sendGroupMessage(messageBuilder, groupId); + } + public Pair> sendMessageReaction( String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, List recipients ) throws IOException, InvalidNumberException { diff --git a/man/signal-cli-dbus.5.adoc b/man/signal-cli-dbus.5.adoc index eccfd821..ece2460f 100755 --- a/man/signal-cli-dbus.5.adoc +++ b/man/signal-cli-dbus.5.adoc @@ -149,6 +149,24 @@ Depending on the type of the recipient(s) field this sends a reaction to one or Exceptions: Failure, InvalidNumber +sendGroupRemoteDeleteMessage(targetSentTimestamp, groupId) -> timestamp:: +* targetSentTimestamp : Long representing timestamp of the message to delete +* groupId : Byte array with base64 encoded group identifier +* timestamp : Long, can be used to identify the corresponding signal reply + +Exceptions: Failure, GroupNotFound + +sendRemoteDeleteMessage(targetSentTimestamp, recipient) -> timestamp:: +sendRemoteDeleteMessage(targetSentTimestamp, recipients) -> timestamp:: +* targetSentTimestamp : Long representing timestamp of the message to delete +* recipient : String with the phone number of a single recipient +* recipients : Array of strings with phone numbers, should there be more recipients +* timestamp : Long, can be used to identify the corresponding signal reply + +Depending on the type of the recipient(s) field this deletes a message with one or multiple recipients. + +Exceptions: Failure, InvalidNumber + getContactName(number) -> name:: * number : Phone number * name : Contact's name in local storage (from the master device for a linked account, or the one set with setContactName); if not set, contact's profile name is used diff --git a/man/signal-cli.1.adoc b/man/signal-cli.1.adoc index 16b684ea..f6145385 100644 --- a/man/signal-cli.1.adoc +++ b/man/signal-cli.1.adoc @@ -193,6 +193,19 @@ Specify the timestamp of the message to which to react. *-r*, *--remove*:: Remove a reaction. +=== remoteDelete + +Remotely delete a previously sent message. + +RECIPIENT:: +Specify the recipients’ phone number. + +*-g* GROUP, *--group* GROUP:: +Specify the recipient group ID in base64 encoding. + +*-t* TIMESTAMP, *--target-timestamp* TIMESTAMP:: +Specify the timestamp of the message to delete. + === receive Query the server for new messages. diff --git a/src/main/java/org/asamk/Signal.java b/src/main/java/org/asamk/Signal.java index f8841da9..0093ab9b 100644 --- a/src/main/java/org/asamk/Signal.java +++ b/src/main/java/org/asamk/Signal.java @@ -21,6 +21,18 @@ public interface Signal extends DBusInterface { String message, List attachments, List recipients ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; + long sendRemoteDeleteMessage( + long targetSentTimestamp, String recipient + ) throws Error.Failure, Error.InvalidNumber; + + long sendRemoteDeleteMessage( + long targetSentTimestamp, List recipients + ) throws Error.Failure, Error.InvalidNumber; + + long sendGroupRemoteDeleteMessage( + long targetSentTimestamp, byte[] groupId + ) throws Error.Failure, Error.GroupNotFound; + long sendMessageReaction( String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, String recipient ) throws Error.InvalidNumber, Error.Failure; diff --git a/src/main/java/org/asamk/signal/commands/Commands.java b/src/main/java/org/asamk/signal/commands/Commands.java index 4bc17930..830049a5 100644 --- a/src/main/java/org/asamk/signal/commands/Commands.java +++ b/src/main/java/org/asamk/signal/commands/Commands.java @@ -22,20 +22,21 @@ public class Commands { addCommand("receive", new ReceiveCommand()); addCommand("register", new RegisterCommand()); addCommand("removeDevice", new RemoveDeviceCommand()); + addCommand("remoteDelete", new RemoteDeleteCommand()); addCommand("removePin", new RemovePinCommand()); addCommand("send", new SendCommand()); - addCommand("sendReaction", new SendReactionCommand()); addCommand("sendContacts", new SendContactsCommand()); - addCommand("updateContact", new UpdateContactCommand()); + addCommand("sendReaction", new SendReactionCommand()); addCommand("setPin", new SetPinCommand()); addCommand("trust", new TrustCommand()); addCommand("unblock", new UnblockCommand()); addCommand("unregister", new UnregisterCommand()); addCommand("updateAccount", new UpdateAccountCommand()); + addCommand("updateContact", new UpdateContactCommand()); addCommand("updateGroup", new UpdateGroupCommand()); addCommand("updateProfile", new UpdateProfileCommand()); - addCommand("verify", new VerifyCommand()); addCommand("uploadStickerPack", new UploadStickerPackCommand()); + addCommand("verify", new VerifyCommand()); } public static Map getCommands() { diff --git a/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java b/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java new file mode 100644 index 00000000..796a3344 --- /dev/null +++ b/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java @@ -0,0 +1,82 @@ +package org.asamk.signal.commands; + +import net.sourceforge.argparse4j.inf.Namespace; +import net.sourceforge.argparse4j.inf.Subparser; + +import org.asamk.Signal; +import org.asamk.signal.PlainTextWriterImpl; +import org.asamk.signal.commands.exceptions.CommandException; +import org.asamk.signal.commands.exceptions.UnexpectedErrorException; +import org.asamk.signal.commands.exceptions.UserErrorException; +import org.asamk.signal.manager.groups.GroupIdFormatException; +import org.asamk.signal.util.Util; +import org.freedesktop.dbus.errors.UnknownObject; +import org.freedesktop.dbus.exceptions.DBusExecutionException; + +import java.util.List; + +import static org.asamk.signal.util.ErrorUtils.handleAssertionError; + +public class RemoteDeleteCommand implements DbusCommand { + + @Override + public void attachToSubparser(final Subparser subparser) { + subparser.help("Remotely delete a previously sent message."); + subparser.addArgument("-t", "--target-timestamp") + .required(true) + .type(long.class) + .help("Specify the timestamp of the message to delete."); + subparser.addArgument("-g", "--group") + .help("Specify the recipient group ID."); + subparser.addArgument("recipient") + .help("Specify the recipients' phone number.").nargs("*"); + } + + @Override + public void handleCommand(final Namespace ns, final Signal signal) throws CommandException { + final List recipients = ns.getList("recipient"); + final var groupIdString = ns.getString("group"); + + final var noRecipients = recipients == null || recipients.isEmpty(); + if (noRecipients && groupIdString == null) { + throw new UserErrorException("No recipients given"); + } + if (!noRecipients && groupIdString != null) { + throw new UserErrorException("You cannot specify recipients by phone number and groups at the same time"); + } + + final long targetTimestamp = ns.getLong("target_timestamp"); + + final var writer = new PlainTextWriterImpl(System.out); + + byte[] groupId = null; + if (groupIdString != null) { + try { + groupId = Util.decodeGroupId(groupIdString).serialize(); + } catch (GroupIdFormatException e) { + throw new UserErrorException("Invalid group id: " + e.getMessage()); + } + } + + try { + long timestamp; + if (groupId != null) { + timestamp = signal.sendGroupRemoteDeleteMessage(targetTimestamp, groupId); + } else { + timestamp = signal.sendRemoteDeleteMessage(targetTimestamp, recipients); + } + writer.println("{}", timestamp); + } catch (AssertionError e) { + handleAssertionError(e); + throw e; + } catch (UnknownObject e) { + throw new UserErrorException("Failed to find dbus object, maybe missing the -u flag: " + e.getMessage()); + } catch (Signal.Error.InvalidNumber e) { + throw new UserErrorException("Invalid number: " + e.getMessage()); + } catch (Signal.Error.GroupNotFound e) { + throw new UserErrorException("Failed to send to group: " + e.getMessage()); + } catch (DBusExecutionException e) { + throw new UnexpectedErrorException("Failed to send message: " + e.getMessage()); + } + } +} diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 9bc4b67f..6b22029b 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -103,6 +103,45 @@ public class DbusSignalImpl implements Signal { } } + @Override + public long sendRemoteDeleteMessage( + final long targetSentTimestamp, final String recipient + ) { + var recipients = new ArrayList(1); + recipients.add(recipient); + return sendRemoteDeleteMessage(targetSentTimestamp, recipients); + } + + @Override + public long sendRemoteDeleteMessage( + final long targetSentTimestamp, final List recipients + ) { + try { + final var results = m.sendRemoteDeleteMessage(targetSentTimestamp, recipients); + checkSendMessageResults(results.first(), results.second()); + return results.first(); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); + } catch (InvalidNumberException e) { + throw new Error.InvalidNumber(e.getMessage()); + } + } + + @Override + public long sendGroupRemoteDeleteMessage( + final long targetSentTimestamp, final byte[] groupId + ) { + try { + final var results = m.sendGroupRemoteDeleteMessage(targetSentTimestamp, GroupId.unknownVersion(groupId)); + checkSendMessageResults(results.first(), results.second()); + return results.first(); + } catch (IOException e) { + throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException e) { + throw new Error.GroupNotFound(e.getMessage()); + } + } + @Override public long sendMessageReaction( final String emoji, final boolean remove, final String targetAuthor, final long targetSentTimestamp, final String recipient