mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-19 08:09:12 +01:00
Support pinned messages in backups.
This commit is contained in:
committed by
jeffrey-signal
parent
b99fec4274
commit
b65079ec20
@@ -139,6 +139,10 @@ object ExportSkips {
|
||||
return log(sentTimestamp, "Poll was not in a group chat.")
|
||||
}
|
||||
|
||||
fun pinMessageIsInvalid(sentTimestamp: Long): String {
|
||||
return log(sentTimestamp, "Pin message update was invalid.")
|
||||
}
|
||||
|
||||
fun individualChatUpdateInWrongTypeOfChat(sentTimestamp: Long): String {
|
||||
return log(sentTimestamp, "A chat update that only makes sense for individual chats was found in a different kind of chat.")
|
||||
}
|
||||
|
||||
@@ -65,7 +65,10 @@ fun MessageTable.getMessagesForBackup(db: SignalDatabase, backupTime: Long, self
|
||||
${MessageTable.MISMATCHED_IDENTITIES},
|
||||
${MessageTable.TYPE},
|
||||
${MessageTable.MESSAGE_EXTRAS},
|
||||
${MessageTable.VIEW_ONCE}
|
||||
${MessageTable.VIEW_ONCE},
|
||||
${MessageTable.PINNED_UNTIL},
|
||||
${MessageTable.PINNING_MESSAGE_ID},
|
||||
${MessageTable.PINNED_AT}
|
||||
)
|
||||
WHERE $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1
|
||||
""".trimMargin()
|
||||
@@ -155,7 +158,10 @@ fun MessageTable.getMessagesForBackup(db: SignalDatabase, backupTime: Long, self
|
||||
MessageTable.TYPE,
|
||||
MessageTable.MESSAGE_EXTRAS,
|
||||
MessageTable.VIEW_ONCE,
|
||||
PARENT_STORY_ID
|
||||
PARENT_STORY_ID,
|
||||
MessageTable.PINNED_UNTIL,
|
||||
MessageTable.PINNING_MESSAGE_ID,
|
||||
MessageTable.PINNED_AT
|
||||
)
|
||||
.from("${MessageTable.TABLE_NAME} INDEXED BY $dateReceivedIndex")
|
||||
.where("$STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1 AND ($EXPIRES_IN == 0 OR $EXPIRES_IN > ${1.days.inWholeMilliseconds}) AND $DATE_RECEIVED >= $lastSeenReceivedTime $cutoffQuery")
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.database.Cursor
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.signal.core.models.ServiceId
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.EventTimer
|
||||
import org.signal.core.util.Hex
|
||||
@@ -53,6 +54,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.IndividualCall
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.LearnedProfileChatUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.MessageAttachment
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.PaymentNotification
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.PinMessageUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.Poll
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.PollTerminateUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ProfileChangeChatUpdate
|
||||
@@ -413,6 +415,16 @@ class ChatItemArchiveExporter(
|
||||
transformTimer.emit("poll")
|
||||
}
|
||||
|
||||
MessageTypes.isPinnedMessageUpdate(record.type) -> {
|
||||
val pinMessageUpdate = record.toRemotePinMessageUpdate(exportState)
|
||||
if (pinMessageUpdate == null) {
|
||||
Log.w(TAG, ExportSkips.pinMessageIsInvalid(record.dateSent))
|
||||
continue
|
||||
}
|
||||
builder.updateMessage = ChatUpdateMessage(pinMessage = pinMessageUpdate)
|
||||
transformTimer.emit("pin-message")
|
||||
}
|
||||
|
||||
else -> {
|
||||
val attachments = extraData.attachmentsById[record.id]
|
||||
val sticker = attachments?.firstOrNull { dbAttachment -> dbAttachment.isSticker }
|
||||
@@ -595,6 +607,7 @@ private fun BackupMessageRecord.toBasicChatItemBuilder(selfRecipientId: Recipien
|
||||
expiresInMs = record.expiresIn.takeIf { it > 0 }
|
||||
revisions = emptyList()
|
||||
sms = record.type.isSmsType()
|
||||
pinDetails = record.toPinDetails()
|
||||
when (direction) {
|
||||
Direction.DIRECTIONLESS -> {
|
||||
directionless = ChatItem.DirectionlessMessageDetails()
|
||||
@@ -847,6 +860,27 @@ private fun BackupMessageRecord.toRemotePollTerminateUpdate(): PollTerminateUpda
|
||||
)
|
||||
}
|
||||
|
||||
private fun BackupMessageRecord.toPinDetails(): ChatItem.PinDetails? {
|
||||
return if (this.pinnedAt == 0L || this.pinnedUntil == 0L) {
|
||||
null
|
||||
} else {
|
||||
ChatItem.PinDetails(
|
||||
pinnedAtTimestamp = this.pinnedAt,
|
||||
pinExpiresAtTimestamp = this.pinnedUntil.takeIf { it != MessageTable.PIN_FOREVER },
|
||||
pinNeverExpires = (this.pinnedUntil == MessageTable.PIN_FOREVER).takeIf { it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BackupMessageRecord.toRemotePinMessageUpdate(exportState: ExportState): PinMessageUpdate? {
|
||||
val pinMessage = this.messageExtras?.pinnedMessage ?: return null
|
||||
val authorId = exportState.aciToRecipientId[ServiceId.ACI.parseOrNull(pinMessage.targetAuthorAci).toString()] ?: return null
|
||||
return PinMessageUpdate(
|
||||
targetSentTimestamp = pinMessage.targetTimestamp,
|
||||
authorId = authorId
|
||||
)
|
||||
}
|
||||
|
||||
private fun BackupMessageRecord.toRemoteSharedContact(attachments: List<DatabaseAttachment>?): Contact? {
|
||||
if (this.sharedContacts.isNullOrEmpty()) {
|
||||
return null
|
||||
@@ -1591,7 +1625,8 @@ private fun Long.isDirectionlessType(): Boolean {
|
||||
MessageTypes.isGroupUpdate(this) ||
|
||||
MessageTypes.isGroupV1MigrationEvent(this) ||
|
||||
MessageTypes.isGroupQuit(this) ||
|
||||
MessageTypes.isPollTerminate(this)
|
||||
MessageTypes.isPollTerminate(this) ||
|
||||
MessageTypes.isPinnedMessageUpdate(this)
|
||||
}
|
||||
|
||||
private fun Long.isIdentityVerifyType(): Boolean {
|
||||
@@ -1776,6 +1811,8 @@ private fun Cursor.toBackupMessageRecord(pastIds: Set<Long>, backupStartTime: Lo
|
||||
messageExtras = messageExtras.parseMessageExtras(),
|
||||
viewOnce = this.requireBoolean(MessageTable.VIEW_ONCE),
|
||||
parentStoryId = this.requireLong(MessageTable.PARENT_STORY_ID),
|
||||
pinnedAt = this.requireLong(MessageTable.PINNED_AT),
|
||||
pinnedUntil = this.requireLong(MessageTable.PINNED_UNTIL),
|
||||
messageExtrasSize = messageExtras?.size ?: 0
|
||||
)
|
||||
}
|
||||
@@ -1816,6 +1853,8 @@ private class BackupMessageRecord(
|
||||
val baseType: Long,
|
||||
val messageExtras: MessageExtras?,
|
||||
val viewOnce: Boolean,
|
||||
val pinnedAt: Long,
|
||||
val pinnedUntil: Long,
|
||||
private val messageExtrasSize: Int
|
||||
) {
|
||||
val estimatedSizeInBytes: Int = (body?.length ?: 0) +
|
||||
|
||||
@@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescrip
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PaymentTombstone
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PinnedMessage
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PollTerminate
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent
|
||||
@@ -137,7 +138,10 @@ class ChatItemArchiveImporter(
|
||||
MessageTable.LATEST_REVISION_ID,
|
||||
MessageTable.REVISION_NUMBER,
|
||||
MessageTable.PARENT_STORY_ID,
|
||||
MessageTable.NOTIFIED
|
||||
MessageTable.NOTIFIED,
|
||||
MessageTable.PINNED_UNTIL,
|
||||
MessageTable.PINNING_MESSAGE_ID,
|
||||
MessageTable.PINNED_AT
|
||||
)
|
||||
|
||||
private val REACTION_COLUMNS = arrayOf(
|
||||
@@ -343,6 +347,32 @@ class ChatItemArchiveImporter(
|
||||
SignalDatabase.polls.endPoll(pollId = pollId, endingMessageId = endPollMessageId)
|
||||
}
|
||||
}
|
||||
} else if (this.updateMessage.pinMessage != null) {
|
||||
followUps += { pinUpdateMessageId ->
|
||||
val targetAuthorId = importState.remoteToLocalRecipientId[updateMessage.pinMessage.authorId]
|
||||
if (targetAuthorId != null) {
|
||||
val pinnedMessageId = SignalDatabase.messages.getMessageFor(updateMessage.pinMessage.targetSentTimestamp, targetAuthorId)?.id ?: -1
|
||||
val messageExtras = MessageExtras(
|
||||
pinnedMessage = PinnedMessage(
|
||||
pinnedMessageId = pinnedMessageId,
|
||||
targetAuthorAci = recipients.getRecord(targetAuthorId).aci!!.toByteString(),
|
||||
targetTimestamp = updateMessage.pinMessage.targetSentTimestamp
|
||||
)
|
||||
)
|
||||
|
||||
db.update(MessageTable.TABLE_NAME)
|
||||
.values(MessageTable.MESSAGE_EXTRAS to messageExtras.encode())
|
||||
.where("${MessageTable.ID} = ?", pinUpdateMessageId)
|
||||
.run()
|
||||
|
||||
if (pinnedMessageId != -1L) {
|
||||
db.update(MessageTable.TABLE_NAME)
|
||||
.values(MessageTable.PINNING_MESSAGE_ID to pinUpdateMessageId)
|
||||
.where("${MessageTable.ID} = ?", pinnedMessageId)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +675,12 @@ class ChatItemArchiveImporter(
|
||||
contentValues.put(MessageTable.REMOTE_DELETED, 0)
|
||||
contentValues.put(MessageTable.PARENT_STORY_ID, 0)
|
||||
|
||||
if (this.pinDetails != null) {
|
||||
val pinnedUntil = if (this.pinDetails.pinNeverExpires == true) MessageTable.PIN_FOREVER else this.pinDetails.pinExpiresAtTimestamp
|
||||
contentValues.put(MessageTable.PINNED_UNTIL, pinnedUntil ?: 0)
|
||||
contentValues.put(MessageTable.PINNED_AT, this.pinDetails.pinnedAtTimestamp)
|
||||
}
|
||||
|
||||
when {
|
||||
this.standardMessage != null -> contentValues.addStandardMessage(this.standardMessage)
|
||||
this.remoteDeletedMessage != null -> contentValues.put(MessageTable.REMOTE_DELETED, 1)
|
||||
@@ -846,6 +882,9 @@ class ChatItemArchiveImporter(
|
||||
updateMessage.pollTerminate != null -> {
|
||||
typeFlags = MessageTypes.SPECIAL_TYPE_POLL_TERMINATE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv())
|
||||
}
|
||||
updateMessage.pinMessage != null -> {
|
||||
typeFlags = MessageTypes.SPECIAL_TYPE_PINNED_MESSAGE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv())
|
||||
}
|
||||
updateMessage.sessionSwitchover != null -> {
|
||||
typeFlags = MessageTypes.SESSION_SWITCHOVER_TYPE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv())
|
||||
val sessionSwitchoverDetails = SessionSwitchoverEvent(e164 = updateMessage.sessionSwitchover.e164.toString()).encode()
|
||||
|
||||
Reference in New Issue
Block a user