Split Backend.fetchMessage() into two methods

The two new methods now also save the downloaded message data instead of returning a Message instance.
MessageStore.saveRemoteMessage() will now replace a message if it already exists.
This commit is contained in:
cketti 2021-04-16 22:06:57 +02:00
parent 4bfe03de35
commit 428ae60a58
17 changed files with 310 additions and 191 deletions

View file

@ -557,11 +557,6 @@ public class MessagingController {
private void loadSearchResultsSynchronous(Account account, List<String> messageServerIds, LocalFolder localFolder)
throws MessagingException {
FetchProfile fetchProfile = new FetchProfile();
fetchProfile.add(FetchProfile.Item.FLAGS);
fetchProfile.add(FetchProfile.Item.ENVELOPE);
fetchProfile.add(FetchProfile.Item.STRUCTURE);
Backend backend = getBackend(account);
String folderServerId = localFolder.getServerId();
@ -569,9 +564,7 @@ public class MessagingController {
LocalMessage localMessage = localFolder.getMessage(messageServerId);
if (localMessage == null) {
int maxDownloadSize = account.getMaximumAutoDownloadMessageSize();
Message message = backend.fetchMessage(folderServerId, messageServerId, fetchProfile, maxDownloadSize);
localFolder.appendMessages(Collections.singletonList(message));
backend.downloadMessageStructure(folderServerId, messageServerId);
}
}
}
@ -1252,12 +1245,7 @@ public class MessagingController {
SyncConfig syncConfig = createSyncConfig(account);
backend.downloadMessage(syncConfig, folderServerId, uid);
} else {
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY);
fp.add(FetchProfile.Item.FLAGS);
int maxDownloadSize = account.getMaximumAutoDownloadMessageSize();
Message remoteMessage = backend.fetchMessage(folderServerId, uid, fp, maxDownloadSize);
localFolder.appendMessages(Collections.singletonList(remoteMessage));
backend.downloadCompleteMessage(folderServerId, uid);
}
message = localFolder.getMessage(uid);

View file

@ -16,7 +16,6 @@ import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
@ -50,7 +49,6 @@ import org.robolectric.shadows.ShadowLog;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
@ -94,8 +92,6 @@ public class MessagingControllerTest extends K9RobolectricTest {
@Mock
private NotificationStrategy notificationStrategy;
@Captor
private ArgumentCaptor<FetchProfile> fetchProfileCaptor;
@Captor
private ArgumentCaptor<MessageRetrievalListener<LocalMessage>> messageRetrievalListenerCaptor;
private Context appContext;
@ -232,17 +228,10 @@ public class MessagingControllerTest extends K9RobolectricTest {
}
}
);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
hasFetchedMessage = true;
return null;
}
}).when(backend).fetchMessage(
eq(FOLDER_NAME),
eq("newMessageUid2"),
any(FetchProfile.class),
eq(MAXIMUM_SMALL_MESSAGE_SIZE));
doAnswer((Answer<Void>) invocation -> {
hasFetchedMessage = true;
return null;
}).when(backend).downloadMessageStructure(eq(FOLDER_NAME), eq("newMessageUid2"));
reqFlags = Collections.singleton(Flag.ANSWERED);
forbiddenFlags = Collections.singleton(Flag.DELETED);
@ -300,8 +289,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
controller.searchRemoteMessagesSynchronous(accountUuid, FOLDER_ID, "query", reqFlags, forbiddenFlags, listener);
verify(backend).fetchMessage(eq(FOLDER_NAME), eq("newMessageUid2"), fetchProfileCaptor.capture(),
eq(MAXIMUM_SMALL_MESSAGE_SIZE));
verify(backend).downloadMessageStructure(eq(FOLDER_NAME), eq("newMessageUid2"));
}
@Test
@ -310,8 +298,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
controller.searchRemoteMessagesSynchronous(accountUuid, FOLDER_ID, "query", reqFlags, forbiddenFlags, listener);
verify(backend, never()).fetchMessage(eq(FOLDER_NAME), eq("newMessageUid1"), fetchProfileCaptor.capture(),
eq(MAXIMUM_SMALL_MESSAGE_SIZE));
verify(backend, never()).downloadMessageStructure(eq(FOLDER_NAME), eq("newMessageUid1"));
}
@Test

View file

@ -45,6 +45,7 @@ class K9MessageStore(
override fun saveRemoteMessage(folderId: Long, messageServerId: String, messageData: SaveMessageData) {
saveMessageOperations.saveRemoteMessage(folderId, messageServerId, messageData)
localStore.notifyChange()
}
override fun moveMessage(messageId: Long, destinationFolderId: Long): Long {

View file

@ -45,6 +45,20 @@ internal class SaveMessageOperations(
lockableDatabase.execute(true) { database ->
val message = messageData.message
val existingMessageInfo = getMessage(folderId, messageServerId)
if (existingMessageInfo != null) {
val (existingMessageId, existingRootMessagePartId) = existingMessageInfo
replaceMessage(
database,
folderId,
messageServerId,
existingMessageId,
existingRootMessagePartId,
messageData
)
return@execute
}
val threadInfo = threadMessageOperations.doMessageThreading(database, folderId, message.toThreadHeaders())
val rootMessagePartId = saveMessageParts(database, message)
@ -54,7 +68,7 @@ internal class SaveMessageOperations(
messageServerId,
rootMessagePartId,
messageData,
emptyMessageId = threadInfo.messageId
replaceMessageId = threadInfo.messageId
)
if (threadInfo.threadId == null) {
@ -65,6 +79,31 @@ internal class SaveMessageOperations(
}
}
private fun replaceMessage(
database: SQLiteDatabase,
folderId: Long,
messageServerId: String,
existingMessageId: Long,
existingRootMessagePartId: Long?,
messageData: SaveMessageData
) {
if (existingRootMessagePartId != null) {
deleteMessagePartsAndDataFromDisk(database, existingRootMessagePartId)
}
val rootMessagePartId = saveMessageParts(database, messageData.message)
val messageId = saveMessage(
database,
folderId,
messageServerId,
rootMessagePartId,
messageData,
replaceMessageId = existingMessageId
)
createOrReplaceFulltextEntry(database, messageId, messageData)
}
private fun saveMessageParts(database: SQLiteDatabase, message: Message): Long {
val rootPartContainer = PartContainer(parentId = null, part = message)
val rootId = saveMessagePart(database, rootPartContainer, rootId = null, order = 0)
@ -289,7 +328,7 @@ internal class SaveMessageOperations(
messageServerId: String,
rootMessagePartId: Long,
messageData: SaveMessageData,
emptyMessageId: Long?
replaceMessageId: Long?
): Long {
val message = messageData.message
@ -332,10 +371,10 @@ internal class SaveMessageOperations(
}
}
return if (emptyMessageId != null) {
values.put("id", emptyMessageId)
return if (replaceMessageId != null) {
values.put("id", replaceMessageId)
database.replace("messages", null, values)
emptyMessageId
replaceMessageId
} else {
database.insert("messages", null, values)
}
@ -351,6 +390,54 @@ internal class SaveMessageOperations(
database.replace("messages_fulltext", null, values)
}
private fun getMessage(folderId: Long, messageServerId: String): Pair<Long, Long?>? {
return lockableDatabase.execute(false) { db ->
db.query(
"messages",
arrayOf("id", "message_part_id"),
"folder_id = ? AND uid = ?",
arrayOf(folderId.toString(), messageServerId),
null,
null,
null
).use { cursor ->
if (cursor.moveToFirst()) {
val messageId = cursor.getLong(0)
val messagePartId = cursor.getLong(1)
messageId to messagePartId
} else {
null
}
}
}
}
private fun deleteMessagePartsAndDataFromDisk(database: SQLiteDatabase, rootMessagePartId: Long) {
deleteMessageDataFromDisk(database, rootMessagePartId)
deleteMessageParts(database, rootMessagePartId)
}
private fun deleteMessageDataFromDisk(database: SQLiteDatabase, rootMessagePartId: Long) {
database.query(
"message_parts",
arrayOf("id"),
"root = ? AND data_location = " + DataLocation.ON_DISK,
arrayOf(rootMessagePartId.toString()),
null,
null,
null
).use { cursor ->
while (cursor.moveToNext()) {
val messagePartId = cursor.getLong(0)
attachmentFileManager.deleteFile(messagePartId)
}
}
}
private fun deleteMessageParts(database: SQLiteDatabase, rootMessagePartId: Long) {
database.delete("message_parts", "root = ?", arrayOf(rootMessagePartId.toString()))
}
}
private fun Set<Flag>.toDatabaseValue(): String {

View file

@ -303,6 +303,61 @@ class SaveMessageOperationsTest : RobolectricTest() {
assertThat(message3.uid).isEqualTo("uid1")
}
@Test
fun `save message with server ID already existing in MessageStore should replace that message`() {
val existingMessageData = buildMessage {
multipart("alternative") {
bodyPart("text/plain") {
textBody("plain")
}
bodyPart("text/html") {
textBody("html")
}
}
}.toSaveMessageData()
saveMessageOperations.saveRemoteMessage(folderId = 1, messageServerId = "uid1", existingMessageData)
val messageData = buildMessage {
textBody("new")
}.toSaveMessageData()
saveMessageOperations.saveRemoteMessage(folderId = 1, messageServerId = "uid1", messageData)
val messages = sqliteDatabase.readMessages()
assertThat(messages).hasSize(1)
val messageParts = sqliteDatabase.readMessageParts()
assertThat(messageParts).hasSize(1)
val messagePart = messageParts.first()
with(messagePart) {
assertThat(type).isEqualTo(MessagePartType.UNKNOWN)
assertThat(root).isEqualTo(messagePart.id)
assertThat(parent).isEqualTo(-1)
assertThat(mimeType).isEqualTo("text/plain")
assertThat(displayName).isEqualTo("noname.txt")
assertThat(header).isNotNull()
assertThat(encoding).isEqualTo("quoted-printable")
assertThat(charset).isNull()
assertThat(dataLocation).isEqualTo(DataLocation.IN_DATABASE)
assertThat(decodedBodySize).isEqualTo(3)
assertThat(data?.toString(Charsets.UTF_8)).isEqualTo("new")
assertThat(preamble).isNull()
assertThat(epilogue).isNull()
assertThat(boundary).isNull()
assertThat(contentId).isNull()
assertThat(serverExtra).isNull()
}
val threads = sqliteDatabase.readThreads()
assertThat(threads).hasSize(1)
val thread = threads.first()
val message = messages.first()
assertThat(thread.root).isEqualTo(thread.id)
assertThat(thread.parent).isNull()
assertThat(thread.messageId).isEqualTo(message.id)
}
private fun Message.toSaveMessageData(
subject: String? = getSubject(),
date: Long = sentDate?.time ?: System.currentTimeMillis(),

View file

@ -1,7 +1,6 @@
package com.fsck.k9.backend.api
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessagingException
@ -27,6 +26,12 @@ interface Backend {
@Throws(MessagingException::class)
fun downloadMessage(syncConfig: SyncConfig, folderServerId: String, messageServerId: String)
@Throws(MessagingException::class)
fun downloadMessageStructure(folderServerId: String, messageServerId: String)
@Throws(MessagingException::class)
fun downloadCompleteMessage(folderServerId: String, messageServerId: String)
@Throws(MessagingException::class)
fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean)
@ -75,14 +80,6 @@ interface Backend {
performFullTextSearch: Boolean
): List<String>
@Throws(MessagingException::class)
fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message
@Throws(MessagingException::class)
fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory)

View file

@ -0,0 +1,53 @@
package com.fsck.k9.backend.imap
import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.mail.FetchProfile
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.helper.fetchProfileOf
import com.fsck.k9.mail.store.imap.ImapFolder
import com.fsck.k9.mail.store.imap.ImapMessage
import com.fsck.k9.mail.store.imap.ImapStore
internal class CommandDownloadMessage(private val backendStorage: BackendStorage, private val imapStore: ImapStore) {
fun downloadMessageStructure(folderServerId: String, messageServerId: String) {
val folder = imapStore.getFolder(folderServerId)
try {
folder.open(ImapFolder.OPEN_MODE_RO)
val message = folder.getMessage(messageServerId)
// fun fact: ImapFolder.fetch can't handle getting STRUCTURE at same time as headers
fetchMessage(folder, message, fetchProfileOf(FLAGS, ENVELOPE))
fetchMessage(folder, message, fetchProfileOf(STRUCTURE))
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.savePartialMessage(message)
} finally {
folder.close()
}
}
fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
val folder = imapStore.getFolder(folderServerId)
try {
folder.open(ImapFolder.OPEN_MODE_RO)
val message = folder.getMessage(messageServerId)
fetchMessage(folder, message, fetchProfileOf(FLAGS, BODY))
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
} finally {
folder.close()
}
}
private fun fetchMessage(remoteFolder: ImapFolder, message: ImapMessage, fetchProfile: FetchProfile) {
val maxDownloadSize = 0
remoteFolder.fetch(listOf(message), fetchProfile, null, maxDownloadSize)
}
}

View file

@ -1,46 +1,12 @@
package com.fsck.k9.backend.imap
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Part
import com.fsck.k9.mail.store.imap.ImapFolder
import com.fsck.k9.mail.store.imap.ImapMessage
import com.fsck.k9.mail.store.imap.ImapStore
internal class CommandFetchMessage(private val imapStore: ImapStore) {
fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
val folder = imapStore.getFolder(folderServerId)
try {
folder.open(ImapFolder.OPEN_MODE_RO)
val message = folder.getMessage(messageServerId)
// fun fact: ImapFolder.fetch can't handle getting STRUCTURE at same time as headers
if (fetchProfile.contains(FetchProfile.Item.STRUCTURE) &&
fetchProfile.contains(FetchProfile.Item.ENVELOPE)
) {
val headerFetchProfile = fetchProfile.without(FetchProfile.Item.STRUCTURE)
val structureFetchProfile = FetchProfile().apply { add(FetchProfile.Item.STRUCTURE) }
fetchMessage(folder, message, headerFetchProfile, maxDownloadSize)
fetchMessage(folder, message, structureFetchProfile, maxDownloadSize)
} else {
fetchMessage(folder, message, fetchProfile, maxDownloadSize)
}
return message
} finally {
folder.close()
}
}
fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory) {
val folder = imapStore.getFolder(folderServerId)
try {
@ -52,19 +18,4 @@ internal class CommandFetchMessage(private val imapStore: ImapStore) {
folder.close()
}
}
private fun fetchMessage(
remoteFolder: ImapFolder,
message: ImapMessage,
fetchProfile: FetchProfile,
maxDownloadSize: Int
) {
remoteFolder.fetch(listOf(message), fetchProfile, null, maxDownloadSize)
}
private fun FetchProfile.without(item: FetchProfile.Item) = FetchProfile().apply {
this@without.forEach {
if (it != item) add(it)
}
}
}

View file

@ -5,7 +5,6 @@ import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.backend.api.SyncConfig
import com.fsck.k9.backend.api.SyncListener
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Part
@ -28,6 +27,7 @@ class ImapBackend(
private val commandMoveOrCopyMessages = CommandMoveOrCopyMessages(imapStore)
private val commandDeleteAll = CommandDeleteAll(imapStore)
private val commandSearch = CommandSearch(imapStore)
private val commandDownloadMessage = CommandDownloadMessage(backendStorage, imapStore)
private val commandFetchMessage = CommandFetchMessage(imapStore)
private val commandFindByMessageId = CommandFindByMessageId(imapStore)
private val commandUploadMessage = CommandUploadMessage(imapStore)
@ -54,6 +54,14 @@ class ImapBackend(
imapSync.downloadMessage(syncConfig, folderServerId, messageServerId)
}
override fun downloadMessageStructure(folderServerId: String, messageServerId: String) {
commandDownloadMessage.downloadMessageStructure(folderServerId, messageServerId)
}
override fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
commandDownloadMessage.downloadCompleteMessage(folderServerId, messageServerId)
}
override fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean) {
commandSetFlag.setFlag(folderServerId, messageServerIds, flag, newState)
}
@ -120,15 +128,6 @@ class ImapBackend(
return commandSearch.search(folderServerId, query, requiredFlags, forbiddenFlags, performFullTextSearch)
}
override fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile, maxDownloadSize)
}
override fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory) {
commandFetchMessage.fetchPart(folderServerId, messageServerId, part, bodyFactory)
}

View file

@ -5,7 +5,6 @@ import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.backend.api.SyncConfig
import com.fsck.k9.backend.api.SyncListener
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Part
@ -52,6 +51,14 @@ class JmapBackend(
throw UnsupportedOperationException("not implemented")
}
override fun downloadMessageStructure(folderServerId: String, messageServerId: String) {
throw UnsupportedOperationException("not implemented")
}
override fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
throw UnsupportedOperationException("not implemented")
}
override fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean) {
commandSetFlag.setFlag(messageServerIds, flag, newState)
}
@ -109,15 +116,6 @@ class JmapBackend(
throw UnsupportedOperationException("not implemented")
}
override fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
throw UnsupportedOperationException("not implemented")
}
override fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory) {
throw UnsupportedOperationException("not implemented")
}

View file

@ -0,0 +1,25 @@
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.helper.fetchProfileOf
import com.fsck.k9.mail.store.pop3.Pop3Store
internal class CommandDownloadMessage(private val backendStorage: BackendStorage, private val pop3Store: Pop3Store) {
fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
val folder = pop3Store.getFolder(folderServerId)
try {
folder.open()
val message = folder.getMessage(messageServerId)
folder.fetch(listOf(message), fetchProfileOf(FLAGS, BODY), null, 0)
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
} finally {
folder.close()
}
}
}

View file

@ -1,27 +0,0 @@
package com.fsck.k9.backend.pop3
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.store.pop3.Pop3Store
internal class CommandFetchMessage(private val pop3Store: Pop3Store) {
fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
val folder = pop3Store.getFolder(folderServerId)
try {
folder.open()
val message = folder.getMessage(messageServerId)
folder.fetch(listOf(message), fetchProfile, null, maxDownloadSize)
return message
} finally {
folder.close()
}
}
}

View file

@ -5,7 +5,6 @@ import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.backend.api.SyncConfig
import com.fsck.k9.backend.api.SyncListener
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Part
@ -21,7 +20,7 @@ class Pop3Backend(
private val pop3Sync: Pop3Sync = Pop3Sync(accountName, backendStorage, pop3Store)
private val commandRefreshFolderList = CommandRefreshFolderList(backendStorage)
private val commandSetFlag = CommandSetFlag(pop3Store)
private val commandFetchMessage = CommandFetchMessage(pop3Store)
private val commandDownloadMessage = CommandDownloadMessage(backendStorage, pop3Store)
override val supportsFlags = false
override val supportsExpunge = false
@ -45,6 +44,14 @@ class Pop3Backend(
throw UnsupportedOperationException("not implemented")
}
override fun downloadMessageStructure(folderServerId: String, messageServerId: String) {
throw UnsupportedOperationException("not implemented")
}
override fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
commandDownloadMessage.downloadCompleteMessage(folderServerId, messageServerId)
}
override fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean) {
commandSetFlag.setFlag(folderServerId, messageServerIds, flag, newState)
}
@ -103,15 +110,6 @@ class Pop3Backend(
throw UnsupportedOperationException("not supported")
}
override fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile, maxDownloadSize)
}
override fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory) {
throw UnsupportedOperationException("not supported")
}

View file

@ -0,0 +1,24 @@
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.helper.fetchProfileOf
import com.fsck.k9.mail.store.webdav.WebDavStore
internal class CommandDownloadMessage(val backendStorage: BackendStorage, private val webDavStore: WebDavStore) {
fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
val folder = webDavStore.getFolder(folderServerId)
try {
val message = folder.getMessage(messageServerId)
folder.fetch(listOf(message), fetchProfileOf(FLAGS, BODY), null, 0)
val backendFolder = backendStorage.getFolder(folderServerId)
backendFolder.saveCompleteMessage(message)
} finally {
folder.close()
}
}
}

View file

@ -1,26 +0,0 @@
package com.fsck.k9.backend.webdav
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.store.webdav.WebDavStore
internal class CommandFetchMessage(private val webDavStore: WebDavStore) {
fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
val folder = webDavStore.getFolder(folderServerId)
try {
val message = folder.getMessage(messageServerId)
folder.fetch(listOf(message), fetchProfile, null, maxDownloadSize)
return message
} finally {
folder.close()
}
}
}

View file

@ -5,7 +5,6 @@ import com.fsck.k9.backend.api.BackendStorage
import com.fsck.k9.backend.api.SyncConfig
import com.fsck.k9.backend.api.SyncListener
import com.fsck.k9.mail.BodyFactory
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.Flag
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.MessagingException
@ -24,7 +23,7 @@ class WebDavBackend(
private val commandGetFolders = CommandRefreshFolderList(backendStorage, webDavStore)
private val commandSetFlag = CommandSetFlag(webDavStore)
private val commandMoveOrCopyMessages = CommandMoveOrCopyMessages(webDavStore)
private val commandFetchMessage = CommandFetchMessage(webDavStore)
private val commandDownloadMessage = CommandDownloadMessage(backendStorage, webDavStore)
private val commandUploadMessage = CommandUploadMessage(webDavStore)
override val supportsFlags = true
@ -49,6 +48,14 @@ class WebDavBackend(
throw UnsupportedOperationException("not implemented")
}
override fun downloadMessageStructure(folderServerId: String, messageServerId: String) {
throw UnsupportedOperationException("not implemented")
}
override fun downloadCompleteMessage(folderServerId: String, messageServerId: String) {
commandDownloadMessage.downloadCompleteMessage(folderServerId, messageServerId)
}
@Throws(MessagingException::class)
override fun setFlag(folderServerId: String, messageServerIds: List<String>, flag: Flag, newState: Boolean) {
commandSetFlag.setFlag(folderServerId, messageServerIds, flag, newState)
@ -113,15 +120,6 @@ class WebDavBackend(
throw UnsupportedOperationException("not supported")
}
override fun fetchMessage(
folderServerId: String,
messageServerId: String,
fetchProfile: FetchProfile,
maxDownloadSize: Int
): Message {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile, maxDownloadSize)
}
override fun fetchPart(folderServerId: String, messageServerId: String, part: Part, bodyFactory: BodyFactory) {
throw UnsupportedOperationException("not supported")
}

View file

@ -0,0 +1,11 @@
package com.fsck.k9.mail.helper
import com.fsck.k9.mail.FetchProfile
fun fetchProfileOf(vararg items: FetchProfile.Item): FetchProfile {
return FetchProfile().apply {
for (item in items) {
add(item)
}
}
}