diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt index c56c04f2fb..e01508ba56 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ImportExportTest.kt @@ -9,9 +9,12 @@ import okio.ByteString.Companion.toByteString import org.junit.Assert import org.junit.Before import org.junit.Test +import org.signal.libsignal.messagebackup.MessageBackup +import org.signal.libsignal.messagebackup.MessageBackupKey import org.signal.libsignal.zkgroup.profiles.ProfileKey import org.thoughtcrime.securesms.backup.v2.proto.AccountData import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo +import org.thoughtcrime.securesms.backup.v2.proto.BodyRange import org.thoughtcrime.securesms.backup.v2.proto.Call import org.thoughtcrime.securesms.backup.v2.proto.Chat import org.thoughtcrime.securesms.backup.v2.proto.ChatItem @@ -19,10 +22,15 @@ import org.thoughtcrime.securesms.backup.v2.proto.Contact import org.thoughtcrime.securesms.backup.v2.proto.DistributionList import org.thoughtcrime.securesms.backup.v2.proto.Frame import org.thoughtcrime.securesms.backup.v2.proto.Group +import org.thoughtcrime.securesms.backup.v2.proto.Quote +import org.thoughtcrime.securesms.backup.v2.proto.Reaction import org.thoughtcrime.securesms.backup.v2.proto.Recipient import org.thoughtcrime.securesms.backup.v2.proto.ReleaseNotes import org.thoughtcrime.securesms.backup.v2.proto.Self +import org.thoughtcrime.securesms.backup.v2.proto.SendStatus +import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage import org.thoughtcrime.securesms.backup.v2.proto.StickerPack +import org.thoughtcrime.securesms.backup.v2.proto.Text import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupReader import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupWriter import org.thoughtcrime.securesms.keyvalue.SignalStore @@ -34,6 +42,7 @@ import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.util.ArrayList import java.util.UUID +import java.util.concurrent.TimeUnit import kotlin.random.Random import kotlin.time.Duration.Companion.days @@ -53,7 +62,7 @@ class ImportExportTest { val releaseNotes = Recipient(id = 2, releaseNotes = ReleaseNotes()) val standardAccountData = AccountData( profileKey = SELF_PROFILE_KEY.serialize().toByteString(), - username = "testusername", + username = "self.01", usernameLink = null, givenName = "Peter", familyName = "Parker", @@ -81,6 +90,24 @@ class ImportExportTest { preferredReactionEmoji = listOf("a", "b", "c") ) ) + val alice = Recipient( + id = 3, + contact = Contact( + aci = TestRecipientUtils.nextAci().toByteString(), + pni = TestRecipientUtils.nextPni().toByteString(), + username = "cool.01", + e164 = 141255501234, + blocked = false, + hidden = false, + registered = Contact.Registered.REGISTERED, + unregisteredTimestamp = 0L, + profileKey = TestRecipientUtils.generateProfileKey().toByteString(), + profileSharing = true, + profileGivenName = "Alexa", + profileFamilyName = "Kim", + hideStory = true + ) + ) /** * When using standardFrames you must start recipient ids at 3. @@ -111,7 +138,7 @@ class ImportExportTest { contact = Contact( aci = TestRecipientUtils.nextAci().toByteString(), pni = TestRecipientUtils.nextPni().toByteString(), - username = "coolusername", + username = "cool.01", e164 = 141255501234, blocked = true, hidden = true, @@ -181,7 +208,7 @@ class ImportExportTest { contact = Contact( aci = TestRecipientUtils.nextAci().toByteString(), pni = TestRecipientUtils.nextPni().toByteString(), - username = "coolusername", + username = "cool.01", e164 = 141255501234, blocked = true, hidden = true, @@ -251,7 +278,7 @@ class ImportExportTest { contact = Contact( aci = TestRecipientUtils.nextAci().toByteString(), pni = TestRecipientUtils.nextPni().toByteString(), - username = "coolusername", + username = "cool.01", e164 = 141255501234, blocked = true, hidden = true, @@ -296,7 +323,7 @@ class ImportExportTest { contact = Contact( aci = TestRecipientUtils.nextAci().toByteString(), pni = TestRecipientUtils.nextPni().toByteString(), - username = "coolusername", + username = "cool.01", e164 = 141255501234, blocked = false, hidden = false, @@ -398,7 +425,7 @@ class ImportExportTest { contact = Contact( aci = TestRecipientUtils.nextAci().toByteString(), pni = TestRecipientUtils.nextPni().toByteString(), - username = "coolusername", + username = "cool.01", e164 = 141255501234, blocked = false, hidden = false, @@ -426,6 +453,397 @@ class ImportExportTest { ) } + @Test + fun messageWithOnlyText() { + var dateSent = System.currentTimeMillis() + val sendStatuses = enumerateSendStatuses(alice.id) + val incomingMessageDetails = enumerateIncomingMessageDetails(dateSent + 200) + val outgoingMessages = ArrayList() + val incomingMessages = ArrayList() + for (sendStatus in sendStatuses) { + outgoingMessages.add( + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = dateSent++, + expireStartDate = dateSent + 1000, + expiresInMs = TimeUnit.DAYS.toMillis(2), + sms = false, + outgoing = ChatItem.OutgoingMessageDetails( + sendStatus = listOf(sendStatus) + ), + standardMessage = StandardMessage( + text = Text( + body = "Text only body" + ) + ) + ) + ) + } + dateSent++ + for (incomingDetail in incomingMessageDetails) { + incomingMessages.add( + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = dateSent++, + expireStartDate = dateSent + 1000, + expiresInMs = TimeUnit.DAYS.toMillis(2), + sms = false, + incoming = incomingDetail, + standardMessage = StandardMessage( + text = Text( + body = "Text only body" + ) + ) + ) + ) + } + + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + *outgoingMessages.toArray(), + *incomingMessages.toArray() + ) + } + + @Test + fun messageWithTextMentionsBodyRangesAndReactions() { + val time = System.currentTimeMillis() + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 100, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Hey check this out I love spans!", + bodyRanges = listOf( + BodyRange( + start = 6, + length = 3, + style = BodyRange.Style.BOLD + ), + BodyRange( + start = 10, + length = 3, + style = BodyRange.Style.ITALIC + ), + BodyRange( + start = 14, + length = 3, + style = BodyRange.Style.SPOILER + ), + BodyRange( + start = 18, + length = 3, + style = BodyRange.Style.STRIKETHROUGH + ), + BodyRange( + start = 22, + length = 3, + style = BodyRange.Style.MONOSPACE + ), + BodyRange( + start = 4, + length = 0, + mentionAci = alice.contact!!.aci + ) + ) + ), + reactions = listOf( + Reaction(emoji = "F", authorId = selfRecipient.id, sentTimestamp = 302, receivedTimestamp = 303), + Reaction(emoji = "F", authorId = alice.id, sentTimestamp = 301, receivedTimestamp = 302) + ) + ) + ) + ) + } + + @Test + fun messageWithTextAndQuotes() { + val spans = listOf( + BodyRange( + start = 6, + length = 3, + style = BodyRange.Style.BOLD + ), + BodyRange( + start = 10, + length = 3, + style = BodyRange.Style.ITALIC + ), + BodyRange( + start = 14, + length = 3, + style = BodyRange.Style.SPOILER + ), + BodyRange( + start = 18, + length = 3, + style = BodyRange.Style.STRIKETHROUGH + ), + BodyRange( + start = 22, + length = 3, + style = BodyRange.Style.MONOSPACE + ) + ) + val time = System.currentTimeMillis() + importExport( + *standardFrames, + alice, + buildChat(alice, 1), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 100, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 101, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "I quoted an existing message" + ), + quote = Quote( + targetSentTimestamp = 100, + authorId = alice.id, + type = Quote.Type.NORMAL, + text = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ), + ChatItem( + chatId = 1, + authorId = selfRecipient.id, + dateSent = 102, + expireStartDate = time, + expiresInMs = TimeUnit.DAYS.toMillis(2), + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 105, + dateServerSent = 104, + read = true, + sealedSender = true + ), + standardMessage = StandardMessage( + text = Text( + body = "I quoted an non-existing message" + ), + quote = Quote( + targetSentTimestamp = 60, + authorId = alice.id, + type = Quote.Type.NORMAL, + text = "Hey check this out I love spans!", + bodyRanges = spans + ) + ) + ) + ) + } + + @Test + fun messagesNearExpirationNotExported() { + val chat = buildChat(alice, 1) + val expirationNotStarted = ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = 101, + expireStartDate = null, + expiresInMs = TimeUnit.DAYS.toMillis(1), + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 100, + dateServerSent = 100, + read = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Expiration not started but less than or equal to 1 day" + ) + ) + ) + import( + *standardFrames, + alice, + chat, + ChatItem( + chatId = 1, + authorId = alice.id, + dateSent = 100, + expireStartDate = System.currentTimeMillis(), + expiresInMs = TimeUnit.DAYS.toMillis(1), + sms = false, + incoming = ChatItem.IncomingMessageDetails( + dateReceived = 100, + dateServerSent = 100, + read = true + ), + standardMessage = StandardMessage( + text = Text( + body = "Near expiration" + ) + ) + ), + expirationNotStarted + ) + val exported = export() + val expected = exportFrames( + *standardFrames, + alice, + chat, + expirationNotStarted + ) + compare(expected, exported) + } + + fun enumerateIncomingMessageDetails(dateSent: Long): List { + val details = mutableListOf() + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = true, + sealedSender = true + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = true, + sealedSender = false + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = false, + sealedSender = true + ) + ) + details.add( + ChatItem.IncomingMessageDetails( + dateReceived = dateSent + 1, + dateServerSent = dateSent, + read = false, + sealedSender = false + ) + ) + return details + } + + fun enumerateSendStatuses(recipientId: Long): List { + val statuses = ArrayList() + val sealedSenderStates = listOf(true, false) + for (sealedSender in sealedSenderStates) { + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.DELIVERED, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.PENDING, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1, + networkFailure = true + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.SENT, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.READ, + sealedSender = sealedSender, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.PENDING, + sealedSender = sealedSender, + networkFailure = true, + lastStatusUpdateTimestamp = -1 + ) + ) + statuses.add( + SendStatus( + recipientId = recipientId, + deliveryStatus = SendStatus.Status.FAILED, + sealedSender = sealedSender, + identityKeyMismatch = true, + lastStatusUpdateTimestamp = -1 + ) + ) + } + return statuses + } + + private fun buildChat(recipient: Recipient, id: Long): Chat { + return Chat( + id = id, + recipientId = recipient.id, + archived = false, + pinnedOrder = 0, + expirationTimerMs = 0, + muteUntilMs = 0, + markedUnread = false, + dontNotifyForMentionsIfMuted = false, + wallpaper = null + ) + } + /** * Export passed in frames as a backup. Does not automatically include * any standard frames (e.g. backup header). @@ -468,7 +886,18 @@ class ImportExportTest { /** * Export our current database as a backup. */ - private fun export() = BackupRepository.export() + private fun export(): ByteArray { + val exportData = BackupRepository.export() + return exportData + } + + private fun validate(importData: ByteArray): MessageBackup.ValidationResult { + val factory = { ByteArrayInputStream(importData) } + val masterKey = SignalStore.svr().getOrCreateMasterKey() + val key = MessageBackupKey(masterKey.serialize(), org.signal.libsignal.protocol.ServiceId.Aci.parseFromBinary(SELF_ACI.toByteArray())) + + return MessageBackup.validate(key, factory, importData.size.toLong()) + } /** * Imports the passed in frames and then exports them. @@ -552,7 +981,7 @@ class ImportExportTest { prettyAssertEquals(accountImported, accountExported) prettyAssertEquals(recipientsImported, recipientsExported) { it.id } prettyAssertEquals(chatsImported, chatsExported) { it.id } - prettyAssertEquals(chatItemsImported, chatItemsExported) + prettyAssertEquals(chatItemsImported, chatItemsExported) { it.dateSent } prettyAssertEquals(callsImported, callsExported) { it.callId } prettyAssertEquals(stickersImported, stickersExported) { it.packId } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index 506058880e..4dd7c4fb05 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -70,13 +70,13 @@ object BackupRepository { ) } - val exportState = ExportState() + val exportState = ExportState(System.currentTimeMillis()) writer.use { writer.write( BackupInfo( version = VERSION, - backupTimeMs = System.currentTimeMillis() + backupTimeMs = exportState.backupTime ) ) // Note: Without a transaction, we may export inconsistent state. But because we have a transaction, @@ -396,7 +396,7 @@ object BackupRepository { } } -class ExportState { +class ExportState(val backupTime: Long) { val recipientIds = HashSet() val threadIds = HashSet() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt index 233b986a2a..b977ad34b8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt @@ -188,10 +188,10 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: } else { when { MessageTypes.isMissedAudioCall(record.type) -> { - builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_AUDIO_CALL))) + builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_INCOMING_AUDIO_CALL))) } MessageTypes.isMissedVideoCall(record.type) -> { - builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_VIDEO_CALL))) + builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.MISSED_INCOMING_VIDEO_CALL))) } MessageTypes.isIncomingAudioCall(record.type) -> { builder.updateMessage = ChatUpdateMessage(callingMessage = CallChatUpdate(callMessage = IndividualCallChatUpdate(type = IndividualCallChatUpdate.Type.INCOMING_AUDIO_CALL))) @@ -268,7 +268,6 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: chatId = record.threadId authorId = record.fromRecipientId dateSent = record.dateSent - sealedSender = record.sealedSender expireStartDate = if (record.expireStarted > 0) record.expireStarted else null expiresInMs = if (record.expiresIn > 0) record.expiresIn else null revisions = emptyList() @@ -282,7 +281,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: incoming = ChatItem.IncomingMessageDetails( dateServerSent = record.dateServer, dateReceived = record.dateReceived, - read = record.read + read = record.read, + sealedSender = record.sealedSender ) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt index 3fe1131b80..cfca33c537 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt @@ -268,7 +268,7 @@ class ChatItemImportInserter( contentValues.put(MessageTable.VIEWED_COLUMN, 0) contentValues.put(MessageTable.HAS_READ_RECEIPT, 0) contentValues.put(MessageTable.HAS_DELIVERY_RECEIPT, 0) - contentValues.put(MessageTable.UNIDENTIFIED, this.sealedSender?.toInt()) + contentValues.put(MessageTable.UNIDENTIFIED, this.incoming?.sealedSender?.toInt() ?: 0) contentValues.put(MessageTable.READ, this.incoming?.read?.toInt() ?: 0) contentValues.put(MessageTable.NOTIFIED, 1) } @@ -428,8 +428,10 @@ class ChatItemImportInserter( IndividualCallChatUpdate.Type.INCOMING_VIDEO_CALL -> MessageTypes.INCOMING_VIDEO_CALL_TYPE IndividualCallChatUpdate.Type.OUTGOING_AUDIO_CALL -> MessageTypes.OUTGOING_AUDIO_CALL_TYPE IndividualCallChatUpdate.Type.OUTGOING_VIDEO_CALL -> MessageTypes.OUTGOING_VIDEO_CALL_TYPE - IndividualCallChatUpdate.Type.MISSED_AUDIO_CALL -> MessageTypes.MISSED_AUDIO_CALL_TYPE - IndividualCallChatUpdate.Type.MISSED_VIDEO_CALL -> MessageTypes.MISSED_VIDEO_CALL_TYPE + IndividualCallChatUpdate.Type.MISSED_INCOMING_AUDIO_CALL -> MessageTypes.MISSED_AUDIO_CALL_TYPE + IndividualCallChatUpdate.Type.MISSED_INCOMING_VIDEO_CALL -> MessageTypes.MISSED_VIDEO_CALL_TYPE + IndividualCallChatUpdate.Type.UNANSWERED_OUTGOING_AUDIO_CALL -> MessageTypes.OUTGOING_AUDIO_CALL_TYPE + IndividualCallChatUpdate.Type.UNANSWERED_OUTGOING_VIDEO_CALL -> MessageTypes.OUTGOING_VIDEO_CALL_TYPE IndividualCallChatUpdate.Type.UNKNOWN -> typeFlags } } @@ -508,7 +510,7 @@ class ChatItemImportInserter( } return BodyRangeList( - ranges = this.map { bodyRange -> + ranges = this.filter { it.mentionAci == null }.map { bodyRange -> BodyRangeList.BodyRange( mentionUuid = bodyRange.mentionAci?.let { UuidUtil.fromByteString(it) }?.toString(), style = bodyRange.style?.let { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableBackupExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableBackupExtensions.kt index 5c483431d4..e08b820643 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableBackupExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableBackupExtensions.kt @@ -11,11 +11,12 @@ import org.signal.core.util.select import org.thoughtcrime.securesms.backup.v2.BackupState import org.thoughtcrime.securesms.database.MessageTable import org.thoughtcrime.securesms.database.MessageTypes +import java.util.concurrent.TimeUnit private val TAG = Log.tag(MessageTable::class.java) private const val BASE_TYPE = "base_type" -fun MessageTable.getMessagesForBackup(): ChatItemExportIterator { +fun MessageTable.getMessagesForBackup(backupTime: Long): ChatItemExportIterator { val cursor = readableDatabase .select( MessageTable.ID, @@ -53,13 +54,19 @@ fun MessageTable.getMessagesForBackup(): ChatItemExportIterator { .from(MessageTable.TABLE_NAME) .where( """ - $BASE_TYPE IN ( + ($BASE_TYPE IN ( ${MessageTypes.BASE_INBOX_TYPE}, ${MessageTypes.BASE_OUTBOX_TYPE}, ${MessageTypes.BASE_SENT_TYPE}, ${MessageTypes.BASE_SENDING_TYPE}, ${MessageTypes.BASE_SENT_FAILED_TYPE} - ) OR ${MessageTable.IS_CALL_TYPE_CLAUSE} + ) OR ${MessageTable.IS_CALL_TYPE_CLAUSE}) + AND + ( + ${MessageTable.EXPIRE_STARTED} = 0 + OR + (${MessageTable.EXPIRES_IN} > 0 AND (${MessageTable.EXPIRE_STARTED} + ${MessageTable.EXPIRES_IN}) > $backupTime + ${TimeUnit.DAYS.toMillis(1)}) + ) """ ) .orderBy("${MessageTable.DATE_RECEIVED} ASC") diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemBackupProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemBackupProcessor.kt index ef1aa6ab57..807e2931e6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemBackupProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemBackupProcessor.kt @@ -19,7 +19,7 @@ object ChatItemBackupProcessor { val TAG = Log.tag(ChatItemBackupProcessor::class.java) fun export(exportState: ExportState, emitter: BackupFrameEmitter) { - SignalDatabase.messages.getMessagesForBackup().use { chatItems -> + SignalDatabase.messages.getMessagesForBackup(exportState.backupTime).use { chatItems -> for (chatItem in chatItems) { if (exportState.threadIds.contains(chatItem.chatId)) { emitter.emit(Frame(chatItem = chatItem)) diff --git a/app/src/main/protowire/Backup.proto b/app/src/main/protowire/Backup.proto index 3897400c43..86f39d6757 100644 --- a/app/src/main/protowire/Backup.proto +++ b/app/src/main/protowire/Backup.proto @@ -48,21 +48,20 @@ message AccountData { bool readReceipts = 1; bool sealedSenderIndicators = 2; bool typingIndicators = 3; - bool noteToSelfMarkedUnread = 4; - bool linkPreviews = 5; - bool notDiscoverableByPhoneNumber = 6; - bool preferContactAvatars = 7; - uint32 universalExpireTimer = 8; // 0 means no universal expire timer. - repeated string preferredReactionEmoji = 9; - bool displayBadgesOnProfile = 10; - bool keepMutedChatsArchived = 11; - bool hasSetMyStoriesPrivacy = 12; - bool hasViewedOnboardingStory = 13; - bool storiesDisabled = 14; - optional bool storyViewReceiptsEnabled = 15; - bool hasSeenGroupStoryEducationSheet = 16; - bool hasCompletedUsernameOnboarding = 17; - PhoneNumberSharingMode phoneNumberSharingMode = 18; + bool linkPreviews = 4; + bool notDiscoverableByPhoneNumber = 5; + bool preferContactAvatars = 6; + uint32 universalExpireTimer = 7; // 0 means no universal expire timer. + repeated string preferredReactionEmoji = 8; + bool displayBadgesOnProfile = 9; + bool keepMutedChatsArchived = 10; + bool hasSetMyStoriesPrivacy = 11; + bool hasViewedOnboardingStory = 12; + bool storiesDisabled = 13; + optional bool storyViewReceiptsEnabled = 14; + bool hasSeenGroupStoryEducationSheet = 15; + bool hasCompletedUsernameOnboarding = 16; + PhoneNumberSharingMode phoneNumberSharingMode = 17; } bytes profileKey = 1; @@ -196,6 +195,7 @@ message ChatItem { uint64 dateReceived = 1; uint64 dateServerSent = 2; bool read = 3; + bool sealedSender = 4; } message OutgoingMessageDetails { @@ -208,24 +208,23 @@ message ChatItem { uint64 chatId = 1; // conversation id uint64 authorId = 2; // recipient id uint64 dateSent = 3; - bool sealedSender = 4; - optional uint64 expireStartDate = 5; // timestamp of when expiration timer started ticking down - optional uint64 expiresInMs = 6; // how long timer of message is (ms) - repeated ChatItem revisions = 7; // ordered from oldest to newest - bool sms = 8; + optional uint64 expireStartDate = 4; // timestamp of when expiration timer started ticking down + optional uint64 expiresInMs = 5; // how long timer of message is (ms) + repeated ChatItem revisions = 6; // ordered from oldest to newest + bool sms = 7; oneof directionalDetails { - IncomingMessageDetails incoming = 9; - OutgoingMessageDetails outgoing = 10; - DirectionlessMessageDetails directionless = 11; + IncomingMessageDetails incoming = 8; + OutgoingMessageDetails outgoing = 9; + DirectionlessMessageDetails directionless = 10; } oneof item { - StandardMessage standardMessage = 13; - ContactMessage contactMessage = 14; - StickerMessage stickerMessage = 15; - RemoteDeletedMessage remoteDeletedMessage = 16; - ChatUpdateMessage updateMessage = 17; + StandardMessage standardMessage = 11; + ContactMessage contactMessage = 12; + StickerMessage stickerMessage = 13; + RemoteDeletedMessage remoteDeletedMessage = 14; + ChatUpdateMessage updateMessage = 15; } } @@ -507,8 +506,10 @@ message IndividualCallChatUpdate { INCOMING_VIDEO_CALL = 2; OUTGOING_AUDIO_CALL = 3; OUTGOING_VIDEO_CALL = 4; - MISSED_AUDIO_CALL = 5; - MISSED_VIDEO_CALL = 6; + MISSED_INCOMING_AUDIO_CALL = 5; + MISSED_INCOMING_VIDEO_CALL = 6; + UNANSWERED_OUTGOING_AUDIO_CALL = 7; + UNANSWERED_OUTGOING_VIDEO_CALL = 8; } Type type = 1;