From 8a887b65a1adc3b87279b21f3f2fe5cd01912925 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Sat, 21 Mar 2026 08:53:47 -0400 Subject: [PATCH] Extract base archive classes into their own module. --- app/build.gradle.kts | 2 + .../backup/v2/ArchiveImportExportTests.kt | 4 +- .../securesms/backup/v2/ArchiveTypeAliases.kt | 6 +- .../securesms/backup/v2/BackupRepository.kt | 58 +-- .../RecipientTableArchiveExtensions.kt | 2 +- .../v2/exporters/AdHocCallArchiveExporter.kt | 2 +- .../v2/exporters/CallLinkArchiveExporter.kt | 2 +- .../v2/exporters/ChatArchiveExporter.kt | 2 +- .../v2/exporters/ChatItemArchiveExporter.kt | 89 +++-- .../v2/exporters/ContactArchiveExporter.kt | 4 +- .../DistributionListArchiveExporter.kt | 4 +- .../v2/exporters/GroupArchiveExporter.kt | 2 +- .../v2/importer/AdHodCallArchiveImporter.kt | 2 +- .../v2/importer/CallLinkArchiveImporter.kt | 2 +- .../backup/v2/importer/ChatArchiveImporter.kt | 2 +- .../v2/importer/ChatItemArchiveImporter.kt | 367 ++++++++++-------- .../v2/importer/ContactArchiveImporter.kt | 12 +- .../DistributionListArchiveImporter.kt | 9 +- .../v2/importer/GroupArchiveImporter.kt | 14 +- .../backup/v2/local/ArchiveFileSystem.kt | 1 + .../backup/v2/local/LocalArchiver.kt | 12 +- .../processor/AccountDataArchiveProcessor.kt | 91 +++-- .../v2/processor/AdHocCallArchiveProcessor.kt | 6 +- .../v2/processor/ChatArchiveProcessor.kt | 6 +- .../processor/ChatFolderArchiveProcessor.kt | 8 +- .../v2/processor/ChatItemArchiveProcessor.kt | 6 +- .../NotificationProfileArchiveProcessor.kt | 6 +- .../v2/processor/RecipientArchiveProcessor.kt | 23 +- .../v2/processor/StickerArchiveProcessor.kt | 6 +- .../v2/util/ArchiveConverterExtensions.kt | 35 +- .../backup/v2/util/ChatStyleConverter.kt | 10 +- .../backup/v2/util/FrameExtensions.kt | 34 +- .../InternalBackupPlaygroundViewModel.kt | 4 +- .../securesms/database/AttachmentTable.kt | 2 +- .../V258_FixGroupRevokedInviteeUpdate.kt | 9 +- .../migration/V264_FixGroupAddMemberUpdate.kt | 7 +- .../V267_FixGroupInvitationDeclinedUpdate.kt | 7 +- .../model/GroupCallUpdateDetailsUtil.java | 2 +- .../model/GroupsV2UpdateMessageConverter.kt | 68 ++-- .../model/GroupsV2UpdateMessageProducer.java | 74 ++-- .../database/model/MessageRecord.java | 4 +- .../securesms/groups/GroupProtoUtil.java | 2 +- .../securesms/keyvalue/InternalValues.kt | 2 +- .../thoughtcrime/securesms/BackupPlugin.kt | 30 +- .../backup/v2/local/LocalArchiverTest.kt | 10 +- .../stream/EncryptedBackupReaderWriterTest.kt | 8 +- lib/archive/build.gradle.kts | 27 ++ .../org/signal/archive/LocalBackupMetadata.kt | 16 + .../archive/LocalBackupRestoreProgress.kt | 30 ++ .../archive}/local/ArchivedFilesReader.kt | 4 +- .../archive}/local/ArchivedFilesWriter.kt | 4 +- .../archive}/stream/BackupExportWriter.kt | 6 +- .../archive}/stream/BackupFrameEmitter.kt | 4 +- .../archive}/stream/BackupImportReader.kt | 6 +- .../archive}/stream/BackupImportStream.kt | 4 +- .../archive}/stream/EncryptedBackupReader.kt | 6 +- .../archive}/stream/EncryptedBackupWriter.kt | 7 +- .../archive}/stream/PaddedGzipOutputStream.kt | 2 +- .../archive}/stream/PlainTextBackupReader.kt | 6 +- .../archive}/stream/PlainTextBackupWriter.kt | 6 +- .../archive}/src/main/protowire/Backup.proto | 2 +- .../src/main/protowire/BackupDebugInfo.proto | 2 +- .../src/main/protowire/LocalArchive.proto | 2 +- settings.gradle.kts | 1 + 64 files changed, 668 insertions(+), 525 deletions(-) create mode 100644 lib/archive/build.gradle.kts create mode 100644 lib/archive/src/main/java/org/signal/archive/LocalBackupMetadata.kt create mode 100644 lib/archive/src/main/java/org/signal/archive/LocalBackupRestoreProgress.kt rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/local/ArchivedFilesReader.kt (89%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/local/ArchivedFilesWriter.kt (82%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/BackupExportWriter.kt (54%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/BackupFrameEmitter.kt (68%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/BackupImportReader.kt (59%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/BackupImportStream.kt (57%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/EncryptedBackupReader.kt (97%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/EncryptedBackupWriter.kt (96%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/PaddedGzipOutputStream.kt (97%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/PlainTextBackupReader.kt (90%) rename {app/src/main/java/org/thoughtcrime/securesms/backup/v2 => lib/archive/src/main/java/org/signal/archive}/stream/PlainTextBackupWriter.kt (83%) rename {app => lib/archive}/src/main/protowire/Backup.proto (99%) rename {app => lib/archive}/src/main/protowire/BackupDebugInfo.proto (85%) rename {app => lib/archive}/src/main/protowire/LocalArchive.proto (90%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1b1b5fbfbe..79f0f0f67e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -92,6 +92,7 @@ wire { protoPath { srcDir("${project.rootDir}/lib/libsignal-service/src/main/protowire") + srcDir("${project.rootDir}/lib/archive/src/main/protowire") } // Handled by libsignal prune("signalservice.DecryptionErrorMessage") @@ -594,6 +595,7 @@ dependencies { ktlintRuleset(libs.ktlint.twitter.compose) coreLibraryDesugaring(libs.android.tools.desugar) + implementation(project(":lib:archive")) implementation(project(":lib:libsignal-service")) implementation(project(":lib:paging")) implementation(project(":core:util")) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt index 6f8056f64f..a4d4461ba9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt @@ -13,6 +13,8 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.signal.archive.proto.Frame +import org.signal.archive.stream.PlainTextBackupReader import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.logging.Log @@ -20,8 +22,6 @@ import org.signal.core.util.readFully import org.signal.libsignal.messagebackup.ComparableBackup import org.signal.libsignal.messagebackup.MessageBackup import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.PlainTextBackupReader import org.thoughtcrime.securesms.database.KeyValueDatabase import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveTypeAliases.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveTypeAliases.kt index 58c8f03724..507a2766d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveTypeAliases.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveTypeAliases.kt @@ -5,6 +5,6 @@ package org.thoughtcrime.securesms.backup.v2 -typealias ArchiveRecipient = org.thoughtcrime.securesms.backup.v2.proto.Recipient -typealias ArchiveGroup = org.thoughtcrime.securesms.backup.v2.proto.Group -typealias ArchiveCallLink = org.thoughtcrime.securesms.backup.v2.proto.CallLink +typealias ArchiveRecipient = org.signal.archive.proto.Recipient +typealias ArchiveGroup = org.signal.archive.proto.Group +typealias ArchiveCallLink = org.signal.archive.proto.CallLink 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 e6bb84cab4..7b30471998 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 @@ -18,6 +18,15 @@ import kotlinx.coroutines.withContext import okio.ByteString import okio.ByteString.Companion.toByteString import org.greenrobot.eventbus.EventBus +import org.signal.archive.proto.BackupDebugInfo +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupExportWriter +import org.signal.archive.stream.BackupImportReader +import org.signal.archive.stream.EncryptedBackupReader +import org.signal.archive.stream.EncryptedBackupWriter +import org.signal.archive.stream.PlainTextBackupReader +import org.signal.archive.stream.PlainTextBackupWriter import org.signal.core.models.AccountEntropyPool import org.signal.core.models.ServiceId.ACI import org.signal.core.models.ServiceId.PNI @@ -76,15 +85,6 @@ import org.thoughtcrime.securesms.backup.v2.processor.ChatItemArchiveProcessor import org.thoughtcrime.securesms.backup.v2.processor.NotificationProfileArchiveProcessor import org.thoughtcrime.securesms.backup.v2.processor.RecipientArchiveProcessor import org.thoughtcrime.securesms.backup.v2.processor.StickerArchiveProcessor -import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupExportWriter -import org.thoughtcrime.securesms.backup.v2.stream.BackupImportReader -import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupReader -import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupWriter -import org.thoughtcrime.securesms.backup.v2.stream.PlainTextBackupReader -import org.thoughtcrime.securesms.backup.v2.stream.PlainTextBackupWriter import org.thoughtcrime.securesms.backup.v2.ui.BackupAlert import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity @@ -1311,51 +1311,59 @@ object BackupRepository { val totalLength = frameReader.getStreamLength() var frameCount = 0 for (frame in frameReader) { + val frameAccount = frame.account + val frameRecipient = frame.recipient + val frameChat = frame.chat + val frameAdHocCall = frame.adHocCall + val frameStickerPack = frame.stickerPack + val frameNotificationProfile = frame.notificationProfile + val frameChatFolder = frame.chatFolder + val frameChatItem = frame.chatItem when { - frame.account != null -> { - AccountDataArchiveProcessor.import(frame.account, selfId, importState) + frameAccount != null -> { + AccountDataArchiveProcessor.import(frameAccount, selfId, importState) eventTimer.emit("account") frameCount++ } - frame.recipient != null -> { - RecipientArchiveProcessor.import(frame.recipient, importState) + frameRecipient != null -> { + RecipientArchiveProcessor.import(frameRecipient, importState) eventTimer.emit("recipient") frameCount++ } - frame.chat != null -> { - ChatArchiveProcessor.import(frame.chat, importState) + frameChat != null -> { + ChatArchiveProcessor.import(frameChat, importState) eventTimer.emit("chat") frameCount++ } - frame.adHocCall != null -> { - AdHocCallArchiveProcessor.import(frame.adHocCall, importState) + frameAdHocCall != null -> { + AdHocCallArchiveProcessor.import(frameAdHocCall, importState) eventTimer.emit("call") frameCount++ } - frame.stickerPack != null -> { - StickerArchiveProcessor.import(frame.stickerPack) + frameStickerPack != null -> { + StickerArchiveProcessor.import(frameStickerPack) eventTimer.emit("sticker-pack") frameCount++ } - frame.notificationProfile != null -> { - NotificationProfileArchiveProcessor.import(frame.notificationProfile, importState) + frameNotificationProfile != null -> { + NotificationProfileArchiveProcessor.import(frameNotificationProfile, importState) eventTimer.emit("notification-profile") frameCount++ } - frame.chatFolder != null -> { - ChatFolderArchiveProcessor.import(frame.chatFolder, importState) + frameChatFolder != null -> { + ChatFolderArchiveProcessor.import(frameChatFolder, importState) eventTimer.emit("chat-folder") frameCount++ } - frame.chatItem != null -> { - chatItemInserter.import(frame.chatItem) + frameChatItem != null -> { + chatItemInserter.import(frameChatItem) eventTimer.emit("chatItem") frameCount++ diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/RecipientTableArchiveExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/RecipientTableArchiveExtensions.kt index 4e93ca8195..04e1e69d9e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/RecipientTableArchiveExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/RecipientTableArchiveExtensions.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.backup.v2.database import android.content.ContentValues +import org.signal.archive.proto.AccountData import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.logging.Log @@ -15,7 +16,6 @@ import org.signal.core.util.update import org.signal.libsignal.zkgroup.InvalidInputException import org.thoughtcrime.securesms.backup.v2.exporters.ContactArchiveExporter import org.thoughtcrime.securesms.backup.v2.exporters.GroupArchiveExporter -import org.thoughtcrime.securesms.backup.v2.proto.AccountData import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.IdentityTable import org.thoughtcrime.securesms.database.RecipientTable diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/AdHocCallArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/AdHocCallArchiveExporter.kt index a11ceb3273..86edcd3c56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/AdHocCallArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/AdHocCallArchiveExporter.kt @@ -6,8 +6,8 @@ package org.thoughtcrime.securesms.backup.v2.database import android.database.Cursor +import org.signal.archive.proto.AdHocCall import org.signal.core.util.requireLong -import org.thoughtcrime.securesms.backup.v2.proto.AdHocCall import org.thoughtcrime.securesms.backup.v2.util.clampToValidBackupRange import org.thoughtcrime.securesms.database.CallTable import java.io.Closeable diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/CallLinkArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/CallLinkArchiveExporter.kt index 41d06eb952..f944d0113d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/CallLinkArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/CallLinkArchiveExporter.kt @@ -7,10 +7,10 @@ package org.thoughtcrime.securesms.backup.v2.database import android.database.Cursor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.CallLink import org.signal.core.util.nullIfEmpty import org.signal.ringrtc.CallLinkState import org.thoughtcrime.securesms.backup.v2.ArchiveRecipient -import org.thoughtcrime.securesms.backup.v2.proto.CallLink import org.thoughtcrime.securesms.backup.v2.util.clampToValidBackupRange import org.thoughtcrime.securesms.database.CallLinkTable import java.io.Closeable diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatArchiveExporter.kt index 89ebf186be..989fefcaf6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatArchiveExporter.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.backup.v2.exporters import android.database.Cursor +import org.signal.archive.proto.Chat import org.signal.core.util.decodeOrNull import org.signal.core.util.requireBlob import org.signal.core.util.requireBoolean @@ -13,7 +14,6 @@ import org.signal.core.util.requireInt import org.signal.core.util.requireIntOrNull import org.signal.core.util.requireLong import org.thoughtcrime.securesms.backup.v2.ExportState -import org.thoughtcrime.securesms.backup.v2.proto.Chat import org.thoughtcrime.securesms.backup.v2.util.ChatStyleConverter import org.thoughtcrime.securesms.backup.v2.util.isValid import org.thoughtcrime.securesms.conversation.colors.ChatColors diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt index ec73b60940..1a86ed2781 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt @@ -9,6 +9,38 @@ import android.database.Cursor import okio.ByteString.Companion.toByteString import org.json.JSONArray import org.json.JSONException +import org.signal.archive.proto.AdminDeletedMessage +import org.signal.archive.proto.ChatItem +import org.signal.archive.proto.ChatUpdateMessage +import org.signal.archive.proto.ContactAttachment +import org.signal.archive.proto.ContactMessage +import org.signal.archive.proto.DirectStoryReplyMessage +import org.signal.archive.proto.ExpirationTimerChatUpdate +import org.signal.archive.proto.GenericGroupUpdate +import org.signal.archive.proto.GroupCall +import org.signal.archive.proto.GroupChangeChatUpdate +import org.signal.archive.proto.GroupExpirationTimerUpdate +import org.signal.archive.proto.GroupV2MigrationUpdate +import org.signal.archive.proto.IndividualCall +import org.signal.archive.proto.LearnedProfileChatUpdate +import org.signal.archive.proto.MessageAttachment +import org.signal.archive.proto.PaymentNotification +import org.signal.archive.proto.PinMessageUpdate +import org.signal.archive.proto.Poll +import org.signal.archive.proto.PollTerminateUpdate +import org.signal.archive.proto.ProfileChangeChatUpdate +import org.signal.archive.proto.Quote +import org.signal.archive.proto.Reaction +import org.signal.archive.proto.RemoteDeletedMessage +import org.signal.archive.proto.SendStatus +import org.signal.archive.proto.SessionSwitchoverChatUpdate +import org.signal.archive.proto.SimpleChatUpdate +import org.signal.archive.proto.StandardMessage +import org.signal.archive.proto.Sticker +import org.signal.archive.proto.StickerMessage +import org.signal.archive.proto.Text +import org.signal.archive.proto.ThreadMergeChatUpdate +import org.signal.archive.proto.ViewOnceMessage import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.EventTimer @@ -41,38 +73,6 @@ import org.thoughtcrime.securesms.backup.v2.BackupMode import org.thoughtcrime.securesms.backup.v2.ExportOddities import org.thoughtcrime.securesms.backup.v2.ExportSkips import org.thoughtcrime.securesms.backup.v2.ExportState -import org.thoughtcrime.securesms.backup.v2.proto.AdminDeletedMessage -import org.thoughtcrime.securesms.backup.v2.proto.ChatItem -import org.thoughtcrime.securesms.backup.v2.proto.ChatUpdateMessage -import org.thoughtcrime.securesms.backup.v2.proto.ContactAttachment -import org.thoughtcrime.securesms.backup.v2.proto.ContactMessage -import org.thoughtcrime.securesms.backup.v2.proto.DirectStoryReplyMessage -import org.thoughtcrime.securesms.backup.v2.proto.ExpirationTimerChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GenericGroupUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupCall -import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupExpirationTimerUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationUpdate -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 -import org.thoughtcrime.securesms.backup.v2.proto.Quote -import org.thoughtcrime.securesms.backup.v2.proto.Reaction -import org.thoughtcrime.securesms.backup.v2.proto.RemoteDeletedMessage -import org.thoughtcrime.securesms.backup.v2.proto.SendStatus -import org.thoughtcrime.securesms.backup.v2.proto.SessionSwitchoverChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.SimpleChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage -import org.thoughtcrime.securesms.backup.v2.proto.Sticker -import org.thoughtcrime.securesms.backup.v2.proto.StickerMessage -import org.thoughtcrime.securesms.backup.v2.proto.Text -import org.thoughtcrime.securesms.backup.v2.proto.ThreadMergeChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.ViewOnceMessage import org.thoughtcrime.securesms.backup.v2.util.clampToValidBackupRange import org.thoughtcrime.securesms.backup.v2.util.toRemoteFilePointer import org.thoughtcrime.securesms.contactshare.Contact @@ -117,8 +117,8 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.Future import kotlin.math.max import kotlin.time.Duration.Companion.days -import org.thoughtcrime.securesms.backup.v2.proto.BodyRange as BackupBodyRange -import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge +import org.signal.archive.proto.BodyRange as BackupBodyRange +import org.signal.archive.proto.GiftBadge as BackupGiftBadge private val TAG = Log.tag(ChatItemArchiveExporter::class.java) private val MAX_INLINED_BODY_SIZE = 128.kibiBytes.bytes.toInt() @@ -958,8 +958,8 @@ private fun BackupMessageRecord.toRemoteLinkPreviews(attachments: List.withFixedVoiceNotes(textPresent: Boolean): L } private fun ChatItem.withDowngradeVoiceNotes(): ChatItem { - if (this.standardMessage == null) { - return this - } + val msg = this.standardMessage ?: return this - if (this.standardMessage.attachments.none { it.flag == MessageAttachment.Flag.VOICE_MESSAGE }) { + if (msg.attachments.none { it.flag == MessageAttachment.Flag.VOICE_MESSAGE }) { return this } return this.copy( - standardMessage = this.standardMessage.copy( - attachments = this.standardMessage.attachments.map { + standardMessage = msg.copy( + attachments = msg.attachments.map { if (it.flag == MessageAttachment.Flag.VOICE_MESSAGE) { it.copy(flag = MessageAttachment.Flag.NONE) } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ContactArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ContactArchiveExporter.kt index 61e10bc5a0..9e458bf19c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ContactArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ContactArchiveExporter.kt @@ -7,6 +7,8 @@ package org.thoughtcrime.securesms.backup.v2.exporters import android.database.Cursor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.Contact +import org.signal.archive.proto.Self import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.logging.Log @@ -18,8 +20,6 @@ import org.signal.core.util.requireLong import org.signal.core.util.requireString import org.signal.core.util.toByteArray import org.thoughtcrime.securesms.backup.v2.ArchiveRecipient -import org.thoughtcrime.securesms.backup.v2.proto.Contact -import org.thoughtcrime.securesms.backup.v2.proto.Self import org.thoughtcrime.securesms.backup.v2.util.clampToValidBackupRange import org.thoughtcrime.securesms.backup.v2.util.isValidUsername import org.thoughtcrime.securesms.backup.v2.util.toRemote diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt index e9236be5cd..0a8b68ede0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/DistributionListArchiveExporter.kt @@ -7,6 +7,8 @@ package org.thoughtcrime.securesms.backup.v2.exporters import android.database.Cursor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.DistributionList +import org.signal.archive.proto.DistributionListItem import org.signal.core.util.logging.Log import org.signal.core.util.requireBoolean import org.signal.core.util.requireLong @@ -17,8 +19,6 @@ import org.thoughtcrime.securesms.backup.v2.ArchiveRecipient import org.thoughtcrime.securesms.backup.v2.ExportOddities import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.database.getMembersForBackup -import org.thoughtcrime.securesms.backup.v2.proto.DistributionList -import org.thoughtcrime.securesms.backup.v2.proto.DistributionListItem import org.thoughtcrime.securesms.backup.v2.util.clampToValidBackupRange import org.thoughtcrime.securesms.database.DistributionListTables import org.thoughtcrime.securesms.database.model.DistributionListId diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt index 343ac27246..3c1e84963d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt @@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.backup.v2.exporters import android.database.Cursor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.Group import org.signal.core.models.ServiceId import org.signal.core.util.requireBlob import org.signal.core.util.requireBoolean @@ -24,7 +25,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedRequesting import org.signal.storageservice.storage.protos.groups.local.EnabledState import org.thoughtcrime.securesms.backup.v2.ArchiveGroup import org.thoughtcrime.securesms.backup.v2.ArchiveRecipient -import org.thoughtcrime.securesms.backup.v2.proto.Group import org.thoughtcrime.securesms.backup.v2.util.toRemote import org.thoughtcrime.securesms.conversation.colors.AvatarColor import org.thoughtcrime.securesms.database.GroupTable diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/AdHodCallArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/AdHodCallArchiveImporter.kt index 3d80c14c15..40d52ffabf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/AdHodCallArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/AdHodCallArchiveImporter.kt @@ -5,10 +5,10 @@ package org.thoughtcrime.securesms.backup.v2.importer +import org.signal.archive.proto.AdHocCall import org.signal.core.util.insertInto import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.AdHocCall import org.thoughtcrime.securesms.database.CallTable import org.thoughtcrime.securesms.database.SignalDatabase diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/CallLinkArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/CallLinkArchiveImporter.kt index 8cfc1ee2ac..8f2eebe5ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/CallLinkArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/CallLinkArchiveImporter.kt @@ -5,12 +5,12 @@ package org.thoughtcrime.securesms.backup.v2.importer +import org.signal.archive.proto.CallLink import org.signal.core.util.isEmpty import org.signal.core.util.logging.Log import org.signal.ringrtc.CallLinkRootKey import org.signal.ringrtc.CallLinkState import org.thoughtcrime.securesms.backup.v2.ArchiveCallLink -import org.thoughtcrime.securesms.backup.v2.proto.CallLink import org.thoughtcrime.securesms.database.CallLinkTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.recipients.RecipientId diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatArchiveImporter.kt index bd2ed9c7e2..5d4ef14b9e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatArchiveImporter.kt @@ -6,13 +6,13 @@ package org.thoughtcrime.securesms.backup.v2.importer import androidx.core.content.contentValuesOf +import org.signal.archive.proto.Chat import org.signal.core.util.SqlUtil import org.signal.core.util.insertInto import org.signal.core.util.toInt import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.backup.v2.ImportState import org.thoughtcrime.securesms.backup.v2.database.restoreWallpaperAttachment -import org.thoughtcrime.securesms.backup.v2.proto.Chat import org.thoughtcrime.securesms.backup.v2.util.parseChatWallpaper import org.thoughtcrime.securesms.backup.v2.util.toLocal import org.thoughtcrime.securesms.backup.v2.util.toLocalAttachment diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt index 6af0812cae..cf15461cf6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt @@ -7,6 +7,23 @@ package org.thoughtcrime.securesms.backup.v2.importer import android.content.ContentValues import androidx.core.content.contentValuesOf +import org.signal.archive.proto.BodyRange +import org.signal.archive.proto.ChatItem +import org.signal.archive.proto.ChatUpdateMessage +import org.signal.archive.proto.ContactAttachment +import org.signal.archive.proto.DirectStoryReplyMessage +import org.signal.archive.proto.GroupCall +import org.signal.archive.proto.IndividualCall +import org.signal.archive.proto.LinkPreview +import org.signal.archive.proto.MessageAttachment +import org.signal.archive.proto.PaymentNotification +import org.signal.archive.proto.Quote +import org.signal.archive.proto.Reaction +import org.signal.archive.proto.SendStatus +import org.signal.archive.proto.SimpleChatUpdate +import org.signal.archive.proto.StandardMessage +import org.signal.archive.proto.Sticker +import org.signal.archive.proto.ViewOnceMessage import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.Hex @@ -24,23 +41,6 @@ import org.thoughtcrime.securesms.attachments.PointerAttachment import org.thoughtcrime.securesms.attachments.TombstoneAttachment import org.thoughtcrime.securesms.backup.v2.ImportSkips import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.BodyRange -import org.thoughtcrime.securesms.backup.v2.proto.ChatItem -import org.thoughtcrime.securesms.backup.v2.proto.ChatUpdateMessage -import org.thoughtcrime.securesms.backup.v2.proto.ContactAttachment -import org.thoughtcrime.securesms.backup.v2.proto.DirectStoryReplyMessage -import org.thoughtcrime.securesms.backup.v2.proto.GroupCall -import org.thoughtcrime.securesms.backup.v2.proto.IndividualCall -import org.thoughtcrime.securesms.backup.v2.proto.LinkPreview -import org.thoughtcrime.securesms.backup.v2.proto.MessageAttachment -import org.thoughtcrime.securesms.backup.v2.proto.PaymentNotification -import org.thoughtcrime.securesms.backup.v2.proto.Quote -import org.thoughtcrime.securesms.backup.v2.proto.Reaction -import org.thoughtcrime.securesms.backup.v2.proto.SendStatus -import org.thoughtcrime.securesms.backup.v2.proto.SimpleChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage -import org.thoughtcrime.securesms.backup.v2.proto.Sticker -import org.thoughtcrime.securesms.backup.v2.proto.ViewOnceMessage import org.thoughtcrime.securesms.backup.v2.util.toLocalAttachment import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.database.AttachmentTable @@ -89,7 +89,7 @@ import java.math.BigInteger import java.sql.SQLException import java.util.Optional import java.util.UUID -import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge +import org.signal.archive.proto.GiftBadge as BackupGiftBadge /** * An object that will ingest all of the [ChatItem]s you want to write, buffer them until hitting a specified batch size, and then batch insert them @@ -194,7 +194,8 @@ class ChatItemArchiveImporter( return } - if (chatItem.adminDeletedMessage != null && importState.remoteToLocalRecipientId[chatItem.adminDeletedMessage.adminId] == null) { + val adminDeletedMessage = chatItem.adminDeletedMessage + if (adminDeletedMessage != null && importState.remoteToLocalRecipientId[adminDeletedMessage.adminId] == null) { Log.w(TAG, ImportSkips.missingAdminDeleteRecipient(chatItem.dateSent, chatItem.chatId)) return } @@ -286,17 +287,22 @@ class ChatItemArchiveImporter( val followUps: MutableList<(Long) -> Unit> = mutableListOf() - if (this.updateMessage != null) { - if (this.updateMessage.individualCall != null && this.updateMessage.individualCall.callId != null) { + val updateMessage = this.updateMessage + if (updateMessage != null) { + val individualCall = updateMessage.individualCall + val groupCall = updateMessage.groupCall + val pollTerminate = updateMessage.pollTerminate + val pinMessage = updateMessage.pinMessage + if (individualCall != null && individualCall.callId != null) { followUps += { messageRowId -> val values = contentValuesOf( - CallTable.CALL_ID to updateMessage.individualCall.callId, + CallTable.CALL_ID to individualCall.callId, CallTable.MESSAGE_ID to messageRowId, CallTable.PEER to chatRecipientId.serialize(), - CallTable.TYPE to CallTable.Type.serialize(if (updateMessage.individualCall.type == IndividualCall.Type.VIDEO_CALL) CallTable.Type.VIDEO_CALL else CallTable.Type.AUDIO_CALL), - CallTable.DIRECTION to CallTable.Direction.serialize(if (updateMessage.individualCall.direction == IndividualCall.Direction.OUTGOING) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING), + CallTable.TYPE to CallTable.Type.serialize(if (individualCall.type == IndividualCall.Type.VIDEO_CALL) CallTable.Type.VIDEO_CALL else CallTable.Type.AUDIO_CALL), + CallTable.DIRECTION to CallTable.Direction.serialize(if (individualCall.direction == IndividualCall.Direction.OUTGOING) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING), CallTable.EVENT to CallTable.Event.serialize( - when (updateMessage.individualCall.state) { + when (individualCall.state) { IndividualCall.State.MISSED -> CallTable.Event.MISSED IndividualCall.State.MISSED_NOTIFICATION_PROFILE -> CallTable.Event.MISSED_NOTIFICATION_PROFILE IndividualCall.State.ACCEPTED -> CallTable.Event.ACCEPTED @@ -304,24 +310,24 @@ class ChatItemArchiveImporter( else -> CallTable.Event.MISSED } ), - CallTable.TIMESTAMP to updateMessage.individualCall.startedCallTimestamp, - CallTable.READ to updateMessage.individualCall.read + CallTable.TIMESTAMP to individualCall.startedCallTimestamp, + CallTable.READ to individualCall.read ) db.insert(CallTable.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values) } - } else if (this.updateMessage.groupCall != null && this.updateMessage.groupCall.callId != null) { + } else if (groupCall != null && groupCall.callId != null) { followUps += { messageRowId -> - val ringer: RecipientId? = this.updateMessage.groupCall.ringerRecipientId?.let { importState.remoteToLocalRecipientId[it] } + val ringer: RecipientId? = groupCall.ringerRecipientId?.let { importState.remoteToLocalRecipientId[it] } val values = contentValuesOf( - CallTable.CALL_ID to updateMessage.groupCall.callId, + CallTable.CALL_ID to groupCall.callId, CallTable.MESSAGE_ID to messageRowId, CallTable.PEER to chatRecipientId.serialize(), CallTable.RINGER to ringer?.serialize(), CallTable.TYPE to CallTable.Type.serialize(CallTable.Type.GROUP_CALL), CallTable.DIRECTION to CallTable.Direction.serialize(if (ringer == selfId) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING), CallTable.EVENT to CallTable.Event.serialize( - when (updateMessage.groupCall.state) { + when (groupCall.state) { GroupCall.State.ACCEPTED -> CallTable.Event.ACCEPTED GroupCall.State.MISSED -> CallTable.Event.MISSED GroupCall.State.MISSED_NOTIFICATION_PROFILE -> CallTable.Event.MISSED_NOTIFICATION_PROFILE @@ -333,17 +339,17 @@ class ChatItemArchiveImporter( else -> CallTable.Event.GENERIC_GROUP_CALL } ), - CallTable.TIMESTAMP to updateMessage.groupCall.startedCallTimestamp, + CallTable.TIMESTAMP to groupCall.startedCallTimestamp, CallTable.READ to CallTable.ReadState.serialize(CallTable.ReadState.READ) ) db.insert(CallTable.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values) } - } else if (this.updateMessage.pollTerminate != null) { + } else if (pollTerminate != null) { followUps += { endPollMessageId -> - val pollMessageId = SignalDatabase.messages.getMessageFor(updateMessage.pollTerminate.targetSentTimestamp, fromRecipientId)?.id ?: -1 + val pollMessageId = SignalDatabase.messages.getMessageFor(pollTerminate.targetSentTimestamp, fromRecipientId)?.id ?: -1 val pollId = SignalDatabase.polls.getPollId(pollMessageId) - val messageExtras = MessageExtras(pollTerminate = PollTerminate(question = updateMessage.pollTerminate.question, messageId = pollMessageId, targetTimestamp = updateMessage.pollTerminate.targetSentTimestamp)) + val messageExtras = MessageExtras(pollTerminate = PollTerminate(question = pollTerminate.question, messageId = pollMessageId, targetTimestamp = pollTerminate.targetSentTimestamp)) db.update(MessageTable.TABLE_NAME) .values(MessageTable.MESSAGE_EXTRAS to messageExtras.encode()) .where("${MessageTable.ID} = ?", endPollMessageId) @@ -353,16 +359,16 @@ class ChatItemArchiveImporter( SignalDatabase.polls.endPoll(pollId = pollId, endingMessageId = endPollMessageId) } } - } else if (this.updateMessage.pinMessage != null) { + } else if (pinMessage != null) { followUps += { pinUpdateMessageId -> - val targetAuthorId = importState.remoteToLocalRecipientId[updateMessage.pinMessage.authorId] + val targetAuthorId = importState.remoteToLocalRecipientId[pinMessage.authorId] if (targetAuthorId != null) { - val pinnedMessageId = SignalDatabase.messages.getMessageFor(updateMessage.pinMessage.targetSentTimestamp, targetAuthorId)?.id ?: -1 + val pinnedMessageId = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp, targetAuthorId)?.id ?: -1 val messageExtras = MessageExtras( pinnedMessage = PinnedMessage( pinnedMessageId = pinnedMessageId, targetAuthorAci = recipients.getRecord(targetAuthorId).aci!!.toByteString(), - targetTimestamp = updateMessage.pinMessage.targetSentTimestamp + targetTimestamp = pinMessage.targetSentTimestamp ) ) @@ -397,8 +403,9 @@ class ChatItemArchiveImporter( } } - if (this.contactMessage != null) { - val contact = this.contactMessage.contact?.let { backupContact -> + val contactMessage = this.contactMessage + if (contactMessage != null) { + val contact = contactMessage.contact?.let { backupContact -> Contact( backupContact.name.toLocal(), backupContact.organization, @@ -453,8 +460,9 @@ class ChatItemArchiveImporter( } } - if (this.directStoryReplyMessage != null) { - val (trimmedBodyText, longTextAttachment) = this.directStoryReplyMessage.parseBodyText(importState) + val directStoryReplyMessage = this.directStoryReplyMessage + if (directStoryReplyMessage != null) { + val (trimmedBodyText, longTextAttachment) = directStoryReplyMessage.parseBodyText(importState) if (trimmedBodyText != null) { contentValues.put(MessageTable.BODY, trimmedBodyText) } @@ -469,25 +477,26 @@ class ChatItemArchiveImporter( } } - if (this.standardMessage != null) { - val mentions = this.standardMessage.text?.bodyRanges.filterToLocalMentions() + val standardMessage = this.standardMessage + if (standardMessage != null) { + val mentions = standardMessage.text?.bodyRanges.filterToLocalMentions() if (mentions.isNotEmpty()) { followUps += { messageId -> SignalDatabase.mentions.insert(threadId, messageId, mentions) } } - val linkPreviews = this.standardMessage.linkPreview.map { it.toLocalLinkPreview() } + val linkPreviews = standardMessage.linkPreview.map { it.toLocalLinkPreview() } val linkPreviewAttachments: List = linkPreviews.mapNotNull { it.thumbnail.orNull() } - val attachments: List = this.standardMessage.attachments.mapNotNull { attachment -> + val attachments: List = standardMessage.attachments.mapNotNull { attachment -> attachment.toLocalAttachment() } - val (trimmedBodyText, longTextAttachment) = this.standardMessage.parseBodyText(importState) + val (trimmedBodyText, longTextAttachment) = standardMessage.parseBodyText(importState) if (trimmedBodyText != null) { contentValues.put(MessageTable.BODY, trimmedBodyText) } - val quoteAttachments: List = this.standardMessage.quote?.toLocalAttachments() ?: emptyList() + val quoteAttachments: List = standardMessage.quote?.toLocalAttachments() ?: emptyList() val hasAttachments = attachments.isNotEmpty() || linkPreviewAttachments.isNotEmpty() || quoteAttachments.isNotEmpty() || longTextAttachment != null @@ -515,8 +524,9 @@ class ChatItemArchiveImporter( } } - if (this.stickerMessage != null) { - val sticker = this.stickerMessage.sticker + val stickerMessage = this.stickerMessage + if (stickerMessage != null) { + val sticker = stickerMessage.sticker val attachment = sticker.toLocalAttachment() if (attachment != null) { followUps += { messageRowId -> @@ -525,8 +535,9 @@ class ChatItemArchiveImporter( } } - if (this.viewOnceMessage != null) { - val attachment = this.viewOnceMessage.attachment?.toLocalAttachment() + val viewOnceMessage = this.viewOnceMessage + if (viewOnceMessage != null) { + val attachment = viewOnceMessage.attachment?.toLocalAttachment() if (attachment != null) { followUps += { messageRowId -> SignalDatabase.attachments.insertAttachmentsForMessage(messageRowId, listOf(attachment), emptyList()) @@ -534,7 +545,8 @@ class ChatItemArchiveImporter( } } - if (this.poll != null) { + val poll = this.poll + if (poll != null) { contentValues.put(MessageTable.BODY, poll.question) contentValues.put(MessageTable.VOTES_LAST_SEEN, System.currentTimeMillis()) @@ -582,15 +594,14 @@ class ChatItemArchiveImporter( * If the attachment is non-null, then you should store it along with the message, as it contains the long text. */ private fun StandardMessage.parseBodyText(importState: ImportState): Pair { - if (this.longText != null) { - return null to this.longText.toLocalAttachment(contentType = "text/x-signal-plain") + val longText = this.longText + if (longText != null) { + return null to longText.toLocalAttachment(contentType = "text/x-signal-plain") } - if (this.text?.body == null) { - return null to null - } + val body = this.text?.body ?: return null to null - val splitResult = MessageUtil.getSplitMessage(AppDependencies.application, this.text.body) + val splitResult = MessageUtil.getSplitMessage(AppDependencies.application, body) if (splitResult.textSlide.isPresent) { return splitResult.body to splitResult.textSlide.get().asAttachment() } @@ -606,15 +617,15 @@ class ChatItemArchiveImporter( * If the attachment is non-null, then you should store it along with the message, as it contains the long text. */ private fun DirectStoryReplyMessage.parseBodyText(importState: ImportState): Pair { - if (this.textReply?.longText != null) { - return null to this.textReply.longText.toLocalAttachment(contentType = "text/x-signal-plain") + val textReply = this.textReply + val longText = textReply?.longText + if (longText != null) { + return null to longText.toLocalAttachment(contentType = "text/x-signal-plain") } - if (this.textReply?.text == null) { - return null to null - } + val body = textReply?.text?.body ?: return null to null - val splitResult = MessageUtil.getSplitMessage(AppDependencies.application, this.textReply.text.body) + val splitResult = MessageUtil.getSplitMessage(AppDependencies.application, body) if (splitResult.textSlide.isPresent) { return splitResult.body to splitResult.textSlide.get().asAttachment() } @@ -625,16 +636,20 @@ class ChatItemArchiveImporter( private fun ChatItem.toMessageContentValues(fromRecipientId: RecipientId, chatRecipientId: RecipientId, threadId: Long): ContentValues { val contentValues = ContentValues() - val toRecipientId = if (this.outgoing != null) chatRecipientId else selfId + val outgoing = this.outgoing + val incoming = this.incoming + val directionless = this.directionless + + val toRecipientId = if (outgoing != null) chatRecipientId else selfId contentValues.put(MessageTable.TYPE, this.getMessageType()) contentValues.put(MessageTable.DATE_SENT, this.dateSent) - contentValues.put(MessageTable.DATE_SERVER, this.incoming?.dateServerSent ?: -1) + contentValues.put(MessageTable.DATE_SERVER, incoming?.dateServerSent ?: -1) contentValues.put(MessageTable.FROM_RECIPIENT_ID, fromRecipientId.serialize()) contentValues.put(MessageTable.TO_RECIPIENT_ID, toRecipientId.serialize()) contentValues.put(MessageTable.THREAD_ID, threadId) - contentValues.put(MessageTable.DATE_RECEIVED, this.incoming?.dateReceived ?: this.outgoing?.dateReceived?.takeUnless { it == 0L } ?: this.dateSent) - contentValues.put(MessageTable.RECEIPT_TIMESTAMP, this.outgoing?.sendStatus?.maxOfOrNull { it.timestamp } ?: 0) + contentValues.put(MessageTable.DATE_RECEIVED, incoming?.dateReceived ?: outgoing?.dateReceived?.takeUnless { it == 0L } ?: this.dateSent) + contentValues.put(MessageTable.RECEIPT_TIMESTAMP, outgoing?.sendStatus?.maxOfOrNull { it.timestamp } ?: 0) contentValues.putNull(MessageTable.LATEST_REVISION_ID) contentValues.putNull(MessageTable.ORIGINAL_MESSAGE_ID) contentValues.put(MessageTable.REVISION_NUMBER, 0) @@ -642,29 +657,29 @@ class ChatItemArchiveImporter( contentValues.put(MessageTable.EXPIRE_STARTED, this.expireStartDate ?: 0) when { - this.outgoing != null -> { - val viewed = this.outgoing.sendStatus.any { it.viewed != null } - val hasReadReceipt = viewed || this.outgoing.sendStatus.any { it.read != null } - val hasDeliveryReceipt = viewed || hasReadReceipt || this.outgoing.sendStatus.any { it.delivered != null } + outgoing != null -> { + val viewed = outgoing.sendStatus.any { it.viewed != null } + val hasReadReceipt = viewed || outgoing.sendStatus.any { it.read != null } + val hasDeliveryReceipt = viewed || hasReadReceipt || outgoing.sendStatus.any { it.delivered != null } contentValues.put(MessageTable.VIEWED_COLUMN, viewed.toInt()) contentValues.put(MessageTable.HAS_READ_RECEIPT, hasReadReceipt.toInt()) contentValues.put(MessageTable.HAS_DELIVERY_RECEIPT, hasDeliveryReceipt.toInt()) - contentValues.put(MessageTable.UNIDENTIFIED, this.outgoing.sendStatus.count { it.sealedSender }) + contentValues.put(MessageTable.UNIDENTIFIED, outgoing.sendStatus.count { it.sealedSender }) contentValues.put(MessageTable.READ, 1) contentValues.addNetworkFailures(this, importState) contentValues.addIdentityKeyMismatches(this, importState) } - this.incoming != null -> { + incoming != null -> { 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.incoming.sealedSender.toInt()) - contentValues.put(MessageTable.READ, this.incoming.read.toInt()) + contentValues.put(MessageTable.UNIDENTIFIED, incoming.sealedSender.toInt()) + contentValues.put(MessageTable.READ, incoming.read.toInt()) contentValues.put(MessageTable.NOTIFIED, 1) } - this.directionless != null -> { + directionless != null -> { contentValues.put(MessageTable.VIEWED_COLUMN, 0) contentValues.put(MessageTable.HAS_READ_RECEIPT, 0) contentValues.put(MessageTable.HAS_DELIVERY_RECEIPT, 0) @@ -680,21 +695,30 @@ class ChatItemArchiveImporter( contentValues.put(MessageTable.VIEW_ONCE, 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 + val pinDetails = this.pinDetails + if (pinDetails != null) { + val pinnedUntil = if (pinDetails.pinNeverExpires == true) MessageTable.PIN_FOREVER else pinDetails.pinExpiresAtTimestamp contentValues.put(MessageTable.PINNED_UNTIL, pinnedUntil ?: 0) - contentValues.put(MessageTable.PINNED_AT, this.pinDetails.pinnedAtTimestamp) + contentValues.put(MessageTable.PINNED_AT, pinDetails.pinnedAtTimestamp) } + val itemStandardMessage = this.standardMessage + val itemRemoteDeletedMessage = this.remoteDeletedMessage + val itemUpdateMessage = this.updateMessage + val itemPaymentNotification = this.paymentNotification + val itemGiftBadge = this.giftBadge + val itemViewOnceMessage = this.viewOnceMessage + val itemDirectStoryReplyMessage = this.directStoryReplyMessage + val itemAdminDeletedMessage = this.adminDeletedMessage when { - this.standardMessage != null -> contentValues.addStandardMessage(this.standardMessage) - this.remoteDeletedMessage != null -> contentValues.put(MessageTable.DELETED_BY, fromRecipientId.toLong()) - this.updateMessage != null -> contentValues.addUpdateMessage(this.updateMessage, fromRecipientId, toRecipientId) - this.paymentNotification != null -> contentValues.addPaymentNotification(this, chatRecipientId) - this.giftBadge != null -> contentValues.addGiftBadge(this.giftBadge) - this.viewOnceMessage != null -> contentValues.addViewOnce(this.viewOnceMessage) - this.directStoryReplyMessage != null -> contentValues.addDirectStoryReply(this.directStoryReplyMessage, toRecipientId) - this.adminDeletedMessage != null -> contentValues.put(MessageTable.DELETED_BY, importState.remoteToLocalRecipientId[this.adminDeletedMessage.adminId]!!.toLong()) + itemStandardMessage != null -> contentValues.addStandardMessage(itemStandardMessage) + itemRemoteDeletedMessage != null -> contentValues.put(MessageTable.DELETED_BY, fromRecipientId.toLong()) + itemUpdateMessage != null -> contentValues.addUpdateMessage(itemUpdateMessage, fromRecipientId, toRecipientId) + itemPaymentNotification != null -> contentValues.addPaymentNotification(this, chatRecipientId) + itemGiftBadge != null -> contentValues.addGiftBadge(itemGiftBadge) + itemViewOnceMessage != null -> contentValues.addViewOnce(itemViewOnceMessage) + itemDirectStoryReplyMessage != null -> contentValues.addDirectStoryReply(itemDirectStoryReplyMessage, toRecipientId) + itemAdminDeletedMessage != null -> contentValues.put(MessageTable.DELETED_BY, importState.remoteToLocalRecipientId[itemAdminDeletedMessage.adminId]!!.toLong()) } return contentValues @@ -733,15 +757,13 @@ class ChatItemArchiveImporter( } private fun ChatItem.toReactionContentValues(messageId: Long): List { - val reactions: List = when { - this.standardMessage != null -> this.standardMessage.reactions - this.contactMessage != null -> this.contactMessage.reactions - this.stickerMessage != null -> this.stickerMessage.reactions - this.viewOnceMessage != null -> this.viewOnceMessage.reactions - this.directStoryReplyMessage != null -> this.directStoryReplyMessage.reactions - this.poll != null -> this.poll.reactions - else -> emptyList() - } + val reactions: List = this.standardMessage?.reactions + ?: this.contactMessage?.reactions + ?: this.stickerMessage?.reactions + ?: this.viewOnceMessage?.reactions + ?: this.directStoryReplyMessage?.reactions + ?: this.poll?.reactions + ?: emptyList() return reactions .mapNotNull { @@ -763,16 +785,14 @@ class ChatItemArchiveImporter( } private fun ChatItem.toGroupReceiptContentValues(messageId: Long, chatBackupRecipientId: Long): List { - if (this.outgoing == null) { - return emptyList() - } + val outgoing = this.outgoing ?: return emptyList() // TODO [backup] This seems like an indirect/bad way to detect if this is a 1:1 or group convo - if (this.outgoing.sendStatus.size == 1 && this.outgoing.sendStatus[0].recipientId == chatBackupRecipientId) { + if (outgoing.sendStatus.size == 1 && outgoing.sendStatus[0].recipientId == chatBackupRecipientId) { return emptyList() } - return this.outgoing.sendStatus.mapNotNull { sendStatus -> + return outgoing.sendStatus.mapNotNull { sendStatus -> val recipientId = importState.remoteToLocalRecipientId[sendStatus.recipientId] if (recipientId != null) { @@ -791,16 +811,17 @@ class ChatItemArchiveImporter( } private fun ChatItem.getMessageType(): Long { - var type: Long = if (this.outgoing != null) { - if (this.outgoing.sendStatus.any { it.pending != null }) { + val outgoing = this.outgoing + var type: Long = if (outgoing != null) { + if (outgoing.sendStatus.any { it.pending != null }) { MessageTypes.BASE_SENDING_TYPE - } else if (this.outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.IDENTITY_KEY_MISMATCH }) { + } else if (outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.IDENTITY_KEY_MISMATCH }) { MessageTypes.BASE_SENT_FAILED_TYPE - } else if (this.outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.UNKNOWN }) { + } else if (outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.UNKNOWN }) { MessageTypes.BASE_SENT_FAILED_TYPE - } else if (this.outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.NETWORK }) { + } else if (outgoing.sendStatus.any { it.failed?.reason == SendStatus.Failed.FailureReason.NETWORK }) { MessageTypes.BASE_SENT_FAILED_TYPE - } else if (this.outgoing.sendStatus.all { it.skipped != null }) { + } else if (outgoing.sendStatus.all { it.skipped != null }) { MessageTypes.BASE_SENDING_SKIPPED_TYPE } else { MessageTypes.BASE_SENT_TYPE @@ -825,25 +846,38 @@ class ChatItemArchiveImporter( } private fun ContentValues.addStandardMessage(standardMessage: StandardMessage) { - if (standardMessage.text != null) { - this.put(MessageTable.BODY, standardMessage.text.body) + val text = standardMessage.text + if (text != null) { + this.put(MessageTable.BODY, text.body) - if (standardMessage.text.bodyRanges.isNotEmpty()) { - this.put(MessageTable.MESSAGE_RANGES, standardMessage.text.bodyRanges.toLocalBodyRanges()?.encode()) + if (text.bodyRanges.isNotEmpty()) { + this.put(MessageTable.MESSAGE_RANGES, text.bodyRanges.toLocalBodyRanges()?.encode()) } } - if (standardMessage.quote != null) { - this.addQuote(standardMessage.quote) + val quote = standardMessage.quote + if (quote != null) { + this.addQuote(quote) } } private fun ContentValues.addUpdateMessage(updateMessage: ChatUpdateMessage, fromRecipientId: RecipientId, toRecipientId: RecipientId) { var typeFlags: Long = 0 + val simpleUpdate = updateMessage.simpleUpdate + val expirationTimerChange = updateMessage.expirationTimerChange + val profileChange = updateMessage.profileChange + val learnedProfileChange = updateMessage.learnedProfileChange + val pollTerminate = updateMessage.pollTerminate + val pinMessage = updateMessage.pinMessage + val sessionSwitchover = updateMessage.sessionSwitchover + val threadMerge = updateMessage.threadMerge + val individualCall = updateMessage.individualCall + val groupCall = updateMessage.groupCall + val groupChange = updateMessage.groupChange when { - updateMessage.simpleUpdate != null -> { + simpleUpdate != null -> { val typeWithoutBase = (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) - typeFlags = when (updateMessage.simpleUpdate.type) { + typeFlags = when (simpleUpdate.type) { SimpleChatUpdate.Type.UNKNOWN -> typeWithoutBase SimpleChatUpdate.Type.JOINED_SIGNAL -> MessageTypes.JOINED_TYPE or typeWithoutBase SimpleChatUpdate.Type.IDENTITY_UPDATE -> MessageTypes.KEY_EXCHANGE_IDENTITY_UPDATE_BIT or typeWithoutBase @@ -864,59 +898,59 @@ class ChatItemArchiveImporter( } // Identity verification changes have to/from swapped - if (updateMessage.simpleUpdate.type == SimpleChatUpdate.Type.IDENTITY_VERIFIED || updateMessage.simpleUpdate.type == SimpleChatUpdate.Type.IDENTITY_DEFAULT) { + if (simpleUpdate.type == SimpleChatUpdate.Type.IDENTITY_VERIFIED || simpleUpdate.type == SimpleChatUpdate.Type.IDENTITY_DEFAULT) { put(MessageTable.FROM_RECIPIENT_ID, toRecipientId.serialize()) put(MessageTable.TO_RECIPIENT_ID, fromRecipientId.serialize()) } } - updateMessage.expirationTimerChange != null -> { + expirationTimerChange != null -> { typeFlags = getAsLong(MessageTable.TYPE) or MessageTypes.EXPIRATION_TIMER_UPDATE_BIT - put(MessageTable.EXPIRES_IN, updateMessage.expirationTimerChange.expiresInMs) + put(MessageTable.EXPIRES_IN, expirationTimerChange.expiresInMs) } - updateMessage.profileChange != null -> { + profileChange != null -> { typeFlags = MessageTypes.PROFILE_CHANGE_TYPE - val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = updateMessage.profileChange.previousName, newValue = updateMessage.profileChange.newName)) + val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = profileChange.previousName, newValue = profileChange.newName)) val messageExtras = MessageExtras(profileChangeDetails = profileChangeDetails).encode() put(MessageTable.MESSAGE_EXTRAS, messageExtras) } - updateMessage.learnedProfileChange != null -> { + learnedProfileChange != null -> { typeFlags = MessageTypes.PROFILE_CHANGE_TYPE - val profileChangeDetails = ProfileChangeDetails(learnedProfileName = ProfileChangeDetails.LearnedProfileName(e164 = updateMessage.learnedProfileChange.e164?.toString(), username = updateMessage.learnedProfileChange.username)) + val profileChangeDetails = ProfileChangeDetails(learnedProfileName = ProfileChangeDetails.LearnedProfileName(e164 = learnedProfileChange.e164?.toString(), username = learnedProfileChange.username)) val messageExtras = MessageExtras(profileChangeDetails = profileChangeDetails).encode() put(MessageTable.MESSAGE_EXTRAS, messageExtras) } - updateMessage.pollTerminate != null -> { + pollTerminate != null -> { typeFlags = MessageTypes.SPECIAL_TYPE_POLL_TERMINATE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) } - updateMessage.pinMessage != null -> { + pinMessage != null -> { typeFlags = MessageTypes.SPECIAL_TYPE_PINNED_MESSAGE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) } - updateMessage.sessionSwitchover != null -> { + 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() + val sessionSwitchoverDetails = SessionSwitchoverEvent(e164 = sessionSwitchover.e164.toString()).encode() put(MessageTable.BODY, Base64.encodeWithPadding(sessionSwitchoverDetails)) } - updateMessage.threadMerge != null -> { + threadMerge != null -> { typeFlags = MessageTypes.THREAD_MERGE_TYPE or (getAsLong(MessageTable.TYPE) and MessageTypes.BASE_TYPE_MASK.inv()) - val threadMergeDetails = ThreadMergeEvent(previousE164 = updateMessage.threadMerge.previousE164.toString()).encode() + val threadMergeDetails = ThreadMergeEvent(previousE164 = threadMerge.previousE164.toString()).encode() put(MessageTable.BODY, Base64.encodeWithPadding(threadMergeDetails)) } - updateMessage.individualCall != null -> { - if (updateMessage.individualCall.state == IndividualCall.State.MISSED || updateMessage.individualCall.state == IndividualCall.State.MISSED_NOTIFICATION_PROFILE) { - typeFlags = if (updateMessage.individualCall.type == IndividualCall.Type.AUDIO_CALL) { + individualCall != null -> { + if (individualCall.state == IndividualCall.State.MISSED || individualCall.state == IndividualCall.State.MISSED_NOTIFICATION_PROFILE) { + typeFlags = if (individualCall.type == IndividualCall.Type.AUDIO_CALL) { MessageTypes.MISSED_AUDIO_CALL_TYPE } else { MessageTypes.MISSED_VIDEO_CALL_TYPE } } else { - typeFlags = if (updateMessage.individualCall.direction == IndividualCall.Direction.OUTGOING) { - if (updateMessage.individualCall.type == IndividualCall.Type.AUDIO_CALL) { + typeFlags = if (individualCall.direction == IndividualCall.Direction.OUTGOING) { + if (individualCall.type == IndividualCall.Type.AUDIO_CALL) { MessageTypes.OUTGOING_AUDIO_CALL_TYPE } else { MessageTypes.OUTGOING_VIDEO_CALL_TYPE } } else { - if (updateMessage.individualCall.type == IndividualCall.Type.AUDIO_CALL) { + if (individualCall.type == IndividualCall.Type.AUDIO_CALL) { MessageTypes.INCOMING_AUDIO_CALL_TYPE } else { MessageTypes.INCOMING_VIDEO_CALL_TYPE @@ -925,28 +959,24 @@ class ChatItemArchiveImporter( } this.put(MessageTable.READ, 1) } - updateMessage.groupCall != null -> { - val startedCallRecipientId = if (updateMessage.groupCall.startedCallRecipientId != null) { - importState.remoteToLocalRecipientId[updateMessage.groupCall.startedCallRecipientId] - } else { - null - } + groupCall != null -> { + val startedCallRecipientId = groupCall.startedCallRecipientId?.let { importState.remoteToLocalRecipientId[it] } val startedCall = if (startedCallRecipientId != null) { recipients.getRecord(startedCallRecipientId).aci } else { null } - this.put(MessageTable.BODY, GroupCallUpdateDetailsUtil.createBodyFromBackup(updateMessage.groupCall, startedCall)) - this.put(MessageTable.READ, updateMessage.groupCall.read.toInt()) + this.put(MessageTable.BODY, GroupCallUpdateDetailsUtil.createBodyFromBackup(groupCall, startedCall)) + this.put(MessageTable.READ, groupCall.read.toInt()) typeFlags = MessageTypes.GROUP_CALL_TYPE } - updateMessage.groupChange != null -> { + groupChange != null -> { put(MessageTable.BODY, "") put( MessageTable.MESSAGE_EXTRAS, MessageExtras( gv2UpdateDescription = - GV2UpdateDescription(groupChangeUpdate = updateMessage.groupChange) + GV2UpdateDescription(groupChangeUpdate = groupChange) ).encode() ) typeFlags = getAsLong(MessageTable.TYPE) or MessageTypes.GROUP_V2_BIT or MessageTypes.GROUP_UPDATE_BIT @@ -962,18 +992,18 @@ class ChatItemArchiveImporter( */ private fun ContentValues.addPaymentNotification(chatItem: ChatItem, chatRecipientId: RecipientId) { val paymentNotification = chatItem.paymentNotification!! - if (chatItem.paymentNotification.amountMob.isNullOrEmpty()) { + if (paymentNotification.amountMob.isNullOrEmpty()) { this.addPaymentTombstoneNoAmount() return } val amount = paymentNotification.amountMob?.tryParseMoney() ?: return this.addPaymentTombstoneNoAmount() val fee = paymentNotification.feeMob?.tryParseMoney() ?: return this.addPaymentTombstoneNoAmount() - if (chatItem.paymentNotification.transactionDetails?.failedTransaction != null) { + if (paymentNotification.transactionDetails?.failedTransaction != null) { this.addFailedPaymentNotification(chatItem, amount, fee, chatRecipientId) return } - this.addPaymentTombstoneNoMetadata(chatItem.paymentNotification) + this.addPaymentTombstoneNoMetadata(paymentNotification) } private fun PaymentNotification.TransactionDetails.MobileCoinTxoIdentification.toLocal(): PaymentMetaData { @@ -1062,13 +1092,15 @@ class ChatItemArchiveImporter( put(MessageTable.QUOTE_ID, MessageTable.QUOTE_TARGET_MISSING_ID) put(MessageTable.QUOTE_AUTHOR, toRecipientId.serialize()) - if (directStoryReply.emoji != null) { - put(MessageTable.BODY, directStoryReply.emoji) + val emoji = directStoryReply.emoji + if (emoji != null) { + put(MessageTable.BODY, emoji) } - if (directStoryReply.textReply != null) { - put(MessageTable.BODY, directStoryReply.textReply.text?.body) - put(MessageTable.MESSAGE_RANGES, directStoryReply.textReply.text?.bodyRanges?.toLocalBodyRanges()?.encode()) + val textReply = directStoryReply.textReply + if (textReply != null) { + put(MessageTable.BODY, textReply.text?.body) + put(MessageTable.MESSAGE_RANGES, textReply.text?.bodyRanges?.toLocalBodyRanges()?.encode()) } } @@ -1126,11 +1158,9 @@ class ChatItemArchiveImporter( } private fun ContentValues.addNetworkFailures(chatItem: ChatItem, importState: ImportState) { - if (chatItem.outgoing == null) { - return - } + val outgoing = chatItem.outgoing ?: return - val networkFailures = chatItem.outgoing.sendStatus + val networkFailures = outgoing.sendStatus .filter { status -> status.failed?.reason == SendStatus.Failed.FailureReason.NETWORK } .mapNotNull { status -> importState.remoteToLocalRecipientId[status.recipientId] } .map { recipientId -> NetworkFailure(recipientId) } @@ -1142,11 +1172,9 @@ class ChatItemArchiveImporter( } private fun ContentValues.addIdentityKeyMismatches(chatItem: ChatItem, importState: ImportState) { - if (chatItem.outgoing == null) { - return - } + val outgoing = chatItem.outgoing ?: return - val mismatches = chatItem.outgoing.sendStatus + val mismatches = outgoing.sendStatus .filter { status -> status.failed?.reason == SendStatus.Failed.FailureReason.IDENTITY_KEY_MISMATCH } .mapNotNull { status -> importState.remoteToLocalRecipientId[status.recipientId] } .map { recipientId -> IdentityKeyMismatch(recipientId, null) } // TODO We probably want the actual identity key in this status situation? @@ -1166,8 +1194,8 @@ class ChatItemArchiveImporter( ranges = this.filter { includeMentions || it.mentionAci == null }.map { bodyRange -> BodyRangeList.BodyRange( mentionUuid = bodyRange.mentionAci?.let { UuidUtil.fromByteString(it) }?.toString(), - style = bodyRange.style?.let { - when (bodyRange.style) { + style = bodyRange.style?.let { style -> + when (style) { BodyRange.Style.BOLD -> BodyRangeList.BodyRange.Style.BOLD BodyRange.Style.ITALIC -> BodyRangeList.BodyRange.Style.ITALIC BodyRange.Style.MONOSPACE -> BodyRangeList.BodyRange.Style.MONOSPACE @@ -1217,13 +1245,11 @@ class ChatItemArchiveImporter( return@mapNotNull thumbnail } - if (attachment.contentType == null) { - return@mapNotNull null - } + val contentType = attachment.contentType ?: return@mapNotNull null return@mapNotNull PointerAttachment.forPointer( quotedAttachment = DataMessage.Quote.QuotedAttachment( - contentType = attachment.contentType, + contentType = contentType, fileName = attachment.fileName, thumbnail = null ) @@ -1259,7 +1285,8 @@ class ChatItemArchiveImporter( } private fun MessageAttachment.toLocalAttachment(quote: Boolean = false, quoteTargetContentType: String? = null, contentType: String? = pointer?.contentType): Attachment? { - return pointer?.toLocalAttachment( + val pointer = this.pointer ?: return null + return pointer.toLocalAttachment( voiceNote = flag == MessageAttachment.Flag.VOICE_MESSAGE, borderless = flag == MessageAttachment.Flag.BORDERLESS, gif = flag == MessageAttachment.Flag.GIF, diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ContactArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ContactArchiveImporter.kt index dd1368b7b5..019fc6007a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ContactArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ContactArchiveImporter.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.backup.v2.importer import androidx.core.content.contentValuesOf +import org.signal.archive.proto.Contact import org.signal.core.models.ServiceId.ACI import org.signal.core.models.ServiceId.PNI import org.signal.core.util.Base64 @@ -14,7 +15,6 @@ import org.signal.core.util.logging.Log import org.signal.core.util.toInt import org.signal.core.util.update import org.thoughtcrime.securesms.backup.v2.ImportSkips -import org.thoughtcrime.securesms.backup.v2.proto.Contact import org.thoughtcrime.securesms.backup.v2.util.toLocal import org.thoughtcrime.securesms.database.IdentityTable import org.thoughtcrime.securesms.database.RecipientTable @@ -70,11 +70,12 @@ object ContactArchiveImporter { RecipientTable.KEY_TRANSPARENCY_DATA to contact.keyTransparencyData?.toByteArray() ) + val notRegistered = contact.notRegistered if (contact.registered != null) { values.put(RecipientTable.UNREGISTERED_TIMESTAMP, 0L) values.put(RecipientTable.REGISTERED, RecipientTable.RegisteredState.REGISTERED.id) - } else if (contact.notRegistered != null) { - values.put(RecipientTable.UNREGISTERED_TIMESTAMP, contact.notRegistered.unregisteredTimestamp) + } else if (notRegistered != null) { + values.put(RecipientTable.UNREGISTERED_TIMESTAMP, notRegistered.unregisteredTimestamp) values.put(RecipientTable.REGISTERED, RecipientTable.RegisteredState.NOT_REGISTERED.id) } @@ -84,12 +85,13 @@ object ContactArchiveImporter { .where("${RecipientTable.ID} = ?", id) .run() - if (contact.identityKey != null && (aci != null || pni != null)) { + val identityKey = contact.identityKey + if (identityKey != null && (aci != null || pni != null)) { SignalDatabase.writableDatabase .insertInto(IdentityTable.TABLE_NAME) .values( IdentityTable.ADDRESS to (aci ?: pni).toString(), - IdentityTable.IDENTITY_KEY to Base64.encodeWithPadding(contact.identityKey.toByteArray()), + IdentityTable.IDENTITY_KEY to Base64.encodeWithPadding(identityKey.toByteArray()), IdentityTable.VERIFIED to contact.identityState.toLocal().toInt() ) .run(SQLiteDatabase.CONFLICT_REPLACE) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/DistributionListArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/DistributionListArchiveImporter.kt index 8c8007d028..49882d3c11 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/DistributionListArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/DistributionListArchiveImporter.kt @@ -5,11 +5,11 @@ package org.thoughtcrime.securesms.backup.v2.importer +import org.signal.archive.proto.DistributionList +import org.signal.archive.proto.DistributionListItem import org.signal.core.util.UuidUtil import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.DistributionList -import org.thoughtcrime.securesms.backup.v2.proto.DistributionListItem import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode import org.thoughtcrime.securesms.recipients.RecipientId @@ -23,13 +23,14 @@ object DistributionListArchiveImporter { private val TAG = Log.tag(DistributionListArchiveImporter.javaClass) fun import(dlistItem: DistributionListItem, importState: ImportState): RecipientId? { - if (dlistItem.deletionTimestamp != null && dlistItem.deletionTimestamp > 0) { + val deletionTimestamp = dlistItem.deletionTimestamp + if (deletionTimestamp != null && deletionTimestamp > 0) { val dlistId = SignalDatabase.distributionLists.createList( name = "", members = emptyList(), distributionId = DistributionId.from(UuidUtil.fromByteString(dlistItem.distributionId)), allowsReplies = false, - deletionTimestamp = dlistItem.deletionTimestamp, + deletionTimestamp = deletionTimestamp, storageId = null, privacyMode = DistributionListPrivacyMode.ONLY_WITH )!! diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt index d5c3b557bd..33e1e07db5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.backup.v2.importer import android.content.ContentValues +import org.signal.archive.proto.Group import org.signal.core.models.ServiceId import org.signal.core.util.Base64 import org.signal.core.util.toInt @@ -21,7 +22,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedRequesting import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer import org.signal.storageservice.storage.protos.groups.local.EnabledState import org.thoughtcrime.securesms.backup.v2.ArchiveGroup -import org.thoughtcrime.securesms.backup.v2.proto.Group import org.thoughtcrime.securesms.backup.v2.util.toLocal import org.thoughtcrime.securesms.conversation.colors.AvatarColorHash import org.thoughtcrime.securesms.database.GroupTable @@ -45,10 +45,11 @@ object GroupArchiveImporter { val groupId = GroupId.v2(masterKey) val operations = AppDependencies.groupsV2Operations.forGroup(GroupSecretParams.deriveFromMasterKey(masterKey)) - val decryptedState = if (group.snapshot == null) { + val snapshot = group.snapshot + val decryptedState = if (snapshot == null) { DecryptedGroup(revision = GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) } else { - group.snapshot.toLocal(operations) + snapshot.toLocal(operations) } val values = ContentValues().apply { @@ -84,12 +85,13 @@ private fun Group.StorySendMode.toLocal(): GroupTable.ShowAsStoryState { } private fun Group.MemberPendingProfileKey.toLocal(operations: GroupsV2Operations.GroupOperations): DecryptedPendingMember { + val m = member!! return DecryptedPendingMember( - serviceIdBytes = member!!.userId, - role = member.role.toLocal(), + serviceIdBytes = m.userId, + role = m.role.toLocal(), addedByAci = addedByUserId, timestamp = timestamp, - serviceIdCipherText = operations.encryptServiceId(ServiceId.Companion.parseOrNull(member.userId)) + serviceIdCipherText = operations.encryptServiceId(ServiceId.Companion.parseOrNull(m.userId)) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchiveFileSystem.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchiveFileSystem.kt index ea721addae..710686988d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchiveFileSystem.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchiveFileSystem.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking +import org.signal.archive.local.ArchivedFilesReader import org.signal.core.models.backup.MediaName import org.signal.core.util.Stopwatch import org.signal.core.util.androidx.DocumentFileInfo diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiver.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiver.kt index 22ed0b599b..de0f91b8ed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiver.kt @@ -6,6 +6,10 @@ package org.thoughtcrime.securesms.backup.v2.local import okio.ByteString.Companion.toByteString +import org.signal.archive.local.ArchivedFilesWriter +import org.signal.archive.local.proto.FilesFrame +import org.signal.archive.local.proto.Metadata +import org.signal.archive.stream.EncryptedBackupReader import org.signal.core.models.backup.BackupId import org.signal.core.models.backup.MediaName import org.signal.core.models.backup.MessageBackupKey @@ -16,9 +20,6 @@ import org.signal.core.util.logging.Log import org.signal.core.util.readFully import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.backup.v2.BackupRepository -import org.thoughtcrime.securesms.backup.v2.local.proto.FilesFrame -import org.thoughtcrime.securesms.backup.v2.local.proto.Metadata -import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupReader import org.thoughtcrime.securesms.database.AttachmentTable import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.protos.LocalBackupCreationProgress @@ -166,12 +167,13 @@ object LocalArchiver { return RestoreResult.failure(RestoreFailure.VersionMismatch(metadata.version, VERSION)) } - if (metadata.backupId == null) { + val encryptedBackupId = metadata.backupId + if (encryptedBackupId == null) { Log.w(TAG, "Local backup metadata missing encrypted backup id") return RestoreResult.failure(RestoreFailure.BackupIdMissing) } - val backupId = decryptBackupId(metadata.backupId, messageBackupKey) + val backupId = decryptBackupId(encryptedBackupId, messageBackupKey) val mainStreamLength = snapshotFileSystem.mainLength() ?: return ArchiveResult.failure(RestoreFailure.MainStream) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AccountDataArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AccountDataArchiveProcessor.kt index dbe2ba438b..5bd7e95a95 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AccountDataArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AccountDataArchiveProcessor.kt @@ -8,6 +8,10 @@ package org.thoughtcrime.securesms.backup.v2.processor import android.content.Context import okio.ByteString.Companion.EMPTY import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.AccountData +import org.signal.archive.proto.ChatStyle +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.UuidUtil import org.signal.core.util.logging.Log import org.signal.core.util.toByteArray @@ -18,10 +22,6 @@ import org.thoughtcrime.securesms.backup.v2.ImportState import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.backup.v2.database.restoreSelfFromBackup import org.thoughtcrime.securesms.backup.v2.database.restoreWallpaperAttachment -import org.thoughtcrime.securesms.backup.v2.proto.AccountData -import org.thoughtcrime.securesms.backup.v2.proto.ChatStyle -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.backup.v2.util.ChatStyleConverter import org.thoughtcrime.securesms.backup.v2.util.isValid import org.thoughtcrime.securesms.backup.v2.util.isValidUsername @@ -178,10 +178,11 @@ object AccountDataArchiveProcessor { importSettings(context, settings, importState) } - if (accountData.androidSpecificSettings != null) { - SignalStore.settings.isPreferSystemEmoji = accountData.androidSpecificSettings.useSystemEmoji - TextSecurePreferences.setScreenSecurityEnabled(context, accountData.androidSpecificSettings.screenshotSecurity) - SignalStore.settings.useCompactNavigationBar = accountData.androidSpecificSettings.navigationBarSize.toLocalNavigationBarSize() + val androidSpecificSettings = accountData.androidSpecificSettings + if (androidSpecificSettings != null) { + SignalStore.settings.isPreferSystemEmoji = androidSpecificSettings.useSystemEmoji + TextSecurePreferences.setScreenSecurityEnabled(context, androidSpecificSettings.screenshotSecurity) + SignalStore.settings.useCompactNavigationBar = androidSpecificSettings.navigationBarSize.toLocalNavigationBarSize() } else if (Environment.IS_INSTRUMENTATION) { SignalStore.backup.importedEmptyAndroidSettings = true } @@ -190,16 +191,17 @@ object AccountDataArchiveProcessor { SignalDatabase.recipients.setAbout(selfId, accountData.bioText.takeIf { it.isNotBlank() }, accountData.bioEmoji.takeIf { it.isNotBlank() }) } - if (accountData.donationSubscriberData != null) { - if (accountData.donationSubscriberData.subscriberId.size > 0) { - val remoteSubscriberId = SubscriberId.fromBytes(accountData.donationSubscriberData.subscriberId.toByteArray()) + val donationSubscriberData = accountData.donationSubscriberData + if (donationSubscriberData != null) { + if (donationSubscriberData.subscriberId.size > 0) { + val remoteSubscriberId = SubscriberId.fromBytes(donationSubscriberData.subscriberId.toByteArray()) val localSubscriber = InAppPaymentsRepository.getSubscriber(InAppPaymentSubscriberRecord.Type.DONATION) val subscriber = InAppPaymentSubscriberRecord( subscriberId = remoteSubscriberId, - currency = Currency.getInstance(accountData.donationSubscriberData.currencyCode), + currency = Currency.getInstance(donationSubscriberData.currencyCode), type = InAppPaymentSubscriberRecord.Type.DONATION, - requiresCancel = localSubscriber?.requiresCancel ?: accountData.donationSubscriberData.manuallyCancelled, + requiresCancel = localSubscriber?.requiresCancel ?: donationSubscriberData.manuallyCancelled, paymentMethodType = InAppPaymentsRepository.getLatestPaymentMethodType(InAppPaymentSubscriberRecord.Type.DONATION), iapSubscriptionId = null ) @@ -207,25 +209,27 @@ object AccountDataArchiveProcessor { InAppPaymentsRepository.setSubscriber(subscriber) } - if (accountData.donationSubscriberData.manuallyCancelled) { + if (donationSubscriberData.manuallyCancelled) { SignalStore.inAppPayments.updateLocalStateForManualCancellation(InAppPaymentSubscriberRecord.Type.DONATION) } } - if (accountData.backupsSubscriberData != null && accountData.backupsSubscriberData.subscriberId.size > 0 && (accountData.backupsSubscriberData.purchaseToken != null || accountData.backupsSubscriberData.originalTransactionId != null)) { - val remoteSubscriberId = SubscriberId.fromBytes(accountData.backupsSubscriberData.subscriberId.toByteArray()) + val backupsSubscriberData = accountData.backupsSubscriberData + if (backupsSubscriberData != null && backupsSubscriberData.subscriberId.size > 0 && (backupsSubscriberData.purchaseToken != null || backupsSubscriberData.originalTransactionId != null)) { + val remoteSubscriberId = SubscriberId.fromBytes(backupsSubscriberData.subscriberId.toByteArray()) val localSubscriber = InAppPaymentsRepository.getSubscriber(InAppPaymentSubscriberRecord.Type.BACKUP) + val purchaseToken = backupsSubscriberData.purchaseToken val subscriber = InAppPaymentSubscriberRecord( subscriberId = remoteSubscriberId, currency = localSubscriber?.currency, type = InAppPaymentSubscriberRecord.Type.BACKUP, requiresCancel = localSubscriber?.requiresCancel ?: false, paymentMethodType = InAppPaymentData.PaymentMethodType.UNKNOWN, - iapSubscriptionId = if (accountData.backupsSubscriberData.purchaseToken != null) { - GooglePlayBillingPurchaseToken(accountData.backupsSubscriberData.purchaseToken) + iapSubscriptionId = if (purchaseToken != null) { + GooglePlayBillingPurchaseToken(purchaseToken) } else { - AppleIAPOriginalTransactionId(accountData.backupsSubscriberData.originalTransactionId!!) + AppleIAPOriginalTransactionId(backupsSubscriberData.originalTransactionId!!) } ) @@ -236,12 +240,13 @@ object AccountDataArchiveProcessor { AppDependencies.jobManager.add(RetrieveProfileAvatarJob(Recipient.self().fresh(), accountData.avatarUrlPath)) } - if (accountData.usernameLink != null) { + val usernameLink = accountData.usernameLink + if (usernameLink != null) { SignalStore.account.usernameLink = UsernameLinkComponents( - accountData.usernameLink.entropy.toByteArray(), - UuidUtil.parseOrThrow(accountData.usernameLink.serverId.toByteArray()) + usernameLink.entropy.toByteArray(), + UuidUtil.parseOrThrow(usernameLink.serverId.toByteArray()) ) - SignalStore.misc.usernameQrCodeColorScheme = accountData.usernameLink.color.toLocalUsernameColor() + SignalStore.misc.usernameQrCodeColorScheme = usernameLink.color.toLocalUsernameColor() } else { SignalStore.account.usernameLink = null } @@ -278,9 +283,10 @@ object AccountDataArchiveProcessor { SignalStore.settings.setCallDataMode(settings.callsUseLessDataSetting.toLocalCallDataMode()) SignalStore.settings.automaticVerificationEnabled = settings.allowAutomaticKeyVerification - if (settings.autoDownloadSettings != null) { - val mobileAndWifiDownloadSet = settings.autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI_AND_CELLULAR) - val wifiDownloadSet = mobileAndWifiDownloadSet + settings.autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI) + val autoDownloadSettings = settings.autoDownloadSettings + if (autoDownloadSettings != null) { + val mobileAndWifiDownloadSet = autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI_AND_CELLULAR) + val wifiDownloadSet = mobileAndWifiDownloadSet + autoDownloadSettings.toLocalAutoDownloadSet(AccountData.AutoDownloadSettings.AutoDownloadOption.WIFI) TextSecurePreferences.getSharedPreferences(context).edit().apply { putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF, mobileAndWifiDownloadSet) @@ -289,28 +295,32 @@ object AccountDataArchiveProcessor { } } - if (settings.screenLockTimeoutMinutes != null) { - SignalStore.settings.screenLockTimeout = settings.screenLockTimeoutMinutes.minutes.inWholeSeconds + val screenLockTimeoutMinutes = settings.screenLockTimeoutMinutes + if (screenLockTimeoutMinutes != null) { + SignalStore.settings.screenLockTimeout = screenLockTimeoutMinutes.minutes.inWholeSeconds } - if (settings.pinReminders != null) { - SignalStore.pin.setPinRemindersEnabled(settings.pinReminders) + val pinReminders = settings.pinReminders + if (pinReminders != null) { + SignalStore.pin.setPinRemindersEnabled(pinReminders) } settings.customChatColors .mapNotNull { chatColor -> val id = ChatColors.Id.forLongValue(chatColor.id) + val solidColor = chatColor.solid + val gradientColor = chatColor.gradient when { - chatColor.solid != null -> { - ChatColors.forColor(id, chatColor.solid) + solidColor != null -> { + ChatColors.forColor(id, solidColor) } - chatColor.gradient != null -> { + gradientColor != null -> { ChatColors.forGradient( id, ChatColors.LinearGradient( - degrees = chatColor.gradient.angle.toFloat(), - colors = chatColor.gradient.colors.toIntArray(), - positions = chatColor.gradient.positions.toFloatArray() + degrees = gradientColor.angle.toFloat(), + colors = gradientColor.colors.toIntArray(), + positions = gradientColor.positions.toFloatArray() ) ) } @@ -323,17 +333,18 @@ object AccountDataArchiveProcessor { importState.remoteToLocalColorId[chatColor.id.longValue] = saved.id.longValue } - if (settings.defaultChatStyle != null) { - val chatColors = settings.defaultChatStyle.toLocal(importState) + val defaultChatStyle = settings.defaultChatStyle + if (defaultChatStyle != null) { + val chatColors = defaultChatStyle.toLocal(importState) SignalStore.chatColors.chatColors = chatColors - val wallpaperAttachmentId: AttachmentId? = settings.defaultChatStyle.wallpaperPhoto?.let { filePointer -> + val wallpaperAttachmentId: AttachmentId? = defaultChatStyle.wallpaperPhoto?.let { filePointer -> filePointer.toLocalAttachment()?.let { SignalDatabase.attachments.restoreWallpaperAttachment(it) } } - SignalStore.wallpaper.wallpaper = settings.defaultChatStyle.parseChatWallpaper(wallpaperAttachmentId) + SignalStore.wallpaper.wallpaper = defaultChatStyle.parseChatWallpaper(wallpaperAttachmentId) } else { SignalStore.chatColors.chatColors = null SignalStore.wallpaper.wallpaper = null diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AdHocCallArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AdHocCallArchiveProcessor.kt index 69d1c4e490..6caf534ec8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AdHocCallArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/AdHocCallArchiveProcessor.kt @@ -5,15 +5,15 @@ package org.thoughtcrime.securesms.backup.v2.processor +import org.signal.archive.proto.AdHocCall +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ExportSkips import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.ImportState import org.thoughtcrime.securesms.backup.v2.database.getAdhocCallsForBackup import org.thoughtcrime.securesms.backup.v2.importer.AdHodCallArchiveImporter -import org.thoughtcrime.securesms.backup.v2.proto.AdHocCall -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.database.SignalDatabase /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatArchiveProcessor.kt index 9accda5a70..99b12f1a4b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatArchiveProcessor.kt @@ -5,15 +5,15 @@ package org.thoughtcrime.securesms.backup.v2.processor +import org.signal.archive.proto.Chat +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.ImportSkips import org.thoughtcrime.securesms.backup.v2.ImportState import org.thoughtcrime.securesms.backup.v2.database.getThreadsForBackup import org.thoughtcrime.securesms.backup.v2.importer.ChatArchiveImporter -import org.thoughtcrime.securesms.backup.v2.proto.Chat -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.recipients.RecipientId diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatFolderArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatFolderArchiveProcessor.kt index 09565298c6..ded9a3e1e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatFolderArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatFolderArchiveProcessor.kt @@ -7,6 +7,9 @@ package org.thoughtcrime.securesms.backup.v2.processor import androidx.core.content.contentValuesOf import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.ChatFolder +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.UuidUtil @@ -15,16 +18,13 @@ import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.ImportSkips import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.ChatFolder -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.components.settings.app.chats.folders.ChatFolderRecord import org.thoughtcrime.securesms.database.ChatFolderTables.ChatFolderMembershipTable import org.thoughtcrime.securesms.database.ChatFolderTables.ChatFolderTable import org.thoughtcrime.securesms.database.ChatFolderTables.MembershipType import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.storage.StorageSyncHelper -import org.thoughtcrime.securesms.backup.v2.proto.ChatFolder as ChatFolderProto +import org.signal.archive.proto.ChatFolder as ChatFolderProto /** * Handles exporting and importing [ChatFolderRecord]s. diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemArchiveProcessor.kt index ee211ce21e..375e7cdafe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/ChatItemArchiveProcessor.kt @@ -5,15 +5,15 @@ package org.thoughtcrime.securesms.backup.v2.processor +import org.signal.archive.proto.ChatItem +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.ImportState import org.thoughtcrime.securesms.backup.v2.database.createChatItemInserter import org.thoughtcrime.securesms.backup.v2.database.getMessagesForBackup import org.thoughtcrime.securesms.backup.v2.importer.ChatItemArchiveImporter -import org.thoughtcrime.securesms.backup.v2.proto.ChatItem -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.recipients.RecipientId diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/NotificationProfileArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/NotificationProfileArchiveProcessor.kt index 73aca100bd..53ac1add42 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/NotificationProfileArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/NotificationProfileArchiveProcessor.kt @@ -6,6 +6,8 @@ package org.thoughtcrime.securesms.backup.v2.processor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.Frame +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.Base64 import org.signal.core.util.UuidUtil import org.signal.core.util.insertInto @@ -14,8 +16,6 @@ import org.signal.core.util.toInt import org.thoughtcrime.securesms.backup.v2.ExportState import org.thoughtcrime.securesms.backup.v2.ImportSkips import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.conversation.colors.AvatarColor import org.thoughtcrime.securesms.database.NotificationProfileTables.NotificationProfileAllowedMembersTable import org.thoughtcrime.securesms.database.NotificationProfileTables.NotificationProfileScheduleTable @@ -26,7 +26,7 @@ import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.storage.StorageSyncHelper import java.time.DayOfWeek -import org.thoughtcrime.securesms.backup.v2.proto.NotificationProfile as NotificationProfileProto +import org.signal.archive.proto.NotificationProfile as NotificationProfileProto /** * Handles exporting and importing [NotificationProfile] models. diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt index f85838b789..6058457ffa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/RecipientArchiveProcessor.kt @@ -5,6 +5,9 @@ package org.thoughtcrime.securesms.backup.v2.processor +import org.signal.archive.proto.Frame +import org.signal.archive.proto.ReleaseNotes +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.models.ServiceId import org.signal.core.util.logging.Log import org.signal.core.util.update @@ -22,9 +25,6 @@ import org.thoughtcrime.securesms.backup.v2.importer.CallLinkArchiveImporter import org.thoughtcrime.securesms.backup.v2.importer.ContactArchiveImporter import org.thoughtcrime.securesms.backup.v2.importer.DistributionListArchiveImporter import org.thoughtcrime.securesms.backup.v2.importer.GroupArchiveImporter -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.proto.ReleaseNotes -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.backup.v2.util.toLocal import org.thoughtcrime.securesms.database.RecipientTable import org.thoughtcrime.securesms.database.SignalDatabase @@ -110,16 +110,21 @@ object RecipientArchiveProcessor { } fun import(recipient: ArchiveRecipient, importState: ImportState) { + val recipientContact = recipient.contact + val recipientGroup = recipient.group + val recipientDistributionList = recipient.distributionList + val recipientCallLink = recipient.callLink + val recipientSelf = recipient.self val newId: RecipientId? = when { - recipient.contact != null -> ContactArchiveImporter.import(recipient.contact) - recipient.group != null -> GroupArchiveImporter.import(recipient.group) - recipient.distributionList != null -> DistributionListArchiveImporter.import(recipient.distributionList, importState) + recipientContact != null -> ContactArchiveImporter.import(recipientContact) + recipientGroup != null -> GroupArchiveImporter.import(recipientGroup) + recipientDistributionList != null -> DistributionListArchiveImporter.import(recipientDistributionList, importState) recipient.releaseNotes != null -> SignalDatabase.recipients.restoreReleaseNotes() - recipient.callLink != null -> CallLinkArchiveImporter.import(recipient.callLink) - recipient.self != null -> { + recipientCallLink != null -> CallLinkArchiveImporter.import(recipientCallLink) + recipientSelf != null -> { SignalDatabase.writableDatabase .update(RecipientTable.TABLE_NAME) - .values(RecipientTable.AVATAR_COLOR to recipient.self.avatarColor?.toLocal()?.serialize()) + .values(RecipientTable.AVATAR_COLOR to recipientSelf.avatarColor?.toLocal()?.serialize()) .where("${RecipientTable.ID} = ?", Recipient.self().id) .run() Recipient.self().id diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/StickerArchiveProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/StickerArchiveProcessor.kt index 08ef8105bf..9a1e3b591c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/StickerArchiveProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/processor/StickerArchiveProcessor.kt @@ -6,13 +6,13 @@ package org.thoughtcrime.securesms.backup.v2.processor import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.Frame +import org.signal.archive.proto.StickerPack +import org.signal.archive.stream.BackupFrameEmitter import org.signal.core.util.Hex import org.signal.core.util.insertInto import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.backup.v2.ExportSkips -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.proto.StickerPack -import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter import org.thoughtcrime.securesms.database.SQLiteDatabase import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.StickerTable diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt index fe12543cff..b9fe5c740f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt @@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.backup.v2.util import okio.ByteString import okio.ByteString.Companion.toByteString +import org.signal.archive.proto.FilePointer import org.signal.core.util.Base64 import org.signal.core.util.UuidUtil import org.signal.core.util.isNotNullOrBlank @@ -22,7 +23,6 @@ import org.thoughtcrime.securesms.attachments.PointerAttachment import org.thoughtcrime.securesms.attachments.TombstoneAttachment import org.thoughtcrime.securesms.backup.v2.BackupMode import org.thoughtcrime.securesms.backup.v2.ExportState -import org.thoughtcrime.securesms.backup.v2.proto.FilePointer import org.thoughtcrime.securesms.conversation.colors.AvatarColor import org.thoughtcrime.securesms.conversation.colors.ChatColors import org.thoughtcrime.securesms.database.AttachmentTable @@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.stickers.StickerLocator import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId import java.util.Optional -import org.thoughtcrime.securesms.backup.v2.proto.AvatarColor as RemoteAvatarColor +import org.signal.archive.proto.AvatarColor as RemoteAvatarColor /** * Converts a [FilePointer] to a local [Attachment] object for inserting into the database. @@ -47,11 +47,12 @@ fun FilePointer?.toLocalAttachment( quote: Boolean = false, quoteTargetContentType: String? = null ): Attachment? { - if (this == null || this.locatorInfo == null) return null + if (this == null) return null + val locatorInfo = this.locatorInfo ?: return null val attachmentType = when { - this.locatorInfo.plaintextHash != null -> AttachmentType.ARCHIVE - this.locatorInfo.encryptedDigest != null && this.locatorInfo.transitCdnKey != null -> AttachmentType.TRANSIT + locatorInfo.plaintextHash != null -> AttachmentType.ARCHIVE + locatorInfo.encryptedDigest != null && locatorInfo.transitCdnKey != null -> AttachmentType.TRANSIT else -> AttachmentType.INVALID } @@ -59,13 +60,13 @@ fun FilePointer?.toLocalAttachment( AttachmentType.ARCHIVE -> { ArchivedAttachment( contentType = contentType, - size = this.locatorInfo.size.toLong(), - cdn = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, - uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp ?: 0, - key = this.locatorInfo.key.toByteArray(), - cdnKey = this.locatorInfo.transitCdnKey?.nullIfBlank(), - archiveCdn = this.locatorInfo.mediaTierCdnNumber, - plaintextHash = this.locatorInfo.plaintextHash!!.toByteArray(), + size = locatorInfo.size.toLong(), + cdn = locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, + uploadTimestamp = locatorInfo.transitTierUploadTimestamp ?: 0, + key = locatorInfo.key.toByteArray(), + cdnKey = locatorInfo.transitCdnKey?.nullIfBlank(), + archiveCdn = locatorInfo.mediaTierCdnNumber, + plaintextHash = locatorInfo.plaintextHash!!.toByteArray(), incrementalMac = this.incrementalMac?.toByteArray(), incrementalMacChunkSize = this.incrementalMacChunkSize, width = this.width, @@ -80,20 +81,20 @@ fun FilePointer?.toLocalAttachment( quoteTargetContentType = quoteTargetContentType, uuid = UuidUtil.fromByteStringOrNull(uuid), fileName = fileName, - localBackupKey = this.locatorInfo.localKey?.toByteArray() + localBackupKey = locatorInfo.localKey?.toByteArray() ) } AttachmentType.TRANSIT -> { val signalAttachmentPointer = SignalServiceAttachmentPointer( - cdnNumber = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, + cdnNumber = locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, remoteId = SignalServiceAttachmentRemoteId.from(locatorInfo.transitCdnKey!!), contentType = contentType, - key = this.locatorInfo.key.toByteArray(), + key = locatorInfo.key.toByteArray(), size = Optional.ofNullable(locatorInfo.size), preview = Optional.empty(), width = this.width ?: 0, height = this.height ?: 0, - digest = Optional.ofNullable(this.locatorInfo.encryptedDigest!!.toByteArray()), + digest = Optional.ofNullable(locatorInfo.encryptedDigest!!.toByteArray()), incrementalDigest = Optional.ofNullable(this.incrementalMac?.toByteArray()), incrementalMacChunkSize = this.incrementalMacChunkSize ?: 0, fileName = Optional.ofNullable(fileName), @@ -102,7 +103,7 @@ fun FilePointer?.toLocalAttachment( isGif = gif, caption = Optional.ofNullable(this.caption), blurHash = Optional.ofNullable(this.blurHash), - uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp?.clampToValidBackupRange() ?: 0, + uploadTimestamp = locatorInfo.transitTierUploadTimestamp?.clampToValidBackupRange() ?: 0, uuid = UuidUtil.fromByteStringOrNull(uuid) ) PointerAttachment.forPointer( diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ChatStyleConverter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ChatStyleConverter.kt index 6a5613e4c7..b40a2d6762 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ChatStyleConverter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ChatStyleConverter.kt @@ -5,12 +5,12 @@ package org.thoughtcrime.securesms.backup.v2.util +import org.signal.archive.proto.ChatStyle +import org.signal.archive.proto.FilePointer import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.backup.v2.BackupMode import org.thoughtcrime.securesms.backup.v2.ImportState -import org.thoughtcrime.securesms.backup.v2.proto.ChatStyle -import org.thoughtcrime.securesms.backup.v2.proto.FilePointer import org.thoughtcrime.securesms.conversation.colors.ChatColors import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette import org.thoughtcrime.securesms.database.SignalDatabase @@ -122,6 +122,7 @@ fun ChatStyle.toLocal(importState: ImportState): ChatColors? { ChatStyle.BubbleColorPreset.GRADIENT_SEA -> ChatColorsPalette.Bubbles.SEA ChatStyle.BubbleColorPreset.GRADIENT_TANGERINE -> ChatColorsPalette.Bubbles.TANGERINE ChatStyle.BubbleColorPreset.UNKNOWN_BUBBLE_COLOR_PRESET, ChatStyle.BubbleColorPreset.SOLID_ULTRAMARINE -> ChatColorsPalette.Bubbles.ULTRAMARINE + else -> ChatColorsPalette.Bubbles.ULTRAMARINE } } @@ -198,8 +199,9 @@ fun ChatStyle.WallpaperPreset.toLocal(): ChatWallpaper? { } fun ChatStyle.parseChatWallpaper(wallpaperAttachmentId: AttachmentId?): ChatWallpaper? { - val chatWallpaper = if (this.wallpaperPreset != null) { - this.wallpaperPreset.toLocal() + val localWallpaperPreset = this.wallpaperPreset + val chatWallpaper = if (localWallpaperPreset != null) { + localWallpaperPreset.toLocal() } else if (wallpaperAttachmentId != null) { UriChatWallpaper(PartAuthority.getAttachmentDataUri(wallpaperAttachmentId), 0f) } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/FrameExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/FrameExtensions.kt index 23fa61828c..a0cfb3f250 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/FrameExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/FrameExtensions.kt @@ -6,20 +6,23 @@ package org.thoughtcrime.securesms.backup.v2.util import okio.ByteString +import org.signal.archive.proto.AccountData +import org.signal.archive.proto.Chat +import org.signal.archive.proto.ChatItem +import org.signal.archive.proto.FilePointer +import org.signal.archive.proto.Frame import org.signal.core.models.backup.MediaName import org.thoughtcrime.securesms.attachments.Cdn -import org.thoughtcrime.securesms.backup.v2.proto.AccountData -import org.thoughtcrime.securesms.backup.v2.proto.Chat -import org.thoughtcrime.securesms.backup.v2.proto.ChatItem -import org.thoughtcrime.securesms.backup.v2.proto.FilePointer -import org.thoughtcrime.securesms.backup.v2.proto.Frame fun Frame.getAllReferencedArchiveAttachmentInfos(): Set { val infos: MutableSet = mutableSetOf() + val account = this.account + val chat = this.chat + val chatItem = this.chatItem when { - this.account != null -> infos += this.account.getAllReferencedArchiveAttachmentInfos() - this.chat != null -> infos += this.chat.getAllReferencedArchiveAttachmentInfos() - this.chatItem != null -> infos += this.chatItem.getAllReferencedArchiveAttachmentInfos() + account != null -> infos += account.getAllReferencedArchiveAttachmentInfos() + chat != null -> infos += chat.getAllReferencedArchiveAttachmentInfos() + chatItem != null -> infos += chatItem.getAllReferencedArchiveAttachmentInfos() } return infos.toSet() } @@ -74,18 +77,15 @@ private fun ChatItem.getAllReferencedArchiveAttachmentInfos(): Set - if (change.groupInvitationRevokedUpdate != null) { - val invitees = change.groupInvitationRevokedUpdate.invitees.toMutableList() + val revokedUpdate = change.groupInvitationRevokedUpdate + if (revokedUpdate != null) { + val invitees = revokedUpdate.invitees.toMutableList() invitees.replaceAll { invitee -> val inviteeAciFieldServiceId = ServiceId.parseOrNull(invitee.inviteeAci) @@ -69,7 +70,7 @@ object V258_FixGroupRevokedInviteeUpdate : SignalDatabaseMigration { } } - change.copy(groupInvitationRevokedUpdate = change.groupInvitationRevokedUpdate.copy(invitees = invitees)) + change.copy(groupInvitationRevokedUpdate = revokedUpdate.copy(invitees = invitees)) } else { change } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V264_FixGroupAddMemberUpdate.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V264_FixGroupAddMemberUpdate.kt index fe4eb73e90..8294988dfb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V264_FixGroupAddMemberUpdate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V264_FixGroupAddMemberUpdate.kt @@ -8,12 +8,12 @@ package org.thoughtcrime.securesms.database.helpers.migration import android.app.Application import androidx.core.content.contentValuesOf import okio.IOException +import org.signal.archive.proto.GroupMemberAddedUpdate import org.signal.core.models.ServiceId import org.signal.core.util.forEach import org.signal.core.util.logging.Log import org.signal.core.util.requireBlob import org.signal.core.util.requireLong -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate import org.thoughtcrime.securesms.database.SQLiteDatabase import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras @@ -50,9 +50,10 @@ object V264_FixGroupAddMemberUpdate : SignalDatabaseMigration { updates .replaceAll { change -> - if (change.groupMemberAddedUpdate != null && ServiceId.parseOrNull(change.groupMemberAddedUpdate.updaterAci) is ServiceId.PNI) { + val addedUpdate = change.groupMemberAddedUpdate + if (addedUpdate != null && ServiceId.parseOrNull(addedUpdate.updaterAci) is ServiceId.PNI) { dataMigrated = true - change.copy(groupMemberAddedUpdate = change.groupMemberAddedUpdate.copy(updaterAci = null)) + change.copy(groupMemberAddedUpdate = addedUpdate.copy(updaterAci = null)) } else { change } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt index 19aed468f3..1168686dbb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt @@ -8,12 +8,12 @@ package org.thoughtcrime.securesms.database.helpers.migration import android.app.Application import androidx.core.content.contentValuesOf import okio.IOException +import org.signal.archive.proto.GroupInvitationDeclinedUpdate import org.signal.core.models.ServiceId import org.signal.core.util.forEach import org.signal.core.util.logging.Log import org.signal.core.util.requireBlob import org.signal.core.util.requireLong -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate import org.thoughtcrime.securesms.database.SQLiteDatabase import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras @@ -49,8 +49,9 @@ object V267_FixGroupInvitationDeclinedUpdate : SignalDatabaseMigration { updates .replaceAll { change -> - if (change.groupInvitationDeclinedUpdate != null && ServiceId.parseOrNull(change.groupInvitationDeclinedUpdate.inviteeAci) is ServiceId.PNI) { - change.copy(groupInvitationDeclinedUpdate = change.groupInvitationDeclinedUpdate.copy(inviteeAci = null)) + val declinedUpdate = change.groupInvitationDeclinedUpdate + if (declinedUpdate != null && ServiceId.parseOrNull(declinedUpdate.inviteeAci) is ServiceId.PNI) { + change.copy(groupInvitationDeclinedUpdate = declinedUpdate.copy(inviteeAci = null)) } else { change } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java index 0245696349..56da5bb0ff 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupCallUpdateDetailsUtil.java @@ -5,7 +5,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.Base64; import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.backup.v2.proto.GroupCall; +import org.signal.archive.proto.GroupCall; import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails; import org.thoughtcrime.securesms.recipients.Recipient; import org.signal.core.models.ServiceId; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt index 90869a02bd..c5c4359011 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt @@ -6,6 +6,40 @@ package org.thoughtcrime.securesms.database.model import okio.ByteString +import org.signal.archive.proto.GenericGroupUpdate +import org.signal.archive.proto.GroupAdminStatusUpdate +import org.signal.archive.proto.GroupAnnouncementOnlyChangeUpdate +import org.signal.archive.proto.GroupAttributesAccessLevelChangeUpdate +import org.signal.archive.proto.GroupAvatarUpdate +import org.signal.archive.proto.GroupChangeChatUpdate +import org.signal.archive.proto.GroupCreationUpdate +import org.signal.archive.proto.GroupDescriptionUpdate +import org.signal.archive.proto.GroupExpirationTimerUpdate +import org.signal.archive.proto.GroupInvitationAcceptedUpdate +import org.signal.archive.proto.GroupInvitationDeclinedUpdate +import org.signal.archive.proto.GroupInvitationRevokedUpdate +import org.signal.archive.proto.GroupInviteLinkAdminApprovalUpdate +import org.signal.archive.proto.GroupInviteLinkDisabledUpdate +import org.signal.archive.proto.GroupInviteLinkEnabledUpdate +import org.signal.archive.proto.GroupInviteLinkResetUpdate +import org.signal.archive.proto.GroupJoinRequestApprovalUpdate +import org.signal.archive.proto.GroupJoinRequestCanceledUpdate +import org.signal.archive.proto.GroupJoinRequestUpdate +import org.signal.archive.proto.GroupMemberAddedUpdate +import org.signal.archive.proto.GroupMemberJoinedByLinkUpdate +import org.signal.archive.proto.GroupMemberJoinedUpdate +import org.signal.archive.proto.GroupMemberLabelAccessLevelChangeUpdate +import org.signal.archive.proto.GroupMemberLeftUpdate +import org.signal.archive.proto.GroupMemberRemovedUpdate +import org.signal.archive.proto.GroupMembershipAccessLevelChangeUpdate +import org.signal.archive.proto.GroupNameUpdate +import org.signal.archive.proto.GroupSelfInvitationRevokedUpdate +import org.signal.archive.proto.GroupSequenceOfRequestsAndCancelsUpdate +import org.signal.archive.proto.GroupTerminateChangeUpdate +import org.signal.archive.proto.GroupUnknownInviteeUpdate +import org.signal.archive.proto.GroupV2AccessLevel +import org.signal.archive.proto.SelfInvitedOtherUserToGroupUpdate +import org.signal.archive.proto.SelfInvitedToGroupUpdate import org.signal.core.models.ServiceId import org.signal.core.util.BidiUtil import org.signal.core.util.UuidUtil @@ -18,40 +52,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChang import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember import org.signal.storageservice.storage.protos.groups.local.EnabledState -import org.thoughtcrime.securesms.backup.v2.proto.GenericGroupUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupAdminStatusUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupAnnouncementOnlyChangeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupAttributesAccessLevelChangeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupAvatarUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupCreationUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupDescriptionUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupExpirationTimerUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationAcceptedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationRevokedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkAdminApprovalUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkDisabledUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkEnabledUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkResetUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestApprovalUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestCanceledUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedByLinkUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLabelAccessLevelChangeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLeftUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberRemovedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupNameUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupSelfInvitationRevokedUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupSequenceOfRequestsAndCancelsUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupTerminateChangeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupUnknownInviteeUpdate -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2AccessLevel -import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate -import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedToGroupUpdate import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil import org.whispersystems.signalservice.api.push.ServiceIds diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java index 737c8fc56e..2cb91a94eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java @@ -26,43 +26,43 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMem import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember; import org.signal.storageservice.storage.protos.groups.local.EnabledState; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.backup.v2.proto.GenericGroupUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupAdminStatusUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupAnnouncementOnlyChangeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupAttributesAccessLevelChangeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupAvatarUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupCreationUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupDescriptionUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupExpirationTimerUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationAcceptedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationRevokedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkAdminApprovalUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkDisabledUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkEnabledUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupInviteLinkResetUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestApprovalUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestCanceledUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupJoinRequestUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberAddedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedByLinkUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberJoinedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLabelAccessLevelChangeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberLeftUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMemberRemovedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupMembershipAccessLevelChangeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupNameUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupSelfInvitationRevokedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupTerminateChangeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupUnknownInviteeUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2AccessLevel; -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationDroppedMembersUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationInvitedMembersUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationSelfInvitedUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupV2MigrationUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedOtherUserToGroupUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedToGroupUpdate; +import org.signal.archive.proto.GenericGroupUpdate; +import org.signal.archive.proto.GroupAdminStatusUpdate; +import org.signal.archive.proto.GroupAnnouncementOnlyChangeUpdate; +import org.signal.archive.proto.GroupAttributesAccessLevelChangeUpdate; +import org.signal.archive.proto.GroupAvatarUpdate; +import org.signal.archive.proto.GroupChangeChatUpdate; +import org.signal.archive.proto.GroupCreationUpdate; +import org.signal.archive.proto.GroupDescriptionUpdate; +import org.signal.archive.proto.GroupExpirationTimerUpdate; +import org.signal.archive.proto.GroupInvitationAcceptedUpdate; +import org.signal.archive.proto.GroupInvitationDeclinedUpdate; +import org.signal.archive.proto.GroupInvitationRevokedUpdate; +import org.signal.archive.proto.GroupInviteLinkAdminApprovalUpdate; +import org.signal.archive.proto.GroupInviteLinkDisabledUpdate; +import org.signal.archive.proto.GroupInviteLinkEnabledUpdate; +import org.signal.archive.proto.GroupInviteLinkResetUpdate; +import org.signal.archive.proto.GroupJoinRequestApprovalUpdate; +import org.signal.archive.proto.GroupJoinRequestCanceledUpdate; +import org.signal.archive.proto.GroupJoinRequestUpdate; +import org.signal.archive.proto.GroupMemberAddedUpdate; +import org.signal.archive.proto.GroupMemberJoinedByLinkUpdate; +import org.signal.archive.proto.GroupMemberJoinedUpdate; +import org.signal.archive.proto.GroupMemberLabelAccessLevelChangeUpdate; +import org.signal.archive.proto.GroupMemberLeftUpdate; +import org.signal.archive.proto.GroupMemberRemovedUpdate; +import org.signal.archive.proto.GroupMembershipAccessLevelChangeUpdate; +import org.signal.archive.proto.GroupNameUpdate; +import org.signal.archive.proto.GroupSelfInvitationRevokedUpdate; +import org.signal.archive.proto.GroupTerminateChangeUpdate; +import org.signal.archive.proto.GroupUnknownInviteeUpdate; +import org.signal.archive.proto.GroupV2AccessLevel; +import org.signal.archive.proto.GroupV2MigrationDroppedMembersUpdate; +import org.signal.archive.proto.GroupV2MigrationInvitedMembersUpdate; +import org.signal.archive.proto.GroupV2MigrationSelfInvitedUpdate; +import org.signal.archive.proto.GroupV2MigrationUpdate; +import org.signal.archive.proto.SelfInvitedOtherUserToGroupUpdate; +import org.signal.archive.proto.SelfInvitedToGroupUpdate; import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph; import org.thoughtcrime.securesms.groups.GV2AccessLevelUtil; import org.thoughtcrime.securesms.recipients.Recipient; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 9595718c30..cd6bc7bfbd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -38,8 +38,8 @@ import org.signal.core.util.logging.Log; import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup; import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate; -import org.thoughtcrime.securesms.backup.v2.proto.GroupCreationUpdate; +import org.signal.archive.proto.GroupChangeChatUpdate; +import org.signal.archive.proto.GroupCreationUpdate; import org.thoughtcrime.securesms.components.emoji.EmojiProvider; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.thoughtcrime.securesms.components.transfercontrols.TransferControlView; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java index def5e39011..1ceb804eae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupProtoUtil.java @@ -10,7 +10,7 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup; import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange; import org.signal.storageservice.storage.protos.groups.local.DecryptedMember; import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember; -import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate; +import org.signal.archive.proto.GroupChangeChatUpdate; import org.thoughtcrime.securesms.database.model.GroupsV2UpdateMessageConverter; import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context; import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription; diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.kt index f8393e7b25..94df3fd917 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.kt @@ -1,8 +1,8 @@ package org.thoughtcrime.securesms.keyvalue +import org.signal.archive.proto.BackupDebugInfo import org.signal.ringrtc.CallManager.DataMode import org.thoughtcrime.securesms.BuildConfig -import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo import org.thoughtcrime.securesms.util.Environment.Calling.defaultSfuUrl import org.thoughtcrime.securesms.util.RemoteConfig diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/BackupPlugin.kt b/app/src/spinner/java/org/thoughtcrime/securesms/BackupPlugin.kt index 733d9d5743..8cb4c94e70 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/BackupPlugin.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/BackupPlugin.kt @@ -6,6 +6,10 @@ package org.thoughtcrime.securesms import okio.ByteString +import org.signal.archive.proto.AccountData +import org.signal.archive.proto.BackupDebugInfo +import org.signal.archive.proto.FilePointer +import org.signal.archive.stream.EncryptedBackupReader import org.signal.core.util.bytes import org.signal.core.util.decodeOrNull import org.signal.core.util.logging.Log @@ -14,10 +18,6 @@ import org.signal.spinner.Plugin import org.signal.spinner.PluginResult import org.thoughtcrime.securesms.backup.v2.BackupRepository import org.thoughtcrime.securesms.backup.v2.local.SnapshotFileSystem -import org.thoughtcrime.securesms.backup.v2.proto.AccountData -import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo -import org.thoughtcrime.securesms.backup.v2.proto.FilePointer -import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupReader import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.net.SignalNetwork @@ -205,7 +205,7 @@ class BackupPlugin : Plugin { } frame.recipient != null -> { totalRecipients++ - val recipient = frame.recipient + val recipient = frame.recipient!! recipientNames[recipient.id] = extractRecipientName(recipient) when { @@ -218,7 +218,7 @@ class BackupPlugin : Plugin { } } frame.chat != null -> { - val chat = frame.chat + val chat = frame.chat!! chatInfos[chat.id] = ChatInfo( chatId = chat.id, recipientId = chat.recipientId, @@ -234,7 +234,7 @@ class BackupPlugin : Plugin { } } frame.chatItem != null -> { - val item = frame.chatItem + val item = frame.chatItem!! chatInfos[item.chatId]?.let { chatInfo -> chatInfo.messageCount++ chatInfo.attachmentCount += item.standardMessage?.attachments?.size ?: 0 @@ -319,7 +319,7 @@ class BackupPlugin : Plugin { counters.total++ // Check for plaintextHash - val hasPlaintextHash = filePointer.locatorInfo?.plaintextHash != null && filePointer.locatorInfo.plaintextHash.size > 0 + val hasPlaintextHash = filePointer.locatorInfo?.plaintextHash != null && filePointer.locatorInfo?.plaintextHash!!.size > 0 if (hasPlaintextHash) { counters.withPlaintextHash++ } else { @@ -328,7 +328,7 @@ class BackupPlugin : Plugin { } // Check for localKey - val hasLocalKey = filePointer.locatorInfo?.localKey != null && filePointer.locatorInfo.localKey.size > 0 + val hasLocalKey = filePointer.locatorInfo?.localKey != null && filePointer.locatorInfo?.localKey!!.size > 0 if (hasLocalKey) { counters.withLocalKey++ } else { @@ -527,12 +527,12 @@ class BackupPlugin : Plugin { """.trimIndent() } - private fun extractRecipientName(recipient: org.thoughtcrime.securesms.backup.v2.proto.Recipient?): String { + private fun extractRecipientName(recipient: org.signal.archive.proto.Recipient?): String { if (recipient == null) return "Unknown" return when { recipient.contact != null -> { - val contact = recipient.contact + val contact = recipient.contact!! val name = buildString { if (contact.profileGivenName?.isNotEmpty() == true) { append(contact.profileGivenName) @@ -540,9 +540,9 @@ class BackupPlugin : Plugin { append(" ${contact.profileFamilyName}") } } else if (contact.nickname?.given?.isNotEmpty() == true) { - append(contact.nickname.given) - if (contact.nickname.family.isNotEmpty()) { - append(" ${contact.nickname.family}") + append(contact.nickname!!.given) + if (contact.nickname!!.family.isNotEmpty()) { + append(" ${contact.nickname!!.family}") } } else if (contact.e164 != null) { append("+${contact.e164}") @@ -553,7 +553,7 @@ class BackupPlugin : Plugin { name } recipient.group != null -> { - val group = recipient.group + val group = recipient.group!! group.snapshot?.title?.title ?: "Group ${recipient.id}" } recipient.self != null -> "Self" diff --git a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiverTest.kt b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiverTest.kt index 80e1040ef1..6bfcafc913 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiverTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/local/LocalArchiverTest.kt @@ -18,14 +18,14 @@ import org.junit.rules.TemporaryFolder import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +import org.signal.archive.local.proto.Metadata +import org.signal.archive.proto.AccountData +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame +import org.signal.archive.stream.EncryptedBackupWriter import org.signal.core.models.backup.BackupId import org.signal.core.models.backup.MessageBackupKey import org.signal.core.util.Util -import org.thoughtcrime.securesms.backup.v2.local.proto.Metadata -import org.thoughtcrime.securesms.backup.v2.proto.AccountData -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame -import org.thoughtcrime.securesms.backup.v2.stream.EncryptedBackupWriter import java.io.ByteArrayOutputStream import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec diff --git a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReaderWriterTest.kt b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReaderWriterTest.kt index 0e918fcb62..28337541e3 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReaderWriterTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReaderWriterTest.kt @@ -7,6 +7,11 @@ package org.thoughtcrime.securesms.backup.v2.stream import org.junit.Assert.assertEquals import org.junit.Test +import org.signal.archive.proto.AccountData +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame +import org.signal.archive.stream.EncryptedBackupReader +import org.signal.archive.stream.EncryptedBackupWriter import org.signal.core.models.ServiceId.ACI import org.signal.core.models.backup.BackupId import org.signal.core.models.backup.MessageBackupKey @@ -14,9 +19,6 @@ import org.signal.core.util.Base64 import org.signal.core.util.Hex import org.signal.core.util.Util import org.signal.libsignal.messagebackup.BackupForwardSecrecyToken -import org.thoughtcrime.securesms.backup.v2.proto.AccountData -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame import java.io.ByteArrayOutputStream import java.util.UUID diff --git a/lib/archive/build.gradle.kts b/lib/archive/build.gradle.kts new file mode 100644 index 0000000000..72901068f2 --- /dev/null +++ b/lib/archive/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("signal-library") + id("com.squareup.wire") +} + +android { + namespace = "org.signal.archive" +} + +wire { + kotlin { + javaInterop = true + } + + sourcePath { + srcDir("src/main/protowire") + } +} + +dependencies { + implementation(project(":core:util")) + implementation(project(":core:models-jvm")) + implementation(project(":lib:libsignal-service")) + + implementation(libs.libsignal.android) + implementation(libs.google.guava.android) +} diff --git a/lib/archive/src/main/java/org/signal/archive/LocalBackupMetadata.kt b/lib/archive/src/main/java/org/signal/archive/LocalBackupMetadata.kt new file mode 100644 index 0000000000..b6b5c899b1 --- /dev/null +++ b/lib/archive/src/main/java/org/signal/archive/LocalBackupMetadata.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2026 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.signal.archive + +/** + * Metadata about a local backup file available for restore. + */ +data class LocalBackupMetadata( + /** Size of the backup in bytes. */ + val sizeBytes: Long, + /** Timestamp when the backup was created, in milliseconds since epoch. */ + val timestampMs: Long +) diff --git a/lib/archive/src/main/java/org/signal/archive/LocalBackupRestoreProgress.kt b/lib/archive/src/main/java/org/signal/archive/LocalBackupRestoreProgress.kt new file mode 100644 index 0000000000..37449c6567 --- /dev/null +++ b/lib/archive/src/main/java/org/signal/archive/LocalBackupRestoreProgress.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2026 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.signal.archive + +/** + * Represents the progress of a local backup restore operation. + * Emitted as a flow from the storage controller during restore. + */ +sealed interface LocalBackupRestoreProgress { + /** The restore is being prepared (e.g., reading metadata, validating). */ + data object Preparing : LocalBackupRestoreProgress + + /** The restore is actively in progress. */ + data class InProgress( + val bytesRead: Long, + val totalBytes: Long + ) : LocalBackupRestoreProgress { + val progressFraction: Float + get() = if (totalBytes > 0) (bytesRead.toFloat() / totalBytes.toFloat()).coerceIn(0f, 1f) else 0f + } + + /** The restore completed successfully. */ + data object Complete : LocalBackupRestoreProgress + + /** The restore failed with an error. */ + data class Error(val cause: Throwable) : LocalBackupRestoreProgress +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesReader.kt b/lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesReader.kt similarity index 89% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesReader.kt rename to lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesReader.kt index ca3f1e8cff..736a461180 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesReader.kt +++ b/lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesReader.kt @@ -3,11 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.local +package org.signal.archive.local +import org.signal.archive.local.proto.FilesFrame import org.signal.core.util.readNBytesOrThrow import org.signal.core.util.readVarInt32 -import org.thoughtcrime.securesms.backup.v2.local.proto.FilesFrame import java.io.EOFException import java.io.InputStream diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesWriter.kt b/lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesWriter.kt similarity index 82% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesWriter.kt rename to lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesWriter.kt index a49c2de612..925002468f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/local/ArchivedFilesWriter.kt +++ b/lib/archive/src/main/java/org/signal/archive/local/ArchivedFilesWriter.kt @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.local +package org.signal.archive.local +import org.signal.archive.local.proto.FilesFrame import org.signal.core.util.writeVarInt32 -import org.thoughtcrime.securesms.backup.v2.local.proto.FilesFrame import java.io.IOException import java.io.OutputStream diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupExportWriter.kt b/lib/archive/src/main/java/org/signal/archive/stream/BackupExportWriter.kt similarity index 54% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupExportWriter.kt rename to lib/archive/src/main/java/org/signal/archive/stream/BackupExportWriter.kt index 3c8023d95f..1a667e0ee5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupExportWriter.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/BackupExportWriter.kt @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame interface BackupExportWriter : AutoCloseable { fun write(header: BackupInfo) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupFrameEmitter.kt b/lib/archive/src/main/java/org/signal/archive/stream/BackupFrameEmitter.kt similarity index 68% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupFrameEmitter.kt rename to lib/archive/src/main/java/org/signal/archive/stream/BackupFrameEmitter.kt index 50ae25584f..3dc9feed8e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupFrameEmitter.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/BackupFrameEmitter.kt @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream -import org.thoughtcrime.securesms.backup.v2.proto.Frame +import org.signal.archive.proto.Frame /** * An interface that lets sub-processors emit [Frame]s as they export data. diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportReader.kt b/lib/archive/src/main/java/org/signal/archive/stream/BackupImportReader.kt similarity index 59% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportReader.kt rename to lib/archive/src/main/java/org/signal/archive/stream/BackupImportReader.kt index 80f83893eb..938622f977 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportReader.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/BackupImportReader.kt @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame interface BackupImportReader : Iterator, AutoCloseable { fun getHeader(): BackupInfo? diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportStream.kt b/lib/archive/src/main/java/org/signal/archive/stream/BackupImportStream.kt similarity index 57% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportStream.kt rename to lib/archive/src/main/java/org/signal/archive/stream/BackupImportStream.kt index b47df24bc5..4397f630de 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/BackupImportStream.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/BackupImportStream.kt @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream -import org.thoughtcrime.securesms.backup.v2.proto.Frame +import org.signal.archive.proto.Frame interface BackupImportStream { fun read(): Frame? diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReader.kt b/lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupReader.kt similarity index 97% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReader.kt rename to lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupReader.kt index e045914754..396e99959f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupReader.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupReader.kt @@ -3,10 +3,12 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream import androidx.annotation.VisibleForTesting import com.google.common.io.CountingInputStream +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame import org.signal.core.models.ServiceId.ACI import org.signal.core.models.backup.BackupId import org.signal.core.models.backup.MessageBackupKey @@ -17,8 +19,6 @@ import org.signal.core.util.stream.LimitedInputStream import org.signal.core.util.stream.MacInputStream import org.signal.core.util.writeVarInt32 import org.signal.libsignal.messagebackup.BackupForwardSecrecyToken -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame import java.io.ByteArrayOutputStream import java.io.EOFException import java.io.IOException diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupWriter.kt b/lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupWriter.kt similarity index 96% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupWriter.kt rename to lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupWriter.kt index eb9847fc71..c0a8302dd4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/EncryptedBackupWriter.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/EncryptedBackupWriter.kt @@ -3,8 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame +import org.signal.archive.stream.EncryptedBackupReader.Companion.createForSignalBackup import org.signal.core.models.ServiceId.ACI import org.signal.core.models.backup.BackupId import org.signal.core.models.backup.MessageBackupKey @@ -12,8 +15,6 @@ import org.signal.core.util.Util import org.signal.core.util.stream.MacOutputStream import org.signal.core.util.writeVarInt32 import org.signal.libsignal.messagebackup.BackupForwardSecrecyToken -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame import java.io.IOException import java.io.OutputStream import javax.crypto.Cipher diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PaddedGzipOutputStream.kt b/lib/archive/src/main/java/org/signal/archive/stream/PaddedGzipOutputStream.kt similarity index 97% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PaddedGzipOutputStream.kt rename to lib/archive/src/main/java/org/signal/archive/stream/PaddedGzipOutputStream.kt index 791adc036a..dcfcc04a9b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PaddedGzipOutputStream.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/PaddedGzipOutputStream.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream import org.whispersystems.signalservice.internal.crypto.PaddingInputStream import java.io.FilterOutputStream diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupReader.kt b/lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupReader.kt similarity index 90% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupReader.kt rename to lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupReader.kt index 8ada418766..4a828c6d13 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupReader.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupReader.kt @@ -3,13 +3,13 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream import com.google.common.io.CountingInputStream +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame import org.signal.core.util.readNBytesOrThrow import org.signal.core.util.readVarInt32 -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame import java.io.EOFException import java.io.InputStream diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupWriter.kt b/lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupWriter.kt similarity index 83% rename from app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupWriter.kt rename to lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupWriter.kt index b56f1627b3..ce26c7e707 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/stream/PlainTextBackupWriter.kt +++ b/lib/archive/src/main/java/org/signal/archive/stream/PlainTextBackupWriter.kt @@ -3,11 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.backup.v2.stream +package org.signal.archive.stream +import org.signal.archive.proto.BackupInfo +import org.signal.archive.proto.Frame import org.signal.core.util.writeVarInt32 -import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo -import org.thoughtcrime.securesms.backup.v2.proto.Frame import java.io.IOException import java.io.OutputStream diff --git a/app/src/main/protowire/Backup.proto b/lib/archive/src/main/protowire/Backup.proto similarity index 99% rename from app/src/main/protowire/Backup.proto rename to lib/archive/src/main/protowire/Backup.proto index 8242bb8123..d7407cb505 100644 --- a/app/src/main/protowire/Backup.proto +++ b/lib/archive/src/main/protowire/Backup.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package signal.backup; -option java_package = "org.thoughtcrime.securesms.backup.v2.proto"; +option java_package = "org.signal.archive.proto"; option swift_prefix = "BackupProto_"; message BackupInfo { diff --git a/app/src/main/protowire/BackupDebugInfo.proto b/lib/archive/src/main/protowire/BackupDebugInfo.proto similarity index 85% rename from app/src/main/protowire/BackupDebugInfo.proto rename to lib/archive/src/main/protowire/BackupDebugInfo.proto index ab7a48b895..e028e4b048 100644 --- a/app/src/main/protowire/BackupDebugInfo.proto +++ b/lib/archive/src/main/protowire/BackupDebugInfo.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -option java_package = "org.thoughtcrime.securesms.backup.v2.proto"; +option java_package = "org.signal.archive.proto"; message BackupDebugInfo { message AttachmentDetails { diff --git a/app/src/main/protowire/LocalArchive.proto b/lib/archive/src/main/protowire/LocalArchive.proto similarity index 90% rename from app/src/main/protowire/LocalArchive.proto rename to lib/archive/src/main/protowire/LocalArchive.proto index 5381d79071..889c49f1e2 100644 --- a/app/src/main/protowire/LocalArchive.proto +++ b/lib/archive/src/main/protowire/LocalArchive.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package signal.backup.local; -option java_package = "org.thoughtcrime.securesms.backup.v2.local.proto"; +option java_package = "org.signal.archive.local.proto"; option swift_prefix = "LocalBackupProto_"; message Metadata { diff --git a/settings.gradle.kts b/settings.gradle.kts index 86acfaea70..9b8b35426f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -88,6 +88,7 @@ include(":lib:image-editor") include(":lib:debuglogs-viewer") include(":lib:blurhash") include(":lib:apng") +include(":lib:archive") // Feature modules include(":feature:registration")