]> nmode's Git Repositories - signal-cli/blobdiff - src/main/java/org/asamk/signal/manager/Manager.java
Add commands to update profile name and avatar
[signal-cli] / src / main / java / org / asamk / signal / manager / Manager.java
index 1b703e4291a838b4454d329c4917458eba45d838..5a26ff56622bec74b45d543f249eb8b67a7981e3 100644 (file)
@@ -54,8 +54,10 @@ import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureExcept
 import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 import org.whispersystems.signalservice.api.util.SleepTimer;
+import org.whispersystems.signalservice.api.util.StreamDetails;
 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
 import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
+import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
 import org.whispersystems.signalservice.internal.util.Base64;
 
 import java.io.*;
@@ -73,16 +75,14 @@ public class Manager implements Signal {
     private final String dataPath;
     private final String attachmentsPath;
     private final String avatarsPath;
+    private final SleepTimer timer = new UptimeSleepTimer();
 
     private SignalAccount account;
-
     private String username;
     private SignalServiceAccountManager accountManager;
     private SignalServiceMessagePipe messagePipe = null;
     private SignalServiceMessagePipe unidentifiedMessagePipe = null;
 
-    private SleepTimer timer = new UptimeSleepTimer();
-
     public Manager(String username, String settingsPath) {
         this.username = username;
         this.settingsPath = settingsPath;
@@ -138,6 +138,7 @@ public class Manager implements Signal {
             }
         } catch (AuthorizationFailedException e) {
             System.err.println("Authorization failed, was the number registered elsewhere?");
+            throw e;
         }
     }
 
@@ -163,6 +164,7 @@ public class Manager implements Signal {
         if (account.getProfileKey() == null) {
             // Old config file, creating new profile key
             account.setProfileKey(KeyUtils.createProfileKey());
+            account.save();
         }
     }
 
@@ -189,10 +191,11 @@ public class Manager implements Signal {
         account.setPassword(KeyUtils.createPassword());
         accountManager = new SignalServiceAccountManager(BaseConfig.serviceConfiguration, account.getUsername(), account.getPassword(), BaseConfig.USER_AGENT, timer);
 
-        if (voiceVerification)
-            accountManager.requestVoiceVerificationCode();
-        else
-            accountManager.requestSmsVerificationCode();
+        if (voiceVerification) {
+            accountManager.requestVoiceVerificationCode(Locale.getDefault(), Optional.<String>absent(), Optional.<String>absent());
+        } else {
+            accountManager.requestSmsVerificationCode(false, Optional.<String>absent(), Optional.<String>absent());
+        }
 
         account.setRegistered(false);
         account.save();
@@ -202,11 +205,22 @@ public class Manager implements Signal {
         accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), getSelfUnidentifiedAccessKey(), false);
     }
 
+    public void setProfileName(String name) throws IOException {
+        accountManager.setProfileName(account.getProfileKey(), name);
+    }
+
+    public void setProfileAvatar(File avatar) throws IOException {
+        accountManager.setProfileAvatar(account.getProfileKey(), Utils.createStreamDetailsFromFile(avatar));
+    }
+
     public void unregister() throws IOException {
         // When setting an empty GCM id, the Signal-Server also sets the fetchesMessages property to false.
         // If this is the master device, other users can't send messages to this number anymore.
         // If this is a linked device, other users can still send messages, but this device doesn't receive them anymore.
         accountManager.setGcmId(Optional.<String>absent());
+
+        account.setRegistered(false);
+        account.save();
     }
 
     public String getDeviceLinkUri() throws TimeoutException, IOException {
@@ -250,11 +264,15 @@ public class Manager implements Signal {
     public List<DeviceInfo> getLinkedDevices() throws IOException {
         List<DeviceInfo> devices = accountManager.getDevices();
         account.setMultiDevice(devices.size() > 1);
+        account.save();
         return devices;
     }
 
     public void removeLinkedDevices(int deviceId) throws IOException {
         accountManager.removeDevice(deviceId);
+        List<DeviceInfo> devices = accountManager.getDevices();
+        account.setMultiDevice(devices.size() > 1);
+        account.save();
     }
 
     public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException {
@@ -269,6 +287,7 @@ public class Manager implements Signal {
 
         accountManager.addDevice(deviceIdentifier, deviceKey, identityKeyPair, Optional.of(account.getProfileKey()), verificationCode);
         account.setMultiDevice(true);
+        account.save();
     }
 
     private List<PreKeyRecord> generatePreKeys() {
@@ -505,8 +524,15 @@ public class Manager implements Signal {
             }
         }
 
-        return SignalServiceDataMessage.newBuilder()
+        SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
                 .asGroupMessage(group.build());
+
+        ThreadInfo thread = account.getThreadStore().getThread(Base64.encodeBytes(g.groupId));
+        if (thread != null) {
+            messageBuilder.withExpiration(thread.messageExpirationTime);
+        }
+
+        return messageBuilder;
     }
 
     private void sendGroupInfoRequest(byte[] groupId, String recipient) throws IOException, EncapsulatedExceptions {
@@ -520,6 +546,11 @@ public class Manager implements Signal {
         SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
                 .asGroupMessage(group.build());
 
+        ThreadInfo thread = account.getThreadStore().getThread(Base64.encodeBytes(groupId));
+        if (thread != null) {
+            messageBuilder.withExpiration(thread.messageExpirationTime);
+        }
+
         // Send group info request message to the recipient who sent us a message with this groupId
         final List<String> membersSend = new ArrayList<>();
         membersSend.add(recipient);
@@ -542,6 +573,7 @@ public class Manager implements Signal {
         if (attachments != null) {
             messageBuilder.withAttachments(Utils.getSignalServiceAttachments(attachments));
         }
+        messageBuilder.withProfileKey(account.getProfileKey());
         sendMessageLegacy(messageBuilder, recipients);
     }
 
@@ -757,7 +789,8 @@ public class Manager implements Signal {
             message = messageBuilder.build();
             if (message.getGroupInfo().isPresent()) {
                 try {
-                    List<SendMessageResult> result = messageSender.sendMessage(new ArrayList<>(recipientsTS), getAccessFor(recipientsTS), message);
+                    final boolean isRecipientUpdate = false;
+                    List<SendMessageResult> result = messageSender.sendMessage(new ArrayList<>(recipientsTS), getAccessFor(recipientsTS), isRecipientUpdate, message);
                     for (SendMessageResult r : result) {
                         if (r.getIdentityFailure() != null) {
                             account.getSignalProtocolStore().saveIdentity(r.getAddress().getNumber(), r.getIdentityFailure().getIdentityKey(), TrustLevel.UNTRUSTED);
@@ -768,6 +801,25 @@ public class Manager implements Signal {
                     account.getSignalProtocolStore().saveIdentity(e.getE164Number(), e.getIdentityKey(), TrustLevel.UNTRUSTED);
                     return Collections.emptyList();
                 }
+            } else if (recipientsTS.size() == 1 && recipientsTS.contains(new SignalServiceAddress(username))) {
+                SignalServiceAddress recipient = new SignalServiceAddress(username);
+                final Optional<UnidentifiedAccessPair> unidentifiedAccess = getAccessFor(recipient);
+                SentTranscriptMessage transcript = new SentTranscriptMessage(recipient.getNumber(),
+                        message.getTimestamp(),
+                        message,
+                        message.getExpiresInSeconds(),
+                        Collections.singletonMap(recipient.getNumber(), unidentifiedAccess.isPresent()),
+                        false);
+                SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forSentTranscript(transcript);
+
+                List<SendMessageResult> results = new ArrayList<>(recipientsTS.size());
+                try {
+                    messageSender.sendMessage(syncMessage, unidentifiedAccess);
+                } catch (UntrustedIdentityException e) {
+                    account.getSignalProtocolStore().saveIdentity(e.getE164Number(), e.getIdentityKey(), TrustLevel.UNTRUSTED);
+                    results.add(SendMessageResult.identityFailure(recipient, e.getIdentityKey()));
+                }
+                return results;
             } else {
                 // Send to all individually, so sync messages are sent correctly
                 List<SendMessageResult> results = new ArrayList<>(recipientsTS.size());
@@ -799,7 +851,7 @@ public class Manager implements Signal {
         }
     }
 
-    private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, ProtocolUntrustedIdentityException, SelfSendException {
+    private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, ProtocolUntrustedIdentityException, SelfSendException, UnsupportedDataMessageException {
         SignalServiceCipher cipher = new SignalServiceCipher(new SignalServiceAddress(username), account.getSignalProtocolStore(), Utils.getCertificateValidator());
         try {
             return cipher.decrypt(envelope);
@@ -1144,6 +1196,10 @@ public class Manager implements Signal {
                                 }
                                 if (c.getExpirationTimer().isPresent()) {
                                     ThreadInfo thread = account.getThreadStore().getThread(c.getNumber());
+                                    if (thread == null) {
+                                        thread = new ThreadInfo();
+                                        thread.id = c.getNumber();
+                                    }
                                     thread.messageExpirationTime = c.getExpirationTimer().get();
                                     account.getThreadStore().updateThread(thread);
                                 }