Add --notify-self parmeter

Fixes #1087
This commit is contained in:
AsamK 2024-01-12 18:07:14 +01:00
parent c07ba14fc6
commit 3290a5bf4d
8 changed files with 66 additions and 42 deletions

View file

@ -2,10 +2,12 @@
## [Unreleased] ## [Unreleased]
**Attention**: Now requires Java 21 **Attention**: Now requires Java 21 and libsignal-client version 0.37
### Added ### Added
- New --hidden parameter for removeContact command - New --hidden parameter for removeContact command
- New --notify-self parameter for send command, for sending a non-sync message when self is part of the recipients or groups.
With this parameter sending to the self number (+XXXX) now behaves the same as the --note-to-self parameter.
### Improved ### Improved
- Better shutdown handling after Ctrl+C and SIGTERM - Better shutdown handling after Ctrl+C and SIGTERM

View file

@ -172,7 +172,7 @@ public interface Manager extends Closeable {
); );
SendMessageResults sendMessage( SendMessageResults sendMessage(
Message message, Set<RecipientIdentifier> recipients Message message, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException;
SendMessageResults sendEditMessage( SendMessageResults sendEditMessage(

View file

@ -551,7 +551,7 @@ public class GroupHelper {
private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId, Optional.empty()); context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId, false, Optional.empty());
} }
private SendGroupMessageResults updateGroupV2( private SendGroupMessageResults updateGroupV2(

View file

@ -101,10 +101,13 @@ public class SendHelper {
* The message is extended with the current expiration timer for the group and the group context. * The message is extended with the current expiration timer for the group and the group context.
*/ */
public List<SendMessageResult> sendAsGroupMessage( public List<SendMessageResult> sendAsGroupMessage(
SignalServiceDataMessage.Builder messageBuilder, GroupId groupId, Optional<Long> editTargetTimestamp final SignalServiceDataMessage.Builder messageBuilder,
final GroupId groupId,
final boolean includeSelf,
final Optional<Long> editTargetTimestamp
) throws IOException, GroupNotFoundException, NotAGroupMemberException, GroupSendingNotAllowedException { ) throws IOException, GroupNotFoundException, NotAGroupMemberException, GroupSendingNotAllowedException {
final var g = getGroupForSending(groupId); final var g = getGroupForSending(groupId);
return sendAsGroupMessage(messageBuilder, g, editTargetTimestamp); return sendAsGroupMessage(messageBuilder, g, includeSelf, editTargetTimestamp);
} }
/** /**
@ -297,13 +300,16 @@ public class SendHelper {
} }
private List<SendMessageResult> sendAsGroupMessage( private List<SendMessageResult> sendAsGroupMessage(
final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g, Optional<Long> editTargetTimestamp final SignalServiceDataMessage.Builder messageBuilder,
final GroupInfo g,
final boolean includeSelf,
final Optional<Long> editTargetTimestamp
) throws IOException, GroupSendingNotAllowedException { ) throws IOException, GroupSendingNotAllowedException {
GroupUtils.setGroupContext(messageBuilder, g); GroupUtils.setGroupContext(messageBuilder, g);
messageBuilder.withExpiration(g.getMessageExpirationTimer()); messageBuilder.withExpiration(g.getMessageExpirationTimer());
final var message = messageBuilder.build(); final var message = messageBuilder.build();
final var recipients = g.getMembersWithout(account.getSelfRecipientId()); final var recipients = includeSelf ? g.getMembers() : g.getMembersWithout(account.getSelfRecipientId());
if (g.isAnnouncementGroup() && !g.isAdmin(account.getSelfRecipientId())) { if (g.isAnnouncementGroup() && !g.isAdmin(account.getSelfRecipientId())) {
if (message.getBody().isPresent() if (message.getBody().isPresent()

View file

@ -71,6 +71,7 @@ import org.asamk.signal.manager.storage.AvatarStore;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfo; import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.identities.IdentityInfo; import org.asamk.signal.manager.storage.identities.IdentityInfo;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack; import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack;
import org.asamk.signal.manager.storage.stickerPacks.StickerPackStore; import org.asamk.signal.manager.storage.stickerPacks.StickerPackStore;
@ -528,21 +529,31 @@ public class ManagerImpl implements Manager {
} }
private SendMessageResults sendMessage( private SendMessageResults sendMessage(
SignalServiceDataMessage.Builder messageBuilder, Set<RecipientIdentifier> recipients SignalServiceDataMessage.Builder messageBuilder, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
return sendMessage(messageBuilder, recipients, Optional.empty()); return sendMessage(messageBuilder, recipients, notifySelf, Optional.empty());
} }
private SendMessageResults sendMessage( private SendMessageResults sendMessage(
SignalServiceDataMessage.Builder messageBuilder, SignalServiceDataMessage.Builder messageBuilder,
Set<RecipientIdentifier> recipients, Set<RecipientIdentifier> recipients,
boolean notifySelf,
Optional<Long> editTargetTimestamp Optional<Long> editTargetTimestamp
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>(); var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
messageBuilder.withTimestamp(timestamp); messageBuilder.withTimestamp(timestamp);
for (final var recipient : recipients) { for (final var recipient : recipients) {
if (recipient instanceof RecipientIdentifier.Single single) { if (recipient instanceof RecipientIdentifier.NoteToSelf || (
recipient instanceof RecipientIdentifier.Single single
&& new RecipientAddress(single.toPartialRecipientAddress()).matches(account.getSelfRecipientAddress())
)) {
final var result = notifySelf
? context.getSendHelper()
.sendMessage(messageBuilder, account.getSelfRecipientId(), editTargetTimestamp)
: context.getSendHelper().sendSelfMessage(messageBuilder, editTargetTimestamp);
results.put(recipient, List.of(toSendMessageResult(result)));
} else if (recipient instanceof RecipientIdentifier.Single single) {
try { try {
final var recipientId = context.getRecipientHelper().resolveRecipient(single); final var recipientId = context.getRecipientHelper().resolveRecipient(single);
final var result = context.getSendHelper() final var result = context.getSendHelper()
@ -552,12 +563,9 @@ public class ManagerImpl implements Manager {
results.put(recipient, results.put(recipient,
List.of(SendMessageResult.unregisteredFailure(single.toPartialRecipientAddress()))); List.of(SendMessageResult.unregisteredFailure(single.toPartialRecipientAddress())));
} }
} else if (recipient instanceof RecipientIdentifier.NoteToSelf) {
final var result = context.getSendHelper().sendSelfMessage(messageBuilder, editTargetTimestamp);
results.put(recipient, List.of(toSendMessageResult(result)));
} else if (recipient instanceof RecipientIdentifier.Group group) { } else if (recipient instanceof RecipientIdentifier.Group group) {
final var result = context.getSendHelper() final var result = context.getSendHelper()
.sendAsGroupMessage(messageBuilder, group.groupId(), editTargetTimestamp); .sendAsGroupMessage(messageBuilder, group.groupId(), notifySelf, editTargetTimestamp);
results.put(recipient, result.stream().map(this::toSendMessageResult).toList()); results.put(recipient, result.stream().map(this::toSendMessageResult).toList());
} }
} }
@ -642,7 +650,7 @@ public class ManagerImpl implements Manager {
@Override @Override
public SendMessageResults sendMessage( public SendMessageResults sendMessage(
Message message, Set<RecipientIdentifier> recipients Message message, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
final var selfProfile = context.getProfileHelper().getSelfProfile(); final var selfProfile = context.getProfileHelper().getSelfProfile();
if (selfProfile == null || selfProfile.getDisplayName().isEmpty()) { if (selfProfile == null || selfProfile.getDisplayName().isEmpty()) {
@ -651,7 +659,7 @@ public class ManagerImpl implements Manager {
} }
final var messageBuilder = SignalServiceDataMessage.newBuilder(); final var messageBuilder = SignalServiceDataMessage.newBuilder();
applyMessage(messageBuilder, message); applyMessage(messageBuilder, message);
return sendMessage(messageBuilder, recipients); return sendMessage(messageBuilder, recipients, notifySelf);
} }
@Override @Override
@ -660,7 +668,7 @@ public class ManagerImpl implements Manager {
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
final var messageBuilder = SignalServiceDataMessage.newBuilder(); final var messageBuilder = SignalServiceDataMessage.newBuilder();
applyMessage(messageBuilder, message); applyMessage(messageBuilder, message);
return sendMessage(messageBuilder, recipients, Optional.of(editTargetTimestamp)); return sendMessage(messageBuilder, recipients, false, Optional.of(editTargetTimestamp));
} }
private void applyMessage( private void applyMessage(
@ -785,7 +793,7 @@ public class ManagerImpl implements Manager {
account.getMessageSendLogStore().deleteEntryForGroup(targetSentTimestamp, r.groupId()); account.getMessageSendLogStore().deleteEntryForGroup(targetSentTimestamp, r.groupId());
} }
} }
return sendMessage(messageBuilder, recipients); return sendMessage(messageBuilder, recipients, false);
} }
@Override @Override
@ -807,7 +815,7 @@ public class ManagerImpl implements Manager {
messageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(authorServiceId, messageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(authorServiceId,
targetSentTimestamp)); targetSentTimestamp));
} }
return sendMessage(messageBuilder, recipients); return sendMessage(messageBuilder, recipients, false);
} }
@Override @Override
@ -818,7 +826,7 @@ public class ManagerImpl implements Manager {
final var payment = new SignalServiceDataMessage.Payment(paymentNotification, null); final var payment = new SignalServiceDataMessage.Payment(paymentNotification, null);
final var messageBuilder = SignalServiceDataMessage.newBuilder().withPayment(payment); final var messageBuilder = SignalServiceDataMessage.newBuilder().withPayment(payment);
try { try {
return sendMessage(messageBuilder, Set.of(recipient)); return sendMessage(messageBuilder, Set.of(recipient), false);
} catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) { } catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
@ -830,7 +838,8 @@ public class ManagerImpl implements Manager {
try { try {
return sendMessage(messageBuilder, return sendMessage(messageBuilder,
recipients.stream().map(RecipientIdentifier.class::cast).collect(Collectors.toSet())); recipients.stream().map(RecipientIdentifier.class::cast).collect(Collectors.toSet()),
false);
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
throw new AssertionError(e); throw new AssertionError(e);
} finally { } finally {
@ -952,7 +961,7 @@ public class ManagerImpl implements Manager {
context.getContactHelper().setExpirationTimer(recipientId, messageExpirationTimer); context.getContactHelper().setExpirationTimer(recipientId, messageExpirationTimer);
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
try { try {
sendMessage(messageBuilder, Set.of(recipient)); sendMessage(messageBuilder, Set.of(recipient), false);
} catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) { } catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }

View file

@ -51,6 +51,9 @@ public class SendCommand implements JsonRpcLocalCommand {
subparser.addArgument("--note-to-self") subparser.addArgument("--note-to-self")
.help("Send the message to self without notification.") .help("Send the message to self without notification.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
subparser.addArgument("--notify-self")
.help("If self is part of recipients/groups send a normal message, not a sync message.")
.action(Arguments.storeTrue());
var mut = subparser.addMutuallyExclusiveGroup(); var mut = subparser.addMutuallyExclusiveGroup();
mut.addArgument("-m", "--message").help("Specify the message to be sent."); mut.addArgument("-m", "--message").help("Specify the message to be sent.");
@ -105,6 +108,7 @@ public class SendCommand implements JsonRpcLocalCommand {
public void handleCommand( public void handleCommand(
final Namespace ns, final Manager m, final OutputWriter outputWriter final Namespace ns, final Manager m, final OutputWriter outputWriter
) throws CommandException { ) throws CommandException {
final var notifySelf = Boolean.TRUE.equals(ns.getBoolean("notify-self"));
final var isNoteToSelf = Boolean.TRUE.equals(ns.getBoolean("note-to-self")); final var isNoteToSelf = Boolean.TRUE.equals(ns.getBoolean("note-to-self"));
final var recipientStrings = ns.<String>getList("recipient"); final var recipientStrings = ns.<String>getList("recipient");
final var groupIdStrings = ns.<String>getList("group-id"); final var groupIdStrings = ns.<String>getList("group-id");
@ -236,7 +240,7 @@ public class SendCommand implements JsonRpcLocalCommand {
textStyles); textStyles);
var results = editTimestamp != null var results = editTimestamp != null
? m.sendEditMessage(message, recipientIdentifiers, editTimestamp) ? m.sendEditMessage(message, recipientIdentifiers, editTimestamp)
: m.sendMessage(message, recipientIdentifiers); : m.sendMessage(message, recipientIdentifiers, notifySelf);
outputResult(outputWriter, results); outputResult(outputWriter, results);
} catch (AttachmentInvalidException | IOException e) { } catch (AttachmentInvalidException | IOException e) {
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass() throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()

View file

@ -397,7 +397,7 @@ public class DbusManagerImpl implements Manager {
@Override @Override
public SendMessageResults sendMessage( public SendMessageResults sendMessage(
final Message message, final Set<RecipientIdentifier> recipients final Message message, final Set<RecipientIdentifier> recipients, final boolean notifySelf
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
return handleMessage(recipients, return handleMessage(recipients,
numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers), numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers),

View file

@ -225,19 +225,20 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
} }
@Override @Override
public long sendMessage(final String message, final List<String> attachments, final List<String> recipients) { public long sendMessage(final String messageText, final List<String> attachments, final List<String> recipients) {
try { try {
final var results = m.sendMessage(new Message(message, final var message = new Message(messageText,
attachments, attachments,
List.of(), List.of(),
Optional.empty(), Optional.empty(),
Optional.empty(), Optional.empty(),
List.of(), List.of(),
Optional.empty(), Optional.empty(),
List.of()), List.of());
getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() final var recipientIdentifiers = getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
.map(RecipientIdentifier.class::cast) .map(RecipientIdentifier.class::cast)
.collect(Collectors.toSet())); .collect(Collectors.toSet());
final var results = m.sendMessage(message, recipientIdentifiers, false);
checkSendMessageResults(results); checkSendMessageResults(results);
return results.timestamp(); return results.timestamp();
@ -384,17 +385,18 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
@Override @Override
public long sendNoteToSelfMessage( public long sendNoteToSelfMessage(
final String message, final List<String> attachments final String messageText, final List<String> attachments
) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity { ) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity {
try { try {
final var results = m.sendMessage(new Message(message, final var message = new Message(messageText,
attachments, attachments,
List.of(), List.of(),
Optional.empty(), Optional.empty(),
Optional.empty(), Optional.empty(),
List.of(), List.of(),
Optional.empty(), Optional.empty(),
List.of()), Set.of(RecipientIdentifier.NoteToSelf.INSTANCE)); List.of());
final var results = m.sendMessage(message, Set.of(RecipientIdentifier.NoteToSelf.INSTANCE), false);
checkSendMessageResults(results); checkSendMessageResults(results);
return results.timestamp(); return results.timestamp();
} catch (AttachmentInvalidException e) { } catch (AttachmentInvalidException e) {
@ -429,16 +431,17 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
} }
@Override @Override
public long sendGroupMessage(final String message, final List<String> attachments, final byte[] groupId) { public long sendGroupMessage(final String messageText, final List<String> attachments, final byte[] groupId) {
try { try {
var results = m.sendMessage(new Message(message, final var message = new Message(messageText,
attachments, attachments,
List.of(), List.of(),
Optional.empty(), Optional.empty(),
Optional.empty(), Optional.empty(),
List.of(), List.of(),
Optional.empty(), Optional.empty(),
List.of()), Set.of(getGroupRecipientIdentifier(groupId))); List.of());
var results = m.sendMessage(message, Set.of(getGroupRecipientIdentifier(groupId)), false);
checkSendMessageResults(results); checkSendMessageResults(results);
return results.timestamp(); return results.timestamp();
} catch (IOException | InvalidStickerException e) { } catch (IOException | InvalidStickerException e) {