diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index 5f4a989f75..b1b1cdab4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -8,6 +8,8 @@ import org.session.libsession.messaging.sending_receiving.attachments.* import org.session.libsession.messaging.threads.Address import org.session.libsignal.libsignal.util.guava.Optional import org.session.libsignal.service.api.messages.SignalServiceAttachment +import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer +import org.session.libsignal.service.api.messages.SignalServiceAttachmentStream import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -32,6 +34,18 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) return databaseAttachment.toAttachmentPointer() } + override fun getSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream? { + val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context) + val databaseAttachment = attachmentDatabase.getAttachment(AttachmentId(attachmentId, 0)) ?: return null + return databaseAttachment.toSignalAttachmentStream(context) + } + + override fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer? { + val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context) + val databaseAttachment = attachmentDatabase.getAttachment(AttachmentId(attachmentId, 0)) ?: return null + return databaseAttachment.toSignalAttachmentPointer() + } + override fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) { val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context) attachmentDatabase.setTransferState(messageID, AttachmentId(attachmentId, 0), attachmentState.value) @@ -103,6 +117,17 @@ fun DatabaseAttachment.toAttachmentStream(context: Context): SessionServiceAttac return attachmentStream } +fun DatabaseAttachment.toSignalAttachmentPointer(): SignalServiceAttachmentPointer { + return SignalServiceAttachmentPointer(attachmentId.rowId, contentType, key?.toByteArray(), Optional.fromNullable(size.toInt()), Optional.absent(), width, height, Optional.fromNullable(digest), Optional.fromNullable(fileName), isVoiceNote, Optional.fromNullable(caption), url) +} + +fun DatabaseAttachment.toSignalAttachmentStream(context: Context): SignalServiceAttachmentStream { + val stream = PartAuthority.getAttachmentStream(context, this.dataUri!!) + val listener = SignalServiceAttachment.ProgressListener { total: Long, progress: Long -> EventBus.getDefault().postSticky(PartProgressEvent(this, total, progress))} + + return SignalServiceAttachmentStream(stream, this.contentType, this.size, Optional.fromNullable(this.fileName), this.isVoiceNote, Optional.absent(), this.width, this.height, Optional.fromNullable(this.caption), listener) +} + fun DatabaseAttachment.shouldHaveImageSize(): Boolean { return (MediaUtil.isVideo(this) || MediaUtil.isImage(this) || MediaUtil.isGif(this)); } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index 7b84e9975d..698ababc18 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -902,6 +902,20 @@ public class MmsDatabase extends MessagingDatabase { return insertMessageInbox(retrieved, contentLocation, threadId, type, 0); } + public Optional insertSecureDecryptedMessageOutbox(OutgoingMediaMessage retrieved, long threadId, long serverTimestamp) + throws MmsException + { + if (threadId == -1) { + threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(retrieved.getRecipient()); + } + long messageId = insertMessageOutbox(retrieved, threadId, false, null, serverTimestamp); + if (messageId == -1) { + return Optional.absent(); + } + markAsSent(messageId, true); + return Optional.fromNullable(new InsertResult(messageId, threadId)); + } + public Optional insertSecureDecryptedMessageInbox(IncomingMediaMessage retrieved, long threadId, long serverTimestamp) throws MmsException { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 61a7af375e..e12d8f7353 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -686,6 +686,18 @@ public class SmsDatabase extends MessagingDatabase { return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp); } + public Optional insertMessageOutbox(long threadId, OutgoingTextMessage message, long serverTimestamp) { + if (threadId == -1) { + threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(message.getRecipient()); + } + long messageId = insertMessageOutbox(threadId, message, false, serverTimestamp, null); + if (messageId == -1) { + return Optional.absent(); + } + markAsSent(messageId, true); + return Optional.fromNullable(new InsertResult(messageId, threadId)); + } + public long insertMessageOutbox(long threadId, OutgoingTextMessage message, boolean forceSms, long date, InsertListener insertListener) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 8fdcb3b100..5c81921634 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -13,6 +13,8 @@ import org.session.libsession.messaging.messages.visible.Attachment import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.opengroups.OpenGroup import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId +import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment +import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachment import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.threads.Address @@ -28,6 +30,7 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer import org.session.libsignal.service.api.messages.SignalServiceGroup import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.loki.api.opengroups.PublicChat +import org.session.libsignal.utilities.logging.Log import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase @@ -36,9 +39,11 @@ import org.thoughtcrime.securesms.loki.utilities.get import org.thoughtcrime.securesms.loki.utilities.getString import org.thoughtcrime.securesms.mms.IncomingMediaMessage import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage +import org.thoughtcrime.securesms.mms.OutgoingMediaMessage import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.sms.IncomingGroupMessage import org.thoughtcrime.securesms.sms.IncomingTextMessage +import org.thoughtcrime.securesms.sms.OutgoingTextMessage class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol { override fun getUserPublicKey(): String? { @@ -91,9 +96,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List, groupPublicKey: String?, openGroupID: String?): Long? { var messageID: Long? = null - val address = Address.fromSerialized(message.sender!!) - val recipient = Recipient.from(context, address, false) - val body: Optional = if (message.text != null) Optional.of(message.text) else Optional.absent() + val senderAddress = Address.fromSerialized(message.sender!!) + val senderRecipient = Recipient.from(context, senderAddress, false) var group: Optional = Optional.absent() if (openGroupID != null) { group = Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT)) @@ -101,17 +105,39 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, group = Optional.of(SignalServiceGroup(groupPublicKey.toByteArray(), SignalServiceGroup.GroupType.SIGNAL)) } if (message.isMediaMessage()) { - val attachments: Optional> = Optional.absent() // TODO figure out how to get SignalServiceAttachment with attachmentID val quote: Optional = if (quotes != null) Optional.of(quotes) else Optional.absent() val linkPreviews: Optional> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! }) - val mediaMessage = IncomingMediaMessage(address, message.receivedTimestamp!!, -1, recipient.expireMessages * 1000L, false, false, body, group, attachments, quote, Optional.absent(), linkPreviews, Optional.absent()) val mmsDatabase = DatabaseFactory.getMmsDatabase(context) mmsDatabase.beginTransaction() - val insertResult: Optional - if (group.isPresent) { - insertResult = mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!); + val insertResult = if (message.sender == getUserPublicKey()) { + val targetAddress = if (message.syncTarget != null) { + Address.fromSerialized(message.syncTarget!!) + } else { + if (group.isPresent) { + Address.fromSerialized(GroupUtil.getEncodedId(group.get())) + } else { + Log.d("Loki", "Cannot handle message from self.") + return null + } + } + val attachments = message.attachmentIDs.mapNotNull { + DatabaseFactory.getAttachmentProvider(context).getSignalAttachmentPointer(it) + }.mapNotNull { + PointerAttachment.forPointer(Optional.of(it)).orNull() + } + val mediaMessage = OutgoingMediaMessage.from(message, Recipient.from(context, targetAddress, false), attachments, quote.orNull(), linkPreviews.orNull()) + mmsDatabase.insertSecureDecryptedMessageOutbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!) } else { - insertResult = mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1) + // It seems like we have replaced SignalServiceAttachment with SessionServiceAttachment + val attachments: Optional> = Optional.of(message.attachmentIDs.mapNotNull { + DatabaseFactory.getAttachmentProvider(context).getSignalAttachmentPointer(it) + }) + val mediaMessage = IncomingMediaMessage.from(message, senderAddress, senderRecipient.expireMessages * 1000L, group, attachments, quote, linkPreviews) + if (group.isPresent) { + mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!) + } else { + mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1) + } } if (insertResult.isPresent) { mmsDatabase.setTransactionSuccessful() @@ -119,9 +145,28 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } mmsDatabase.endTransaction() } else { - val textMessage = IncomingTextMessage(address, 1, message.receivedTimestamp!!, body.get(), group, recipient.expireMessages * 1000L, false) val smsDatabase = DatabaseFactory.getSmsDatabase(context) - val insertResult = smsDatabase.insertMessageInbox(textMessage) + val insertResult = if (message.sender == getUserPublicKey()) { + val targetAddress = if (message.syncTarget != null) { + Address.fromSerialized(message.syncTarget!!) + } else { + if (group.isPresent) { + Address.fromSerialized(GroupUtil.getEncodedId(group.get())) + } else { + Log.d("Loki", "Cannot handle message from self.") + return null + } + } + val textMessage = OutgoingTextMessage.from(message, Recipient.from(context, targetAddress, false)) + smsDatabase.insertMessageOutbox(message.threadID ?: -1, textMessage, message.sentTimestamp!!) + } else { + val textMessage = IncomingTextMessage.from(message, senderAddress, group, senderRecipient.expireMessages * 1000L) + if (group.isPresent) { + smsDatabase.insertMessageInbox(textMessage, message.sentTimestamp!!) + } else { + smsDatabase.insertMessageInbox(textMessage) + } + } if (insertResult.isPresent) { messageID = insertResult.get().messageId } @@ -130,7 +175,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } // JOBS - override fun persistJob(job: Job) { DatabaseFactory.getSessionJobDatabase(context).persistJob(job) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java b/app/src/main/java/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java index 1ade07f466..6ea0ae5c73 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java @@ -1,15 +1,18 @@ package org.thoughtcrime.securesms.mms; +import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment; import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact; import org.session.libsession.messaging.threads.Address; import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview; import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel; +import org.session.libsession.messaging.threads.recipients.Recipient; import org.session.libsession.utilities.GroupUtil; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceAttachment; import org.session.libsignal.service.api.messages.SignalServiceGroup; +import org.thoughtcrime.securesms.ApplicationContext; import java.util.Collections; import java.util.LinkedList; @@ -92,6 +95,18 @@ public class IncomingMediaMessage { } } + public static IncomingMediaMessage from(VisibleMessage message, + Address from, + long expiresIn, + Optional group, + Optional> attachments, + Optional quote, + Optional> linkPreviews) + { + return new IncomingMediaMessage(from, message.getReceivedTimestamp(), -1, expiresIn, false, + false, Optional.fromNullable(message.getText()), group, attachments, quote, Optional.absent(), linkPreviews, Optional.absent()); + } + public int getSubscriptionId() { return subscriptionId; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java index 903c44cbd7..fb22876181 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -4,6 +4,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.text.TextUtils; +import org.session.libsession.messaging.messages.visible.VisibleMessage; +import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; @@ -12,6 +14,7 @@ import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPrevie import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel; import org.session.libsession.messaging.threads.recipients.Recipient; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -86,6 +89,17 @@ public class OutgoingMediaMessage { this.linkPreviews.addAll(that.linkPreviews); } + public static OutgoingMediaMessage from(VisibleMessage message, + Recipient recipient, + List attachments, + @Nullable QuoteModel outgoingQuote, + @NonNull List linkPreviews) + { + return new OutgoingMediaMessage(recipient, message.getText(), attachments, message.getSentTimestamp(), -1, + recipient.getExpireMessages() * 1000, ThreadDatabase.DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(), + linkPreviews, Collections.emptyList(), Collections.emptyList()); + } + public Recipient getRecipient() { return recipient; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index 36f01071d9..e52b7930e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -7,6 +7,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.telephony.SmsMessage; +import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.threads.Address; import org.session.libsession.utilities.GroupUtil; import org.session.libsignal.libsignal.util.guava.Optional; @@ -155,6 +156,14 @@ public class IncomingTextMessage implements Parcelable { this.unidentified = false; } + public static IncomingTextMessage from(VisibleMessage message, + Address sender, + Optional group, + long expiresInMillis) + { + return new IncomingTextMessage(sender, 1, message.getReceivedTimestamp(), message.getText(), group, expiresInMillis, false); + } + public int getSubscriptionId() { return subscriptionId; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java index 76fe051666..c09b426472 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.sms; +import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.session.libsession.messaging.threads.recipients.Recipient; @@ -28,6 +29,10 @@ public class OutgoingTextMessage { this.message = body; } + public static OutgoingTextMessage from(VisibleMessage message, Recipient recipient) { + return new OutgoingTextMessage(recipient, message.getText(), recipient.getExpireMessages() * 1000, -1); + } + public long getExpiresIn() { return expiresIn; } diff --git a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt index 27518b8d34..758710840b 100644 --- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt +++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt @@ -6,6 +6,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.SessionSer import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachmentStream import org.session.libsession.messaging.threads.Address import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer +import org.session.libsignal.service.api.messages.SignalServiceAttachmentStream import java.io.InputStream interface MessageDataProvider { @@ -14,9 +15,11 @@ interface MessageDataProvider { fun deleteMessage(messageID: Long) fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream? - fun getAttachmentPointer(attachmentId: Long): SessionServiceAttachmentPointer? + fun getSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream? + fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer? + fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) fun insertAttachment(messageId: Long, attachmentId: Long, stream : InputStream)