private void handleStaleDevices(TextSecureAddress recipient, StaleDevices staleDevices)
 {
     foreach (uint staleDeviceId in staleDevices.getStaleDevices())
     {
         store.DeleteSession(new AxolotlAddress(recipient.getNumber(), staleDeviceId));
     }
 }
        /**
         * Decrypt a received {@link org.whispersystems.textsecure.api.messages.TextSecureEnvelope}
         *
         * @param envelope The received TextSecureEnvelope
         * @return a decrypted TextSecureMessage
         * @throws InvalidVersionException
         * @throws InvalidMessageException
         * @throws InvalidKeyException
         * @throws DuplicateMessageException
         * @throws InvalidKeyIdException
         * @throws UntrustedIdentityException
         * @throws LegacyMessageException
         * @throws NoSessionException
         */
        public TextSecureContent decrypt(TextSecureEnvelope envelope)
        {
            try
            {
                TextSecureContent content = new TextSecureContent();

                if (envelope.hasLegacyMessage())
                {
                    DataMessage message = DataMessage.ParseFrom(decrypt(envelope, envelope.getLegacyMessage()));
                    content = new TextSecureContent(createTextSecureMessage(envelope, message));
                }
                else if (envelope.hasContent())
                {
                    Content message = Content.ParseFrom(decrypt(envelope, envelope.getContent()));

                    if (message.HasDataMessage)
                    {
                        content = new TextSecureContent(createTextSecureMessage(envelope, message.DataMessage));
                    }
                    else if (message.HasSyncMessage && localAddress.getNumber().Equals(envelope.getSource()))
                    {
                        content = new TextSecureContent(createSynchronizeMessage(envelope, message.SyncMessage));
                    }
                }

                return(content);
            }
            catch (InvalidProtocolBufferException e)
            {
                throw new InvalidMessageException(e);
            }
        }
        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 async Task <OutgoingPushMessageList> getEncryptedMessages(PushServiceSocket socket,
                                                                          TextSecureAddress recipient,
                                                                          ulong timestamp,
                                                                          byte[] plaintext,
                                                                          bool legacy)
        {
            List <OutgoingPushMessage> messages = new List <OutgoingPushMessage>();

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

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

            return(new OutgoingPushMessageList(recipient.getNumber(), timestamp, recipient.getRelay().HasValue ? recipient.getRelay().ForceGetValue() : null, messages));
        }
        private async Task <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 = await socket.getPreKeys(recipient, deviceId);

                    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));
        }
        /**
         * Send a message to a single recipient.
         *
         * @param recipient The message's destination.
         * @param message The message.
         * @throws UntrustedIdentityException
         * @throws IOException
         */
        public async void sendMessage(TextSecureAddress recipient, TextSecureDataMessage message)
        {
            byte[] content = await createMessageContent(message);

            ulong timestamp = message.getTimestamp();
            SendMessageResponse response = await sendMessage(recipient, timestamp, content, true);

            if (response != null && response.getNeedsSync())
            {
                byte[] syncMessage = createMultiDeviceSentTranscriptContent(content, new May <TextSecureAddress>(recipient), timestamp);
                await sendMessage(localAddress, timestamp, syncMessage, false);
            }

            if (message.isEndSession())
            {
                store.DeleteAllSessions(recipient.getNumber());

                if (eventListener.HasValue)
                {
                    eventListener.ForceGetValue().onSecurityEvent(recipient);
                }
            }
        }
 /**
  * Send a delivery receipt for a received message.  It is not necessary to call this
  * when receiving messages through {@link org.whispersystems.textsecure.api.TextSecureMessagePipe}.
  * @param recipient The sender of the received message you're acknowledging.
  * @param messageId The message id of the received message you're acknowledging.
  * @throws IOException
  */
 public void sendDeliveryReceipt(TextSecureAddress recipient, ulong messageId)
 {
     this.socket.sendReceipt(recipient.getNumber(), messageId, recipient.getRelay());
 }