]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java
Add command to delete local account data
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / ManagerImpl.java
index 992dfb8bba0d2d1aa7d83f950a56f61b5334e196..fa041c55d4898666b01d7b05cfa5064e772f4c38 100644 (file)
@@ -62,11 +62,11 @@ import org.asamk.signal.manager.util.KeyUtils;
 import org.asamk.signal.manager.util.StickerUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.SignalSessionLock;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
+import org.whispersystems.signalservice.api.push.ACI;
 import org.whispersystems.signalservice.api.util.DeviceNameUtil;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
@@ -82,6 +82,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ExecutorService;
@@ -99,6 +100,7 @@ class ManagerImpl implements Manager {
     private final static Logger logger = LoggerFactory.getLogger(ManagerImpl.class);
 
     private SignalAccount account;
+    private AccountFileUpdater accountFileUpdater;
     private final SignalDependencies dependencies;
     private final Context context;
 
@@ -109,6 +111,7 @@ class ManagerImpl implements Manager {
     private final Set<ReceiveMessageHandler> weakHandlers = new HashSet<>();
     private final Set<ReceiveMessageHandler> messageHandlers = new HashSet<>();
     private final List<Runnable> closedListeners = new ArrayList<>();
+    private final List<Runnable> addressChangedListeners = new ArrayList<>();
     private final CompositeDisposable disposable = new CompositeDisposable();
 
     ManagerImpl(
@@ -119,6 +122,7 @@ class ManagerImpl implements Manager {
             String userAgent
     ) {
         this.account = account;
+        this.accountFileUpdater = accountFileUpdater;
 
         final var sessionLock = new SignalSessionLock() {
             private final ReentrantLock LEGACY_LOCK = new ReentrantLock();
@@ -132,19 +136,27 @@ class ManagerImpl implements Manager {
         this.dependencies = new SignalDependencies(serviceEnvironmentConfig,
                 userAgent,
                 account.getCredentialsProvider(),
-                account.getSignalProtocolStore(),
+                account.getSignalServiceDataStore(),
                 executor,
                 sessionLock);
         final var avatarStore = new AvatarStore(pathConfig.avatarsPath());
         final var attachmentStore = new AttachmentStore(pathConfig.attachmentsPath());
         final var stickerPackStore = new StickerPackStore(pathConfig.stickerPacksPath());
 
-        this.context = new Context(account,
-                accountFileUpdater,
-                dependencies,
-                avatarStore,
-                attachmentStore,
-                stickerPackStore);
+        this.context = new Context(account, new AccountFileUpdater() {
+            @Override
+            public void updateAccountIdentifiers(final String number, final ACI aci) {
+                accountFileUpdater.updateAccountIdentifiers(number, aci);
+                synchronized (addressChangedListeners) {
+                    addressChangedListeners.forEach(Runnable::run);
+                }
+            }
+
+            @Override
+            public void removeAccount() {
+                accountFileUpdater.removeAccount();
+            }
+        }, dependencies, avatarStore, attachmentStore, stickerPackStore);
         this.context.getAccountHelper().setUnregisteredListener(this::close);
         this.context.getReceiveHelper().setAuthenticationFailureListener(this::close);
         this.context.getReceiveHelper().setCaughtUpWithOldMessagesListener(() -> {
@@ -245,14 +257,9 @@ class ManagerImpl implements Manager {
 
     @Override
     public void setProfile(
-            String givenName, final String familyName, String about, String aboutEmoji, java.util.Optional<File> avatar
+            String givenName, final String familyName, String about, String aboutEmoji, Optional<File> avatar
     ) throws IOException {
-        context.getProfileHelper()
-                .setProfile(givenName,
-                        familyName,
-                        about,
-                        aboutEmoji,
-                        avatar == null ? null : Optional.fromNullable(avatar.orElse(null)));
+        context.getProfileHelper().setProfile(givenName, familyName, about, aboutEmoji, avatar);
         context.getSyncHelper().sendSyncFetchProfileMessage();
     }
 
@@ -277,7 +284,7 @@ class ManagerImpl implements Manager {
     public List<Device> getLinkedDevices() throws IOException {
         var devices = dependencies.getAccountManager().getDevices();
         account.setMultiDevice(devices.size() > 1);
-        var identityKey = account.getIdentityKeyPair().getPrivateKey();
+        var identityKey = account.getAciIdentityKeyPair().getPrivateKey();
         return devices.stream().map(d -> {
             String deviceName = d.getName();
             if (deviceName != null) {
@@ -307,7 +314,7 @@ class ManagerImpl implements Manager {
     }
 
     @Override
-    public void setRegistrationLockPin(java.util.Optional<String> pin) throws IOException, NotMasterDeviceException {
+    public void setRegistrationLockPin(Optional<String> pin) throws IOException, NotMasterDeviceException {
         if (!account.isMasterDevice()) {
             throw new NotMasterDeviceException();
         }
@@ -352,6 +359,11 @@ class ManagerImpl implements Manager {
 
     @Override
     public void deleteGroup(GroupId groupId) throws IOException {
+        final var group = context.getGroupHelper().getGroup(groupId);
+        if (group.isMember(account.getSelfRecipientId())) {
+            throw new IOException(
+                    "The local group information cannot be removed, as the user is still a member of the group");
+        }
         context.getGroupHelper().deleteGroup(groupId);
     }
 
@@ -385,6 +397,12 @@ class ManagerImpl implements Manager {
                         updateGroup.getRemoveAdmins() == null
                                 ? null
                                 : context.getRecipientHelper().resolveRecipients(updateGroup.getRemoveAdmins()),
+                        updateGroup.getBanMembers() == null
+                                ? null
+                                : context.getRecipientHelper().resolveRecipients(updateGroup.getBanMembers()),
+                        updateGroup.getUnbanMembers() == null
+                                ? null
+                                : context.getRecipientHelper().resolveRecipients(updateGroup.getUnbanMembers()),
                         updateGroup.isResetGroupLink(),
                         updateGroup.getGroupLinkState(),
                         updateGroup.getAddMemberPermission(),
@@ -441,7 +459,7 @@ class ManagerImpl implements Manager {
         final var timestamp = System.currentTimeMillis();
         for (var recipient : recipients) {
             if (recipient instanceof RecipientIdentifier.Single single) {
-                final var message = new SignalServiceTypingMessage(action, timestamp, Optional.absent());
+                final var message = new SignalServiceTypingMessage(action, timestamp, Optional.empty());
                 try {
                     final var recipientId = context.getRecipientHelper().resolveRecipient(single);
                     final var result = context.getSendHelper().sendTypingMessage(message, recipientId);
@@ -510,6 +528,11 @@ class ManagerImpl implements Manager {
     public SendMessageResults sendMessage(
             Message message, Set<RecipientIdentifier> recipients
     ) 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 wit the updateProfile command. This may become mandatory in the future.");
+        }
         final var messageBuilder = SignalServiceDataMessage.newBuilder();
         applyMessage(messageBuilder, message);
         return sendMessage(messageBuilder, recipients);
@@ -533,7 +556,8 @@ class ManagerImpl implements Manager {
                             .resolveSignalServiceAddress(context.getRecipientHelper().resolveRecipient(quote.author())),
                     quote.message(),
                     List.of(),
-                    resolveMentions(quote.mentions())));
+                    resolveMentions(quote.mentions()),
+                    SignalServiceDataMessage.Quote.Type.NORMAL));
         }
         if (message.sticker().isPresent()) {
             final var sticker = message.sticker().get();
@@ -557,7 +581,7 @@ class ManagerImpl implements Manager {
                     stickerPack.getPackKey(),
                     stickerId,
                     manifestSticker.emoji(),
-                    AttachmentUtils.createAttachment(streamDetails, Optional.absent())));
+                    AttachmentUtils.createAttachment(streamDetails, Optional.empty())));
         }
     }
 
@@ -567,7 +591,7 @@ class ManagerImpl implements Manager {
             final var recipientId = context.getRecipientHelper().resolveRecipient(m.recipient());
             mentions.add(new SignalServiceDataMessage.Mention(context.getRecipientHelper()
                     .resolveSignalServiceAddress(recipientId)
-                    .getAci(), m.start(), m.length()));
+                    .getServiceId(), m.start(), m.length()));
         }
         return mentions;
     }
@@ -718,7 +742,7 @@ class ManagerImpl implements Manager {
                             pack.isInstalled(),
                             manifest.title(),
                             manifest.author(),
-                            java.util.Optional.ofNullable(manifest.cover() == null ? null : manifest.cover().toApi()),
+                            Optional.ofNullable(manifest.cover() == null ? null : manifest.cover().toApi()),
                             manifest.stickers().stream().map(JsonStickerPack.JsonSticker::toApi).toList());
                 } catch (Exception e) {
                     logger.warn("Failed to read local sticker pack manifest: {}", e.getMessage(), e);
@@ -764,24 +788,17 @@ class ManagerImpl implements Manager {
         }
         receiveThread = new Thread(() -> {
             logger.debug("Starting receiving messages");
-            while (!Thread.interrupted()) {
-                try {
-                    context.getReceiveHelper().receiveMessages(Duration.ofMinutes(1), false, (envelope, e) -> {
-                        synchronized (messageHandlers) {
-                            Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
-                                try {
-                                    h.handleMessage(envelope, e);
-                                } catch (Exception ex) {
-                                    logger.warn("Message handler failed, ignoring", ex);
-                                }
-                            });
+            context.getReceiveHelper().receiveMessagesContinuously((envelope, e) -> {
+                synchronized (messageHandlers) {
+                    Stream.concat(messageHandlers.stream(), weakHandlers.stream()).forEach(h -> {
+                        try {
+                            h.handleMessage(envelope, e);
+                        } catch (Throwable ex) {
+                            logger.warn("Message handler failed, ignoring", ex);
                         }
                     });
-                    break;
-                } catch (IOException e) {
-                    logger.warn("Receiving messages failed, retrying", e);
                 }
-            }
+            });
             logger.debug("Finished receiving messages");
             synchronized (messageHandlers) {
                 receiveThread = null;
@@ -815,7 +832,10 @@ class ManagerImpl implements Manager {
     }
 
     private void stopReceiveThread(final Thread thread) {
-        thread.interrupt();
+        if (context.getReceiveHelper().requestStopReceiveMessages()) {
+            logger.debug("Receive stop requested, interrupting read from server.");
+            thread.interrupt();
+        }
         try {
             thread.join();
         } catch (InterruptedException ignored) {
@@ -998,6 +1018,13 @@ class ManagerImpl implements Manager {
         return updated;
     }
 
+    @Override
+    public void addAddressChangedListener(final Runnable listener) {
+        synchronized (addressChangedListeners) {
+            addressChangedListeners.add(listener);
+        }
+    }
+
     @Override
     public void addClosedListener(final Runnable listener) {
         synchronized (closedListeners) {
@@ -1022,14 +1049,15 @@ class ManagerImpl implements Manager {
         dependencies.getSignalWebSocket().disconnect();
         disposable.dispose();
 
+        if (account != null) {
+            account.close();
+        }
+
         synchronized (closedListeners) {
             closedListeners.forEach(Runnable::run);
             closedListeners.clear();
         }
 
-        if (account != null) {
-            account.close();
-        }
         account = null;
     }
 }