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:
parent
4bfe03de35
commit
428ae60a58
17 changed files with 310 additions and 191 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue