## [Unreleased]
-**Attention**: Now requires Java 21
+**Attention**: Now requires Java 21 and libsignal-client version 0.37
### Added
- 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
- Better shutdown handling after Ctrl+C and SIGTERM
);
SendMessageResults sendMessage(
- Message message, Set<RecipientIdentifier> recipients
+ Message message, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException;
SendMessageResults sendEditMessage(
private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
- context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId, Optional.empty());
+ context.getSendHelper().sendAsGroupMessage(messageBuilder, groupId, false, Optional.empty());
}
private SendGroupMessageResults updateGroupV2(
* 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, Optional<Long> editTargetTimestamp
+ final SignalServiceDataMessage.Builder messageBuilder,
+ final GroupId groupId,
+ final boolean includeSelf,
+ final Optional<Long> editTargetTimestamp
) throws IOException, GroupNotFoundException, NotAGroupMemberException, GroupSendingNotAllowedException {
final var g = getGroupForSending(groupId);
- return sendAsGroupMessage(messageBuilder, g, editTargetTimestamp);
+ return sendAsGroupMessage(messageBuilder, g, includeSelf, editTargetTimestamp);
}
/**
}
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 {
GroupUtils.setGroupContext(messageBuilder, g);
messageBuilder.withExpiration(g.getMessageExpirationTimer());
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 (message.getBody().isPresent()
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfo;
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.stickerPacks.JsonStickerPack;
import org.asamk.signal.manager.storage.stickerPacks.StickerPackStore;
}
private SendMessageResults sendMessage(
- SignalServiceDataMessage.Builder messageBuilder, Set<RecipientIdentifier> recipients
+ SignalServiceDataMessage.Builder messageBuilder, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
- return sendMessage(messageBuilder, recipients, Optional.empty());
+ return sendMessage(messageBuilder, recipients, notifySelf, Optional.empty());
}
private SendMessageResults sendMessage(
SignalServiceDataMessage.Builder messageBuilder,
Set<RecipientIdentifier> recipients,
+ boolean notifySelf,
Optional<Long> editTargetTimestamp
) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
long timestamp = System.currentTimeMillis();
messageBuilder.withTimestamp(timestamp);
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 {
final var recipientId = context.getRecipientHelper().resolveRecipient(single);
final var result = context.getSendHelper()
results.put(recipient,
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) {
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());
}
}
@Override
public SendMessageResults sendMessage(
- Message message, Set<RecipientIdentifier> recipients
+ Message message, Set<RecipientIdentifier> recipients, boolean notifySelf
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
final var selfProfile = context.getProfileHelper().getSelfProfile();
if (selfProfile == null || selfProfile.getDisplayName().isEmpty()) {
}
final var messageBuilder = SignalServiceDataMessage.newBuilder();
applyMessage(messageBuilder, message);
- return sendMessage(messageBuilder, recipients);
+ return sendMessage(messageBuilder, recipients, notifySelf);
}
@Override
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
final var messageBuilder = SignalServiceDataMessage.newBuilder();
applyMessage(messageBuilder, message);
- return sendMessage(messageBuilder, recipients, Optional.of(editTargetTimestamp));
+ return sendMessage(messageBuilder, recipients, false, Optional.of(editTargetTimestamp));
}
private void applyMessage(
account.getMessageSendLogStore().deleteEntryForGroup(targetSentTimestamp, r.groupId());
}
}
- return sendMessage(messageBuilder, recipients);
+ return sendMessage(messageBuilder, recipients, false);
}
@Override
messageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(authorServiceId,
targetSentTimestamp));
}
- return sendMessage(messageBuilder, recipients);
+ return sendMessage(messageBuilder, recipients, false);
}
@Override
final var payment = new SignalServiceDataMessage.Payment(paymentNotification, null);
final var messageBuilder = SignalServiceDataMessage.newBuilder().withPayment(payment);
try {
- return sendMessage(messageBuilder, Set.of(recipient));
+ return sendMessage(messageBuilder, Set.of(recipient), false);
} catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) {
throw new AssertionError(e);
}
try {
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) {
throw new AssertionError(e);
} finally {
context.getContactHelper().setExpirationTimer(recipientId, messageExpirationTimer);
final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate();
try {
- sendMessage(messageBuilder, Set.of(recipient));
+ sendMessage(messageBuilder, Set.of(recipient), false);
} catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) {
throw new AssertionError(e);
}
subparser.addArgument("--note-to-self")
.help("Send the message to self without notification.")
.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();
mut.addArgument("-m", "--message").help("Specify the message to be sent.");
public void handleCommand(
final Namespace ns, final Manager m, final OutputWriter outputWriter
) 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 recipientStrings = ns.<String>getList("recipient");
final var groupIdStrings = ns.<String>getList("group-id");
textStyles);
var results = editTimestamp != null
? m.sendEditMessage(message, recipientIdentifiers, editTimestamp)
- : m.sendMessage(message, recipientIdentifiers);
+ : m.sendMessage(message, recipientIdentifiers, notifySelf);
outputResult(outputWriter, results);
} catch (AttachmentInvalidException | IOException e) {
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
@Override
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 {
return handleMessage(recipients,
numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers),
}
@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 {
- final var results = m.sendMessage(new Message(message,
- attachments,
- List.of(),
- Optional.empty(),
- Optional.empty(),
- List.of(),
- Optional.empty(),
- List.of()),
- getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
- .map(RecipientIdentifier.class::cast)
- .collect(Collectors.toSet()));
+ final var message = new Message(messageText,
+ attachments,
+ List.of(),
+ Optional.empty(),
+ Optional.empty(),
+ List.of(),
+ Optional.empty(),
+ List.of());
+ final var recipientIdentifiers = getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
+ .map(RecipientIdentifier.class::cast)
+ .collect(Collectors.toSet());
+ final var results = m.sendMessage(message, recipientIdentifiers, false);
checkSendMessageResults(results);
return results.timestamp();
@Override
public long sendNoteToSelfMessage(
- final String message, final List<String> attachments
+ final String messageText, final List<String> attachments
) throws Error.AttachmentInvalid, Error.Failure, Error.UntrustedIdentity {
try {
- final var results = m.sendMessage(new Message(message,
+ final var message = new Message(messageText,
attachments,
List.of(),
Optional.empty(),
Optional.empty(),
List.of(),
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);
return results.timestamp();
} catch (AttachmentInvalidException e) {
}
@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 {
- var results = m.sendMessage(new Message(message,
+ final var message = new Message(messageText,
attachments,
List.of(),
Optional.empty(),
Optional.empty(),
List.of(),
Optional.empty(),
- List.of()), Set.of(getGroupRecipientIdentifier(groupId)));
+ List.of());
+ var results = m.sendMessage(message, Set.of(getGroupRecipientIdentifier(groupId)), false);
checkSendMessageResults(results);
return results.timestamp();
} catch (IOException | InvalidStickerException e) {