Add handling for import/export of edited messages.

This commit is contained in:
Clark 2024-05-31 10:17:55 -04:00 committed by Cody Henthorne
parent 1565ecdcea
commit 54cd84b842
2 changed files with 45 additions and 9 deletions

View file

@ -15,6 +15,7 @@ import org.signal.core.util.requireBlob
import org.signal.core.util.requireBoolean import org.signal.core.util.requireBoolean
import org.signal.core.util.requireInt import org.signal.core.util.requireInt
import org.signal.core.util.requireLong import org.signal.core.util.requireLong
import org.signal.core.util.requireLongOrNull
import org.signal.core.util.requireString import org.signal.core.util.requireString
import org.thoughtcrime.securesms.attachments.Cdn import org.thoughtcrime.securesms.attachments.Cdn
import org.thoughtcrime.securesms.attachments.DatabaseAttachment import org.thoughtcrime.securesms.attachments.DatabaseAttachment
@ -70,6 +71,7 @@ import org.whispersystems.signalservice.api.util.UuidUtil
import org.whispersystems.signalservice.api.util.toByteArray import org.whispersystems.signalservice.api.util.toByteArray
import java.io.Closeable import java.io.Closeable
import java.io.IOException import java.io.IOException
import java.util.HashMap
import java.util.LinkedList import java.util.LinkedList
import java.util.Queue import java.util.Queue
import kotlin.jvm.optionals.getOrNull import kotlin.jvm.optionals.getOrNull
@ -96,6 +98,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
*/ */
private val buffer: Queue<ChatItem> = LinkedList() private val buffer: Queue<ChatItem> = LinkedList()
private val revisionMap: HashMap<Long, ArrayList<ChatItem>> = HashMap()
override fun hasNext(): Boolean { override fun hasNext(): Boolean {
return buffer.isNotEmpty() || (cursor.count > 0 && !cursor.isLast && !cursor.isAfterLast) return buffer.isNotEmpty() || (cursor.count > 0 && !cursor.isLast && !cursor.isAfterLast)
} }
@ -346,8 +350,20 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
} }
else -> builder.standardMessage = record.toStandardMessage(reactionsById[id], mentions = mentionsById[id], attachments = attachmentsById[record.id]) else -> builder.standardMessage = record.toStandardMessage(reactionsById[id], mentions = mentionsById[id], attachments = attachmentsById[record.id])
} }
if (record.latestRevisionId == null) {
buffer += builder.build() val previousEdits = revisionMap.remove(record.id)
if (previousEdits != null) {
builder.revisions = previousEdits
}
buffer += builder.build()
} else {
var previousEdits = revisionMap[record.latestRevisionId]
if (previousEdits == null) {
previousEdits = ArrayList()
revisionMap[record.latestRevisionId] = previousEdits
}
previousEdits += builder.build()
}
} }
return if (buffer.isNotEmpty()) { return if (buffer.isNotEmpty()) {
@ -709,8 +725,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
quoteMissing = this.requireBoolean(MessageTable.QUOTE_MISSING), quoteMissing = this.requireBoolean(MessageTable.QUOTE_MISSING),
quoteBodyRanges = this.requireBlob(MessageTable.QUOTE_BODY_RANGES), quoteBodyRanges = this.requireBlob(MessageTable.QUOTE_BODY_RANGES),
quoteType = this.requireInt(MessageTable.QUOTE_TYPE), quoteType = this.requireInt(MessageTable.QUOTE_TYPE),
originalMessageId = this.requireLong(MessageTable.ORIGINAL_MESSAGE_ID), originalMessageId = this.requireLongOrNull(MessageTable.ORIGINAL_MESSAGE_ID),
latestRevisionId = this.requireLong(MessageTable.LATEST_REVISION_ID), latestRevisionId = this.requireLongOrNull(MessageTable.LATEST_REVISION_ID),
hasDeliveryReceipt = this.requireBoolean(MessageTable.HAS_DELIVERY_RECEIPT), hasDeliveryReceipt = this.requireBoolean(MessageTable.HAS_DELIVERY_RECEIPT),
viewed = this.requireBoolean(MessageTable.VIEWED_COLUMN), viewed = this.requireBoolean(MessageTable.VIEWED_COLUMN),
hasReadReceipt = this.requireBoolean(MessageTable.HAS_READ_RECEIPT), hasReadReceipt = this.requireBoolean(MessageTable.HAS_READ_RECEIPT),
@ -744,8 +760,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
val quoteMissing: Boolean, val quoteMissing: Boolean,
val quoteBodyRanges: ByteArray?, val quoteBodyRanges: ByteArray?,
val quoteType: Int, val quoteType: Int,
val originalMessageId: Long, val originalMessageId: Long?,
val latestRevisionId: Long, val latestRevisionId: Long?,
val hasDeliveryReceipt: Boolean, val hasDeliveryReceipt: Boolean,
val hasReadReceipt: Boolean, val hasReadReceipt: Boolean,
val viewed: Boolean, val viewed: Boolean,

View file

@ -105,7 +105,9 @@ class ChatItemImportInserter(
MessageTable.LINK_PREVIEWS, MessageTable.LINK_PREVIEWS,
MessageTable.MESSAGE_RANGES, MessageTable.MESSAGE_RANGES,
MessageTable.VIEW_ONCE, MessageTable.VIEW_ONCE,
MessageTable.MESSAGE_EXTRAS MessageTable.MESSAGE_EXTRAS,
MessageTable.ORIGINAL_MESSAGE_ID,
MessageTable.LATEST_REVISION_ID
) )
private val REACTION_COLUMNS = arrayOf( private val REACTION_COLUMNS = arrayOf(
@ -157,8 +159,22 @@ class ChatItemImportInserter(
Log.w(TAG, "[insert] Could not find a backup recipientId for backup chatId ${chatItem.chatId}! Skipping.") Log.w(TAG, "[insert] Could not find a backup recipientId for backup chatId ${chatItem.chatId}! Skipping.")
return return
} }
val messageInsert = chatItem.toMessageInsert(fromLocalRecipientId, chatLocalRecipientId, localThreadId)
if (chatItem.revisions.isNotEmpty()) {
val originalId = messageId
val latestRevisionId = originalId + chatItem.revisions.size
val sortedRevisions = chatItem.revisions.sortedBy { it.dateSent }.map { it.toMessageInsert(fromLocalRecipientId, chatLocalRecipientId, localThreadId) }
for (revision in sortedRevisions) {
revision.contentValues.put(MessageTable.ORIGINAL_MESSAGE_ID, originalId)
revision.contentValues.put(MessageTable.LATEST_REVISION_ID, latestRevisionId)
revision.contentValues.put(MessageTable.REVISION_NUMBER, (messageId - originalId))
buffer.messages += revision
messageId++
}
buffer.messages += chatItem.toMessageInsert(fromLocalRecipientId, chatLocalRecipientId, localThreadId) messageInsert.contentValues.put(MessageTable.ORIGINAL_MESSAGE_ID, originalId)
}
buffer.messages += messageInsert
buffer.reactions += chatItem.toReactionContentValues(messageId) buffer.reactions += chatItem.toReactionContentValues(messageId)
buffer.groupReceipts += chatItem.toGroupReceiptContentValues(messageId, chatBackupRecipientId) buffer.groupReceipts += chatItem.toGroupReceiptContentValues(messageId, chatBackupRecipientId)
@ -697,7 +713,11 @@ class ChatItemImportInserter(
?: if (this.contentType == null) null else PointerAttachment.forPointer(quotedAttachment = DataMessage.Quote.QuotedAttachment(contentType = this.contentType, fileName = this.fileName, thumbnail = null)).orNull() ?: if (this.contentType == null) null else PointerAttachment.forPointer(quotedAttachment = DataMessage.Quote.QuotedAttachment(contentType = this.contentType, fileName = this.fileName, thumbnail = null)).orNull()
} }
private class MessageInsert(val contentValues: ContentValues, val followUp: ((Long) -> Unit)?) private class MessageInsert(
val contentValues: ContentValues,
val followUp: ((Long) -> Unit)?,
val edits: List<MessageInsert>? = null
)
private class Buffer( private class Buffer(
val messages: MutableList<MessageInsert> = mutableListOf(), val messages: MutableList<MessageInsert> = mutableListOf(),