Merge pull request #7722 from thunderbird/expunge_handling
IMAP: Change EXPUNGE behavior after moving a message
This commit is contained in:
commit
8ef13f5dcd
10 changed files with 51 additions and 5 deletions
|
@ -2,6 +2,7 @@ package com.fsck.k9.backends
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.fsck.k9.Account
|
import com.fsck.k9.Account
|
||||||
|
import com.fsck.k9.Account.Expunge
|
||||||
import com.fsck.k9.backend.BackendFactory
|
import com.fsck.k9.backend.BackendFactory
|
||||||
import com.fsck.k9.backend.api.Backend
|
import com.fsck.k9.backend.api.Backend
|
||||||
import com.fsck.k9.backend.imap.ImapBackend
|
import com.fsck.k9.backend.imap.ImapBackend
|
||||||
|
@ -74,6 +75,8 @@ class ImapBackendFactory(
|
||||||
|
|
||||||
override fun isSubscribedFoldersOnly() = account.isSubscribedFoldersOnly
|
override fun isSubscribedFoldersOnly() = account.isSubscribedFoldersOnly
|
||||||
|
|
||||||
|
override fun isExpungeImmediately() = account.expungePolicy == Expunge.EXPUNGE_IMMEDIATELY
|
||||||
|
|
||||||
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class ImapFolderFetcher internal constructor(
|
||||||
val config = object : ImapStoreConfig {
|
val config = object : ImapStoreConfig {
|
||||||
override val logLabel = "folder-fetcher"
|
override val logLabel = "folder-fetcher"
|
||||||
override fun isSubscribedFoldersOnly() = false
|
override fun isSubscribedFoldersOnly() = false
|
||||||
|
override fun isExpungeImmediately() = false
|
||||||
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
||||||
}
|
}
|
||||||
val oAuth2TokenProvider = createOAuth2TokenProviderOrNull(authStateStorage)
|
val oAuth2TokenProvider = createOAuth2TokenProviderOrNull(authStateStorage)
|
||||||
|
|
|
@ -32,6 +32,7 @@ class ImapServerSettingsValidator(
|
||||||
val config = object : ImapStoreConfig {
|
val config = object : ImapStoreConfig {
|
||||||
override val logLabel = "check"
|
override val logLabel = "check"
|
||||||
override fun isSubscribedFoldersOnly() = false
|
override fun isSubscribedFoldersOnly() = false
|
||||||
|
override fun isExpungeImmediately() = false
|
||||||
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
override fun clientId() = ImapClientId(appName = clientIdAppName, appVersion = clientIdAppVersion)
|
||||||
}
|
}
|
||||||
val oAuth2TokenProvider = createOAuth2TokenProviderOrNull(authStateStorage)
|
val oAuth2TokenProvider = createOAuth2TokenProviderOrNull(authStateStorage)
|
||||||
|
|
|
@ -3,5 +3,6 @@ package com.fsck.k9.mail.store.imap
|
||||||
interface ImapStoreConfig {
|
interface ImapStoreConfig {
|
||||||
val logLabel: String
|
val logLabel: String
|
||||||
fun isSubscribedFoldersOnly(): Boolean
|
fun isSubscribedFoldersOnly(): Boolean
|
||||||
|
fun isExpungeImmediately(): Boolean
|
||||||
fun clientId(): ImapClientId
|
fun clientId(): ImapClientId
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.fsck.k9.mail.Flag
|
||||||
|
|
||||||
internal interface InternalImapStore {
|
internal interface InternalImapStore {
|
||||||
val logLabel: String
|
val logLabel: String
|
||||||
|
val config: ImapStoreConfig
|
||||||
|
|
||||||
fun getCombinedPrefix(): String
|
fun getCombinedPrefix(): String
|
||||||
|
|
||||||
|
|
|
@ -354,7 +354,7 @@ internal class RealImapFolder(
|
||||||
|
|
||||||
val uidMapping = copyMessages(messages, folder)
|
val uidMapping = copyMessages(messages, folder)
|
||||||
setFlags(messages, setOf(Flag.DELETED), true)
|
setFlags(messages, setOf(Flag.DELETED), true)
|
||||||
expungeUidsOnly(uids)
|
expungeUidsAfterDelete(uids)
|
||||||
|
|
||||||
return uidMapping
|
return uidMapping
|
||||||
}
|
}
|
||||||
|
@ -1117,8 +1117,8 @@ internal class RealImapFolder(
|
||||||
expungeUids(uids, fullExpungeFallback = true)
|
expungeUids(uids, fullExpungeFallback = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expungeUidsOnly(uids: List<String>) {
|
private fun expungeUidsAfterDelete(uids: List<String>) {
|
||||||
expungeUids(uids, fullExpungeFallback = false)
|
expungeUids(uids, fullExpungeFallback = internalImapStore.config.isExpungeImmediately())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expungeUids(uids: List<String>, fullExpungeFallback: Boolean) {
|
private fun expungeUids(uids: List<String>, fullExpungeFallback: Boolean) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.LinkedList
|
||||||
|
|
||||||
internal open class RealImapStore(
|
internal open class RealImapStore(
|
||||||
private val serverSettings: ServerSettings,
|
private val serverSettings: ServerSettings,
|
||||||
private val config: ImapStoreConfig,
|
override val config: ImapStoreConfig,
|
||||||
private val trustedSocketFactory: TrustedSocketFactory,
|
private val trustedSocketFactory: TrustedSocketFactory,
|
||||||
private val oauthTokenProvider: OAuth2TokenProvider?,
|
private val oauthTokenProvider: OAuth2TokenProvider?,
|
||||||
) : ImapStore, ImapConnectionManager, InternalImapStore {
|
) : ImapStore, ImapConnectionManager, InternalImapStore {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.fsck.k9.mail.store.imap
|
||||||
|
|
||||||
|
class FakeImapStoreConfig : ImapStoreConfig {
|
||||||
|
var expungeImmediately = true
|
||||||
|
|
||||||
|
override var logLabel: String = "irrelevant"
|
||||||
|
|
||||||
|
override fun isSubscribedFoldersOnly(): Boolean {
|
||||||
|
throw UnsupportedOperationException("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isExpungeImmediately(): Boolean = expungeImmediately
|
||||||
|
|
||||||
|
override fun clientId(): ImapClientId {
|
||||||
|
throw UnsupportedOperationException("not implemented")
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,8 +54,10 @@ import org.mockito.kotlin.stub
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
class RealImapFolderTest {
|
class RealImapFolderTest {
|
||||||
|
private val imapStoreConfig = FakeImapStoreConfig()
|
||||||
private val internalImapStore = object : InternalImapStore {
|
private val internalImapStore = object : InternalImapStore {
|
||||||
override val logLabel = "Account"
|
override val logLabel = "Account"
|
||||||
|
override val config = imapStoreConfig
|
||||||
override fun getCombinedPrefix() = ""
|
override fun getCombinedPrefix() = ""
|
||||||
override fun getPermanentFlagsIndex() = mutableSetOf<Flag>()
|
override fun getPermanentFlagsIndex() = mutableSetOf<Flag>()
|
||||||
}
|
}
|
||||||
|
@ -355,7 +357,26 @@ class RealImapFolderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `moveMessages() should delete messages from source folder but not issue EXPUNGE command`() {
|
fun `moveMessages() with expungeImmediately = true should delete and expunge`() {
|
||||||
|
imapStoreConfig.expungeImmediately = true
|
||||||
|
val sourceFolder = createFolder("Folder")
|
||||||
|
prepareImapFolderForOpen(OpenMode.READ_WRITE)
|
||||||
|
imapConnection.stub {
|
||||||
|
on { isUidPlusCapable } doReturn false
|
||||||
|
}
|
||||||
|
val destinationFolder = createFolder("Destination")
|
||||||
|
val messages = listOf(createImapMessage("1"))
|
||||||
|
sourceFolder.open(OpenMode.READ_WRITE)
|
||||||
|
|
||||||
|
sourceFolder.moveMessages(messages, destinationFolder)
|
||||||
|
|
||||||
|
assertCommandWithIdsIssued("UID STORE 1 +FLAGS.SILENT (\\Deleted)")
|
||||||
|
assertCommandIssued("EXPUNGE")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `moveMessages() with expungeImmediately = false should delete but not expunge`() {
|
||||||
|
imapStoreConfig.expungeImmediately = false
|
||||||
val sourceFolder = createFolder("Folder")
|
val sourceFolder = createFolder("Folder")
|
||||||
prepareImapFolderForOpen(OpenMode.READ_WRITE)
|
prepareImapFolderForOpen(OpenMode.READ_WRITE)
|
||||||
imapConnection.stub {
|
imapConnection.stub {
|
||||||
|
|
|
@ -408,6 +408,7 @@ class RealImapStoreTest {
|
||||||
return object : ImapStoreConfig {
|
return object : ImapStoreConfig {
|
||||||
override val logLabel: String = "irrelevant"
|
override val logLabel: String = "irrelevant"
|
||||||
override fun isSubscribedFoldersOnly(): Boolean = isSubscribedFoldersOnly
|
override fun isSubscribedFoldersOnly(): Boolean = isSubscribedFoldersOnly
|
||||||
|
override fun isExpungeImmediately(): Boolean = true
|
||||||
override fun clientId(): ImapClientId = ImapClientId(appName = "irrelevant", appVersion = "irrelevant")
|
override fun clientId(): ImapClientId = ImapClientId(appName = "irrelevant", appVersion = "irrelevant")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue