Search in sources :

Example 11 with SendMessageResult

use of org.whispersystems.signalservice.api.messages.SendMessageResult in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method createMultiDeviceSentTranscriptContent.

private Content createMultiDeviceSentTranscriptContent(Content content, Optional<SignalServiceAddress> recipient, long timestamp, List<SendMessageResult> sendMessageResults, boolean isRecipientUpdate) {
    Content.Builder container = Content.newBuilder();
    SyncMessage.Builder syncMessage = createSyncMessageBuilder();
    SyncMessage.Sent.Builder sentMessage = SyncMessage.Sent.newBuilder();
    DataMessage dataMessage = content.getDataMessage();
    sentMessage.setTimestamp(timestamp);
    sentMessage.setMessage(dataMessage);
    for (SendMessageResult result : sendMessageResults) {
        if (result.getSuccess() != null) {
            SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder builder = SyncMessage.Sent.UnidentifiedDeliveryStatus.newBuilder();
            builder.setDestinationUuid(result.getAddress().getServiceId().toString());
            if (result.getAddress().getNumber().isPresent()) {
                builder.setDestinationE164(result.getAddress().getNumber().get());
            }
            builder.setUnidentified(result.getSuccess().isUnidentified());
            sentMessage.addUnidentifiedStatus(builder.build());
        }
    }
    if (recipient.isPresent()) {
        sentMessage.setDestinationUuid(recipient.get().getServiceId().toString());
        if (recipient.get().getNumber().isPresent()) {
            sentMessage.setDestinationE164(recipient.get().getNumber().get());
        }
    }
    if (dataMessage.getExpireTimer() > 0) {
        sentMessage.setExpirationStartTimestamp(System.currentTimeMillis());
    }
    if (dataMessage.getIsViewOnce()) {
        dataMessage = dataMessage.toBuilder().clearAttachments().build();
        sentMessage.setMessage(dataMessage);
    }
    sentMessage.setIsRecipientUpdate(isRecipientUpdate);
    return container.setSyncMessage(syncMessage.setSent(sentMessage)).build();
}
Also used : SyncMessage(org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage) SignalServiceSyncMessage(org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage) EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) DataMessage(org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult)

Example 12 with SendMessageResult

use of org.whispersystems.signalservice.api.messages.SendMessageResult in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method sendGroupDataMessage.

/**
 * Sends a {@link SignalServiceDataMessage} to a group using sender keys.
 */
public List<SendMessageResult> sendGroupDataMessage(DistributionId distributionId, List<SignalServiceAddress> recipients, List<UnidentifiedAccess> unidentifiedAccess, boolean isRecipientUpdate, ContentHint contentHint, SignalServiceDataMessage message, SenderKeyGroupEvents sendEvents) throws IOException, UntrustedIdentityException, NoSessionException, InvalidKeyException, InvalidRegistrationIdException {
    Log.d(TAG, "[" + message.getTimestamp() + "] Sending a group data message to " + recipients.size() + " recipients using DistributionId " + distributionId);
    Content content = createMessageContent(message);
    Optional<byte[]> groupId = message.getGroupId();
    List<SendMessageResult> results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId.orNull(), false, sendEvents);
    sendEvents.onMessageSent();
    if (store.isMultiDevice()) {
        Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.absent(), message.getTimestamp(), results, isRecipientUpdate);
        EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.absent());
        sendMessage(localAddress, Optional.absent(), message.getTimestamp(), syncMessageContent, false, null);
    }
    sendEvents.onSyncMessageSent();
    return results;
}
Also used : EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent)

Example 13 with SendMessageResult

use of org.whispersystems.signalservice.api.messages.SendMessageResult in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method sendMessage.

private List<SendMessageResult> sendMessage(List<SignalServiceAddress> recipients, List<Optional<UnidentifiedAccess>> unidentifiedAccess, long timestamp, EnvelopeContent content, boolean online, PartialSendCompleteListener partialListener, CancelationSignal cancelationSignal) throws IOException {
    Log.d(TAG, "[" + timestamp + "] Sending to " + recipients.size() + " recipients.");
    enforceMaxContentSize(content);
    long startTime = System.currentTimeMillis();
    List<Future<SendMessageResult>> futureResults = new LinkedList<>();
    Iterator<SignalServiceAddress> recipientIterator = recipients.iterator();
    Iterator<Optional<UnidentifiedAccess>> unidentifiedAccessIterator = unidentifiedAccess.iterator();
    while (recipientIterator.hasNext()) {
        SignalServiceAddress recipient = recipientIterator.next();
        Optional<UnidentifiedAccess> access = unidentifiedAccessIterator.next();
        futureResults.add(executor.submit(() -> {
            SendMessageResult result = sendMessage(recipient, access, timestamp, content, online, cancelationSignal);
            if (partialListener != null) {
                partialListener.onPartialSendComplete(result);
            }
            return result;
        }));
    }
    List<SendMessageResult> results = new ArrayList<>(futureResults.size());
    recipientIterator = recipients.iterator();
    for (Future<SendMessageResult> futureResult : futureResults) {
        SignalServiceAddress recipient = recipientIterator.next();
        try {
            results.add(futureResult.get());
        } catch (ExecutionException e) {
            if (e.getCause() instanceof UntrustedIdentityException) {
                Log.w(TAG, e);
                results.add(SendMessageResult.identityFailure(recipient, ((UntrustedIdentityException) e.getCause()).getIdentityKey()));
            } else if (e.getCause() instanceof UnregisteredUserException) {
                Log.w(TAG, "[" + timestamp + "] Found unregistered user.");
                results.add(SendMessageResult.unregisteredFailure(recipient));
            } else if (e.getCause() instanceof PushNetworkException) {
                Log.w(TAG, e);
                results.add(SendMessageResult.networkFailure(recipient));
            } else if (e.getCause() instanceof ServerRejectedException) {
                Log.w(TAG, e);
                throw ((ServerRejectedException) e.getCause());
            } else if (e.getCause() instanceof ProofRequiredException) {
                Log.w(TAG, e);
                results.add(SendMessageResult.proofRequiredFailure(recipient, (ProofRequiredException) e.getCause()));
            } else {
                throw new IOException(e);
            }
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }
    double sendsForAverage = 0;
    for (SendMessageResult result : results) {
        if (result.getSuccess() != null && result.getSuccess().getDuration() != -1) {
            sendsForAverage++;
        }
    }
    double average = 0;
    if (sendsForAverage > 0) {
        for (SendMessageResult result : results) {
            if (result.getSuccess() != null && result.getSuccess().getDuration() != -1) {
                average += result.getSuccess().getDuration() / sendsForAverage;
            }
        }
    }
    Log.d(TAG, "[" + timestamp + "] Completed send to " + recipients.size() + " recipients in " + (System.currentTimeMillis() - startTime) + " ms, with an average time of " + Math.round(average) + " ms per send.");
    return results;
}
Also used : UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) PushNetworkException(org.whispersystems.signalservice.api.push.exceptions.PushNetworkException) Optional(org.whispersystems.libsignal.util.guava.Optional) ArrayList(java.util.ArrayList) ServerRejectedException(org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException) ProofRequiredException(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException) IOException(java.io.IOException) LinkedList(java.util.LinkedList) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) Future(java.util.concurrent.Future) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) ExecutionException(java.util.concurrent.ExecutionException)

Example 14 with SendMessageResult

use of org.whispersystems.signalservice.api.messages.SendMessageResult in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method sendDataMessage.

/**
 * Send a message to a single recipient.
 *
 * @param recipient The message's destination.
 * @param message The message.
 * @throws UntrustedIdentityException
 * @throws IOException
 */
public SendMessageResult sendDataMessage(SignalServiceAddress recipient, Optional<UnidentifiedAccessPair> unidentifiedAccess, ContentHint contentHint, SignalServiceDataMessage message, IndividualSendEvents sendEvents) throws UntrustedIdentityException, IOException {
    Log.d(TAG, "[" + message.getTimestamp() + "] Sending a data message.");
    Content content = createMessageContent(message);
    EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, message.getGroupId());
    sendEvents.onMessageEncrypted();
    long timestamp = message.getTimestamp();
    SendMessageResult result = sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null);
    sendEvents.onMessageSent();
    if (result.getSuccess() != null && result.getSuccess().isNeedsSync()) {
        Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp, Collections.singletonList(result), false);
        EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.absent());
        sendMessage(localAddress, Optional.absent(), timestamp, syncMessageContent, false, null);
    }
    sendEvents.onSyncMessageSent();
    return result;
}
Also used : EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent)

Example 15 with SendMessageResult

use of org.whispersystems.signalservice.api.messages.SendMessageResult in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method createMultiDeviceSentTranscriptContent.

private Content createMultiDeviceSentTranscriptContent(SentTranscriptMessage transcript, boolean unidentifiedAccess) throws IOException {
    SignalServiceAddress address = transcript.getDestination().get();
    Content content = createMessageContent(transcript.getMessage());
    SendMessageResult result = SendMessageResult.success(address, Collections.emptyList(), unidentifiedAccess, true, -1, Optional.of(content));
    return createMultiDeviceSentTranscriptContent(content, Optional.of(address), transcript.getTimestamp(), Collections.singletonList(result), false);
}
Also used : EnvelopeContent(org.whispersystems.signalservice.api.crypto.EnvelopeContent) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) Content(org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult)

Aggregations

SendMessageResult (org.whispersystems.signalservice.api.messages.SendMessageResult)24 Recipient (org.thoughtcrime.securesms.recipients.Recipient)14 SignalServiceAddress (org.whispersystems.signalservice.api.push.SignalServiceAddress)13 SignalServiceDataMessage (org.whispersystems.signalservice.api.messages.SignalServiceDataMessage)11 SignalServiceMessageSender (org.whispersystems.signalservice.api.SignalServiceMessageSender)10 NonNull (androidx.annotation.NonNull)9 List (java.util.List)8 Content (org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content)8 IOException (java.io.IOException)7 Collectors (java.util.stream.Collectors)7 GroupId (org.thoughtcrime.securesms.groups.GroupId)7 PlaintextContent (org.whispersystems.libsignal.protocol.PlaintextContent)7 Optional (org.whispersystems.libsignal.util.guava.Optional)7 EnvelopeContent (org.whispersystems.signalservice.api.crypto.EnvelopeContent)7 UnidentifiedAccessPair (org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair)7 UntrustedIdentityException (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException)7 ServerRejectedException (org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException)7 Log (org.signal.core.util.logging.Log)6 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)6 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)6