From c49e11a8dde73eae581578dc383170795fcc4880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:07:55 +0100 Subject: [PATCH 1/8] Rename .java to .kt --- .../k9/backend/pop3/{CommandSetFlag.java => CommandSetFlag.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/pop3/src/main/java/com/fsck/k9/backend/pop3/{CommandSetFlag.java => CommandSetFlag.kt} (100%) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.java b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt similarity index 100% rename from backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.java rename to backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt From ee0b55ce046853c98d1a45e1adedb8c57a995dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:07:55 +0100 Subject: [PATCH 2/8] Change CommandSetFlag to Kotlin --- .../fsck/k9/backend/pop3/CommandSetFlag.kt | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt index 8d0f06b668d..68fab8b96f5 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt @@ -1,47 +1,41 @@ -package com.fsck.k9.backend.pop3; +package com.fsck.k9.backend.pop3 +import com.fsck.k9.mail.Flag +import com.fsck.k9.mail.MessagingException +import com.fsck.k9.mail.store.pop3.Pop3Message +import com.fsck.k9.mail.store.pop3.Pop3Store +import java.util.ArrayList -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +internal class CommandSetFlag(pop3Store: Pop3Store) { + private val pop3Store: Pop3Store -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.store.pop3.Pop3Folder; -import com.fsck.k9.mail.store.pop3.Pop3Message; -import com.fsck.k9.mail.store.pop3.Pop3Store; -import org.jetbrains.annotations.NotNull; - - -class CommandSetFlag { - private final Pop3Store pop3Store; - - - CommandSetFlag(Pop3Store pop3Store) { - this.pop3Store = pop3Store; + init { + this.pop3Store = pop3Store } - void setFlag(@NotNull String folderServerId, @NotNull List messageServerIds, @NotNull Flag flag, - boolean newState) throws MessagingException { - - Pop3Folder remoteFolder = pop3Store.getFolder(folderServerId); + @Throws(MessagingException::class) + fun setFlag( + folderServerId: String, messageServerIds: MutableList, flag: Flag, + newState: Boolean + ) { + val remoteFolder = pop3Store.getFolder(folderServerId) if (!remoteFolder.isFlagSupported(flag)) { - return; + return } try { - remoteFolder.open(); - List messages = new ArrayList<>(); - for (String uid : messageServerIds) { - messages.add(remoteFolder.getMessage(uid)); + remoteFolder.open() + val messages: MutableList = ArrayList() + for (uid in messageServerIds) { + messages.add(remoteFolder.getMessage(uid)) } if (messages.isEmpty()) { - return; + return } - remoteFolder.setFlags(messages, Collections.singleton(flag), newState); + remoteFolder.setFlags(messages, mutableSetOf(flag), newState) } finally { - remoteFolder.close(); + remoteFolder.close() } } } From df27b09262573bc67c859333681ba3018e56519a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:10:59 +0100 Subject: [PATCH 3/8] Refactor CommandSetFlag --- .../fsck/k9/backend/pop3/CommandSetFlag.kt | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt index 68fab8b96f5..daf236ad822 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/CommandSetFlag.kt @@ -2,40 +2,33 @@ package com.fsck.k9.backend.pop3 import com.fsck.k9.mail.Flag import com.fsck.k9.mail.MessagingException -import com.fsck.k9.mail.store.pop3.Pop3Message import com.fsck.k9.mail.store.pop3.Pop3Store -import java.util.ArrayList -internal class CommandSetFlag(pop3Store: Pop3Store) { - private val pop3Store: Pop3Store - - init { - this.pop3Store = pop3Store - } +internal class CommandSetFlag(private val pop3Store: Pop3Store) { @Throws(MessagingException::class) fun setFlag( - folderServerId: String, messageServerIds: MutableList, flag: Flag, - newState: Boolean + folderServerId: String, + messageServerIds: List, + flag: Flag, + newState: Boolean, ) { - val remoteFolder = pop3Store.getFolder(folderServerId) - if (!remoteFolder.isFlagSupported(flag)) { + val folder = pop3Store.getFolder(folderServerId) + if (!folder.isFlagSupported(flag)) { return } try { - remoteFolder.open() - val messages: MutableList = ArrayList() - for (uid in messageServerIds) { - messages.add(remoteFolder.getMessage(uid)) - } + folder.open() + val messages = messageServerIds.map { folder.getMessage(it) } if (messages.isEmpty()) { return } - remoteFolder.setFlags(messages, mutableSetOf(flag), newState) + + folder.setFlags(messages, setOf(flag), newState) } finally { - remoteFolder.close() + folder.close() } } } From 0672ea58d73bb187e977bebaa7ad9382171923b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:22:40 +0100 Subject: [PATCH 4/8] Change Pop3Folder.getMessage to NotNull --- .../src/main/java/com/fsck/k9/mail/store/pop3/Pop3Folder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mail/protocols/pop3/src/main/java/com/fsck/k9/mail/store/pop3/Pop3Folder.java b/mail/protocols/pop3/src/main/java/com/fsck/k9/mail/store/pop3/Pop3Folder.java index 5570da63767..78c24b4b15d 100644 --- a/mail/protocols/pop3/src/main/java/com/fsck/k9/mail/store/pop3/Pop3Folder.java +++ b/mail/protocols/pop3/src/main/java/com/fsck/k9/mail/store/pop3/Pop3Folder.java @@ -16,6 +16,7 @@ import com.fsck.k9.mail.K9MailLib; import com.fsck.k9.mail.MessageRetrievalListener; import com.fsck.k9.mail.MessagingException; +import org.jetbrains.annotations.NotNull; import static com.fsck.k9.mail.K9MailLib.DEBUG_PROTOCOL_POP3; import static com.fsck.k9.mail.store.pop3.Pop3Commands.*; @@ -101,6 +102,7 @@ public int getMessageCount() { return messageCount; } + @NotNull public Pop3Message getMessage(String uid) { Pop3Message message = uidToMsgMap.get(uid); if (message == null) { From 01d41d90d5dcba9a20cfd17b6fe1b22817f6148c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:35:52 +0100 Subject: [PATCH 5/8] Rename .java to .kt --- .../java/com/fsck/k9/backend/pop3/{Pop3Sync.java => Pop3Sync.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/pop3/src/main/java/com/fsck/k9/backend/pop3/{Pop3Sync.java => Pop3Sync.kt} (100%) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.java b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt similarity index 100% rename from backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.java rename to backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt From 6f25e0e7eda78b4258b1ead93acd41527b13d3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:35:53 +0100 Subject: [PATCH 6/8] Change Pop3Sync to Kotlin --- .../java/com/fsck/k9/backend/pop3/Pop3Sync.kt | 730 +++++++++--------- 1 file changed, 384 insertions(+), 346 deletions(-) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt index 8eae32f22b3..1d3f0288cc9 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt @@ -1,74 +1,64 @@ -package com.fsck.k9.backend.pop3; - - -import com.fsck.k9.backend.api.BackendFolder; -import com.fsck.k9.backend.api.BackendFolder.MoreMessages; -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.helper.ExceptionHelper; -import com.fsck.k9.logging.Timber; -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; -import com.fsck.k9.mail.store.pop3.Pop3Message; -import com.fsck.k9.mail.store.pop3.Pop3Store; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - - -class Pop3Sync { - private static final String EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME = "latestOldMessageSeenTime"; - - private final String accountName; - private final BackendStorage backendStorage; - private final Pop3Store remoteStore; - - - Pop3Sync(String accountName, BackendStorage backendStorage, Pop3Store pop3Store) { - this.accountName = accountName; - this.backendStorage = backendStorage; - this.remoteStore = pop3Store; +package com.fsck.k9.backend.pop3 + +import com.fsck.k9.backend.api.BackendFolder +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.helper.ExceptionHelper +import com.fsck.k9.logging.Timber +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 +import com.fsck.k9.mail.store.pop3.Pop3Message +import com.fsck.k9.mail.store.pop3.Pop3Store +import java.lang.Exception +import java.util.ArrayList +import java.util.Date +import java.util.HashMap +import java.util.concurrent.atomic.AtomicInteger +import kotlin.math.max + +internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop3Store: Pop3Store) { + private val accountName: String + private val backendStorage: BackendStorage + private val remoteStore: Pop3Store + + init { + this.accountName = accountName + this.backendStorage = backendStorage + this.remoteStore = pop3Store } - void sync(String folder, SyncConfig syncConfig, SyncListener listener) { - synchronizeMailboxSynchronous(folder, syncConfig, listener); + fun sync(folder: String, syncConfig: SyncConfig, listener: SyncListener) { + synchronizeMailboxSynchronous(folder, syncConfig, listener) } - void synchronizeMailboxSynchronous(String folder, SyncConfig syncConfig, SyncListener listener) { - Pop3Folder remoteFolder = null; + fun synchronizeMailboxSynchronous(folder: String, syncConfig: SyncConfig, listener: SyncListener) { + var remoteFolder: Pop3Folder? = null - Timber.i("Synchronizing folder %s:%s", accountName, folder); + Timber.i("Synchronizing folder %s:%s", accountName, folder) - BackendFolder backendFolder = null; + var backendFolder: BackendFolder? = null try { - Timber.d("SYNC: About to process pending commands for account %s", accountName); + Timber.d("SYNC: About to process pending commands for account %s", accountName) - Timber.v("SYNC: About to get local folder %s", folder); - backendFolder = backendStorage.getFolder(folder); + Timber.v("SYNC: About to get local folder %s", folder) + backendFolder = backendStorage.getFolder(folder) - listener.syncStarted(folder); + listener.syncStarted(folder) /* * Get the message list from the local store and create an index of * the uids within the list. */ + var localUidMap: Map? = backendFolder.getAllMessagesAndEffectiveDates() - Map localUidMap = backendFolder.getAllMessagesAndEffectiveDates(); - - Timber.v("SYNC: About to get remote folder %s", folder); - remoteFolder = remoteStore.getFolder(folder); + Timber.v("SYNC: About to get remote folder %s", folder) + remoteFolder = remoteStore.getFolder(folder) /* * Synchronization process: @@ -91,481 +81,524 @@ class Pop3Sync { /* * Open the remote folder. This pre-loads certain metadata like message count. */ - Timber.v("SYNC: About to open remote folder %s", folder); + Timber.v("SYNC: About to open remote folder %s", folder) - remoteFolder.open(); + remoteFolder.open() - listener.syncAuthenticationSuccess(); + listener.syncAuthenticationSuccess() /* * Get the remote message count. */ - int remoteMessageCount = remoteFolder.getMessageCount(); + val remoteMessageCount = remoteFolder.getMessageCount() - int visibleLimit = backendFolder.getVisibleLimit(); + var visibleLimit = backendFolder.visibleLimit if (visibleLimit < 0) { - visibleLimit = syncConfig.getDefaultVisibleLimit(); + visibleLimit = syncConfig.defaultVisibleLimit } - final List remoteMessages = new ArrayList<>(); - Map remoteUidMap = new HashMap<>(); - - Timber.v("SYNC: Remote message count for folder %s is %d", folder, remoteMessageCount); + val remoteMessages: MutableList = ArrayList() + val remoteUidMap: MutableMap = HashMap() - final Date earliestDate = syncConfig.getEarliestPollDate(); - long earliestTimestamp = earliestDate != null ? earliestDate.getTime() : 0L; + Timber.v("SYNC: Remote message count for folder %s is %d", folder, remoteMessageCount) + val earliestDate = syncConfig.earliestPollDate + val earliestTimestamp = if (earliestDate != null) earliestDate.getTime() else 0L - int remoteStart = 1; + var remoteStart = 1 if (remoteMessageCount > 0) { /* Message numbers start at 1. */ if (visibleLimit > 0) { - remoteStart = Math.max(0, remoteMessageCount - visibleLimit) + 1; + remoteStart = max(0, remoteMessageCount - visibleLimit) + 1 } else { - remoteStart = 1; + remoteStart = 1 } - Timber.v("SYNC: About to get messages %d through %d for folder %s", - remoteStart, remoteMessageCount, folder); - - final AtomicInteger headerProgress = new AtomicInteger(0); - listener.syncHeadersStarted(folder); + Timber.v( + "SYNC: About to get messages %d through %d for folder %s", + remoteStart, remoteMessageCount, folder + ) + val headerProgress = AtomicInteger(0) + listener.syncHeadersStarted(folder) - List remoteMessageArray = - remoteFolder.getMessages(remoteStart, remoteMessageCount, null); + val remoteMessageArray = + remoteFolder.getMessages(remoteStart, remoteMessageCount, null) - int messageCount = remoteMessageArray.size(); + val messageCount = remoteMessageArray.size - for (Pop3Message thisMess : remoteMessageArray) { - headerProgress.incrementAndGet(); - listener.syncHeadersProgress(folder, headerProgress.get(), messageCount); + for (thisMess in remoteMessageArray) { + headerProgress.incrementAndGet() + listener.syncHeadersProgress(folder, headerProgress.get(), messageCount) - Long localMessageTimestamp = localUidMap.get(thisMess.getUid()); + val localMessageTimestamp = localUidMap!!.get(thisMess.getUid()) if (localMessageTimestamp == null || localMessageTimestamp >= earliestTimestamp) { - remoteMessages.add(thisMess); - remoteUidMap.put(thisMess.getUid(), thisMess); + remoteMessages.add(thisMess) + remoteUidMap.put(thisMess.getUid(), thisMess) } } - Timber.v("SYNC: Got %d messages for folder %s", remoteUidMap.size(), folder); + Timber.v("SYNC: Got %d messages for folder %s", remoteUidMap.size, folder) - listener.syncHeadersFinished(folder, headerProgress.get(), remoteUidMap.size()); + listener.syncHeadersFinished(folder, headerProgress.get(), remoteUidMap.size) } else if (remoteMessageCount < 0) { - throw new Exception("Message count " + remoteMessageCount + " for folder " + folder); + throw Exception("Message count " + remoteMessageCount + " for folder " + folder) } /* * Remove any messages that are in the local store but no longer on the remote store or are too old */ - MoreMessages moreMessages = backendFolder.getMoreMessages(); - if (syncConfig.getSyncRemoteDeletions()) { - List destroyMessageUids = new ArrayList<>(); - for (String localMessageUid : localUidMap.keySet()) { + var moreMessages = backendFolder.getMoreMessages() + if (syncConfig.syncRemoteDeletions) { + val destroyMessageUids: MutableList = ArrayList() + for (localMessageUid in localUidMap!!.keys) { if (remoteUidMap.get(localMessageUid) == null) { - destroyMessageUids.add(localMessageUid); + destroyMessageUids.add(localMessageUid!!) } } if (!destroyMessageUids.isEmpty()) { - moreMessages = MoreMessages.UNKNOWN; + moreMessages = BackendFolder.MoreMessages.UNKNOWN - backendFolder.destroyMessages(destroyMessageUids); - for (String uid : destroyMessageUids) { - listener.syncRemovedMessage(folder, uid); + backendFolder.destroyMessages(destroyMessageUids) + for (uid in destroyMessageUids) { + listener.syncRemovedMessage(folder, uid) } } - } // noinspection UnusedAssignment, free memory early? (better break up the method!) - localUidMap = null; + localUidMap = null - if (moreMessages == MoreMessages.UNKNOWN) { - updateMoreMessages(remoteFolder, backendFolder, remoteStart); + if (moreMessages == BackendFolder.MoreMessages.UNKNOWN) { + updateMoreMessages(remoteFolder, backendFolder, remoteStart) } /* * Now we download the actual content of messages. */ - int newMessages = downloadMessages(syncConfig, remoteFolder, backendFolder, remoteMessages, - listener); + val newMessages = downloadMessages( + syncConfig, remoteFolder, backendFolder, remoteMessages, + listener + ) - listener.folderStatusChanged(folder); + listener.folderStatusChanged(folder) /* Notify listeners that we're finally done. */ - - backendFolder.setLastChecked(System.currentTimeMillis()); - backendFolder.setStatus(null); - - Timber.d("Done synchronizing folder %s:%s @ %tc with %d new messages", - accountName, - folder, - System.currentTimeMillis(), - newMessages); - - listener.syncFinished(folder); - - Timber.i("Done synchronizing folder %s:%s", accountName, folder); - - } catch (AuthenticationFailedException e) { - listener.syncFailed(folder, "Authentication failure", e); - } catch (Exception e) { - Timber.e(e, "synchronizeMailbox"); + backendFolder.setLastChecked(System.currentTimeMillis()) + backendFolder.setStatus(null) + + Timber.d( + "Done synchronizing folder %s:%s @ %tc with %d new messages", + accountName, + folder, + System.currentTimeMillis(), + newMessages + ) + + listener.syncFinished(folder) + + Timber.i("Done synchronizing folder %s:%s", accountName, folder) + } catch (e: AuthenticationFailedException) { + listener.syncFailed(folder, "Authentication failure", e) + } catch (e: Exception) { + Timber.e(e, "synchronizeMailbox") // If we don't set the last checked, it can try too often during // failure conditions - String rootMessage = ExceptionHelper.getRootCauseMessage(e); + val rootMessage = ExceptionHelper.getRootCauseMessage(e) if (backendFolder != null) { try { - backendFolder.setStatus(rootMessage); - backendFolder.setLastChecked(System.currentTimeMillis()); - } catch (Exception e1) { - Timber.e(e1, "Could not set last checked on folder %s:%s", accountName, folder); + backendFolder.setStatus(rootMessage) + backendFolder.setLastChecked(System.currentTimeMillis()) + } catch (e1: Exception) { + Timber.e(e1, "Could not set last checked on folder %s:%s", accountName, folder) } } - listener.syncFailed(folder, rootMessage, e); - - Timber.e("Failed synchronizing folder %s:%s @ %tc", accountName, folder, - System.currentTimeMillis()); + listener.syncFailed(folder, rootMessage, e) + Timber.e( + "Failed synchronizing folder %s:%s @ %tc", + accountName, + folder, + System.currentTimeMillis(), + ) } finally { if (remoteFolder != null) { - remoteFolder.close(); + remoteFolder.close() } } } - private void updateMoreMessages(Pop3Folder remoteFolder, BackendFolder backendFolder, - int remoteStart) { - + private fun updateMoreMessages( + remoteFolder: Pop3Folder, backendFolder: BackendFolder, + remoteStart: Int + ) { if (remoteStart == 1) { - backendFolder.setMoreMessages(MoreMessages.FALSE); + backendFolder.setMoreMessages(BackendFolder.MoreMessages.FALSE) } else { - boolean moreMessagesAvailable = remoteFolder.areMoreMessagesAvailable(remoteStart); + val moreMessagesAvailable = remoteFolder.areMoreMessagesAvailable(remoteStart) - MoreMessages newMoreMessages = (moreMessagesAvailable) ? MoreMessages.TRUE : MoreMessages.FALSE; - backendFolder.setMoreMessages(newMoreMessages); + val newMoreMessages = + if ((moreMessagesAvailable)) BackendFolder.MoreMessages.TRUE else BackendFolder.MoreMessages.FALSE + backendFolder.setMoreMessages(newMoreMessages) } } - private int downloadMessages(final SyncConfig syncConfig, final Pop3Folder remoteFolder, - final BackendFolder backendFolder, List inputMessages, - final SyncListener listener) throws MessagingException { - - final Date earliestDate = syncConfig.getEarliestPollDate(); - Date downloadStarted = new Date(); // now + @Throws(MessagingException::class) + private fun downloadMessages( + syncConfig: SyncConfig, remoteFolder: Pop3Folder, + backendFolder: BackendFolder, inputMessages: MutableList, + listener: SyncListener + ): Int { + val earliestDate = syncConfig.earliestPollDate + val downloadStarted = Date() // now if (earliestDate != null) { - Timber.d("Only syncing messages after %s", earliestDate); + Timber.d("Only syncing messages after %s", earliestDate) } - final String folder = remoteFolder.getServerId(); + val folder = remoteFolder.getServerId() - List syncFlagMessages = new ArrayList<>(); - List unsyncedMessages = new ArrayList<>(); - final AtomicInteger newMessages = new AtomicInteger(0); + val syncFlagMessages: MutableList = ArrayList() + var unsyncedMessages: MutableList = ArrayList() + val newMessages = AtomicInteger(0) - List messages = new ArrayList<>(inputMessages); + val messages: MutableList = ArrayList(inputMessages) - for (Pop3Message message : messages) { - evaluateMessageForDownload(message, folder, backendFolder, unsyncedMessages, syncFlagMessages, listener); + for (message in messages) { + evaluateMessageForDownload(message, folder, backendFolder, unsyncedMessages, syncFlagMessages, listener) } - final AtomicInteger progress = new AtomicInteger(0); - final int todo = unsyncedMessages.size() + syncFlagMessages.size(); - listener.syncProgress(folder, progress.get(), todo); + val progress = AtomicInteger(0) + val todo = unsyncedMessages.size + syncFlagMessages.size + listener.syncProgress(folder, progress.get(), todo) - Timber.d("SYNC: Have %d unsynced messages", unsyncedMessages.size()); + Timber.d("SYNC: Have %d unsynced messages", unsyncedMessages.size) - messages.clear(); - final List largeMessages = new ArrayList<>(); - final List smallMessages = new ArrayList<>(); + messages.clear() + val largeMessages: MutableList = ArrayList() + val smallMessages: MutableList = ArrayList() if (!unsyncedMessages.isEmpty()) { - int visibleLimit = backendFolder.getVisibleLimit(); - int listSize = unsyncedMessages.size(); + val visibleLimit = backendFolder.visibleLimit + val listSize = unsyncedMessages.size if ((visibleLimit > 0) && (listSize > visibleLimit)) { - unsyncedMessages = unsyncedMessages.subList(0, visibleLimit); + unsyncedMessages = unsyncedMessages.subList(0, visibleLimit) } - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.ENVELOPE); + val fp = FetchProfile() + fp.add(FetchProfile.Item.ENVELOPE) - Timber.d("SYNC: About to fetch %d unsynced messages for folder %s", unsyncedMessages.size(), folder); + Timber.d("SYNC: About to fetch %d unsynced messages for folder %s", unsyncedMessages.size, folder) - fetchUnsyncedMessages(syncConfig, remoteFolder, unsyncedMessages, smallMessages, largeMessages, progress, - todo, fp, listener); + fetchUnsyncedMessages( + syncConfig, remoteFolder, unsyncedMessages, smallMessages, largeMessages, progress, + todo, fp, listener + ) - Timber.d("SYNC: Synced unsynced messages for folder %s", folder); + Timber.d("SYNC: Synced unsynced messages for folder %s", folder) } - Timber.d("SYNC: Have %d large messages and %d small messages out of %d unsynced messages", - largeMessages.size(), smallMessages.size(), unsyncedMessages.size()); + Timber.d( + "SYNC: Have %d large messages and %d small messages out of %d unsynced messages", + largeMessages.size, smallMessages.size, unsyncedMessages.size + ) - unsyncedMessages.clear(); + unsyncedMessages.clear() /* * Grab the content of the small messages first. This is going to * be very fast and at very worst will be a single up of a few bytes and a single * download of 625k. */ - FetchProfile fp = new FetchProfile(); + var fp = FetchProfile() //TODO: Only fetch small and large messages if we have some - fp.add(FetchProfile.Item.BODY); + fp.add(FetchProfile.Item.BODY) // fp.add(FetchProfile.Item.FLAGS); // fp.add(FetchProfile.Item.ENVELOPE); - downloadSmallMessages(remoteFolder, backendFolder, smallMessages, progress, newMessages, todo, fp, listener); - smallMessages.clear(); + downloadSmallMessages(remoteFolder, backendFolder, smallMessages, progress, newMessages, todo, fp, listener) + smallMessages.clear() /* * Now do the large messages that require more round trips. */ - fp = new FetchProfile(); - fp.add(FetchProfile.Item.STRUCTURE); - downloadLargeMessages(syncConfig, remoteFolder, backendFolder, largeMessages, progress, newMessages, todo, fp, listener); - largeMessages.clear(); - - Timber.d("SYNC: Synced remote messages for folder %s, %d new messages", folder, newMessages.get()); + fp = FetchProfile() + fp.add(FetchProfile.Item.STRUCTURE) + downloadLargeMessages( + syncConfig, + remoteFolder, + backendFolder, + largeMessages, + progress, + newMessages, + todo, + fp, + listener + ) + largeMessages.clear() + + Timber.d("SYNC: Synced remote messages for folder %s, %d new messages", folder, newMessages.get()) // If the oldest message seen on this sync is newer than the oldest message seen on the previous sync, then // we want to move our high-water mark forward. - Date oldestMessageTime = backendFolder.getOldestMessageDate(); + val oldestMessageTime = backendFolder.getOldestMessageDate() if (oldestMessageTime != null) { if (oldestMessageTime.before(downloadStarted) && - oldestMessageTime.after(getLatestOldMessageSeenTime(backendFolder))) { - setLatestOldMessageSeenTime(backendFolder, oldestMessageTime); + oldestMessageTime.after(getLatestOldMessageSeenTime(backendFolder)) + ) { + setLatestOldMessageSeenTime(backendFolder, oldestMessageTime) } } - return newMessages.get(); + return newMessages.get() } - private Date getLatestOldMessageSeenTime(BackendFolder backendFolder) { - Long latestOldMessageSeenTime = backendFolder.getFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME); - long timestamp = latestOldMessageSeenTime != null ? latestOldMessageSeenTime : 0L; - return new Date(timestamp); + private fun getLatestOldMessageSeenTime(backendFolder: BackendFolder): Date { + val latestOldMessageSeenTime = backendFolder.getFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME) + val timestamp = if (latestOldMessageSeenTime != null) latestOldMessageSeenTime else 0L + return Date(timestamp) } - private void setLatestOldMessageSeenTime(BackendFolder backendFolder, Date oldestMessageTime) { - backendFolder.setFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME, oldestMessageTime.getTime()); + private fun setLatestOldMessageSeenTime(backendFolder: BackendFolder, oldestMessageTime: Date) { + backendFolder.setFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME, oldestMessageTime.getTime()) } - private void evaluateMessageForDownload( - final Pop3Message message, - final String folder, - final BackendFolder backendFolder, - final List unsyncedMessages, - final List syncFlagMessages, - SyncListener listener) { - - String messageServerId = message.getUid(); + private fun evaluateMessageForDownload( + message: Pop3Message, + folder: String, + backendFolder: BackendFolder, + unsyncedMessages: MutableList, + syncFlagMessages: MutableList, + listener: SyncListener + ) { + val messageServerId = message.getUid() if (message.isSet(Flag.DELETED)) { - Timber.v("Message with uid %s is marked as deleted", messageServerId); + Timber.v("Message with uid %s is marked as deleted", messageServerId) - syncFlagMessages.add(message); - return; + syncFlagMessages.add(message) + return } - boolean messagePresentLocally = backendFolder.isMessagePresent(messageServerId); + val messagePresentLocally = backendFolder.isMessagePresent(messageServerId) if (!messagePresentLocally) { if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL)) { - Timber.v("Message with uid %s has not yet been downloaded", messageServerId); + Timber.v("Message with uid %s has not yet been downloaded", messageServerId) - unsyncedMessages.add(message); + unsyncedMessages.add(message) } else { - Timber.v("Message with uid %s is partially or fully downloaded", messageServerId); + Timber.v("Message with uid %s is partially or fully downloaded", messageServerId) // Store the updated message locally - boolean completeMessage = message.isSet(Flag.X_DOWNLOADED_FULL); + val completeMessage = message.isSet(Flag.X_DOWNLOADED_FULL) if (completeMessage) { - backendFolder.saveMessage(message, MessageDownloadState.FULL); + backendFolder.saveMessage(message, MessageDownloadState.FULL) } else { - backendFolder.saveMessage(message, MessageDownloadState.PARTIAL); + backendFolder.saveMessage(message, MessageDownloadState.PARTIAL) } - boolean isOldMessage = isOldMessage(backendFolder, message); - listener.syncNewMessage(folder, messageServerId, isOldMessage); + val isOldMessage = isOldMessage(backendFolder, message) + listener.syncNewMessage(folder, messageServerId, isOldMessage) } - return; + return } - Set messageFlags = backendFolder.getMessageFlags(messageServerId); + val messageFlags: Set = backendFolder.getMessageFlags(messageServerId) if (!messageFlags.contains(Flag.DELETED)) { - Timber.v("Message with uid %s is present in the local store", messageServerId); + Timber.v("Message with uid %s is present in the local store", messageServerId) if (!messageFlags.contains(Flag.X_DOWNLOADED_FULL) && !messageFlags.contains(Flag.X_DOWNLOADED_PARTIAL)) { - Timber.v("Message with uid %s is not downloaded, even partially; trying again", messageServerId); + Timber.v("Message with uid %s is not downloaded, even partially; trying again", messageServerId) - unsyncedMessages.add(message); + unsyncedMessages.add(message) } else { - syncFlagMessages.add(message); + syncFlagMessages.add(message) } } else { - Timber.v("Local copy of message with uid %s is marked as deleted", messageServerId); + Timber.v("Local copy of message with uid %s is marked as deleted", messageServerId) } } - private void fetchUnsyncedMessages(final SyncConfig syncConfig, final Pop3Folder remoteFolder, - List unsyncedMessages, - final List smallMessages, - final List largeMessages, - final AtomicInteger progress, - final int todo, - FetchProfile fp, - final SyncListener listener) throws MessagingException { - final String folder = remoteFolder.getServerId(); - - final Date earliestDate = syncConfig.getEarliestPollDate(); - remoteFolder.fetch(unsyncedMessages, fp, - new MessageRetrievalListener() { - @Override - public void messageFinished(Pop3Message message) { - try { - if (message.isSet(Flag.DELETED) || message.olderThan(earliestDate)) { - if (message.isSet(Flag.DELETED)) { - Timber.v("Newly downloaded message %s:%s:%s was marked deleted on server, " + - "skipping", accountName, folder, message.getUid()); - } else { - Timber.d("Newly downloaded message %s is older than %s, skipping", - message.getUid(), earliestDate); - } - - progress.incrementAndGet(); - - //TODO: This might be the source of poll count errors in the UI. Is todo always the same as ofTotal - listener.syncProgress(folder, progress.get(), todo); - return; - } - - if (syncConfig.getMaximumAutoDownloadMessageSize() > 0 && - message.getSize() > syncConfig.getMaximumAutoDownloadMessageSize()) { - largeMessages.add(message); + @Throws(MessagingException::class) + private fun fetchUnsyncedMessages( + syncConfig: SyncConfig, remoteFolder: Pop3Folder, + unsyncedMessages: MutableList?, + smallMessages: MutableList, + largeMessages: MutableList, + progress: AtomicInteger, + todo: Int, + fp: FetchProfile?, + listener: SyncListener + ) { + val folder = remoteFolder.getServerId() + + val earliestDate = syncConfig.earliestPollDate + remoteFolder.fetch( + unsyncedMessages, fp, + object : MessageRetrievalListener { + override fun messageFinished(message: Pop3Message) { + try { + if (message.isSet(Flag.DELETED) || message.olderThan(earliestDate)) { + if (message.isSet(Flag.DELETED)) { + Timber.v( + "Newly downloaded message %s:%s:%s was marked deleted on server, " + + "skipping", accountName, folder, message.getUid() + ) } else { - smallMessages.add(message); + Timber.d( + "Newly downloaded message %s is older than %s, skipping", + message.getUid(), earliestDate + ) } - } catch (Exception e) { - Timber.e(e, "Error while storing downloaded message."); + + progress.incrementAndGet() + + //TODO: This might be the source of poll count errors in the UI. Is todo always the same as ofTotal + listener.syncProgress(folder, progress.get(), todo) + return + } + + if (syncConfig.maximumAutoDownloadMessageSize > 0 && + message.getSize() > syncConfig.maximumAutoDownloadMessageSize + ) { + largeMessages.add(message) + } else { + smallMessages.add(message) } + } catch (e: Exception) { + Timber.e(e, "Error while storing downloaded message.") } - }, - syncConfig.getMaximumAutoDownloadMessageSize()); + } + }, + syncConfig.maximumAutoDownloadMessageSize + ) } - private void downloadSmallMessages( - final Pop3Folder remoteFolder, - final BackendFolder backendFolder, - List smallMessages, - final AtomicInteger progress, - final AtomicInteger newMessages, - final int todo, - FetchProfile fp, - final SyncListener listener) throws MessagingException { - final String folder = remoteFolder.getServerId(); - - Timber.d("SYNC: Fetching %d small messages for folder %s", smallMessages.size(), folder); - - remoteFolder.fetch(smallMessages, - fp, new MessageRetrievalListener() { - @Override - public void messageFinished(final Pop3Message message) { - try { - - // Store the updated message locally - backendFolder.saveMessage(message, MessageDownloadState.FULL); - progress.incrementAndGet(); - - // Increment the number of "new messages" if the newly downloaded message is - // not marked as read. - if (!message.isSet(Flag.SEEN)) { - newMessages.incrementAndGet(); - } + @Throws(MessagingException::class) + private fun downloadSmallMessages( + remoteFolder: Pop3Folder, + backendFolder: BackendFolder, + smallMessages: MutableList, + progress: AtomicInteger, + newMessages: AtomicInteger, + todo: Int, + fp: FetchProfile?, + listener: SyncListener + ) { + val folder = remoteFolder.getServerId() + + Timber.d("SYNC: Fetching %d small messages for folder %s", smallMessages.size, folder) + + remoteFolder.fetch( + smallMessages, + fp, object : MessageRetrievalListener { + override fun messageFinished(message: Pop3Message) { + try { + // Store the updated message locally + + backendFolder.saveMessage(message, MessageDownloadState.FULL) + progress.incrementAndGet() + + // Increment the number of "new messages" if the newly downloaded message is + // not marked as read. + if (!message.isSet(Flag.SEEN)) { + newMessages.incrementAndGet() + } - String messageServerId = message.getUid(); - Timber.v("About to notify listeners that we got a new small message %s:%s:%s", - accountName, folder, messageServerId); + val messageServerId = message.getUid() + Timber.v( + "About to notify listeners that we got a new small message %s:%s:%s", + accountName, folder, messageServerId + ) - // Update the listener with what we've found - listener.syncProgress(folder, progress.get(), todo); + // Update the listener with what we've found + listener.syncProgress(folder, progress.get(), todo) - boolean isOldMessage = isOldMessage(backendFolder, message); - listener.syncNewMessage(folder, messageServerId, isOldMessage); - } catch (Exception e) { - Timber.e(e, "SYNC: fetch small messages"); - } + val isOldMessage = isOldMessage(backendFolder, message) + listener.syncNewMessage(folder, messageServerId, isOldMessage) + } catch (e: Exception) { + Timber.e(e, "SYNC: fetch small messages") } - }, - -1); + } + }, + -1 + ) - Timber.d("SYNC: Done fetching small messages for folder %s", folder); + Timber.d("SYNC: Done fetching small messages for folder %s", folder) } - private boolean isOldMessage(BackendFolder backendFolder, Pop3Message message) { - return message.olderThan(getLatestOldMessageSeenTime(backendFolder)); + private fun isOldMessage(backendFolder: BackendFolder, message: Pop3Message): Boolean { + return message.olderThan(getLatestOldMessageSeenTime(backendFolder)) } - private void downloadLargeMessages( - final SyncConfig syncConfig, - final Pop3Folder remoteFolder, - final BackendFolder backendFolder, - List largeMessages, - final AtomicInteger progress, - final AtomicInteger newMessages, - final int todo, - FetchProfile fp, - SyncListener listener) throws MessagingException { - final String folder = remoteFolder.getServerId(); - - Timber.d("SYNC: Fetching large messages for folder %s", folder); - - int maxDownloadSize = syncConfig.getMaximumAutoDownloadMessageSize(); - remoteFolder.fetch(largeMessages, fp, null, maxDownloadSize); - for (Pop3Message message : largeMessages) { - - downloadSaneBody(syncConfig, remoteFolder, backendFolder, message); - - String messageServerId = message.getUid(); - Timber.v("About to notify listeners that we got a new large message %s:%s:%s", - accountName, folder, messageServerId); + @Throws(MessagingException::class) + private fun downloadLargeMessages( + syncConfig: SyncConfig, + remoteFolder: Pop3Folder, + backendFolder: BackendFolder, + largeMessages: MutableList, + progress: AtomicInteger, + newMessages: AtomicInteger, + todo: Int, + fp: FetchProfile?, + listener: SyncListener + ) { + val folder = remoteFolder.getServerId() + + Timber.d("SYNC: Fetching large messages for folder %s", folder) + + val maxDownloadSize = syncConfig.maximumAutoDownloadMessageSize + remoteFolder.fetch(largeMessages, fp, null, maxDownloadSize) + for (message in largeMessages) { + downloadSaneBody(syncConfig, remoteFolder, backendFolder, message) + + val messageServerId = message.getUid() + Timber.v( + "About to notify listeners that we got a new large message %s:%s:%s", + accountName, folder, messageServerId + ) // Update the listener with what we've found - progress.incrementAndGet(); + progress.incrementAndGet() // TODO do we need to re-fetch this here? - Set flags = backendFolder.getMessageFlags(messageServerId); + val flags: Set = backendFolder.getMessageFlags(messageServerId) // Increment the number of "new messages" if the newly downloaded message is // not marked as read. if (!flags.contains(Flag.SEEN)) { - newMessages.incrementAndGet(); + newMessages.incrementAndGet() } - listener.syncProgress(folder, progress.get(), todo); + listener.syncProgress(folder, progress.get(), todo) - boolean isOldMessage = isOldMessage(backendFolder, message); - listener.syncNewMessage(folder, messageServerId, isOldMessage); + val isOldMessage = isOldMessage(backendFolder, message) + listener.syncNewMessage(folder, messageServerId, isOldMessage) } - Timber.d("SYNC: Done fetching large messages for folder %s", folder); + Timber.d("SYNC: Done fetching large messages for folder %s", folder) } - private void downloadSaneBody(SyncConfig syncConfig, Pop3Folder remoteFolder, BackendFolder backendFolder, - Pop3Message message) throws MessagingException { + @Throws(MessagingException::class) + private fun downloadSaneBody( + syncConfig: SyncConfig, remoteFolder: Pop3Folder, backendFolder: BackendFolder, + message: Pop3Message + ) { /* * The provider was unable to get the structure of the message, so * we'll download a reasonable portion of the message and mark it as * incomplete so the entire thing can be downloaded later if the user * wishes to download it. */ - FetchProfile fp = new FetchProfile(); - fp.add(FetchProfile.Item.BODY_SANE); + val fp = FetchProfile() + fp.add(FetchProfile.Item.BODY_SANE) + /* * TODO a good optimization here would be to make sure that all Stores set * the proper size after this fetch and compare the before and after size. If * they equal we can mark this SYNCHRONIZED instead of PARTIALLY_SYNCHRONIZED */ + val maxDownloadSize = syncConfig.maximumAutoDownloadMessageSize + remoteFolder.fetch(mutableListOf(message), fp, null, maxDownloadSize) - int maxDownloadSize = syncConfig.getMaximumAutoDownloadMessageSize(); - remoteFolder.fetch(Collections.singletonList(message), fp, null, maxDownloadSize); - - boolean completeMessage = false; + var completeMessage = false // Certain (POP3) servers give you the whole message even when you ask for only the first x Kb if (!message.isSet(Flag.X_DOWNLOADED_FULL)) { /* @@ -577,17 +610,22 @@ class Pop3Sync { * If there is no limit on autodownload size, that's the same as the message * being smaller than the max size */ - if (syncConfig.getMaximumAutoDownloadMessageSize() == 0 - || message.getSize() < syncConfig.getMaximumAutoDownloadMessageSize()) { - completeMessage = true; + if (syncConfig.maximumAutoDownloadMessageSize == 0 + || message.getSize() < syncConfig.maximumAutoDownloadMessageSize + ) { + completeMessage = true } } // Store the updated message locally if (completeMessage) { - backendFolder.saveMessage(message, MessageDownloadState.FULL); + backendFolder.saveMessage(message, MessageDownloadState.FULL) } else { - backendFolder.saveMessage(message, MessageDownloadState.PARTIAL); + backendFolder.saveMessage(message, MessageDownloadState.PARTIAL) } } + + companion object { + private const val EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME = "latestOldMessageSeenTime" + } } From ee1b772bfe8ce0c309ba5a5a6c2fecae66f8ae1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Mon, 17 Feb 2025 19:39:22 +0100 Subject: [PATCH 7/8] Change Pop3Sync code style --- .../java/com/fsck/k9/backend/pop3/Pop3Sync.kt | 101 +++++++++++------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt index 1d3f0288cc9..250de256f93 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt @@ -22,16 +22,11 @@ import java.util.HashMap import java.util.concurrent.atomic.AtomicInteger import kotlin.math.max -internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop3Store: Pop3Store) { - private val accountName: String - private val backendStorage: BackendStorage - private val remoteStore: Pop3Store - - init { - this.accountName = accountName - this.backendStorage = backendStorage - this.remoteStore = pop3Store - } +internal class Pop3Sync( + private val accountName: String, + private val backendStorage: BackendStorage, + private val remoteStore: Pop3Store, +) { fun sync(folder: String, syncConfig: SyncConfig, listener: SyncListener) { synchronizeMailboxSynchronous(folder, syncConfig, listener) @@ -117,7 +112,9 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop Timber.v( "SYNC: About to get messages %d through %d for folder %s", - remoteStart, remoteMessageCount, folder + remoteStart, + remoteMessageCount, + folder, ) val headerProgress = AtomicInteger(0) @@ -178,8 +175,11 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop * Now we download the actual content of messages. */ val newMessages = downloadMessages( - syncConfig, remoteFolder, backendFolder, remoteMessages, - listener + syncConfig, + remoteFolder, + backendFolder, + remoteMessages, + listener, ) listener.folderStatusChanged(folder) @@ -193,7 +193,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop accountName, folder, System.currentTimeMillis(), - newMessages + newMessages, ) listener.syncFinished(folder) @@ -231,8 +231,9 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop } private fun updateMoreMessages( - remoteFolder: Pop3Folder, backendFolder: BackendFolder, - remoteStart: Int + remoteFolder: Pop3Folder, + backendFolder: BackendFolder, + remoteStart: Int, ) { if (remoteStart == 1) { backendFolder.setMoreMessages(BackendFolder.MoreMessages.FALSE) @@ -247,9 +248,11 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop @Throws(MessagingException::class) private fun downloadMessages( - syncConfig: SyncConfig, remoteFolder: Pop3Folder, - backendFolder: BackendFolder, inputMessages: MutableList, - listener: SyncListener + syncConfig: SyncConfig, + remoteFolder: Pop3Folder, + backendFolder: BackendFolder, + inputMessages: MutableList, + listener: SyncListener, ): Int { val earliestDate = syncConfig.earliestPollDate val downloadStarted = Date() // now @@ -293,7 +296,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop fetchUnsyncedMessages( syncConfig, remoteFolder, unsyncedMessages, smallMessages, largeMessages, progress, - todo, fp, listener + todo, fp, listener, ) Timber.d("SYNC: Synced unsynced messages for folder %s", folder) @@ -301,7 +304,9 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop Timber.d( "SYNC: Have %d large messages and %d small messages out of %d unsynced messages", - largeMessages.size, smallMessages.size, unsyncedMessages.size + largeMessages.size, + smallMessages.size, + unsyncedMessages.size, ) unsyncedMessages.clear() @@ -311,7 +316,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop * download of 625k. */ var fp = FetchProfile() - //TODO: Only fetch small and large messages if we have some + // TODO: Only fetch small and large messages if we have some fp.add(FetchProfile.Item.BODY) // fp.add(FetchProfile.Item.FLAGS); // fp.add(FetchProfile.Item.ENVELOPE); @@ -331,7 +336,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop newMessages, todo, fp, - listener + listener, ) largeMessages.clear() @@ -367,7 +372,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop backendFolder: BackendFolder, unsyncedMessages: MutableList, syncFlagMessages: MutableList, - listener: SyncListener + listener: SyncListener, ) { val messageServerId = message.getUid() if (message.isSet(Flag.DELETED)) { @@ -419,20 +424,22 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop @Throws(MessagingException::class) private fun fetchUnsyncedMessages( - syncConfig: SyncConfig, remoteFolder: Pop3Folder, + syncConfig: SyncConfig, + remoteFolder: Pop3Folder, unsyncedMessages: MutableList?, smallMessages: MutableList, largeMessages: MutableList, progress: AtomicInteger, todo: Int, fp: FetchProfile?, - listener: SyncListener + listener: SyncListener, ) { val folder = remoteFolder.getServerId() val earliestDate = syncConfig.earliestPollDate remoteFolder.fetch( - unsyncedMessages, fp, + unsyncedMessages, + fp, object : MessageRetrievalListener { override fun messageFinished(message: Pop3Message) { try { @@ -440,18 +447,23 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop if (message.isSet(Flag.DELETED)) { Timber.v( "Newly downloaded message %s:%s:%s was marked deleted on server, " + - "skipping", accountName, folder, message.getUid() + "skipping", + accountName, + folder, + message.getUid(), ) } else { Timber.d( "Newly downloaded message %s is older than %s, skipping", - message.getUid(), earliestDate + message.getUid(), + earliestDate, ) } progress.incrementAndGet() - //TODO: This might be the source of poll count errors in the UI. Is todo always the same as ofTotal + // TODO: This might be the source of poll count errors in the UI. + // Is todo always the same as ofTotal listener.syncProgress(folder, progress.get(), todo) return } @@ -468,7 +480,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop } } }, - syncConfig.maximumAutoDownloadMessageSize + syncConfig.maximumAutoDownloadMessageSize, ) } @@ -481,7 +493,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop newMessages: AtomicInteger, todo: Int, fp: FetchProfile?, - listener: SyncListener + listener: SyncListener, ) { val folder = remoteFolder.getServerId() @@ -489,7 +501,8 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop remoteFolder.fetch( smallMessages, - fp, object : MessageRetrievalListener { + fp, + object : MessageRetrievalListener { override fun messageFinished(message: Pop3Message) { try { // Store the updated message locally @@ -506,7 +519,9 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop val messageServerId = message.getUid() Timber.v( "About to notify listeners that we got a new small message %s:%s:%s", - accountName, folder, messageServerId + accountName, + folder, + messageServerId, ) // Update the listener with what we've found @@ -519,7 +534,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop } } }, - -1 + -1, ) Timber.d("SYNC: Done fetching small messages for folder %s", folder) @@ -539,7 +554,7 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop newMessages: AtomicInteger, todo: Int, fp: FetchProfile?, - listener: SyncListener + listener: SyncListener, ) { val folder = remoteFolder.getServerId() @@ -553,7 +568,9 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop val messageServerId = message.getUid() Timber.v( "About to notify listeners that we got a new large message %s:%s:%s", - accountName, folder, messageServerId + accountName, + folder, + messageServerId, ) // Update the listener with what we've found @@ -578,8 +595,10 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop @Throws(MessagingException::class) private fun downloadSaneBody( - syncConfig: SyncConfig, remoteFolder: Pop3Folder, backendFolder: BackendFolder, - message: Pop3Message + syncConfig: SyncConfig, + remoteFolder: Pop3Folder, + backendFolder: BackendFolder, + message: Pop3Message, ) { /* * The provider was unable to get the structure of the message, so @@ -610,8 +629,8 @@ internal class Pop3Sync(accountName: String, backendStorage: BackendStorage, pop * If there is no limit on autodownload size, that's the same as the message * being smaller than the max size */ - if (syncConfig.maximumAutoDownloadMessageSize == 0 - || message.getSize() < syncConfig.maximumAutoDownloadMessageSize + if (syncConfig.maximumAutoDownloadMessageSize == 0 || + message.getSize() < syncConfig.maximumAutoDownloadMessageSize ) { completeMessage = true } From 3b670293620a6252f6a843972a6c52a75868ab04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montwe=CC=81?= Date: Tue, 18 Feb 2025 14:54:48 +0100 Subject: [PATCH 8/8] Refactor Pop3Sync --- .../java/com/fsck/k9/backend/pop3/Pop3Sync.kt | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt index 250de256f93..1517d2e0f4b 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Sync.kt @@ -20,8 +20,8 @@ import java.util.ArrayList import java.util.Date import java.util.HashMap import java.util.concurrent.atomic.AtomicInteger -import kotlin.math.max +@Suppress("TooManyFunctions") internal class Pop3Sync( private val accountName: String, private val backendStorage: BackendStorage, @@ -32,6 +32,13 @@ internal class Pop3Sync( synchronizeMailboxSynchronous(folder, syncConfig, listener) } + @Suppress( + "TooGenericExceptionCaught", + "TooGenericExceptionThrown", + "LongMethod", + "CyclomaticComplexMethod", + "NestedBlockDepth", + ) fun synchronizeMailboxSynchronous(folder: String, syncConfig: SyncConfig, listener: SyncListener) { var remoteFolder: Pop3Folder? = null @@ -50,7 +57,7 @@ internal class Pop3Sync( * Get the message list from the local store and create an index of * the uids within the list. */ - var localUidMap: Map? = backendFolder.getAllMessagesAndEffectiveDates() + var localUidMap: Map = backendFolder.getAllMessagesAndEffectiveDates() Timber.v("SYNC: About to get remote folder %s", folder) remoteFolder = remoteStore.getFolder(folder) @@ -85,7 +92,7 @@ internal class Pop3Sync( /* * Get the remote message count. */ - val remoteMessageCount = remoteFolder.getMessageCount() + val remoteMessageCount = remoteFolder.messageCount var visibleLimit = backendFolder.visibleLimit @@ -99,15 +106,14 @@ internal class Pop3Sync( Timber.v("SYNC: Remote message count for folder %s is %d", folder, remoteMessageCount) val earliestDate = syncConfig.earliestPollDate - val earliestTimestamp = if (earliestDate != null) earliestDate.getTime() else 0L + val earliestTimestamp = if (earliestDate != null) earliestDate.time else 0L + /* Message numbers start at 1. */ var remoteStart = 1 if (remoteMessageCount > 0) { - /* Message numbers start at 1. */ + // Adjust the starting message number based on the visible limit if (visibleLimit > 0) { - remoteStart = max(0, remoteMessageCount - visibleLimit) + 1 - } else { - remoteStart = 1 + remoteStart += (remoteMessageCount - visibleLimit).coerceAtLeast(0) } Timber.v( @@ -120,8 +126,7 @@ internal class Pop3Sync( val headerProgress = AtomicInteger(0) listener.syncHeadersStarted(folder) - val remoteMessageArray = - remoteFolder.getMessages(remoteStart, remoteMessageCount, null) + val remoteMessageArray = remoteFolder.getMessages(remoteStart, remoteMessageCount, null) val messageCount = remoteMessageArray.size @@ -129,10 +134,10 @@ internal class Pop3Sync( headerProgress.incrementAndGet() listener.syncHeadersProgress(folder, headerProgress.get(), messageCount) - val localMessageTimestamp = localUidMap!!.get(thisMess.getUid()) + val localMessageTimestamp = localUidMap[thisMess.uid] if (localMessageTimestamp == null || localMessageTimestamp >= earliestTimestamp) { remoteMessages.add(thisMess) - remoteUidMap.put(thisMess.getUid(), thisMess) + remoteUidMap.put(thisMess.uid, thisMess) } } @@ -140,7 +145,7 @@ internal class Pop3Sync( listener.syncHeadersFinished(folder, headerProgress.get(), remoteUidMap.size) } else if (remoteMessageCount < 0) { - throw Exception("Message count " + remoteMessageCount + " for folder " + folder) + throw Exception("Message count $remoteMessageCount for folder $folder") } /* @@ -149,9 +154,9 @@ internal class Pop3Sync( var moreMessages = backendFolder.getMoreMessages() if (syncConfig.syncRemoteDeletions) { val destroyMessageUids: MutableList = ArrayList() - for (localMessageUid in localUidMap!!.keys) { - if (remoteUidMap.get(localMessageUid) == null) { - destroyMessageUids.add(localMessageUid!!) + for (localMessageUid in localUidMap.keys) { + if (remoteUidMap[localMessageUid] == null) { + destroyMessageUids.add(localMessageUid) } } @@ -164,8 +169,6 @@ internal class Pop3Sync( } } } - // noinspection UnusedAssignment, free memory early? (better break up the method!) - localUidMap = null if (moreMessages == BackendFolder.MoreMessages.UNKNOWN) { updateMoreMessages(remoteFolder, backendFolder, remoteStart) @@ -224,9 +227,7 @@ internal class Pop3Sync( System.currentTimeMillis(), ) } finally { - if (remoteFolder != null) { - remoteFolder.close() - } + remoteFolder?.close() } } @@ -246,6 +247,7 @@ internal class Pop3Sync( } } + @Suppress("TooGenericExceptionCaught", "LongMethod") @Throws(MessagingException::class) private fun downloadMessages( syncConfig: SyncConfig, @@ -260,7 +262,7 @@ internal class Pop3Sync( if (earliestDate != null) { Timber.d("Only syncing messages after %s", earliestDate) } - val folder = remoteFolder.getServerId() + val folder = remoteFolder.serverId val syncFlagMessages: MutableList = ArrayList() var unsyncedMessages: MutableList = ArrayList() @@ -363,7 +365,7 @@ internal class Pop3Sync( } private fun setLatestOldMessageSeenTime(backendFolder: BackendFolder, oldestMessageTime: Date) { - backendFolder.setFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME, oldestMessageTime.getTime()) + backendFolder.setFolderExtraNumber(EXTRA_LATEST_OLD_MESSAGE_SEEN_TIME, oldestMessageTime.time) } private fun evaluateMessageForDownload( @@ -374,7 +376,7 @@ internal class Pop3Sync( syncFlagMessages: MutableList, listener: SyncListener, ) { - val messageServerId = message.getUid() + val messageServerId = message.uid if (message.isSet(Flag.DELETED)) { Timber.v("Message with uid %s is marked as deleted", messageServerId) @@ -422,6 +424,7 @@ internal class Pop3Sync( } } + @Suppress("LongParameterList") @Throws(MessagingException::class) private fun fetchUnsyncedMessages( syncConfig: SyncConfig, @@ -434,13 +437,15 @@ internal class Pop3Sync( fp: FetchProfile?, listener: SyncListener, ) { - val folder = remoteFolder.getServerId() + val folder = remoteFolder.serverId val earliestDate = syncConfig.earliestPollDate remoteFolder.fetch( unsyncedMessages, fp, object : MessageRetrievalListener { + + @Suppress("TooGenericExceptionCaught") override fun messageFinished(message: Pop3Message) { try { if (message.isSet(Flag.DELETED) || message.olderThan(earliestDate)) { @@ -450,12 +455,12 @@ internal class Pop3Sync( "skipping", accountName, folder, - message.getUid(), + message.uid, ) } else { Timber.d( "Newly downloaded message %s is older than %s, skipping", - message.getUid(), + message.uid, earliestDate, ) } @@ -469,7 +474,7 @@ internal class Pop3Sync( } if (syncConfig.maximumAutoDownloadMessageSize > 0 && - message.getSize() > syncConfig.maximumAutoDownloadMessageSize + message.size > syncConfig.maximumAutoDownloadMessageSize ) { largeMessages.add(message) } else { @@ -484,6 +489,7 @@ internal class Pop3Sync( ) } + @Suppress("LongParameterList") @Throws(MessagingException::class) private fun downloadSmallMessages( remoteFolder: Pop3Folder, @@ -495,7 +501,7 @@ internal class Pop3Sync( fp: FetchProfile?, listener: SyncListener, ) { - val folder = remoteFolder.getServerId() + val folder = remoteFolder.serverId Timber.d("SYNC: Fetching %d small messages for folder %s", smallMessages.size, folder) @@ -503,6 +509,8 @@ internal class Pop3Sync( smallMessages, fp, object : MessageRetrievalListener { + + @Suppress("TooGenericExceptionCaught") override fun messageFinished(message: Pop3Message) { try { // Store the updated message locally @@ -516,7 +524,7 @@ internal class Pop3Sync( newMessages.incrementAndGet() } - val messageServerId = message.getUid() + val messageServerId = message.uid Timber.v( "About to notify listeners that we got a new small message %s:%s:%s", accountName, @@ -544,6 +552,7 @@ internal class Pop3Sync( return message.olderThan(getLatestOldMessageSeenTime(backendFolder)) } + @Suppress("LongParameterList") @Throws(MessagingException::class) private fun downloadLargeMessages( syncConfig: SyncConfig, @@ -556,7 +565,7 @@ internal class Pop3Sync( fp: FetchProfile?, listener: SyncListener, ) { - val folder = remoteFolder.getServerId() + val folder = remoteFolder.serverId Timber.d("SYNC: Fetching large messages for folder %s", folder) @@ -565,7 +574,7 @@ internal class Pop3Sync( for (message in largeMessages) { downloadSaneBody(syncConfig, remoteFolder, backendFolder, message) - val messageServerId = message.getUid() + val messageServerId = message.uid Timber.v( "About to notify listeners that we got a new large message %s:%s:%s", accountName, @@ -630,7 +639,7 @@ internal class Pop3Sync( * being smaller than the max size */ if (syncConfig.maximumAutoDownloadMessageSize == 0 || - message.getSize() < syncConfig.maximumAutoDownloadMessageSize + message.size < syncConfig.maximumAutoDownloadMessageSize ) { completeMessage = true }