Search in sources :

Example 26 with MmsException

use of org.thoughtcrime.securesms.mms.MmsException in project Signal-Android by signalapp.

the class MessageSender method sendLocalMediaSelf.

private static void sendLocalMediaSelf(Context context, long messageId) {
    try {
        ExpiringMessageManager expirationManager = ApplicationDependencies.getExpiringMessageManager();
        MessageDatabase mmsDatabase = SignalDatabase.mms();
        MmsSmsDatabase mmsSmsDatabase = SignalDatabase.mmsSms();
        OutgoingMediaMessage message = mmsDatabase.getOutgoingMessage(messageId);
        SyncMessageId syncId = new SyncMessageId(Recipient.self().getId(), message.getSentTimeMillis());
        List<Attachment> attachments = new LinkedList<>();
        attachments.addAll(message.getAttachments());
        attachments.addAll(Stream.of(message.getLinkPreviews()).map(LinkPreview::getThumbnail).filter(Optional::isPresent).map(Optional::get).toList());
        attachments.addAll(Stream.of(message.getSharedContacts()).map(Contact::getAvatar).withoutNulls().map(Contact.Avatar::getAttachment).withoutNulls().toList());
        List<AttachmentCompressionJob> compressionJobs = Stream.of(attachments).map(a -> AttachmentCompressionJob.fromAttachment((DatabaseAttachment) a, false, -1)).toList();
        List<AttachmentMarkUploadedJob> fakeUploadJobs = Stream.of(attachments).map(a -> new AttachmentMarkUploadedJob(messageId, ((DatabaseAttachment) a).getAttachmentId())).toList();
        ApplicationDependencies.getJobManager().startChain(compressionJobs).then(fakeUploadJobs).enqueue();
        mmsDatabase.markAsSent(messageId, true);
        mmsDatabase.markUnidentified(messageId, true);
        mmsSmsDatabase.incrementDeliveryReceiptCount(syncId, System.currentTimeMillis());
        mmsSmsDatabase.incrementReadReceiptCount(syncId, System.currentTimeMillis());
        mmsSmsDatabase.incrementViewedReceiptCount(syncId, System.currentTimeMillis());
        if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
            mmsDatabase.markExpireStarted(messageId);
            expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
        }
    } catch (NoSuchMessageException | MmsException e) {
        Log.w(TAG, "Failed to update self-sent message.", e);
    }
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) Arrays(java.util.Arrays) LinkPreview(org.thoughtcrime.securesms.linkpreview.LinkPreview) NonNull(androidx.annotation.NonNull) JobManager(org.thoughtcrime.securesms.jobmanager.JobManager) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) AttachmentMarkUploadedJob(org.thoughtcrime.securesms.jobs.AttachmentMarkUploadedJob) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) SmsDatabase(org.thoughtcrime.securesms.database.SmsDatabase) Preconditions(org.whispersystems.libsignal.util.guava.Preconditions) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) ParcelUtil(org.thoughtcrime.securesms.util.ParcelUtil) ReactionSendJob(org.thoughtcrime.securesms.jobs.ReactionSendJob) Recipient(org.thoughtcrime.securesms.recipients.Recipient) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId) PushMediaSendJob(org.thoughtcrime.securesms.jobs.PushMediaSendJob) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) Collection(java.util.Collection) OutgoingSecureMediaMessage(org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage) ReactionRecord(org.thoughtcrime.securesms.database.model.ReactionRecord) ThreadDatabase(org.thoughtcrime.securesms.database.ThreadDatabase) Log(org.signal.core.util.logging.Log) List(java.util.List) Nullable(androidx.annotation.Nullable) Job(org.thoughtcrime.securesms.jobmanager.Job) ResumableUploadSpecJob(org.thoughtcrime.securesms.jobs.ResumableUploadSpecJob) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) PushGroupSendJob(org.thoughtcrime.securesms.jobs.PushGroupSendJob) NoSuchMessageException(org.thoughtcrime.securesms.database.NoSuchMessageException) Attachment(org.thoughtcrime.securesms.attachments.Attachment) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) AttachmentCompressionJob(org.thoughtcrime.securesms.jobs.AttachmentCompressionJob) Context(android.content.Context) MmsSmsDatabase(org.thoughtcrime.securesms.database.MmsSmsDatabase) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) ProfileKeySendJob(org.thoughtcrime.securesms.jobs.ProfileKeySendJob) Stream(com.annimon.stream.Stream) DirectoryHelper(org.thoughtcrime.securesms.contacts.sync.DirectoryHelper) SignalLocalMetrics(org.thoughtcrime.securesms.util.SignalLocalMetrics) WorkerThread(androidx.annotation.WorkerThread) AttachmentDatabase(org.thoughtcrime.securesms.database.AttachmentDatabase) RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) Parcel(android.os.Parcel) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) ArrayList(java.util.ArrayList) RemoteDeleteSendJob(org.thoughtcrime.securesms.jobs.RemoteDeleteSendJob) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) MmsSendJob(org.thoughtcrime.securesms.jobs.MmsSendJob) AttachmentUploadJob(org.thoughtcrime.securesms.jobs.AttachmentUploadJob) PushTextSendJob(org.thoughtcrime.securesms.jobs.PushTextSendJob) EventBus(org.greenrobot.eventbus.EventBus) AttachmentCopyJob(org.thoughtcrime.securesms.jobs.AttachmentCopyJob) LinkedList(java.util.LinkedList) Parcelable(android.os.Parcelable) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Contact(org.thoughtcrime.securesms.contactshare.Contact) MmsException(org.thoughtcrime.securesms.mms.MmsException) IOException(java.io.IOException) Optional(org.whispersystems.libsignal.util.guava.Optional) TimeUnit(java.util.concurrent.TimeUnit) AttachmentId(org.thoughtcrime.securesms.attachments.AttachmentId) SmsSendJob(org.thoughtcrime.securesms.jobs.SmsSendJob) ExpiringMessageManager(org.thoughtcrime.securesms.service.ExpiringMessageManager) SmsMessageRecord(org.thoughtcrime.securesms.database.model.SmsMessageRecord) Collections(java.util.Collections) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) NoSuchMessageException(org.thoughtcrime.securesms.database.NoSuchMessageException) Optional(org.whispersystems.libsignal.util.guava.Optional) LinkPreview(org.thoughtcrime.securesms.linkpreview.LinkPreview) AttachmentMarkUploadedJob(org.thoughtcrime.securesms.jobs.AttachmentMarkUploadedJob) ExpiringMessageManager(org.thoughtcrime.securesms.service.ExpiringMessageManager) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) Attachment(org.thoughtcrime.securesms.attachments.Attachment) DatabaseAttachment(org.thoughtcrime.securesms.attachments.DatabaseAttachment) LinkedList(java.util.LinkedList) Contact(org.thoughtcrime.securesms.contactshare.Contact) MmsException(org.thoughtcrime.securesms.mms.MmsException) MmsSmsDatabase(org.thoughtcrime.securesms.database.MmsSmsDatabase) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId) AttachmentCompressionJob(org.thoughtcrime.securesms.jobs.AttachmentCompressionJob)

Example 27 with MmsException

use of org.thoughtcrime.securesms.mms.MmsException in project Signal-Android by signalapp.

the class MessageSender method sendPushWithPreUploadedMedia.

public static long sendPushWithPreUploadedMedia(final Context context, final OutgoingMediaMessage message, final Collection<PreUploadResult> preUploadResults, final long threadId, final SmsDatabase.InsertListener insertListener) {
    Log.i(TAG, "Sending media message with pre-uploads to " + message.getRecipient().getId() + ", thread: " + threadId);
    Preconditions.checkArgument(message.getAttachments().isEmpty(), "If the media is pre-uploaded, there should be no attachments on the message.");
    try {
        ThreadDatabase threadDatabase = SignalDatabase.threads();
        MessageDatabase mmsDatabase = SignalDatabase.mms();
        AttachmentDatabase attachmentDatabase = SignalDatabase.attachments();
        long allocatedThreadId;
        if (threadId == -1) {
            allocatedThreadId = threadDatabase.getOrCreateThreadIdFor(message.getRecipient(), message.getDistributionType());
        } else {
            allocatedThreadId = threadId;
        }
        Recipient recipient = message.getRecipient();
        long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), allocatedThreadId, false, insertListener);
        List<AttachmentId> attachmentIds = Stream.of(preUploadResults).map(PreUploadResult::getAttachmentId).toList();
        List<String> jobIds = Stream.of(preUploadResults).map(PreUploadResult::getJobIds).flatMap(Stream::of).toList();
        attachmentDatabase.updateMessageId(attachmentIds, messageId);
        sendMediaMessage(context, recipient, false, messageId, jobIds);
        onMessageSent();
        threadDatabase.update(threadId, true);
        return allocatedThreadId;
    } catch (MmsException e) {
        Log.w(TAG, e);
        return threadId;
    }
}
Also used : MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) MmsException(org.thoughtcrime.securesms.mms.MmsException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ThreadDatabase(org.thoughtcrime.securesms.database.ThreadDatabase) AttachmentDatabase(org.thoughtcrime.securesms.database.AttachmentDatabase) AttachmentId(org.thoughtcrime.securesms.attachments.AttachmentId)

Example 28 with MmsException

use of org.thoughtcrime.securesms.mms.MmsException in project Signal-Android by signalapp.

the class MessageSender method send.

public static long send(final Context context, final OutgoingMediaMessage message, final long threadId, final boolean forceSms, @Nullable final String metricId, final SmsDatabase.InsertListener insertListener) {
    Log.i(TAG, "Sending media message to " + message.getRecipient().getId() + ", thread: " + threadId);
    try {
        ThreadDatabase threadDatabase = SignalDatabase.threads();
        MessageDatabase database = SignalDatabase.mms();
        long allocatedThreadId = threadDatabase.getOrCreateValidThreadId(message.getRecipient(), threadId, message.getDistributionType());
        Recipient recipient = message.getRecipient();
        long messageId = database.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), allocatedThreadId, forceSms, insertListener);
        if (message.getRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) {
            SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId);
        } else {
            SignalLocalMetrics.GroupMessageSend.cancel(metricId);
        }
        sendMediaMessage(context, recipient, forceSms, messageId, Collections.emptyList());
        onMessageSent();
        threadDatabase.update(threadId, true);
        return allocatedThreadId;
    } catch (MmsException e) {
        Log.w(TAG, e);
        return threadId;
    }
}
Also used : MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) MmsException(org.thoughtcrime.securesms.mms.MmsException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ThreadDatabase(org.thoughtcrime.securesms.database.ThreadDatabase)

Example 29 with MmsException

use of org.thoughtcrime.securesms.mms.MmsException in project Signal-Android by signalapp.

the class AttachmentCompressionJob method transcodeVideoIfNeededToDatabase.

@NonNull
private static DatabaseAttachment transcodeVideoIfNeededToDatabase(@NonNull Context context, @NonNull AttachmentDatabase attachmentDatabase, @NonNull DatabaseAttachment attachment, @NonNull MediaConstraints constraints, @NonNull EventBus eventBus, @NonNull TranscoderCancelationSignal cancelationSignal) throws UndeliverableMessageException {
    AttachmentDatabase.TransformProperties transformProperties = attachment.getTransformProperties();
    boolean allowSkipOnFailure = false;
    if (!MediaConstraints.isVideoTranscodeAvailable()) {
        if (transformProperties.isVideoEdited()) {
            throw new UndeliverableMessageException("Video edited, but transcode is not available");
        }
        return attachment;
    }
    try (NotificationController notification = GenericForegroundService.startForegroundTask(context, context.getString(R.string.AttachmentUploadJob_compressing_video_start))) {
        notification.setIndeterminateProgress();
        try (MediaDataSource dataSource = attachmentDatabase.mediaDataSourceFor(attachment.getAttachmentId())) {
            if (dataSource == null) {
                throw new UndeliverableMessageException("Cannot get media data source for attachment.");
            }
            allowSkipOnFailure = !transformProperties.isVideoEdited();
            TranscoderOptions options = null;
            if (transformProperties.isVideoTrim()) {
                options = new TranscoderOptions(transformProperties.getVideoTrimStartTimeUs(), transformProperties.getVideoTrimEndTimeUs());
            }
            if (FeatureFlags.useStreamingVideoMuxer() || !MemoryFileDescriptor.supported()) {
                StreamingTranscoder transcoder = new StreamingTranscoder(dataSource, options, constraints.getCompressedVideoMaxSize(context));
                if (transcoder.isTranscodeRequired()) {
                    Log.i(TAG, "Compressing with streaming muxer");
                    AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
                    File file = SignalDatabase.attachments().newFile();
                    file.deleteOnExit();
                    try {
                        try (OutputStream outputStream = ModernEncryptingPartOutputStream.createFor(attachmentSecret, file, true).second) {
                            transcoder.transcode(percent -> {
                                notification.setProgress(100, percent);
                                eventBus.postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.COMPRESSION, 100, percent));
                            }, outputStream, cancelationSignal);
                        }
                        MediaStream mediaStream = new MediaStream(ModernDecryptingPartInputStream.createFor(attachmentSecret, file, 0), MimeTypes.VIDEO_MP4, 0, 0);
                        attachmentDatabase.updateAttachmentData(attachment, mediaStream, transformProperties.isVideoEdited());
                    } finally {
                        if (!file.delete()) {
                            Log.w(TAG, "Failed to delete temp file");
                        }
                    }
                    attachmentDatabase.markAttachmentAsTransformed(attachment.getAttachmentId());
                    return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.getAttachmentId()));
                } else {
                    Log.i(TAG, "Transcode was not required");
                }
            } else {
                try (InMemoryTranscoder transcoder = new InMemoryTranscoder(context, dataSource, options, constraints.getCompressedVideoMaxSize(context))) {
                    if (transcoder.isTranscodeRequired()) {
                        Log.i(TAG, "Compressing with android in-memory muxer");
                        MediaStream mediaStream = transcoder.transcode(percent -> {
                            notification.setProgress(100, percent);
                            eventBus.postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.COMPRESSION, 100, percent));
                        }, cancelationSignal);
                        attachmentDatabase.updateAttachmentData(attachment, mediaStream, transformProperties.isVideoEdited());
                        attachmentDatabase.markAttachmentAsTransformed(attachment.getAttachmentId());
                        return Objects.requireNonNull(attachmentDatabase.getAttachment(attachment.getAttachmentId()));
                    } else {
                        Log.i(TAG, "Transcode was not required (in-memory transcoder)");
                    }
                }
            }
        }
    } catch (VideoSourceException | EncodingException | MemoryFileException e) {
        if (attachment.getSize() > constraints.getVideoMaxSize(context)) {
            throw new UndeliverableMessageException("Duration not found, attachment too large to skip transcode", e);
        } else {
            if (allowSkipOnFailure) {
                Log.w(TAG, "Problem with video source, but video small enough to skip transcode", e);
            } else {
                throw new UndeliverableMessageException("Failed to transcode and cannot skip due to editing", e);
            }
        }
    } catch (IOException | MmsException e) {
        throw new UndeliverableMessageException("Failed to transcode", e);
    }
    return attachment;
}
Also used : VideoSourceException(org.thoughtcrime.securesms.video.VideoSourceException) MemoryFileException(org.thoughtcrime.securesms.util.MemoryFileDescriptor.MemoryFileException) EncodingException(org.thoughtcrime.securesms.video.videoconverter.EncodingException) OutputStream(java.io.OutputStream) ModernEncryptingPartOutputStream(org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream) PartProgressEvent(org.thoughtcrime.securesms.events.PartProgressEvent) IOException(java.io.IOException) AttachmentDatabase(org.thoughtcrime.securesms.database.AttachmentDatabase) TranscoderOptions(org.thoughtcrime.securesms.video.TranscoderOptions) MmsException(org.thoughtcrime.securesms.mms.MmsException) InMemoryTranscoder(org.thoughtcrime.securesms.video.InMemoryTranscoder) MediaStream(org.thoughtcrime.securesms.mms.MediaStream) MediaDataSource(android.media.MediaDataSource) UndeliverableMessageException(org.thoughtcrime.securesms.transport.UndeliverableMessageException) StreamingTranscoder(org.thoughtcrime.securesms.video.StreamingTranscoder) AttachmentSecret(org.thoughtcrime.securesms.crypto.AttachmentSecret) File(java.io.File) NotificationController(org.thoughtcrime.securesms.service.NotificationController) NonNull(androidx.annotation.NonNull)

Example 30 with MmsException

use of org.thoughtcrime.securesms.mms.MmsException in project Signal-Android by signalapp.

the class MessageContentProcessor method handleExpirationUpdate.

@Nullable
private MessageId handleExpirationUpdate(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Optional<Long> smsMessageId, @NonNull Optional<GroupId> groupId, @NonNull Recipient senderRecipient, @NonNull Recipient threadRecipient, long receivedTime) throws StorageFailedException {
    log(content.getTimestamp(), "Expiration update.");
    if (groupId.isPresent() && groupId.get().isV2()) {
        warn(String.valueOf(content.getTimestamp()), "Expiration update received for GV2. Ignoring.");
        return null;
    }
    int expiresInSeconds = message.getExpiresInSeconds();
    Optional<SignalServiceGroupContext> groupContext = message.getGroupContext();
    if (threadRecipient.getExpiresInSeconds() == expiresInSeconds) {
        log(String.valueOf(content.getTimestamp()), "No change in message expiry for group. Ignoring.");
        return null;
    }
    try {
        MessageDatabase database = SignalDatabase.mms();
        IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(), content.getTimestamp(), content.getServerReceivedTimestamp(), receivedTime, -1, expiresInSeconds * 1000L, true, false, content.isNeedsReceipt(), Optional.absent(), groupContext, Optional.absent(), Optional.absent(), Optional.absent(), Optional.absent(), Optional.absent(), Optional.absent(), content.getServerUuid());
        Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
        SignalDatabase.recipients().setExpireMessages(threadRecipient.getId(), expiresInSeconds);
        if (smsMessageId.isPresent()) {
            SignalDatabase.sms().deleteMessage(smsMessageId.get());
        }
        if (insertResult.isPresent()) {
            return new MessageId(insertResult.get().getMessageId(), true);
        }
    } catch (MmsException e) {
        throw new StorageFailedException(e, content.getSender().getIdentifier(), content.getSenderDevice());
    }
    return null;
}
Also used : InsertResult(org.thoughtcrime.securesms.database.MessageDatabase.InsertResult) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) MmsException(org.thoughtcrime.securesms.mms.MmsException) IncomingMediaMessage(org.thoughtcrime.securesms.mms.IncomingMediaMessage) SuppressLint(android.annotation.SuppressLint) SignalServiceGroupContext(org.whispersystems.signalservice.api.messages.SignalServiceGroupContext) MessageId(org.thoughtcrime.securesms.database.model.MessageId) SyncMessageId(org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId) Nullable(androidx.annotation.Nullable)

Aggregations

MmsException (org.thoughtcrime.securesms.mms.MmsException)61 IOException (java.io.IOException)26 Recipient (org.thoughtcrime.securesms.recipients.Recipient)26 MessageDatabase (org.thoughtcrime.securesms.database.MessageDatabase)24 NonNull (androidx.annotation.NonNull)20 DatabaseAttachment (org.thoughtcrime.securesms.attachments.DatabaseAttachment)20 OutgoingMediaMessage (org.thoughtcrime.securesms.mms.OutgoingMediaMessage)19 Nullable (androidx.annotation.Nullable)18 Attachment (org.thoughtcrime.securesms.attachments.Attachment)18 AttachmentDatabase (org.thoughtcrime.securesms.database.AttachmentDatabase)15 List (java.util.List)14 MessageId (org.thoughtcrime.securesms.database.model.MessageId)14 Context (android.content.Context)12 WorkerThread (androidx.annotation.WorkerThread)12 Stream (com.annimon.stream.Stream)12 LinkedList (java.util.LinkedList)12 Log (org.signal.core.util.logging.Log)12 AttachmentId (org.thoughtcrime.securesms.attachments.AttachmentId)12 NoSuchMessageException (org.thoughtcrime.securesms.database.NoSuchMessageException)12 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)12