diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index f72f9cf1a5..0c2afbff5e 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -891,7 +891,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { return threadId; } - private long handleSynchronizeSentMediaMessage(@NonNull SentTranscriptMessage message) + public long handleSynchronizeSentMediaMessage(@NonNull SentTranscriptMessage message) throws MmsException { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); @@ -927,6 +927,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { try { long messageId = database.insertMessageOutbox(mediaMessage, threadId, false, null); + if (message.messageServerID >= 0) { DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageId, message.messageServerID); } if (recipients.getAddress().isGroup()) { GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context); @@ -1222,7 +1223,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } - private long handleSynchronizeSentTextMessage(@NonNull SentTranscriptMessage message) + public long handleSynchronizeSentTextMessage(@NonNull SentTranscriptMessage message) throws MmsException { @@ -1245,6 +1246,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage); messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, null); + if (message.messageServerID >= 0) { DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageId, message.messageServerID); } + database = DatabaseFactory.getMmsDatabase(context); GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context); diff --git a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt index 810353a614..cbaa33cf65 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt @@ -4,23 +4,15 @@ import android.content.Context import android.os.Handler import android.util.Log import org.thoughtcrime.securesms.crypto.IdentityKeyUtil -import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.jobs.PushDecryptJob -import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository -import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil -import org.thoughtcrime.securesms.mms.OutgoingMediaMessage -import org.thoughtcrime.securesms.mms.QuoteModel -import org.thoughtcrime.securesms.recipients.Recipient -import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.thoughtcrime.securesms.util.Util import org.whispersystems.libsignal.util.guava.Optional import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceGroup +import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.LokiPublicChat import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI @@ -28,6 +20,7 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage import org.whispersystems.signalservice.loki.api.LokiStorageAPI import org.whispersystems.signalservice.loki.utilities.get import org.whispersystems.signalservice.loki.utilities.successBackground +import java.util.* class LokiPublicChatPoller(private val context: Context, private val group: LokiPublicChat) { private val handler = Handler() @@ -97,18 +90,17 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki // endregion // region Polling - private fun pollForNewMessages() { - fun processIncomingMessage(message: LokiPublicChatMessage) { - val id = group.id.toByteArray() - val serviceGroup = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) - val quote = if (message.quote != null) { - SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) - } else { - null - } - val attachments = message.attachments.mapNotNull { attachment -> - if (attachment.kind != LokiPublicChatMessage.Attachment.Kind.Attachment) { return@mapNotNull null } - SignalServiceAttachmentPointer( + private fun getDataMessage(message: LokiPublicChatMessage): SignalServiceDataMessage { + val id = group.id.toByteArray() + val serviceGroup = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) + val quote = if (message.quote != null) { + SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) + } else { + null + } + val attachments = message.attachments.mapNotNull { attachment -> + if (attachment.kind != LokiPublicChatMessage.Attachment.Kind.Attachment) { return@mapNotNull null } + SignalServiceAttachmentPointer( attachment.serverID, attachment.contentType, ByteArray(0), @@ -120,86 +112,57 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki false, Optional.fromNullable(attachment.caption), attachment.url) - } - val linkPreview = message.attachments.firstOrNull { it.kind == LokiPublicChatMessage.Attachment.Kind.LinkPreview } - val signalLinkPreviews = mutableListOf() - if (linkPreview != null) { - val attachment = SignalServiceAttachmentPointer( - linkPreview.serverID, - linkPreview.contentType, - ByteArray(0), - Optional.of(linkPreview.size), - Optional.absent(), - linkPreview.width, linkPreview.height, - Optional.absent(), - Optional.of(linkPreview.fileName), - false, - Optional.fromNullable(linkPreview.caption), - linkPreview.url) - signalLinkPreviews.add(SignalServiceDataMessage.Preview(linkPreview.linkPreviewURL!!, linkPreview.linkPreviewTitle!!, Optional.of(attachment))) - } - val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body - val serviceDataMessage = SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, false, 0, false, null, false, quote, null, signalLinkPreviews, null) + } + val linkPreview = message.attachments.firstOrNull { it.kind == LokiPublicChatMessage.Attachment.Kind.LinkPreview } + val signalLinkPreviews = mutableListOf() + if (linkPreview != null) { + val attachment = SignalServiceAttachmentPointer( + linkPreview.serverID, + linkPreview.contentType, + ByteArray(0), + Optional.of(linkPreview.size), + Optional.absent(), + linkPreview.width, linkPreview.height, + Optional.absent(), + Optional.of(linkPreview.fileName), + false, + Optional.fromNullable(linkPreview.caption), + linkPreview.url) + signalLinkPreviews.add(SignalServiceDataMessage.Preview(linkPreview.linkPreviewURL!!, linkPreview.linkPreviewTitle!!, Optional.of(attachment))) + } + val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body + return SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, false, 0, false, null, false, quote, null, signalLinkPreviews, null) + } + + private fun pollForNewMessages() { + fun processIncomingMessage(message: LokiPublicChatMessage) { + val serviceDataMessage = getDataMessage(message) val serviceContent = SignalServiceContent(serviceDataMessage, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - if (quote != null || attachments.count() > 0 || linkPreview != null) { + if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) { PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else { PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } } + fun processOutgoingMessage(message: LokiPublicChatMessage) { val messageServerID = message.serverID ?: return - val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null + val isDuplicate = DatabaseFactory.getLokiMessageDatabase(context).getMessageID(messageServerID) != null if (isDuplicate) { return } if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return } - val id = group.id.toByteArray() - val mmsDatabase = DatabaseFactory.getMmsDatabase(context) - val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) - val quote: QuoteModel? - if (message.quote != null) { - quote = QuoteModel(message.quote!!.quotedMessageTimestamp, Address.fromSerialized(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, false, listOf()) + val localNumber = TextSecurePreferences.getLocalNumber(context) + val dataMessage = getDataMessage(message) + val transcript = SentTranscriptMessage(localNumber, dataMessage.timestamp, dataMessage, dataMessage.expiresInSeconds.toLong(), Collections.singletonMap(localNumber, false)) + transcript.messageServerID = messageServerID + if (dataMessage.quote.isPresent || (dataMessage.attachments.isPresent && dataMessage.attachments.get().size > 0) || dataMessage.previews.isPresent) { + PushDecryptJob(context).handleSynchronizeSentMediaMessage(transcript) } else { - quote = null - } - // TODO: Handle attachments correctly for our previous messages - val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body - val signalMessage = OutgoingMediaMessage(recipient, body, listOf(), message.timestamp, 0, 0, - ThreadDatabase.DistributionTypes.DEFAULT, quote, listOf(), listOf(), listOf(), listOf()) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - fun finalize() { - val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null) - mmsDatabase.markAsSent(messageID, true) - mmsDatabase.markUnidentified(messageID, false) - lokiMessageDatabase.setServerID(messageID, messageServerID) - } - val urls = LinkPreviewUtil.findWhitelistedUrls(message.body) - val urlCount = urls.size - if (urlCount != 0) { - val lpr = LinkPreviewRepository(context) - var count = 0 - urls.forEach { url -> - lpr.getLinkPreview(context, url.url) { lp -> - Util.runOnMain { - count += 1 - if (lp.isPresent) { signalMessage.linkPreviews.add(lp.get()) } - if (count == urlCount) { - try { - finalize() - } catch (e: Exception) { - // TODO: Handle - } - - } - } - } - } - } else { - finalize() + PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript) } } + api.getMessages(group.channel, group.server).successBackground { messages -> if (messages.isNotEmpty()) { val ourDevices = LokiStorageAPI.shared.getAllDevicePublicKeys(userHexEncodedPublicKey).get(setOf())