From 811dc0dcf392ae0a6ba260f64743f72328363ad0 Mon Sep 17 00:00:00 2001 From: Scott Lewis Date: Mon, 27 Jan 2025 16:45:20 -0800 Subject: [PATCH] Added sendStoryMessage --- .../org/asamk/signal/manager/Manager.java | 4 + .../signal/manager/internal/ManagerImpl.java | 16 + src/main/java/org/asamk/Signal.java | 1153 ++++++++--------- .../asamk/signal/dbus/DbusManagerImpl.java | 10 + .../org/asamk/signal/dbus/DbusSignalImpl.java | 25 + 5 files changed, 601 insertions(+), 607 deletions(-) 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 4b086994..7fcaa690 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -189,6 +189,10 @@ public interface Manager extends Closeable { Message message, Set recipients, boolean notifySelf ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; + SendMessageResults sendStoryMessage( + Message message, Set recipients, boolean notifySelf + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; + SendMessageResults sendEditMessage( Message message, Set recipients, long editTargetTimestamp ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException; diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java index 27bda583..b04023a8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java @@ -96,6 +96,7 @@ import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.SignalSessionLock; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; +import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.StoryContext; import org.whispersystems.signalservice.api.messages.SignalServicePreview; import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage; import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage; @@ -736,6 +737,21 @@ public class ManagerImpl implements Manager { return sendMessage(messageBuilder, recipients, notifySelf); } + @Override + public SendMessageResults sendStoryMessage( + Message message, Set recipients, boolean notifySelf + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { + final var selfProfile = context.getProfileHelper().getSelfProfile(); + if (selfProfile == null || selfProfile.getDisplayName().isEmpty()) { + logger.warn( + "No profile name set. When sending a message it's recommended to set a profile name with the updateProfile command. This may become mandatory in the future."); + } + final var messageBuilder = SignalServiceDataMessage.newBuilder(); + applyMessage(messageBuilder, message); + messageBuilder.withStoryContext(new StoryContext(account.getSelfAddress().getServiceId(), System.currentTimeMillis())); + return sendMessage(messageBuilder, recipients, notifySelf); + } + @Override public SendMessageResults sendEditMessage( Message message, Set recipients, long editTargetTimestamp diff --git a/src/main/java/org/asamk/Signal.java b/src/main/java/org/asamk/Signal.java index 1d715659..f825b5ec 100644 --- a/src/main/java/org/asamk/Signal.java +++ b/src/main/java/org/asamk/Signal.java @@ -15,723 +15,662 @@ import java.util.List; import java.util.Map; /** - * DBus interface for the org.asamk.Signal service. - * Including emitted Signals and returned Errors. + * DBus interface for the org.asamk.Signal service. Including emitted Signals + * and returned Errors. */ public interface Signal extends DBusInterface { - String getSelfNumber(); + String getSelfNumber(); - void subscribeReceive(); + void subscribeReceive(); - void unsubscribeReceive(); + void unsubscribeReceive(); - long sendMessage( - String message, List attachments, String recipient - ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; + long sendMessage(String message, List attachments, String recipient) + throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; - long sendMessage( - String message, List attachments, List recipients - ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; + long sendMessage(String message, List attachments, List recipients) + throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; - void sendTyping( - String recipient, boolean stop - ) throws Error.Failure, Error.UntrustedIdentity; + void sendTyping(String recipient, boolean stop) throws Error.Failure, Error.UntrustedIdentity; - void sendReadReceipt( - String recipient, List messageIds - ) throws Error.Failure, Error.UntrustedIdentity; + void sendReadReceipt(String recipient, List messageIds) throws Error.Failure, Error.UntrustedIdentity; - void sendViewedReceipt( - String recipient, List messageIds - ) throws Error.Failure, Error.UntrustedIdentity; + void sendViewedReceipt(String recipient, List messageIds) throws Error.Failure, Error.UntrustedIdentity; - long sendRemoteDeleteMessage( - long targetSentTimestamp, String recipient - ) throws Error.Failure, Error.InvalidNumber; + long sendRemoteDeleteMessage(long targetSentTimestamp, String recipient) throws Error.Failure, Error.InvalidNumber; - long sendRemoteDeleteMessage( - long targetSentTimestamp, List recipients - ) throws Error.Failure, Error.InvalidNumber; + long sendRemoteDeleteMessage(long targetSentTimestamp, List recipients) + throws Error.Failure, Error.InvalidNumber; - long sendMessageReaction( - String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, String recipient - ) throws Error.InvalidNumber, Error.Failure; + long sendMessageReaction(String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, + String recipient) throws Error.InvalidNumber, Error.Failure; - long sendMessageReaction( - String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, List recipients - ) throws Error.InvalidNumber, Error.Failure; + long sendMessageReaction(String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, + List recipients) throws Error.InvalidNumber, Error.Failure; - long sendPaymentNotification(byte[] receipt, String note, String recipient) throws Error.Failure; + long sendPaymentNotification(byte[] receipt, String note, String recipient) throws Error.Failure; - void sendContacts() throws Error.Failure; + void sendContacts() throws Error.Failure; - void sendSyncRequest() throws Error.Failure; + void sendSyncRequest() throws Error.Failure; - long sendNoteToSelfMessage( - String message, List attachments - ) throws Error.AttachmentInvalid, Error.Failure; + long sendNoteToSelfMessage(String message, List attachments) throws Error.AttachmentInvalid, Error.Failure; - void sendEndSessionMessage(List recipients) throws Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; + void sendEndSessionMessage(List recipients) + throws Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; - void deleteRecipient(final String recipient) throws Error.Failure; + void deleteRecipient(final String recipient) throws Error.Failure; - void deleteContact(final String recipient) throws Error.Failure; + void deleteContact(final String recipient) throws Error.Failure; - long sendGroupMessage( - String message, List attachments, byte[] groupId - ) throws Error.GroupNotFound, Error.Failure, Error.AttachmentInvalid, Error.InvalidGroupId; + long sendGroupMessage(String message, List attachments, byte[] groupId) + throws Error.GroupNotFound, Error.Failure, Error.AttachmentInvalid, Error.InvalidGroupId; - void sendGroupTyping( - final byte[] groupId, final boolean stop - ) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity; + long sendStoryMessage(String messageText, List attachments, byte[] groupId); - long sendGroupRemoteDeleteMessage( - long targetSentTimestamp, byte[] groupId - ) throws Error.Failure, Error.GroupNotFound, Error.InvalidGroupId; + void sendGroupTyping(final byte[] groupId, final boolean stop) + throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity; - long sendGroupMessageReaction( - String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, byte[] groupId - ) throws Error.GroupNotFound, Error.Failure, Error.InvalidNumber, Error.InvalidGroupId; + long sendGroupRemoteDeleteMessage(long targetSentTimestamp, byte[] groupId) + throws Error.Failure, Error.GroupNotFound, Error.InvalidGroupId; - String getContactName(String number) throws Error.InvalidNumber; + long sendGroupMessageReaction(String emoji, boolean remove, String targetAuthor, long targetSentTimestamp, + byte[] groupId) throws Error.GroupNotFound, Error.Failure, Error.InvalidNumber, Error.InvalidGroupId; - void setContactName(String number, String name) throws Error.InvalidNumber; + String getContactName(String number) throws Error.InvalidNumber; - void setExpirationTimer(final String number, final int expiration) throws Error.Failure; + void setContactName(String number, String name) throws Error.InvalidNumber; - void setContactBlocked(String number, boolean blocked) throws Error.InvalidNumber; + void setExpirationTimer(final String number, final int expiration) throws Error.Failure; - @Deprecated - void setGroupBlocked(byte[] groupId, boolean blocked) throws Error.GroupNotFound, Error.InvalidGroupId; + void setContactBlocked(String number, boolean blocked) throws Error.InvalidNumber; - @Deprecated - List getGroupIds(); + @Deprecated + void setGroupBlocked(byte[] groupId, boolean blocked) throws Error.GroupNotFound, Error.InvalidGroupId; - DBusPath getGroup(byte[] groupId); + @Deprecated + List getGroupIds(); - List listGroups(); + DBusPath getGroup(byte[] groupId); - @Deprecated - String getGroupName(byte[] groupId) throws Error.InvalidGroupId; + List listGroups(); - @Deprecated - List getGroupMembers(byte[] groupId) throws Error.InvalidGroupId; + @Deprecated + String getGroupName(byte[] groupId) throws Error.InvalidGroupId; - byte[] createGroup( - String name, List members, String avatar - ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber; + @Deprecated + List getGroupMembers(byte[] groupId) throws Error.InvalidGroupId; - @Deprecated - byte[] updateGroup( - byte[] groupId, String name, List members, String avatar - ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.GroupNotFound, Error.InvalidGroupId; + byte[] createGroup(String name, List members, String avatar) + throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber; - @Deprecated - boolean isRegistered() throws Error.Failure, Error.InvalidNumber; + @Deprecated + byte[] updateGroup(byte[] groupId, String name, List members, String avatar) throws Error.AttachmentInvalid, + Error.Failure, Error.InvalidNumber, Error.GroupNotFound, Error.InvalidGroupId; - boolean isRegistered(String number) throws Error.Failure, Error.InvalidNumber; + @Deprecated + boolean isRegistered() throws Error.Failure, Error.InvalidNumber; - List isRegistered(List numbers) throws Error.Failure, Error.InvalidNumber; + boolean isRegistered(String number) throws Error.Failure, Error.InvalidNumber; - void addDevice(String uri) throws Error.InvalidUri; + List isRegistered(List numbers) throws Error.Failure, Error.InvalidNumber; - DBusPath getDevice(long deviceId); + void addDevice(String uri) throws Error.InvalidUri; - DBusPath getIdentity(String number); + DBusPath getDevice(long deviceId); - List listIdentities(); + DBusPath getIdentity(String number); - List listDevices() throws Error.Failure; + List listIdentities(); - DBusPath getThisDevice(); + List listDevices() throws Error.Failure; - void updateProfile( - String givenName, - String familyName, - String about, - String aboutEmoji, - String avatarPath, - boolean removeAvatar - ) throws Error.Failure; + DBusPath getThisDevice(); - void updateProfile( - String name, String about, String aboutEmoji, String avatarPath, boolean removeAvatar - ) throws Error.Failure; + void updateProfile(String givenName, String familyName, String about, String aboutEmoji, String avatarPath, + boolean removeAvatar) throws Error.Failure; - void removePin(); + void updateProfile(String name, String about, String aboutEmoji, String avatarPath, boolean removeAvatar) + throws Error.Failure; - void setPin(String registrationLockPin); + void removePin(); - String version(); + void setPin(String registrationLockPin); - List listNumbers(); + String version(); - List getContactNumber(final String name) throws Error.Failure; + List listNumbers(); - @Deprecated - void quitGroup(final byte[] groupId) throws Error.GroupNotFound, Error.Failure, Error.InvalidGroupId; + List getContactNumber(final String name) throws Error.Failure; - boolean isContactBlocked(final String number) throws Error.InvalidNumber; + @Deprecated + void quitGroup(final byte[] groupId) throws Error.GroupNotFound, Error.Failure, Error.InvalidGroupId; - @Deprecated - boolean isGroupBlocked(final byte[] groupId) throws Error.InvalidGroupId; + boolean isContactBlocked(final String number) throws Error.InvalidNumber; - @Deprecated - boolean isMember(final byte[] groupId) throws Error.InvalidGroupId; + @Deprecated + boolean isGroupBlocked(final byte[] groupId) throws Error.InvalidGroupId; - byte[] joinGroup(final String groupLink) throws Error.Failure; + @Deprecated + boolean isMember(final byte[] groupId) throws Error.InvalidGroupId; - String uploadStickerPack(String stickerPackPath) throws Error.Failure; + byte[] joinGroup(final String groupLink) throws Error.Failure; - void submitRateLimitChallenge(String challenge, String captchaString) throws Error.Failure; + String uploadStickerPack(String stickerPackPath) throws Error.Failure; - void unregister() throws Error.Failure; + void submitRateLimitChallenge(String challenge, String captchaString) throws Error.Failure; - void deleteAccount() throws Error.Failure; + void unregister() throws Error.Failure; - class MessageReceivedV2 extends DBusSignal { + void deleteAccount() throws Error.Failure; - private final long timestamp; - private final String sender; - private final byte[] groupId; - private final String message; - private final Map> extras; + class MessageReceivedV2 extends DBusSignal { - public MessageReceivedV2( - String objectpath, - long timestamp, - String sender, - byte[] groupId, - String message, - final Map> extras - ) throws DBusException { - super(objectpath, timestamp, sender, groupId, message, extras); - this.timestamp = timestamp; - this.sender = sender; - this.groupId = groupId; - this.message = message; - this.extras = extras; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSender() { - return sender; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getMessage() { - return message; - } - - public Map> getExtras() { - return extras; - } - } - - class EditMessageReceived extends DBusSignal { - - private final long timestamp; - private final long targetSentTimestamp; - private final String sender; - private final byte[] groupId; - private final String message; - private final Map> extras; - - public EditMessageReceived( - String objectpath, - long timestamp, - final long targetSentTimestamp, - String sender, - byte[] groupId, - String message, - final Map> extras - ) throws DBusException { - super(objectpath, timestamp, targetSentTimestamp, sender, groupId, message, extras); - this.timestamp = timestamp; - this.targetSentTimestamp = targetSentTimestamp; - this.sender = sender; - this.groupId = groupId; - this.message = message; - this.extras = extras; - } - - public long getTimestamp() { - return timestamp; - } - - public long getTargetSentTimestamp() { - return targetSentTimestamp; - } - - public String getSender() { - return sender; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getMessage() { - return message; - } - - public Map> getExtras() { - return extras; - } - } - - class MessageReceived extends DBusSignal { - - private final long timestamp; - private final String sender; - private final byte[] groupId; - private final String message; - private final List attachments; - - public MessageReceived( - String objectpath, - long timestamp, - String sender, - byte[] groupId, - String message, - List attachments - ) throws DBusException { - super(objectpath, timestamp, sender, groupId, message, attachments); - this.timestamp = timestamp; - this.sender = sender; - this.groupId = groupId; - this.message = message; - this.attachments = attachments; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSender() { - return sender; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getMessage() { - return message; - } - - public List getAttachments() { - return attachments; - } - } - - class ReceiptReceived extends DBusSignal { - - private final long timestamp; - private final String sender; - - public ReceiptReceived(String objectpath, long timestamp, String sender) throws DBusException { - super(objectpath, timestamp, sender); - this.timestamp = timestamp; - this.sender = sender; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSender() { - return sender; - } - } - - class ReceiptReceivedV2 extends DBusSignal { - - private final long timestamp; - private final String sender; - private final String type; - private final Map> extras; - - public ReceiptReceivedV2( - String objectpath, - long timestamp, - String sender, - final String type, - final Map> extras - ) throws DBusException { - super(objectpath, timestamp, sender, type, extras); - this.timestamp = timestamp; - this.sender = sender; - this.type = type; - this.extras = extras; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSender() { - return sender; - } - - public String getReceiptType() { - return type; - } - - public Map> getExtras() { - return extras; - } - } - - class SyncMessageReceived extends DBusSignal { - - private final long timestamp; - private final String source; - private final String destination; - private final byte[] groupId; - private final String message; - private final List attachments; - - public SyncMessageReceived( - String objectpath, - long timestamp, - String source, - String destination, - byte[] groupId, - String message, - List attachments - ) throws DBusException { - super(objectpath, timestamp, source, destination, groupId, message, attachments); - this.timestamp = timestamp; - this.source = source; - this.destination = destination; - this.groupId = groupId; - this.message = message; - this.attachments = attachments; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSource() { - return source; - } - - public String getDestination() { - return destination; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getMessage() { - return message; - } - - public List getAttachments() { - return attachments; - } - } - - class SyncMessageReceivedV2 extends DBusSignal { - - private final long timestamp; - private final String source; - private final String destination; - private final byte[] groupId; - private final String message; - private final Map> extras; - - public SyncMessageReceivedV2( - String objectpath, - long timestamp, - String source, - String destination, - byte[] groupId, - String message, - final Map> extras - ) throws DBusException { - super(objectpath, timestamp, source, destination, groupId, message, extras); - this.timestamp = timestamp; - this.source = source; - this.destination = destination; - this.groupId = groupId; - this.message = message; - this.extras = extras; - } - - public long getTimestamp() { - return timestamp; - } - - public String getSource() { - return source; - } - - public String getDestination() { - return destination; - } - - public byte[] getGroupId() { - return groupId; - } - - public String getMessage() { - return message; - } - - public Map> getExtras() { - return extras; - } - } - - class StructDevice extends Struct { - - @Position(0) - final DBusPath objectPath; - - @Position(1) - final Long id; - - @Position(2) - final String name; - - public StructDevice(final DBusPath objectPath, final Long id, final String name) { - this.objectPath = objectPath; - this.id = id; - this.name = name; - } - - public DBusPath getObjectPath() { - return objectPath; - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - } - - @DBusProperty(name = "Id", type = Integer.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Name", type = String.class) - @DBusProperty(name = "Created", type = String.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "LastSeen", type = String.class, access = DBusProperty.Access.READ) - interface Device extends DBusInterface, Properties { - - void removeDevice() throws Error.Failure; - } - - @DBusProperty(name = "ReadReceipts", type = Boolean.class) - @DBusProperty(name = "UnidentifiedDeliveryIndicators", type = Boolean.class) - @DBusProperty(name = "TypingIndicators", type = Boolean.class) - @DBusProperty(name = "LinkPreviews", type = Boolean.class) - interface Configuration extends DBusInterface, Properties {} - - class StructGroup extends Struct { - - @Position(0) - final DBusPath objectPath; - - @Position(1) - final byte[] id; - - @Position(2) - final String name; - - public StructGroup(final DBusPath objectPath, final byte[] id, final String name) { - this.objectPath = objectPath; - this.id = id; - this.name = name; - } - - public DBusPath getObjectPath() { - return objectPath; - } + private final long timestamp; + private final String sender; + private final byte[] groupId; + private final String message; + private final Map> extras; - public byte[] getId() { - return id; - } + public MessageReceivedV2(String objectpath, long timestamp, String sender, byte[] groupId, String message, + final Map> extras) throws DBusException { + super(objectpath, timestamp, sender, groupId, message, extras); + this.timestamp = timestamp; + this.sender = sender; + this.groupId = groupId; + this.message = message; + this.extras = extras; + } - public String getName() { - return name; - } - } + public long getTimestamp() { + return timestamp; + } - @DBusProperty(name = "Id", type = Byte[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Name", type = String.class) - @DBusProperty(name = "Description", type = String.class) - @DBusProperty(name = "Avatar", type = String.class, access = DBusProperty.Access.WRITE) - @DBusProperty(name = "IsBlocked", type = Boolean.class) - @DBusProperty(name = "IsMember", type = Boolean.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "IsAdmin", type = Boolean.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "MessageExpirationTimer", type = Integer.class) - @DBusProperty(name = "Members", type = String[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "PendingMembers", type = String[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "RequestingMembers", type = String[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Admins", type = String[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Banned", type = String[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "PermissionAddMember", type = String.class) - @DBusProperty(name = "PermissionEditDetails", type = String.class) - @DBusProperty(name = "PermissionSendMessage", type = String.class) - @DBusProperty(name = "GroupInviteLink", type = String.class, access = DBusProperty.Access.READ) - interface Group extends DBusInterface, Properties { + public String getSender() { + return sender; + } - void quitGroup() throws Error.Failure, Error.LastGroupAdmin; + public byte[] getGroupId() { + return groupId; + } - void deleteGroup() throws Error.Failure; + public String getMessage() { + return message; + } - void addMembers(List recipients) throws Error.Failure; + public Map> getExtras() { + return extras; + } + } - void removeMembers(List recipients) throws Error.Failure; + class EditMessageReceived extends DBusSignal { - void addAdmins(List recipients) throws Error.Failure; + private final long timestamp; + private final long targetSentTimestamp; + private final String sender; + private final byte[] groupId; + private final String message; + private final Map> extras; - void removeAdmins(List recipients) throws Error.Failure; + public EditMessageReceived(String objectpath, long timestamp, final long targetSentTimestamp, String sender, + byte[] groupId, String message, final Map> extras) throws DBusException { + super(objectpath, timestamp, targetSentTimestamp, sender, groupId, message, extras); + this.timestamp = timestamp; + this.targetSentTimestamp = targetSentTimestamp; + this.sender = sender; + this.groupId = groupId; + this.message = message; + this.extras = extras; + } - void resetLink() throws Error.Failure; + public long getTimestamp() { + return timestamp; + } - void disableLink() throws Error.Failure; + public long getTargetSentTimestamp() { + return targetSentTimestamp; + } - void enableLink(boolean requiresApproval) throws Error.Failure; - } + public String getSender() { + return sender; + } - class StructIdentity extends Struct { + public byte[] getGroupId() { + return groupId; + } + + public String getMessage() { + return message; + } + + public Map> getExtras() { + return extras; + } + } + + class MessageReceived extends DBusSignal { + + private final long timestamp; + private final String sender; + private final byte[] groupId; + private final String message; + private final List attachments; + + public MessageReceived(String objectpath, long timestamp, String sender, byte[] groupId, String message, + List attachments) throws DBusException { + super(objectpath, timestamp, sender, groupId, message, attachments); + this.timestamp = timestamp; + this.sender = sender; + this.groupId = groupId; + this.message = message; + this.attachments = attachments; + } + + public long getTimestamp() { + return timestamp; + } + + public String getSender() { + return sender; + } + + public byte[] getGroupId() { + return groupId; + } + + public String getMessage() { + return message; + } + + public List getAttachments() { + return attachments; + } + } + + class ReceiptReceived extends DBusSignal { + + private final long timestamp; + private final String sender; + + public ReceiptReceived(String objectpath, long timestamp, String sender) throws DBusException { + super(objectpath, timestamp, sender); + this.timestamp = timestamp; + this.sender = sender; + } + + public long getTimestamp() { + return timestamp; + } + + public String getSender() { + return sender; + } + } + + class ReceiptReceivedV2 extends DBusSignal { + + private final long timestamp; + private final String sender; + private final String type; + private final Map> extras; + + public ReceiptReceivedV2(String objectpath, long timestamp, String sender, final String type, + final Map> extras) throws DBusException { + super(objectpath, timestamp, sender, type, extras); + this.timestamp = timestamp; + this.sender = sender; + this.type = type; + this.extras = extras; + } + + public long getTimestamp() { + return timestamp; + } + + public String getSender() { + return sender; + } + + public String getReceiptType() { + return type; + } + + public Map> getExtras() { + return extras; + } + } + + class SyncMessageReceived extends DBusSignal { + + private final long timestamp; + private final String source; + private final String destination; + private final byte[] groupId; + private final String message; + private final List attachments; + + public SyncMessageReceived(String objectpath, long timestamp, String source, String destination, byte[] groupId, + String message, List attachments) throws DBusException { + super(objectpath, timestamp, source, destination, groupId, message, attachments); + this.timestamp = timestamp; + this.source = source; + this.destination = destination; + this.groupId = groupId; + this.message = message; + this.attachments = attachments; + } + + public long getTimestamp() { + return timestamp; + } + + public String getSource() { + return source; + } + + public String getDestination() { + return destination; + } + + public byte[] getGroupId() { + return groupId; + } + + public String getMessage() { + return message; + } + + public List getAttachments() { + return attachments; + } + } + + class SyncMessageReceivedV2 extends DBusSignal { + + private final long timestamp; + private final String source; + private final String destination; + private final byte[] groupId; + private final String message; + private final Map> extras; + + public SyncMessageReceivedV2(String objectpath, long timestamp, String source, String destination, + byte[] groupId, String message, final Map> extras) throws DBusException { + super(objectpath, timestamp, source, destination, groupId, message, extras); + this.timestamp = timestamp; + this.source = source; + this.destination = destination; + this.groupId = groupId; + this.message = message; + this.extras = extras; + } + + public long getTimestamp() { + return timestamp; + } + + public String getSource() { + return source; + } + + public String getDestination() { + return destination; + } + + public byte[] getGroupId() { + return groupId; + } + + public String getMessage() { + return message; + } + + public Map> getExtras() { + return extras; + } + } + + class StructDevice extends Struct { + + @Position(0) + final DBusPath objectPath; + + @Position(1) + final Long id; + + @Position(2) + final String name; + + public StructDevice(final DBusPath objectPath, final Long id, final String name) { + this.objectPath = objectPath; + this.id = id; + this.name = name; + } + + public DBusPath getObjectPath() { + return objectPath; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + } + + @DBusProperty(name = "Id", type = Integer.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Name", type = String.class) + @DBusProperty(name = "Created", type = String.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "LastSeen", type = String.class, access = DBusProperty.Access.READ) + interface Device extends DBusInterface, Properties { + + void removeDevice() throws Error.Failure; + } + + @DBusProperty(name = "ReadReceipts", type = Boolean.class) + @DBusProperty(name = "UnidentifiedDeliveryIndicators", type = Boolean.class) + @DBusProperty(name = "TypingIndicators", type = Boolean.class) + @DBusProperty(name = "LinkPreviews", type = Boolean.class) + interface Configuration extends DBusInterface, Properties { + } + + class StructGroup extends Struct { + + @Position(0) + final DBusPath objectPath; + + @Position(1) + final byte[] id; + + @Position(2) + final String name; + + public StructGroup(final DBusPath objectPath, final byte[] id, final String name) { + this.objectPath = objectPath; + this.id = id; + this.name = name; + } - @Position(0) - final DBusPath objectPath; + public DBusPath getObjectPath() { + return objectPath; + } - @Position(1) - final String uuid; + public byte[] getId() { + return id; + } - @Position(2) - final String number; + public String getName() { + return name; + } + } - public StructIdentity(final DBusPath objectPath, final String uuid, final String number) { - this.objectPath = objectPath; - this.uuid = uuid; - this.number = number; - } + @DBusProperty(name = "Id", type = Byte[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Name", type = String.class) + @DBusProperty(name = "Description", type = String.class) + @DBusProperty(name = "Avatar", type = String.class, access = DBusProperty.Access.WRITE) + @DBusProperty(name = "IsBlocked", type = Boolean.class) + @DBusProperty(name = "IsMember", type = Boolean.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "IsAdmin", type = Boolean.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "MessageExpirationTimer", type = Integer.class) + @DBusProperty(name = "Members", type = String[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "PendingMembers", type = String[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "RequestingMembers", type = String[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Admins", type = String[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Banned", type = String[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "PermissionAddMember", type = String.class) + @DBusProperty(name = "PermissionEditDetails", type = String.class) + @DBusProperty(name = "PermissionSendMessage", type = String.class) + @DBusProperty(name = "GroupInviteLink", type = String.class, access = DBusProperty.Access.READ) + interface Group extends DBusInterface, Properties { - public DBusPath getObjectPath() { - return objectPath; - } + void quitGroup() throws Error.Failure, Error.LastGroupAdmin; - public String getUuid() { - return uuid; - } + void deleteGroup() throws Error.Failure; - public String getNumber() { - return number; - } - } + void addMembers(List recipients) throws Error.Failure; - @DBusProperty(name = "Number", type = String.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Uuid", type = String.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "Fingerprint", type = Byte[].class, access = DBusProperty.Access.READ) - @DBusProperty(name = "SafetyNumber", type = String.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "TrustLevel", type = String.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "AddedDate", type = Long.class, access = DBusProperty.Access.READ) - @DBusProperty(name = "ScannableSafetyNumber", type = Byte[].class, access = DBusProperty.Access.READ) - interface Identity extends DBusInterface, Properties { + void removeMembers(List recipients) throws Error.Failure; - void trust() throws Error.Failure; + void addAdmins(List recipients) throws Error.Failure; - void trustVerified(String safetyNumber) throws Error.Failure; - } + void removeAdmins(List recipients) throws Error.Failure; - interface Error { + void resetLink() throws Error.Failure; - class AttachmentInvalid extends DBusExecutionException { + void disableLink() throws Error.Failure; - public AttachmentInvalid(final String message) { - super("Invalid attachment: " + message); - } - } + void enableLink(boolean requiresApproval) throws Error.Failure; + } - class InvalidUri extends DBusExecutionException { + class StructIdentity extends Struct { - public InvalidUri(final String message) { - super("Invalid uri: " + message); - } - } + @Position(0) + final DBusPath objectPath; - class Failure extends DBusExecutionException { + @Position(1) + final String uuid; - public Failure(final Exception e) { - super("Failure: " + e.getMessage() + " (" + e.getClass().getSimpleName() + ")"); - } + @Position(2) + final String number; - public Failure(final String message) { - super("Failure: " + message); - } - } + public StructIdentity(final DBusPath objectPath, final String uuid, final String number) { + this.objectPath = objectPath; + this.uuid = uuid; + this.number = number; + } - class DeviceNotFound extends DBusExecutionException { + public DBusPath getObjectPath() { + return objectPath; + } - public DeviceNotFound(final String message) { - super("Device not found: " + message); - } - } + public String getUuid() { + return uuid; + } - class GroupNotFound extends DBusExecutionException { + public String getNumber() { + return number; + } + } - public GroupNotFound(final String message) { - super("Group not found: " + message); - } - } + @DBusProperty(name = "Number", type = String.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Uuid", type = String.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "Fingerprint", type = Byte[].class, access = DBusProperty.Access.READ) + @DBusProperty(name = "SafetyNumber", type = String.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "TrustLevel", type = String.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "AddedDate", type = Long.class, access = DBusProperty.Access.READ) + @DBusProperty(name = "ScannableSafetyNumber", type = Byte[].class, access = DBusProperty.Access.READ) + interface Identity extends DBusInterface, Properties { - class NotAGroupMember extends DBusExecutionException { + void trust() throws Error.Failure; - public NotAGroupMember(final String message) { - super("Not a group member: " + message); - } - } + void trustVerified(String safetyNumber) throws Error.Failure; + } - class InvalidGroupId extends DBusExecutionException { + interface Error { - public InvalidGroupId(final String message) { - super("Invalid group id: " + message); - } - } + class AttachmentInvalid extends DBusExecutionException { - class LastGroupAdmin extends DBusExecutionException { + public AttachmentInvalid(final String message) { + super("Invalid attachment: " + message); + } + } - public LastGroupAdmin(final String message) { - super("Last group admin: " + message); - } - } + class InvalidUri extends DBusExecutionException { - class InvalidNumber extends DBusExecutionException { + public InvalidUri(final String message) { + super("Invalid uri: " + message); + } + } - public InvalidNumber(final String message) { - super("Invalid number: " + message); - } - } + class Failure extends DBusExecutionException { - class UntrustedIdentity extends DBusExecutionException { + public Failure(final Exception e) { + super("Failure: " + e.getMessage() + " (" + e.getClass().getSimpleName() + ")"); + } - public UntrustedIdentity(final String message) { - super("Untrusted identity: " + message); - } - } + public Failure(final String message) { + super("Failure: " + message); + } + } - class UnregisteredRecipient extends DBusExecutionException { + class DeviceNotFound extends DBusExecutionException { + + public DeviceNotFound(final String message) { + super("Device not found: " + message); + } + } + + class GroupNotFound extends DBusExecutionException { + + public GroupNotFound(final String message) { + super("Group not found: " + message); + } + } + + class NotAGroupMember extends DBusExecutionException { + + public NotAGroupMember(final String message) { + super("Not a group member: " + message); + } + } + + class InvalidGroupId extends DBusExecutionException { + + public InvalidGroupId(final String message) { + super("Invalid group id: " + message); + } + } + + class LastGroupAdmin extends DBusExecutionException { + + public LastGroupAdmin(final String message) { + super("Last group admin: " + message); + } + } + + class InvalidNumber extends DBusExecutionException { + + public InvalidNumber(final String message) { + super("Invalid number: " + message); + } + } + + class UntrustedIdentity extends DBusExecutionException { + + public UntrustedIdentity(final String message) { + super("Untrusted identity: " + message); + } + } + + class UnregisteredRecipient extends DBusExecutionException { + + public UnregisteredRecipient(final String message) { + super("Unregistered recipient: " + message); + } + } + } - public UnregisteredRecipient(final String message) { - super("Unregistered recipient: " + message); - } - } - } } diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index 9ae3001a..0397659d 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -420,6 +420,16 @@ public class DbusManagerImpl implements Manager { groupId -> signal.sendGroupMessage(message.messageText(), message.attachments(), groupId)); } + @Override + public SendMessageResults sendStoryMessage( + final Message message, final Set recipients, final boolean notifySelf + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { + return handleMessage(recipients, + numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers), + () -> signal.sendNoteToSelfMessage(message.messageText(), message.attachments()), + groupId -> signal.sendStoryMessage(message.messageText(), message.attachments(), groupId)); + } + @Override public SendMessageResults sendEditMessage( final Message message, final Set recipients, final long editTargetTimestamp diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 1b8b7825..13e85508 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -459,6 +459,31 @@ public class DbusSignalImpl implements Signal, AutoCloseable { } } + @Override + public long sendStoryMessage(final String messageText, final List attachments, final byte[] groupId) { + try { + final var message = new Message(messageText, + attachments, + List.of(), + Optional.empty(), + Optional.empty(), + List.of(), + Optional.empty(), + List.of()); + var results = m.sendStoryMessage(message, Set.of(getGroupRecipientIdentifier(groupId)), false); + checkSendMessageResults(results); + return results.timestamp(); + } catch (IOException | InvalidStickerException e) { + throw new Error.Failure(e.getMessage()); + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { + throw new Error.GroupNotFound(e.getMessage()); + } catch (AttachmentInvalidException e) { + throw new Error.AttachmentInvalid(e.getMessage()); + } catch (UnregisteredRecipientException e) { + throw new Error.UntrustedIdentity(e.getSender().getIdentifier() + " is not registered."); + } + } + @Override public void sendGroupTyping( final byte[] groupId, final boolean stop