Merge pull request #5293 from k9mail/download_state

Correctly persist message download state
This commit is contained in:
cketti 2021-05-11 19:52:55 +02:00 committed by GitHub
commit db177eca59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 79 additions and 55 deletions

View file

@ -7,6 +7,7 @@ import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend
import com.fsck.k9.controller.MessagingControllerCommands.PendingReplace
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.MessagingException
import com.fsck.k9.mailstore.LocalFolder
import com.fsck.k9.mailstore.LocalMessage
@ -164,6 +165,6 @@ internal class DraftOperations(
}
private fun Message.toSaveMessageData(subject: String?): SaveMessageData {
return saveMessageDataCreator.createSaveMessageData(this, partialMessage = false, subject)
return saveMessageDataCreator.createSaveMessageData(this, MessageDownloadState.FULL, subject)
}
}

View file

@ -67,6 +67,7 @@ import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
import com.fsck.k9.mailstore.LocalStoreProvider;
import com.fsck.k9.mail.MessageDownloadState;
import com.fsck.k9.mailstore.MessageStore;
import com.fsck.k9.mailstore.MessageStoreManager;
import com.fsck.k9.mailstore.OutboxState;
@ -1375,7 +1376,8 @@ public class MessagingController {
message.setFlag(Flag.SEEN, true);
MessageStore messageStore = messageStoreManager.getMessageStore(account);
SaveMessageData messageData = saveMessageDataCreator.createSaveMessageData(message, false, plaintextSubject);
SaveMessageData messageData = saveMessageDataCreator.createSaveMessageData(
message, MessageDownloadState.FULL, plaintextSubject);
long messageId = messageStore.saveLocalMessage(outboxFolderId, messageData, null);
LocalStore localStore = localStoreProvider.getInstance(account);

View file

@ -4,6 +4,7 @@ import com.fsck.k9.backend.api.BackendFolder
import com.fsck.k9.backend.api.BackendFolder.MoreMessages
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import java.util.Date
import com.fsck.k9.mailstore.MoreMessages as StoreMoreMessages
@ -85,18 +86,10 @@ class K9BackendFolder(
messageStore.setMessageFlag(folderId, messageServerId, flag, value)
}
override fun saveCompleteMessage(message: Message) {
saveMessage(message, partialMessage = false)
}
override fun savePartialMessage(message: Message) {
saveMessage(message, partialMessage = true)
}
private fun saveMessage(message: Message, partialMessage: Boolean) {
override fun saveMessage(message: Message, downloadState: MessageDownloadState) {
requireMessageServerId(message)
val messageData = saveMessageDataCreator.createSaveMessageData(message, partialMessage)
val messageData = saveMessageDataCreator.createSaveMessageData(message, downloadState)
messageStore.saveRemoteMessage(folderId, message.uid, messageData)
}

View file

@ -1,6 +1,7 @@
package com.fsck.k9.mailstore
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.message.extractors.PreviewResult
data class SaveMessageData(
@ -8,7 +9,7 @@ data class SaveMessageData(
val subject: String?,
val date: Long,
val internalDate: Long,
val partialMessage: Boolean,
val downloadState: MessageDownloadState,
val attachmentCount: Int,
val previewResult: PreviewResult,
val textForSearchIndex: String? = null,

View file

@ -2,6 +2,7 @@ package com.fsck.k9.mailstore
import com.fsck.k9.crypto.EncryptionExtractor
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.message.extractors.AttachmentCounter
import com.fsck.k9.message.extractors.MessageFulltextCreator
import com.fsck.k9.message.extractors.MessagePreviewCreator
@ -12,7 +13,11 @@ class SaveMessageDataCreator(
private val messageFulltextCreator: MessageFulltextCreator,
private val attachmentCounter: AttachmentCounter
) {
fun createSaveMessageData(message: Message, partialMessage: Boolean, subject: String? = null): SaveMessageData {
fun createSaveMessageData(
message: Message,
downloadState: MessageDownloadState,
subject: String? = null
): SaveMessageData {
val now = System.currentTimeMillis()
val date = message.sentDate?.time ?: now
val internalDate = message.internalDate?.time ?: now
@ -25,7 +30,7 @@ class SaveMessageDataCreator(
subject = displaySubject,
date = date,
internalDate = internalDate,
partialMessage = partialMessage,
downloadState = downloadState,
attachmentCount = encryptionResult.attachmentCount,
previewResult = encryptionResult.previewResult,
textForSearchIndex = encryptionResult.textForSearchIndex,
@ -37,7 +42,7 @@ class SaveMessageDataCreator(
subject = displaySubject,
date = date,
internalDate = internalDate,
partialMessage = partialMessage,
downloadState = downloadState,
attachmentCount = attachmentCounter.getAttachmentCount(message),
previewResult = messagePreviewCreator.createPreview(message),
textForSearchIndex = messageFulltextCreator.createFulltext(message),

View file

@ -13,6 +13,7 @@ import com.fsck.k9.mail.Address
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.FolderType
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.internet.MimeMessage
import com.fsck.k9.mail.internet.MimeMessageHelper
import com.fsck.k9.mail.internet.TextBody
@ -92,7 +93,7 @@ class K9BackendFolderTest : K9RobolectricTest() {
val message = createMessage(messageServerId = null)
try {
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
fail("Expected exception")
} catch (e: IllegalStateException) {
}
@ -103,7 +104,7 @@ class K9BackendFolderTest : K9RobolectricTest() {
val message = createMessage(messageServerId = null)
try {
backendFolder.savePartialMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL)
fail("Expected exception")
} catch (e: IllegalStateException) {
}
@ -136,7 +137,7 @@ class K9BackendFolderTest : K9RobolectricTest() {
fun createMessageInBackendFolder(messageServerId: String, flags: Set<Flag> = emptySet()) {
val message = createMessage(messageServerId, flags)
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
val messageServerIds = backendFolder.getMessageServerIds()
assertTrue(messageServerId in messageServerIds)

View file

@ -9,6 +9,7 @@ import com.fsck.k9.mail.BoundaryGenerator
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Message.RecipientType
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.Multipart
import com.fsck.k9.mail.Part
import com.fsck.k9.mail.filter.CountingOutputStream
@ -381,10 +382,10 @@ internal class SaveMessageOperations(
): Long {
val message = messageData.message
if (messageData.partialMessage) {
message.setFlag(Flag.X_DOWNLOADED_PARTIAL, true)
} else {
message.setFlag(Flag.X_DOWNLOADED_FULL, true)
when (messageData.downloadState) {
MessageDownloadState.ENVELOPE -> Unit
MessageDownloadState.PARTIAL -> message.setFlag(Flag.X_DOWNLOADED_PARTIAL, true)
MessageDownloadState.FULL -> message.setFlag(Flag.X_DOWNLOADED_FULL, true)
}
val values = ContentValues().apply {

View file

@ -4,6 +4,7 @@ import com.fsck.k9.K9
import com.fsck.k9.mail.Address
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.Multipart
import com.fsck.k9.mail.Part
import com.fsck.k9.mail.buildMessage
@ -500,7 +501,7 @@ class SaveMessageOperationsTest : RobolectricTest() {
subject: String? = getSubject(),
date: Long = sentDate?.time ?: System.currentTimeMillis(),
internalDate: Long = date,
partialMessage: Boolean = isPartialMessage(),
downloadState: MessageDownloadState = getDownloadState(),
attachmentCount: Int = 0,
previewResult: PreviewResult = PreviewResult.none(),
textForSearchIndex: String? = null,
@ -511,7 +512,7 @@ class SaveMessageOperationsTest : RobolectricTest() {
subject,
date,
internalDate,
partialMessage,
downloadState,
attachmentCount,
previewResult,
textForSearchIndex,
@ -519,14 +520,16 @@ class SaveMessageOperationsTest : RobolectricTest() {
)
}
private fun Message.isPartialMessage(): Boolean {
private fun Message.getDownloadState(): MessageDownloadState {
if (body == null) return MessageDownloadState.ENVELOPE
val stack = Stack<Part>()
stack.push(this)
while (stack.isNotEmpty()) {
val part = stack.pop()
when (val body = part.body) {
null -> return true
null -> return MessageDownloadState.PARTIAL
is Multipart -> {
for (i in 0 until body.count) {
stack.push(body.getBodyPart(i))
@ -535,7 +538,7 @@ class SaveMessageOperationsTest : RobolectricTest() {
}
}
return false
return MessageDownloadState.FULL
}
private fun Message.header(): String {

View file

@ -2,6 +2,7 @@ package com.fsck.k9.backend.api
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import java.util.Date
// FIXME: add documentation
@ -21,8 +22,7 @@ interface BackendFolder {
fun isMessagePresent(messageServerId: String): Boolean
fun getMessageFlags(messageServerId: String): Set<Flag>
fun setMessageFlag(messageServerId: String, flag: Flag, value: Boolean)
fun savePartialMessage(message: Message)
fun saveCompleteMessage(message: Message)
fun saveMessage(message: Message, downloadState: MessageDownloadState)
fun getOldestMessageDate(): Date?
fun getFolderExtraString(name: String): String?
fun setFolderExtraString(name: String, value: String?)

View file

@ -6,6 +6,7 @@ import com.fsck.k9.mail.FetchProfile.Item.BODY
import com.fsck.k9.mail.FetchProfile.Item.ENVELOPE
import com.fsck.k9.mail.FetchProfile.Item.FLAGS
import com.fsck.k9.mail.FetchProfile.Item.STRUCTURE
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.helper.fetchProfileOf
import com.fsck.k9.mail.store.imap.ImapFolder
import com.fsck.k9.mail.store.imap.ImapMessage
@ -25,7 +26,7 @@ internal class CommandDownloadMessage(private val backendStorage: BackendStorage
fetchMessage(folder, message, fetchProfileOf(STRUCTURE))
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.savePartialMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.ENVELOPE)
} finally {
folder.close()
}
@ -40,7 +41,7 @@ internal class CommandDownloadMessage(private val backendStorage: BackendStorage
fetchMessage(folder, message, fetchProfileOf(FLAGS, BODY))
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
} finally {
folder.close()
}

View file

@ -12,6 +12,7 @@ import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.DefaultBodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.MessageRetrievalListener
import com.fsck.k9.mail.internet.MessageExtractor
import com.fsck.k9.mail.store.imap.ImapFolder
@ -526,7 +527,7 @@ internal class ImapSync(
override fun messageFinished(message: ImapMessage, number: Int, ofTotal: Int) {
try {
// Store the updated message locally
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
progress.incrementAndGet()
// Increment the number of "new messages" if the newly downloaded message is not marked as read.
@ -664,7 +665,7 @@ internal class ImapSync(
remoteFolder.fetch(listOf(message), fetchProfile, null, maxDownloadSize)
// Store the updated message locally
backendFolder.savePartialMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL)
}
private fun downloadPartial(
@ -690,7 +691,7 @@ internal class ImapSync(
}
// Store the updated message locally
backendFolder.savePartialMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL)
}
private fun syncFlags(syncConfig: SyncConfig, backendFolder: BackendFolder, remoteMessage: ImapMessage): Boolean {

View file

@ -6,6 +6,7 @@ import com.fsck.k9.backend.api.SyncConfig
import com.fsck.k9.backend.api.SyncListener
import com.fsck.k9.mail.AuthenticationFailedException
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.internet.MimeMessage
import java.util.Date
import okhttp3.HttpUrl
@ -192,7 +193,7 @@ class CommandSync(
setFlags(messageInfo.flags, true)
}
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
} else {
Timber.d("Failed to download message: %s", messageInfo.serverId)
}

View file

@ -4,6 +4,7 @@ import com.fsck.k9.backend.api.BackendFolder
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.FolderType
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.internet.MimeMessage
import java.util.Date
import okio.Buffer
@ -108,16 +109,18 @@ class InMemoryBackendFolder(override var name: String, var type: FolderType) : B
}
}
override fun savePartialMessage(message: Message) {
override fun saveMessage(message: Message, downloadState: MessageDownloadState) {
val messageServerId = checkNotNull(message.uid)
messages[messageServerId] = message
messageFlags[messageServerId] = message.flags.toMutableSet()
}
val flags = message.flags.toMutableSet()
override fun saveCompleteMessage(message: Message) {
val messageServerId = checkNotNull(message.uid)
messages[messageServerId] = message
messageFlags[messageServerId] = message.flags.toMutableSet()
when (downloadState) {
MessageDownloadState.ENVELOPE -> Unit
MessageDownloadState.PARTIAL -> flags.add(Flag.X_DOWNLOADED_PARTIAL)
MessageDownloadState.FULL -> flags.add(Flag.X_DOWNLOADED_FULL)
}
messageFlags[messageServerId] = flags
}
override fun getOldestMessageDate(): Date? {

View file

@ -3,6 +3,7 @@ package com.fsck.k9.backend.pop3
import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.mail.FetchProfile.Item.BODY
import com.fsck.k9.mail.FetchProfile.Item.FLAGS
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.helper.fetchProfileOf
import com.fsck.k9.mail.store.pop3.Pop3Store
@ -17,7 +18,7 @@ internal class CommandDownloadMessage(private val backendStorage: BackendStorage
folder.fetch(listOf(message), fetchProfileOf(FLAGS, BODY), null, 0)
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
} finally {
folder.close()
}

View file

@ -10,6 +10,7 @@ import com.fsck.k9.helper.ExceptionHelper;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.MessageDownloadState;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.pop3.Pop3Folder;
@ -377,9 +378,9 @@ class Pop3Sync {
// Store the updated message locally
boolean completeMessage = message.isSet(Flag.X_DOWNLOADED_FULL);
if (completeMessage) {
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
} else {
backendFolder.savePartialMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL);
}
boolean isOldMessage = isOldMessage(backendFolder, message);
@ -480,7 +481,7 @@ class Pop3Sync {
try {
// Store the updated message locally
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
progress.incrementAndGet();
// Increment the number of "new messages" if the newly downloaded message is
@ -603,9 +604,9 @@ class Pop3Sync {
// Store the updated message locally
if (completeMessage) {
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
} else {
backendFolder.savePartialMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL);
}
}
}

View file

@ -3,6 +3,7 @@ package com.fsck.k9.backend.webdav
import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.mail.FetchProfile.Item.BODY
import com.fsck.k9.mail.FetchProfile.Item.FLAGS
import com.fsck.k9.mail.MessageDownloadState
import com.fsck.k9.mail.helper.fetchProfileOf
import com.fsck.k9.mail.store.webdav.WebDavStore
@ -16,7 +17,7 @@ internal class CommandDownloadMessage(val backendStorage: BackendStorage, privat
folder.fetch(listOf(message), fetchProfileOf(FLAGS, BODY), null, 0)
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
backendFolder.saveMessage(message, MessageDownloadState.FULL)
} finally {
folder.close()
}

View file

@ -10,6 +10,7 @@ import com.fsck.k9.helper.ExceptionHelper;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.MessageDownloadState;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.webdav.WebDavFolder;
@ -364,9 +365,9 @@ class WebDavSync {
// Store the updated message locally
boolean completeMessage = message.isSet(Flag.X_DOWNLOADED_FULL);
if (completeMessage) {
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
} else {
backendFolder.savePartialMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL);
}
listener.syncNewMessage(folder, messageServerId, false);
@ -466,7 +467,7 @@ class WebDavSync {
try {
// Store the updated message locally
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
progress.incrementAndGet();
// Increment the number of "new messages" if the newly downloaded message is
@ -582,9 +583,9 @@ class WebDavSync {
// Store the updated message locally
if (completeMessage) {
backendFolder.saveCompleteMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.FULL);
} else {
backendFolder.savePartialMessage(message);
backendFolder.saveMessage(message, MessageDownloadState.PARTIAL);
}
}

View file

@ -0,0 +1,7 @@
package com.fsck.k9.mail
enum class MessageDownloadState {
ENVELOPE,
PARTIAL,
FULL
}