X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/3666531f8bfe179bdaf5eaa20ffc2ed16e0fcf9b..9741c93ce969a961cb90571b2d7046084a293db3:/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index 320a8533..ea09dba4 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -3,17 +3,38 @@ package org.asamk.signal.dbus; import org.asamk.Signal; import org.asamk.signal.DbusConfig; import org.asamk.signal.manager.Manager; +import org.asamk.signal.manager.api.AlreadyReceivingException; import org.asamk.signal.manager.api.AttachmentInvalidException; +import org.asamk.signal.manager.api.CaptchaRequiredException; import org.asamk.signal.manager.api.Configuration; +import org.asamk.signal.manager.api.Contact; import org.asamk.signal.manager.api.Device; +import org.asamk.signal.manager.api.DeviceLinkUrl; import org.asamk.signal.manager.api.Group; +import org.asamk.signal.manager.api.GroupId; +import org.asamk.signal.manager.api.GroupInviteLinkUrl; +import org.asamk.signal.manager.api.GroupNotFoundException; +import org.asamk.signal.manager.api.GroupPermission; +import org.asamk.signal.manager.api.GroupSendingNotAllowedException; import org.asamk.signal.manager.api.Identity; +import org.asamk.signal.manager.api.IdentityVerificationCode; import org.asamk.signal.manager.api.InactiveGroupLinkException; +import org.asamk.signal.manager.api.IncorrectPinException; import org.asamk.signal.manager.api.InvalidDeviceLinkException; +import org.asamk.signal.manager.api.InvalidStickerException; +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.NotMasterDeviceException; +import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException; +import org.asamk.signal.manager.api.NotAGroupMemberException; +import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; +import org.asamk.signal.manager.api.PinLockedException; +import org.asamk.signal.manager.api.RateLimitException; +import org.asamk.signal.manager.api.ReceiveConfig; +import org.asamk.signal.manager.api.Recipient; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; @@ -21,30 +42,22 @@ import org.asamk.signal.manager.api.StickerPack; import org.asamk.signal.manager.api.StickerPackInvalidException; import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; +import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.api.UpdateProfile; import org.asamk.signal.manager.api.UserStatus; -import org.asamk.signal.manager.groups.GroupId; -import org.asamk.signal.manager.groups.GroupInviteLinkUrl; -import org.asamk.signal.manager.groups.GroupNotFoundException; -import org.asamk.signal.manager.groups.GroupPermission; -import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; -import org.asamk.signal.manager.groups.LastGroupAdminException; -import org.asamk.signal.manager.groups.NotAGroupMemberException; -import org.asamk.signal.manager.storage.recipients.Contact; -import org.asamk.signal.manager.storage.recipients.Profile; -import org.asamk.signal.manager.storage.recipients.Recipient; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.freedesktop.dbus.DBusMap; import org.freedesktop.dbus.DBusPath; import org.freedesktop.dbus.connections.impl.DBusConnection; import org.freedesktop.dbus.exceptions.DBusException; +import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.freedesktop.dbus.interfaces.DBusInterface; import org.freedesktop.dbus.interfaces.DBusSigHandler; import org.freedesktop.dbus.types.Variant; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; @@ -57,6 +70,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.function.Supplier; @@ -76,6 +90,7 @@ public class DbusManagerImpl implements Manager { private final Set messageHandlers = new HashSet<>(); private final List closedListeners = new ArrayList<>(); private DBusSigHandler dbusMsgHandler; + private DBusSigHandler dbusEditMsgHandler; private DBusSigHandler dbusRcptHandler; private DBusSigHandler dbusSyncHandler; @@ -123,7 +138,7 @@ public class DbusManagerImpl implements Manager { } @Override - public void updateConfiguration(Configuration newConfiguration) throws IOException { + public void updateConfiguration(Configuration newConfiguration) { final var configuration = getRemoteObject(new DBusPath(signal.getObjectPath() + "/Configuration"), Signal.Configuration.class); newConfiguration.readReceipts() @@ -144,10 +159,34 @@ public class DbusManagerImpl implements Manager { emptyIfNull(updateProfile.getFamilyName()), emptyIfNull(updateProfile.getAbout()), emptyIfNull(updateProfile.getAboutEmoji()), - updateProfile.getAvatar() == null ? "" : updateProfile.getAvatar().getPath(), + updateProfile.getAvatar() == null ? "" : updateProfile.getAvatar(), updateProfile.isDeleteAvatar()); } + @Override + public String setUsername(final String username) throws IOException, InvalidUsernameException { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteUsername() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void startChangeNumber( + final String newNumber, final boolean voiceVerification, final String captcha + ) throws RateLimitException, IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException { + throw new UnsupportedOperationException(); + } + + @Override + public void finishChangeNumber( + final String newNumber, final String verificationCode, final String pin + ) throws IncorrectPinException, PinLockedException, IOException { + throw new UnsupportedOperationException(); + } + @Override public void unregister() throws IOException { signal.unregister(); @@ -184,8 +223,8 @@ public class DbusManagerImpl implements Manager { } @Override - public void addDeviceLink(final URI linkUri) throws IOException, InvalidDeviceLinkException { - signal.addDevice(linkUri.toString()); + public void addDeviceLink(final DeviceLinkUrl linkUri) throws IOException, InvalidDeviceLinkException { + signal.addDevice(linkUri.createDeviceLinkUri().toString()); } @Override @@ -197,11 +236,6 @@ public class DbusManagerImpl implements Manager { } } - @Override - public Profile getRecipientProfile(final RecipientIdentifier.Single recipient) { - throw new UnsupportedOperationException(); - } - @Override public List getGroups() { final var groups = signal.listGroups(); @@ -212,11 +246,19 @@ public class DbusManagerImpl implements Manager { public SendGroupMessageResults quitGroup( final GroupId groupId, final Set groupAdmins ) throws GroupNotFoundException, IOException, NotAGroupMemberException, LastGroupAdminException { - if (groupAdmins.size() > 0) { + if (!groupAdmins.isEmpty()) { throw new UnsupportedOperationException(); } final var group = getRemoteObject(signal.getGroup(groupId.serialize()), Signal.Group.class); - group.quitGroup(); + try { + group.quitGroup(); + } catch (Signal.Error.GroupNotFound e) { + throw new GroupNotFoundException(groupId); + } catch (Signal.Error.NotAGroupMember e) { + throw new NotAGroupMemberException(groupId, group.Get("org.asamk.Signal.Group", "Name")); + } catch (Signal.Error.LastGroupAdmin e) { + throw new LastGroupAdminException(groupId, group.Get("org.asamk.Signal.Group", "Name")); + } return new SendGroupMessageResults(0, List.of()); } @@ -228,11 +270,11 @@ public class DbusManagerImpl implements Manager { @Override public Pair createGroup( - final String name, final Set members, final File avatarFile + final String name, final Set members, final String avatarFile ) throws IOException, AttachmentInvalidException { final var newGroupId = signal.createGroup(emptyIfNull(name), members.stream().map(RecipientIdentifier.Single::getIdentifier).toList(), - avatarFile == null ? "" : avatarFile.getPath()); + avatarFile == null ? "" : avatarFile); return new Pair<>(GroupId.unknownVersion(newGroupId), new SendGroupMessageResults(0, List.of())); } @@ -250,7 +292,7 @@ public class DbusManagerImpl implements Manager { if (updateGroup.getAvatarFile() != null) { group.Set("org.asamk.Signal.Group", "Avatar", - updateGroup.getAvatarFile() == null ? "" : updateGroup.getAvatarFile().getPath()); + updateGroup.getAvatarFile() == null ? "" : updateGroup.getAvatarFile()); } if (updateGroup.getExpirationTimer() != null) { group.Set("org.asamk.Signal.Group", "MessageExpirationTimer", updateGroup.getExpirationTimer()); @@ -301,8 +343,13 @@ public class DbusManagerImpl implements Manager { @Override public Pair joinGroup(final GroupInviteLinkUrl inviteLinkUrl) throws IOException, InactiveGroupLinkException { - final var newGroupId = signal.joinGroup(inviteLinkUrl.getUrl()); - return new Pair<>(GroupId.unknownVersion(newGroupId), new SendGroupMessageResults(0, List.of())); + try { + final var newGroupId = signal.joinGroup(inviteLinkUrl.getUrl()); + return new Pair<>(GroupId.unknownVersion(newGroupId), new SendGroupMessageResults(0, List.of())); + } catch (DBusExecutionException e) { + throw new IOException("Failed to join group: " + e.getMessage() + " (" + e.getClass().getSimpleName() + ")", + e); + } } @Override @@ -347,6 +394,13 @@ public class DbusManagerImpl implements Manager { groupId -> signal.sendGroupMessage(message.messageText(), message.attachments(), groupId)); } + @Override + public SendMessageResults sendEditMessage( + final Message message, final Set recipients, final long editTargetTimestamp + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException { + throw new UnsupportedOperationException(); + } + @Override public SendMessageResults sendRemoteDeleteMessage( final long targetSentTimestamp, final Set recipients @@ -363,7 +417,8 @@ public class DbusManagerImpl implements Manager { final boolean remove, final RecipientIdentifier.Single targetAuthor, final long targetSentTimestamp, - final Set recipients + final Set recipients, + final boolean isStory ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { return handleMessage(recipients, numbers -> signal.sendMessageReaction(emoji, @@ -387,7 +442,8 @@ public class DbusManagerImpl implements Manager { public SendMessageResults sendPaymentNotificationMessage( final byte[] receipt, final String note, final RecipientIdentifier.Single recipient ) throws IOException { - throw new UnsupportedOperationException(); + final var timestamp = signal.sendPaymentNotification(receipt, note, recipient.getIdentifier()); + return new SendMessageResults(timestamp, Map.of()); } @Override @@ -408,15 +464,15 @@ public class DbusManagerImpl implements Manager { @Override public void setContactName( - final RecipientIdentifier.Single recipient, final String name - ) throws NotMasterDeviceException { - signal.setContactName(recipient.getIdentifier(), name); + final RecipientIdentifier.Single recipient, final String givenName, final String familyName + ) throws NotPrimaryDeviceException { + signal.setContactName(recipient.getIdentifier(), givenName); } @Override public void setContactsBlocked( final Collection recipients, final boolean blocked - ) throws NotMasterDeviceException, IOException { + ) throws NotPrimaryDeviceException, IOException { for (final var recipient : recipients) { signal.setContactBlocked(recipient.getIdentifier(), blocked); } @@ -452,6 +508,11 @@ public class DbusManagerImpl implements Manager { } } + @Override + public void installStickerPack(final StickerPackUrl url) throws IOException { + throw new UnsupportedOperationException(); + } + @Override public List getStickerPacks() { throw new UnsupportedOperationException(); @@ -468,7 +529,7 @@ public class DbusManagerImpl implements Manager { if (isWeakListener) { weakHandlers.add(handler); } else { - if (messageHandlers.size() == 0) { + if (messageHandlers.isEmpty()) { installMessageHandlers(); } messageHandlers.add(handler); @@ -481,7 +542,7 @@ public class DbusManagerImpl implements Manager { synchronized (messageHandlers) { weakHandlers.remove(handler); messageHandlers.remove(handler); - if (messageHandlers.size() == 0) { + if (messageHandlers.isEmpty()) { uninstallMessageHandlers(); } } @@ -490,53 +551,71 @@ public class DbusManagerImpl implements Manager { @Override public boolean isReceiving() { synchronized (messageHandlers) { - return messageHandlers.size() > 0; + return !messageHandlers.isEmpty(); } } - @Override - public void receiveMessages(final ReceiveMessageHandler handler) throws IOException { - addReceiveHandler(handler); - try { - synchronized (this) { - this.wait(); - } - } catch (InterruptedException ignored) { - } - removeReceiveHandler(handler); - } + private Thread receiveThread; @Override public void receiveMessages( - final Duration timeout, final ReceiveMessageHandler handler - ) throws IOException { + Optional timeout, Optional maxMessages, ReceiveMessageHandler handler + ) throws IOException, AlreadyReceivingException { + if (receiveThread != null) { + throw new AlreadyReceivingException("Already receiving message."); + } + receiveThread = Thread.currentThread(); + + final var remainingMessages = new AtomicInteger(maxMessages.orElse(-1)); final var lastMessage = new AtomicLong(System.currentTimeMillis()); + final var thread = Thread.currentThread(); final ReceiveMessageHandler receiveHandler = (envelope, e) -> { lastMessage.set(System.currentTimeMillis()); handler.handleMessage(envelope, e); + if (remainingMessages.get() > 0) { + if (remainingMessages.decrementAndGet() <= 0) { + remainingMessages.set(0); + thread.interrupt(); + } + } }; addReceiveHandler(receiveHandler); - while (true) { - try { - final var sleepTimeRemaining = timeout.toMillis() - (System.currentTimeMillis() - lastMessage.get()); - if (sleepTimeRemaining < 0) { + if (timeout.isPresent()) { + while (remainingMessages.get() != 0) { + try { + final var passedTime = System.currentTimeMillis() - lastMessage.get(); + final var sleepTimeRemaining = timeout.get().toMillis() - passedTime; + if (sleepTimeRemaining < 0) { + break; + } + Thread.sleep(sleepTimeRemaining); + } catch (InterruptedException ignored) { break; } - Thread.sleep(sleepTimeRemaining); + } + } else { + try { + synchronized (this) { + this.wait(); + } } catch (InterruptedException ignored) { } } + removeReceiveHandler(receiveHandler); + receiveThread = null; } @Override - public void setIgnoreAttachments(final boolean ignoreAttachments) { + public void stopReceiveMessages() { + if (receiveThread != null) { + receiveThread.interrupt(); + } } @Override - public boolean hasCaughtUpWithOldMessages() { - return true; + public void setReceiveConfig(final ReceiveConfig receiveConfig) { } @Override @@ -566,7 +645,7 @@ public class DbusManagerImpl implements Manager { return null; } final var contactName = signal.getContactName(n); - if (onlyContacts && contactName.length() == 0) { + if (onlyContacts && contactName.isEmpty()) { return null; } if (name.isPresent() && !name.get().equals(contactName)) { @@ -574,7 +653,7 @@ public class DbusManagerImpl implements Manager { } return Recipient.newBuilder() .withAddress(new RecipientAddress(null, n)) - .withContact(new Contact(contactName, null, 0, contactBlocked, false, false)) + .withContact(new Contact(contactName, null, null, 0, contactBlocked, false, false)) .build(); }).filter(Objects::nonNull).toList(); } @@ -637,20 +716,8 @@ public class DbusManagerImpl implements Manager { } @Override - public boolean trustIdentityVerified(final RecipientIdentifier.Single recipient, final byte[] fingerprint) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean trustIdentityVerifiedSafetyNumber( - final RecipientIdentifier.Single recipient, final String safetyNumber - ) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean trustIdentityVerifiedSafetyNumber( - final RecipientIdentifier.Single recipient, final byte[] safetyNumber + public boolean trustIdentityVerified( + final RecipientIdentifier.Single recipient, final IdentityVerificationCode verificationCode ) { throw new UnsupportedOperationException(); } @@ -677,7 +744,7 @@ public class DbusManagerImpl implements Manager { this.notify(); } synchronized (messageHandlers) { - if (messageHandlers.size() > 0) { + if (!messageHandlers.isEmpty()) { uninstallMessageHandlers(); } weakHandlers.clear(); @@ -701,7 +768,7 @@ public class DbusManagerImpl implements Manager { .map(RecipientIdentifier.Single.class::cast) .map(RecipientIdentifier.Single::getIdentifier) .toList(); - if (singleRecipients.size() > 0) { + if (!singleRecipients.isEmpty()) { timestamp = recipientsHandler.apply(singleRecipients); } @@ -750,12 +817,14 @@ public class DbusManagerImpl implements Manager { messageReceived.getGroupId()), false, 0)) : Optional.empty(), Optional.empty(), + Optional.empty(), Optional.of(messageReceived.getMessage()), 0, false, false, false, false, + false, Optional.empty(), Optional.empty(), Optional.empty(), @@ -764,12 +833,58 @@ public class DbusManagerImpl implements Manager { Optional.empty(), List.of(), List.of(), + List.of(), List.of())), Optional.empty(), + Optional.empty(), + Optional.empty(), Optional.empty()); notifyMessageHandlers(envelope); }; connection.addSigHandler(Signal.MessageReceivedV2.class, signal, this.dbusMsgHandler); + this.dbusEditMsgHandler = messageReceived -> { + final var extras = messageReceived.getExtras(); + final var envelope = new MessageEnvelope(Optional.of(new RecipientAddress(null, + messageReceived.getSender())), + 0, + messageReceived.getTimestamp(), + 0, + 0, + false, + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.of(new MessageEnvelope.Edit(messageReceived.getTargetSentTimestamp(), + new MessageEnvelope.Data(messageReceived.getTimestamp(), + messageReceived.getGroupId().length > 0 + ? Optional.of(new MessageEnvelope.Data.GroupContext(GroupId.unknownVersion( + messageReceived.getGroupId()), false, 0)) + : Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.of(messageReceived.getMessage()), + 0, + false, + false, + false, + false, + false, + Optional.empty(), + Optional.empty(), + Optional.empty(), + getAttachments(extras), + Optional.empty(), + Optional.empty(), + List.of(), + List.of(), + List.of(), + List.of()))), + Optional.empty(), + Optional.empty(), + Optional.empty()); + notifyMessageHandlers(envelope); + }; + connection.addSigHandler(Signal.EditMessageReceived.class, signal, this.dbusEditMsgHandler); this.dbusRcptHandler = receiptReceived -> { final var type = switch (receiptReceived.getReceiptType()) { @@ -791,6 +906,8 @@ public class DbusManagerImpl implements Manager { Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), + Optional.empty(), Optional.empty()); notifyMessageHandlers(envelope); }; @@ -808,6 +925,7 @@ public class DbusManagerImpl implements Manager { Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.of(new MessageEnvelope.Sync(Optional.of(new MessageEnvelope.Sync.Sent(syncReceived.getTimestamp(), syncReceived.getTimestamp(), syncReceived.getDestination().isEmpty() @@ -820,12 +938,14 @@ public class DbusManagerImpl implements Manager { syncReceived.getGroupId()), false, 0)) : Optional.empty(), Optional.empty(), + Optional.empty(), Optional.of(syncReceived.getMessage()), 0, false, false, false, false, + false, Optional.empty(), Optional.empty(), Optional.empty(), @@ -834,7 +954,10 @@ public class DbusManagerImpl implements Manager { Optional.empty(), List.of(), List.of(), - List.of())))), + List.of(), + List.of())), + Optional.empty(), + Optional.empty())), Optional.empty(), List.of(), List.of(), @@ -842,12 +965,13 @@ public class DbusManagerImpl implements Manager { Optional.empty(), Optional.empty(), Optional.empty())), + Optional.empty(), Optional.empty()); notifyMessageHandlers(envelope); }; connection.addSigHandler(Signal.SyncMessageReceivedV2.class, signal, this.dbusSyncHandler); } catch (DBusException e) { - e.printStackTrace(); + throw new RuntimeException(e); } signal.subscribeReceive(); } @@ -863,10 +987,11 @@ public class DbusManagerImpl implements Manager { try { signal.unsubscribeReceive(); connection.removeSigHandler(Signal.MessageReceivedV2.class, signal, this.dbusMsgHandler); + connection.removeSigHandler(Signal.EditMessageReceived.class, signal, this.dbusEditMsgHandler); connection.removeSigHandler(Signal.ReceiptReceivedV2.class, signal, this.dbusRcptHandler); connection.removeSigHandler(Signal.SyncMessageReceivedV2.class, signal, this.dbusSyncHandler); } catch (DBusException e) { - e.printStackTrace(); + throw new RuntimeException(e); } } @@ -897,6 +1022,11 @@ public class DbusManagerImpl implements Manager { }).toList(); } + @Override + public InputStream retrieveAttachment(final String id) throws IOException { + throw new UnsupportedOperationException(); + } + @SuppressWarnings("unchecked") private T getValue( final Map> stringVariantMap, final String field