Loading backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt +4 −0 Original line number Diff line number Diff line Loading @@ -47,4 +47,8 @@ class TestImapStore : ImapStore { override fun closeAllConnections() { throw UnsupportedOperationException("not implemented") } override fun fetchImapPrefix() { throw UnsupportedOperationException("not implemented") } } backend/imap/src/test/kotlin/net/thunderbird/backend/imap/ImapRemoteFolderCreatorTest.kt +4 −0 Original line number Diff line number Diff line Loading @@ -138,4 +138,8 @@ private class FakeImapStore( override fun closeAllConnections() { throw NotImplementedError("closeAllConnections not implemented") } override fun fetchImapPrefix() { throw NotImplementedError("fetchImapPrefix not implemented") } } legacy/storage/build.gradle.kts +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,10 @@ dependencies { implementation(projects.core.logging.api) implementation(projects.legacy.core) // Required for MigrationTo107 implementation(projects.mail.common) implementation(projects.mail.protocols.imap) implementation(libs.androidx.core.ktx) implementation(libs.mime4j.core) implementation(libs.commons.io) Loading legacy/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java +1 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ import net.thunderbird.core.logging.legacy.Log; class StoreSchemaDefinition implements SchemaDefinition { static final int DB_VERSION = 89; static final int DB_VERSION = 90; private final MigrationsHelper migrationsHelper; Loading legacy/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo90.kt 0 → 100644 +122 −0 Original line number Diff line number Diff line package com.fsck.k9.storage.migrations import android.database.sqlite.SQLiteDatabase import com.fsck.k9.mail.AuthType import com.fsck.k9.mail.AuthenticationFailedException import com.fsck.k9.mail.ServerSettings import com.fsck.k9.mail.oauth.AuthStateStorage import com.fsck.k9.mail.oauth.OAuth2TokenProviderFactory import com.fsck.k9.mail.ssl.TrustedSocketFactory import com.fsck.k9.mail.store.imap.ImapClientInfo import com.fsck.k9.mail.store.imap.ImapStore import com.fsck.k9.mail.store.imap.ImapStoreConfig import com.fsck.k9.mail.store.imap.ImapStoreSettings import com.fsck.k9.mail.store.imap.ImapStoreSettings.autoDetectNamespace import com.fsck.k9.mail.store.imap.ImapStoreSettings.pathPrefix import com.fsck.k9.mailstore.MigrationsHelper import net.thunderbird.core.android.account.Expunge import net.thunderbird.core.android.account.LegacyAccountDto import net.thunderbird.core.common.mail.Protocols import net.thunderbird.core.logging.Logger import net.thunderbird.core.logging.legacy.Log import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.qualifier.named private const val TAG = "MigrationTo90" internal class MigrationTo90( private val db: SQLiteDatabase, private val migrationsHelper: MigrationsHelper, private val logger: Logger = Log, ) : KoinComponent { private val trustedSocketFactory: TrustedSocketFactory by inject() private val clientInfoAppName: String by inject(named("ClientInfoAppName")) private val clientInfoAppVersion: String by inject(named("ClientInfoAppVersion")) private val oAuth2TokenProviderFactory: OAuth2TokenProviderFactory by inject() fun removeImapPrefixFromFolderServerId() { val account = migrationsHelper.account if (account.incomingServerSettings.type != Protocols.IMAP) { logger.verbose(TAG) { "account ${account.uuid} is not an IMAP account, skipping db migration for this account." } return } logger.verbose(TAG) { "started db migration to version 107 to account ${account.uuid}" } val imapStore = createImapStore(account) try { logger.verbose(TAG) { "fetching IMAP prefix" } imapStore.fetchImapPrefix() } catch (e: AuthenticationFailedException) { logger.warn(TAG, e) { "failed to fetch IMAP prefix." } return } val imapPrefix = imapStore.combinedPrefix if (imapPrefix?.isNotBlank() == true) { logger.verbose(TAG) { "Imap Prefix ($imapPrefix) detected, updating folder's server_id" } val query = """ |UPDATE folders | SET server_id = REPLACE(server_id, '$imapPrefix', '') |WHERE | server_id LIKE '$imapPrefix%' """.trimMargin() db.execSQL(query) } else { logger.verbose(TAG) { "No Imap Prefix detected, skipping db migration" } } logger.verbose(TAG) { "completed db migration to version 107 for account ${account.uuid}" } } private fun createImapStore(account: LegacyAccountDto): ImapStore { val serverSettings = account.toImapServerSettings() val oAuth2TokenProvider = if (serverSettings.authenticationType == AuthType.XOAUTH2) { val authStateStorage = object : AuthStateStorage { override fun getAuthorizationState(): String? = account.oAuthState override fun updateAuthorizationState(authorizationState: String?) = Unit } oAuth2TokenProviderFactory.create(authStateStorage) } else { null } return ImapStore.create( serverSettings = serverSettings, config = createImapStoreConfig(account), trustedSocketFactory = trustedSocketFactory, oauthTokenProvider = oAuth2TokenProvider, ) } private fun LegacyAccountDto.toImapServerSettings(): ServerSettings { val serverSettings = incomingServerSettings return serverSettings.copy( extra = ImapStoreSettings.createExtra( autoDetectNamespace = serverSettings.autoDetectNamespace, pathPrefix = serverSettings.pathPrefix, useCompression = useCompression, sendClientInfo = isSendClientInfoEnabled, ), ) } private fun createImapStoreConfig(account: LegacyAccountDto): ImapStoreConfig { return object : ImapStoreConfig { override val logLabel get() = account.uuid override fun isSubscribedFoldersOnly() = account.isSubscribedFoldersOnly override fun isExpungeImmediately() = account.expungePolicy == Expunge.EXPUNGE_IMMEDIATELY override fun clientInfo() = ImapClientInfo(appName = clientInfoAppName, appVersion = clientInfoAppVersion) } } } Loading
backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt +4 −0 Original line number Diff line number Diff line Loading @@ -47,4 +47,8 @@ class TestImapStore : ImapStore { override fun closeAllConnections() { throw UnsupportedOperationException("not implemented") } override fun fetchImapPrefix() { throw UnsupportedOperationException("not implemented") } }
backend/imap/src/test/kotlin/net/thunderbird/backend/imap/ImapRemoteFolderCreatorTest.kt +4 −0 Original line number Diff line number Diff line Loading @@ -138,4 +138,8 @@ private class FakeImapStore( override fun closeAllConnections() { throw NotImplementedError("closeAllConnections not implemented") } override fun fetchImapPrefix() { throw NotImplementedError("fetchImapPrefix not implemented") } }
legacy/storage/build.gradle.kts +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,10 @@ dependencies { implementation(projects.core.logging.api) implementation(projects.legacy.core) // Required for MigrationTo107 implementation(projects.mail.common) implementation(projects.mail.protocols.imap) implementation(libs.androidx.core.ktx) implementation(libs.mime4j.core) implementation(libs.commons.io) Loading
legacy/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java +1 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ import net.thunderbird.core.logging.legacy.Log; class StoreSchemaDefinition implements SchemaDefinition { static final int DB_VERSION = 89; static final int DB_VERSION = 90; private final MigrationsHelper migrationsHelper; Loading
legacy/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo90.kt 0 → 100644 +122 −0 Original line number Diff line number Diff line package com.fsck.k9.storage.migrations import android.database.sqlite.SQLiteDatabase import com.fsck.k9.mail.AuthType import com.fsck.k9.mail.AuthenticationFailedException import com.fsck.k9.mail.ServerSettings import com.fsck.k9.mail.oauth.AuthStateStorage import com.fsck.k9.mail.oauth.OAuth2TokenProviderFactory import com.fsck.k9.mail.ssl.TrustedSocketFactory import com.fsck.k9.mail.store.imap.ImapClientInfo import com.fsck.k9.mail.store.imap.ImapStore import com.fsck.k9.mail.store.imap.ImapStoreConfig import com.fsck.k9.mail.store.imap.ImapStoreSettings import com.fsck.k9.mail.store.imap.ImapStoreSettings.autoDetectNamespace import com.fsck.k9.mail.store.imap.ImapStoreSettings.pathPrefix import com.fsck.k9.mailstore.MigrationsHelper import net.thunderbird.core.android.account.Expunge import net.thunderbird.core.android.account.LegacyAccountDto import net.thunderbird.core.common.mail.Protocols import net.thunderbird.core.logging.Logger import net.thunderbird.core.logging.legacy.Log import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.koin.core.qualifier.named private const val TAG = "MigrationTo90" internal class MigrationTo90( private val db: SQLiteDatabase, private val migrationsHelper: MigrationsHelper, private val logger: Logger = Log, ) : KoinComponent { private val trustedSocketFactory: TrustedSocketFactory by inject() private val clientInfoAppName: String by inject(named("ClientInfoAppName")) private val clientInfoAppVersion: String by inject(named("ClientInfoAppVersion")) private val oAuth2TokenProviderFactory: OAuth2TokenProviderFactory by inject() fun removeImapPrefixFromFolderServerId() { val account = migrationsHelper.account if (account.incomingServerSettings.type != Protocols.IMAP) { logger.verbose(TAG) { "account ${account.uuid} is not an IMAP account, skipping db migration for this account." } return } logger.verbose(TAG) { "started db migration to version 107 to account ${account.uuid}" } val imapStore = createImapStore(account) try { logger.verbose(TAG) { "fetching IMAP prefix" } imapStore.fetchImapPrefix() } catch (e: AuthenticationFailedException) { logger.warn(TAG, e) { "failed to fetch IMAP prefix." } return } val imapPrefix = imapStore.combinedPrefix if (imapPrefix?.isNotBlank() == true) { logger.verbose(TAG) { "Imap Prefix ($imapPrefix) detected, updating folder's server_id" } val query = """ |UPDATE folders | SET server_id = REPLACE(server_id, '$imapPrefix', '') |WHERE | server_id LIKE '$imapPrefix%' """.trimMargin() db.execSQL(query) } else { logger.verbose(TAG) { "No Imap Prefix detected, skipping db migration" } } logger.verbose(TAG) { "completed db migration to version 107 for account ${account.uuid}" } } private fun createImapStore(account: LegacyAccountDto): ImapStore { val serverSettings = account.toImapServerSettings() val oAuth2TokenProvider = if (serverSettings.authenticationType == AuthType.XOAUTH2) { val authStateStorage = object : AuthStateStorage { override fun getAuthorizationState(): String? = account.oAuthState override fun updateAuthorizationState(authorizationState: String?) = Unit } oAuth2TokenProviderFactory.create(authStateStorage) } else { null } return ImapStore.create( serverSettings = serverSettings, config = createImapStoreConfig(account), trustedSocketFactory = trustedSocketFactory, oauthTokenProvider = oAuth2TokenProvider, ) } private fun LegacyAccountDto.toImapServerSettings(): ServerSettings { val serverSettings = incomingServerSettings return serverSettings.copy( extra = ImapStoreSettings.createExtra( autoDetectNamespace = serverSettings.autoDetectNamespace, pathPrefix = serverSettings.pathPrefix, useCompression = useCompression, sendClientInfo = isSendClientInfoEnabled, ), ) } private fun createImapStoreConfig(account: LegacyAccountDto): ImapStoreConfig { return object : ImapStoreConfig { override val logLabel get() = account.uuid override fun isSubscribedFoldersOnly() = account.isSubscribedFoldersOnly override fun isExpungeImmediately() = account.expungePolicy == Expunge.EXPUNGE_IMMEDIATELY override fun clientInfo() = ImapClientInfo(appName = clientInfoAppName, appVersion = clientInfoAppVersion) } } }