/**
  * Construct a TextSecureAccountManager.
  *
  * @param url The URL for the TextSecure server.
  * @param trustStore The {@link org.whispersystems.textsecure.api.push.TrustStore} for the TextSecure server's TLS certificate.
  * @param user A TextSecure phone number.
  * @param password A TextSecure password.
  */
 public TextSecureAccountManager(String url, TrustStore trustStore,
                                 String user, String password, string userAgent)
 {
     this.pushServiceSocket = new PushServiceSocket(url, trustStore, new StaticCredentialsProvider(user, password, null), userAgent);
     this.user = user;
     this.userAgent = userAgent;
 }
 /**
  * Construct a TextSecureMessageReceiver.
  *
  * @param url The URL of the TextSecure server.
  * @param trustStore The {@link org.whispersystems.textsecure.api.push.TrustStore} containing
  *                   the server's TLS signing certificate.
  * @param credentials The TextSecure user's credentials.
  */
 public TextSecureMessageReceiver(String url, TrustStore trustStore, CredentialsProvider credentials, string userAgent)
 {
     this.url = url;
     this.trustStore = trustStore;
     this.credentialsProvider = credentials;
     this.socket = new PushServiceSocket(url, trustStore, credentials, userAgent);
     this.userAgent = userAgent;
 }
 /**
  * Construct a TextSecureMessageSender.
  *
  * @param url The URL of the TextSecure server.
  * @param trustStore The trust store containing the TextSecure server's signing TLS certificate.
  * @param user The TextSecure username (eg phone number).
  * @param password The TextSecure user's password.
  * @param store The AxolotlStore.
  * @param eventListener An optional event listener, which fires whenever sessions are
  *                      setup or torn down for a recipient.
  */
 public TextSecureMessageSender(String url, TrustStore trustStore,
                                String user, String password,
                                AxolotlStore store,
                                May<EventListener> eventListener, String userAgent)
 {
     this.socket = new PushServiceSocket(url, trustStore, new StaticCredentialsProvider(user, password, null), userAgent);
     this.store = store;
     this.localAddress = new TextSecureAddress(user);
     this.eventListener = eventListener;
 }
        private async void handleMismatchedDevices(PushServiceSocket socket, TextSecureAddress recipient,
                                           MismatchedDevices mismatchedDevices)
        {
            try
            {
                foreach (uint extraDeviceId in mismatchedDevices.getExtraDevices())
                {
                    store.DeleteSession(new AxolotlAddress(recipient.getNumber(), extraDeviceId));
                }

                foreach (uint missingDeviceId in mismatchedDevices.getMissingDevices())
                {
                    PreKeyBundle preKey = await socket.getPreKey(recipient, missingDeviceId);

                    try
                    {
                        SessionBuilder sessionBuilder = new SessionBuilder(store, new AxolotlAddress(recipient.getNumber(), missingDeviceId));
                        sessionBuilder.process(preKey);
                    }
                    catch (libaxolotl.exceptions.UntrustedIdentityException e)
                    {
                        throw new UntrustedIdentityException("Untrusted identity key!", recipient.getNumber(), preKey.getIdentityKey());
                    }
                }
            }
            catch (InvalidKeyException e)
            {
                throw new Exception(e.Message);
            }
        }
        private OutgoingPushMessage getEncryptedMessage(PushServiceSocket socket, TextSecureAddress recipient, uint deviceId, byte[] plaintext, bool legacy)
        {
            AxolotlAddress axolotlAddress = new AxolotlAddress(recipient.getNumber(), deviceId);
            TextSecureCipher cipher = new TextSecureCipher(localAddress, store);

            if (!store.ContainsSession(axolotlAddress))
            {
                try
                {
                    List<PreKeyBundle> preKeys = socket.getPreKeys(recipient, deviceId).Result;

                    foreach (PreKeyBundle preKey in preKeys)
                    {
                        try
                        {
                            AxolotlAddress preKeyAddress = new AxolotlAddress(recipient.getNumber(), preKey.getDeviceId());
                            SessionBuilder sessionBuilder = new SessionBuilder(store, preKeyAddress);
                            sessionBuilder.process(preKey);
                        }
                        catch (libaxolotl.exceptions.UntrustedIdentityException e)
                        {
                            throw new UntrustedIdentityException("Untrusted identity key!", recipient.getNumber(), preKey.getIdentityKey());
                        }
                    }

                    if (eventListener.HasValue)
                    {
                        eventListener.ForceGetValue().onSecurityEvent(recipient);
                    }
                }
                catch (InvalidKeyException e)
                {
                    throw new Exception(e.Message);
                }
            }

            return cipher.encrypt(axolotlAddress, plaintext, legacy);
        }
        private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket,
                                                   TextSecureAddress recipient,
                                                   ulong timestamp,
                                                   byte[] plaintext,
                                                   bool legacy)
        {
            List<OutgoingPushMessage> messages = new List<OutgoingPushMessage>();

            if (!recipient.Equals(localAddress))
            {
                messages.Add(getEncryptedMessage(socket, recipient, TextSecureAddress.DEFAULT_DEVICE_ID, plaintext, legacy));
            }

            foreach (uint deviceId in store.GetSubDeviceSessions(recipient.getNumber()))
            {
                messages.Add(getEncryptedMessage(socket, recipient, deviceId, plaintext, legacy));
            }

            return new OutgoingPushMessageList(recipient.getNumber(), timestamp, recipient.getRelay().HasValue ? recipient.getRelay().ForceGetValue() : null, messages);
        }