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 598ac75534..874f8662df 100644 --- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt +++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt @@ -1,8 +1,10 @@ package org.session.libsession.database +import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachmentPointer 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 java.io.InputStream @@ -28,4 +30,9 @@ interface MessageDataProvider { @Throws(Exception::class) fun uploadAttachment(attachmentId: Long) + // Quotes + fun getMessageForQuote(timestamp: Long, author: Address): Long? + fun getAttachmentsWithLinkPreviewFor(messageID: Long): List + fun getMessageBodyFor(messageID: Long): String + } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt index ce59f17499..1df7403d79 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt @@ -7,8 +7,11 @@ import org.session.libsession.messaging.jobs.Job import org.session.libsession.messaging.jobs.MessageSendJob import org.session.libsession.messaging.messages.Message 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.linkpreview.LinkPreview +import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.threads.Address import org.session.libsession.messaging.threads.GroupRecord import org.session.libsession.messaging.threads.recipients.Recipient.RecipientSettings @@ -99,9 +102,9 @@ interface StorageProtocol { fun setProfileSharing(address: Address, value: Boolean) // Thread - fun getOrCreateThreadIdFor(address: Address): String - fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): String? - fun getThreadIdFor(address: Address): String? + fun getOrCreateThreadIdFor(address: Address): Long + fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long? + fun getThreadIdFor(address: Address): Long? // Session Request fun getSessionRequestSentTimestamp(publicKey: String): Long? @@ -120,4 +123,8 @@ interface StorageProtocol { // PartAuthority fun getAttachmentDataUri(attachmentId: AttachmentId): Uri fun getAttachmentThumbnailUri(attachmentId: AttachmentId): Uri + + // Message Handling + /// Returns the ID of the `TSIncomingMessage` that was constructed. + fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List, groupPublicKey: String?, openGroupID: String?): Long? } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt index 4e9814fcc2..02ee61a1c2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Message.kt @@ -5,7 +5,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos abstract class Message { var id: String? = null - var threadID: String? = null + var threadID: Long? = null var sentTimestamp: Long? = null var receivedTimestamp: Long? = null var recipient: String? = null diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt index 0e680f22ff..df8f1021b8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt @@ -1,5 +1,9 @@ package org.session.libsession.messaging.sending_receiving +import android.text.TextUtils +import com.annimon.stream.Collectors +import com.annimon.stream.Stream +import com.annimon.stream.function.Function import org.session.libsession.messaging.MessagingConfiguration import org.session.libsession.messaging.jobs.AttachmentDownloadJob import org.session.libsession.messaging.jobs.JobQueue @@ -11,7 +15,10 @@ import org.session.libsession.messaging.messages.control.ReadReceipt import org.session.libsession.messaging.messages.control.TypingIndicator import org.session.libsession.messaging.messages.visible.Attachment import org.session.libsession.messaging.messages.visible.VisibleMessage +import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment +import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI +import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.threads.Address import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.utilities.GroupUtil @@ -19,7 +26,7 @@ import org.session.libsession.utilities.SSKEnvironment import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.libsignal.logging.Log import org.session.libsignal.libsignal.util.Hex - +import org.session.libsignal.libsignal.util.guava.Optional import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupRatchet import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupRatchetCollectionType @@ -132,20 +139,47 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS // Get or create thread val threadID = storage.getOrCreateThreadIdFor(message.sender!!, message.groupPublicKey, openGroupID) ?: throw MessageSender.Error.NoThread // Parse quote if needed + var quoteModel: QuoteModel? = null if (message.quote != null && proto.dataMessage.hasQuote()) { - // TODO + val quote = proto.dataMessage.quote + val author = Address.fromSerialized(quote.author) + val messageID = MessagingConfiguration.shared.messageDataProvider.getMessageForQuote(quote.id, author) + if (messageID != null) { + val attachmentsWithLinkPreview = MessagingConfiguration.shared.messageDataProvider.getAttachmentsWithLinkPreviewFor(messageID) + quoteModel = QuoteModel(quote.id, author, MessagingConfiguration.shared.messageDataProvider.getMessageBodyFor(messageID), false, attachmentsWithLinkPreview) + } else { + quoteModel = QuoteModel(quote.id, author, quote.text, true, PointerAttachment.forPointers(proto.dataMessage.quote.attachmentsList)) + } } // Parse link preview if needed + val linkPreviews: MutableList = mutableListOf() if (message.linkPreview != null && proto.dataMessage.previewCount > 0) { - // TODO + for (preview in proto.dataMessage.previewList) { + val thumbnail = PointerAttachment.forPointer(preview.image) + val url = Optional.fromNullable(preview.url) + val title = Optional.fromNullable(preview.title) + val hasContent = !TextUtils.isEmpty(title.or("")) || thumbnail.isPresent + if (hasContent) { + val linkPreview = LinkPreview(url.get(), title.or(""), thumbnail) + linkPreviews.add(linkPreview) + } else { + Log.w("Loki", "Discarding an invalid link preview. hasContent: $hasContent") + } + } } + // Parse stickers if needed // Persist the message + val messageID = storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID) ?: throw MessageReceiver.Error.NoThread message.threadID = threadID // Start attachment downloads if needed attachmentsToDownload.forEach { attachmentID -> - val downloadJob = AttachmentDownloadJob() + val downloadJob = AttachmentDownloadJob(attachmentID, messageID) + JobQueue.shared.add(downloadJob) } - // TODO finish this process + // Cancel any typing indicators if needed + cancelTypingIndicatorsIfNeeded(message.sender!!) + //Notify the user if needed + SSKEnvironment.shared.notificationManager.updateNotification(context, threadID) } private fun MessageReceiver.handleClosedGroupUpdate(message: ClosedGroupUpdate) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/attachments/PointerAttachment.java b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/attachments/PointerAttachment.java index aa120f5ded..d8aa41253c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/attachments/PointerAttachment.java +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/attachments/PointerAttachment.java @@ -9,6 +9,7 @@ import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceAttachment; import org.session.libsignal.service.api.messages.SignalServiceDataMessage; import org.session.libsession.utilities.Base64; +import org.session.libsignal.service.internal.push.SignalServiceProtos; import java.util.LinkedList; import java.util.List; @@ -53,11 +54,11 @@ public class PointerAttachment extends Attachment { return results; } - public static List forPointers(List pointers) { + public static List forPointers(List pointers) { List results = new LinkedList<>(); if (pointers != null) { - for (SignalServiceDataMessage.Quote.QuotedAttachment pointer : pointers) { + for (SignalServiceProtos.DataMessage.Quote.QuotedAttachment pointer : pointers) { Optional result = forPointer(pointer); if (result.isPresent()) { @@ -103,23 +104,41 @@ public class PointerAttachment extends Attachment { } - public static Optional forPointer(SignalServiceDataMessage.Quote.QuotedAttachment pointer) { - SignalServiceAttachment thumbnail = pointer.getThumbnail(); + public static Optional forPointer(SignalServiceProtos.AttachmentPointer pointer) { + return Optional.of(new PointerAttachment(pointer.getContentType(), + AttachmentTransferProgress.TRANSFER_PROGRESS_PENDING.getValue(), + (long)pointer.getSize(), + pointer.getFileName(), + String.valueOf(pointer != null ? pointer.getId() : 0), + pointer.getKey() != null ? Base64.encodeBytes(pointer.getKey().toByteArray()) : null, + null, + pointer.getDigest().toByteArray(), + null, + false, + pointer.getWidth(), + pointer.getHeight(), + pointer.getCaption(), + null, + pointer.getUrl())); + } + + public static Optional forPointer(SignalServiceProtos.DataMessage.Quote.QuotedAttachment pointer) { + SignalServiceProtos.AttachmentPointer thumbnail = pointer.getThumbnail(); return Optional.of(new PointerAttachment(pointer.getContentType(), AttachmentTransferProgress.TRANSFER_PROGRESS_PENDING.getValue(), - thumbnail != null ? thumbnail.asPointer().getSize().or(0) : 0, - pointer.getFileName(), - String.valueOf(thumbnail != null ? thumbnail.asPointer().getId() : 0), - thumbnail != null && thumbnail.asPointer().getKey() != null ? Base64.encodeBytes(thumbnail.asPointer().getKey()) : null, + thumbnail != null ? (long)thumbnail.getSize() : 0, + thumbnail.getFileName(), + String.valueOf(thumbnail != null ? thumbnail.getId() : 0), + thumbnail != null && thumbnail.getKey() != null ? Base64.encodeBytes(thumbnail.getKey().toByteArray()) : null, null, - thumbnail != null ? thumbnail.asPointer().getDigest().orNull() : null, + thumbnail != null ? thumbnail.getDigest().toByteArray() : null, null, false, - thumbnail != null ? thumbnail.asPointer().getWidth() : 0, - thumbnail != null ? thumbnail.asPointer().getHeight() : 0, - thumbnail != null ? thumbnail.asPointer().getCaption().orNull() : null, + thumbnail != null ? thumbnail.getWidth() : 0, + thumbnail != null ? thumbnail.getHeight() : 0, + thumbnail != null ? thumbnail.getCaption() : null, null, - thumbnail != null ? thumbnail.asPointer().getUrl() : "")); + thumbnail != null ? thumbnail.getUrl() : "")); } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/quotes/QuoteModel.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/quotes/QuoteModel.kt index dbbe730b76..c56774e351 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/quotes/QuoteModel.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/quotes/QuoteModel.kt @@ -1,6 +1,6 @@ package org.session.libsession.messaging.sending_receiving.quotes -import org.session.libsession.messaging.messages.visible.Attachment +import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.threads.Address class QuoteModel(val id: Long,