[neon/kde/kdepim-runtime/Neon/unstable] debian/patches: try out dvratils's imap patch

Carlos De Maine null at kde.org
Thu Jun 12 01:24:09 BST 2025


Git commit 7302fa9333295a99295a7ff0b9f5c5fdf07f5285 by Carlos De Maine.
Committed on 12/06/2025 at 00:24.
Pushed by carlosdem into branch 'Neon/unstable'.

try out dvratils's imap patch

A  +285  -0    debian/patches/imap_avoid_doing_search.diff
A  +1    -0    debian/patches/series

https://invent.kde.org/neon/kde/kdepim-runtime/-/commit/7302fa9333295a99295a7ff0b9f5c5fdf07f5285

diff --git a/debian/patches/imap_avoid_doing_search.diff b/debian/patches/imap_avoid_doing_search.diff
new file mode 100644
index 0000000..8d17197
--- /dev/null
+++ b/debian/patches/imap_avoid_doing_search.diff
@@ -0,0 +1,285 @@
+diff --git a/resources/imap/autotests/testretrieveitemstask.cpp b/resources/imap/autotests/testretrieveitemstask.cpp
+index 1ae9702828ad29d48d1655774e75301eb14fbef5..85ae77f79c39531bc8136d6bd4c272f99b8b6386 100644
+--- a/resources/imap/autotests/testretrieveitemstask.cpp
++++ b/resources/imap/autotests/testretrieveitemstask.cpp
+@@ -229,15 +229,12 @@ private Q_SLOTS:
+                     "Test\r\n"
+                     " )"
+                  << "S: A000007 OK fetch done"
+-                 << "C: A000008 UID SEARCH UID 1:7"
+-                 << "S: * SEARCH 1 2 3 4 5 6 7"
+-                 << "S: A000008 OK search done"
+-                 << "C: A000009 UID FETCH 1:7 (FLAGS UID)"
++                 << "C: A000008 FETCH 1:4 (FLAGS UID)"
+                  << "S: * 1 FETCH"
+                  << "S: * 2 FETCH"
+                  << "S: * 3 FETCH"
+                  << "S: * 4 FETCH"
+-                 << "S: A000009 OK fetch done";
++                 << "S: A000008 OK fetch done";
+ 
+         callNames.clear();
+         callNames << QStringLiteral("itemsRetrievedIncremental") << QStringLiteral("applyCollectionChanges") << QStringLiteral("itemsRetrievedIncremental")
+@@ -260,10 +257,10 @@ private Q_SLOTS:
+                  << "S: * 5 EXISTS"
+                  << "S: * 0 RECENT"
+                  << "S: * OK [ UIDVALIDITY 1149151135  ]"
+-                 << "S: * OK [ UIDNEXT 9  ]"
++                 << "S: * OK [ UIDNEXT 10  ]"
+                  << "S: * OK [ HIGHESTMODSEQ 123456789 ]"
+                  << "S: A000005 OK select done"
+-                 << "C: A000006 UID SEARCH UID 8:9"
++                 << "C: A000006 UID SEARCH UID 8:10"
+                  << "S: * SEARCH 8 9"
+                  << "S: A000006 OK search done"
+                  << "C: A000007 UID FETCH 8:9 (RFC822.SIZE INTERNALDATE BODY.PEEK[] FLAGS UID)"
+@@ -284,17 +281,17 @@ private Q_SLOTS:
+                     "Test\r\n"
+                     " )"
+                  << "S: A000007 OK fetch done"
+-                 << "C: A000008 UID SEARCH UID 1:7"
+-                 << "S: * SEARCH 1 2 3 4 5 6 7"
+-                 << "S: A000008 OK search done"
+-                 << "C: A000009 UID FETCH 1:7 (FLAGS UID)"
+-                 << "S: * 1 FETCH"
+-                 << "S: * 2 FETCH"
+-                 << "S: * 3 FETCH"
+-                 << "S: A000009 OK fetch done";
++                 << "C: A000008 FETCH 1:5 (FLAGS UID)"
++                 << "S: * 1 FETCH ( FLAGS (\\Seen) UID 1 )"
++                 << "S: * 2 FETCH ( FLAGS (\\Seen) UID 2 )"
++                 << "S: * 3 FETCH ( FLAGS (\\Seen) UID 3 )"
++                 << "S: * 4 FETCH ( FLAGS (\\Seen) UID 8 )"
++                 << "S: * 5 FETCH ( FLAGS (\\Seen) UID 9 )"
++                 << "S: A000008 OK fetch done";
+ 
+         callNames.clear();
+-        callNames << QStringLiteral("itemsRetrieved") << QStringLiteral("applyCollectionChanges") << QStringLiteral("itemsRetrievalDone");
++        callNames << QStringLiteral("itemsRetrieved") << QStringLiteral("itemsRetrieved") << QStringLiteral("applyCollectionChanges")
++                  << QStringLiteral("itemsRetrievalDone");
+ 
+         // A new message has been added and an old one removed, we can't do an incremental update
+         QTest::newRow("uidnext changed, fetch new messages and list flags") << collection << scenario << callNames;
+@@ -414,11 +411,8 @@ private Q_SLOTS:
+                  << "S: * OK [ UIDVALIDITY 1149151135  ]"
+                  << "S: * OK [ UIDNEXT 9  ]"
+                  << "S: A000005 OK select done"
+-                 << "C: A000006 UID SEARCH UID 1:9"
+-                 << "S: * SEARCH 1 2 3 4 5 6 7 8 9"
+-                 << "S: A000006 OK search done"
+-                 << "C: A000007 UID FETCH 1:9 (RFC822.SIZE INTERNALDATE BODY.PEEK[] FLAGS UID)"
+-                 << "S: * 1 FETCH ( FLAGS (\\Seen) UID 2321 INTERNALDATE \"29-Jun-2010 15:26:42 +0200\" "
++                 << "C: A000006 FETCH 1 (RFC822.SIZE INTERNALDATE BODY.PEEK[] FLAGS UID)"
++                 << "S: * 1 FETCH ( FLAGS (\\Seen) UID 8 INTERNALDATE \"29-Jun-2010 15:26:42 +0200\" "
+                     "RFC822.SIZE 75 BODY[] {75}\r\n"
+                     "From: Foo <foo at kde.org>\r\n"
+                     "To: Bar <bar at kde.org>\r\n"
+@@ -426,7 +420,7 @@ private Q_SLOTS:
+                     "\r\n"
+                     "Test\r\n"
+                     " )"
+-                 << "S: A000007 OK fetch done";
++                 << "S: A000006 OK fetch done";
+ 
+         callNames.clear();
+         callNames << QStringLiteral("itemsRetrieved") << QStringLiteral("applyCollectionChanges") << QStringLiteral("itemsRetrievalDone");
+@@ -479,17 +473,23 @@ private Q_SLOTS:
+                     " )"
+                  // 4 more would follow but are excluded for clarity
+                  << "S: A000008 OK fetch done"
+-                 << "C: A000009 UID SEARCH UID 1:104"
+-                 << "S: * SEARCH 1 2 99 100"
+-                 << "S: A000009 OK search done"
+-                 << "C: A000010 UID FETCH 1:2,99:100 (FLAGS UID)"
++                 << "C: A000009 FETCH 1:100 (FLAGS UID)"
+                  << "S: * 1 FETCH ( FLAGS (\\Seen) UID 1 )"
++                 // 99 more would follow but are excluded for clarity
++                 << "S: A000009 OK fetch done"
++                 << "C: A000010 FETCH 101:104 (FLAGS UID)"
++                 << "S: * 1 FETCH ( FLAGS (\\Seen) UID 101 )"
+                  // 3 more would follow but are excluded for clarity
+                  << "S: A000010 OK fetch done";
+ 
+         callNames.clear();
+-        callNames << QStringLiteral("itemsRetrievedIncremental") << QStringLiteral("itemsRetrievedIncremental") << QStringLiteral("itemsRetrievedIncremental")
+-                  << QStringLiteral("applyCollectionChanges") << QStringLiteral("itemsRetrievedIncremental") << QStringLiteral("itemsRetrievalDone");
++        callNames << QStringLiteral("itemsRetrievedIncremental") // first batch of new messages
++                  << QStringLiteral("itemsRetrievedIncremental") // second batch of new messages
++                  << QStringLiteral("itemsRetrievedIncremental") // first batch of flags updates
++                  << QStringLiteral("itemsRetrievedIncremental") // second batch of flags updates
++                  << QStringLiteral("applyCollectionChanges") // retrieval done, apply collection changes
++                  << QStringLiteral("itemsRetrievedIncremental") // final call to ensure incremental update
++                  << QStringLiteral("itemsRetrievalDone"); // sync done, no more calls expected
+ 
+         QTest::newRow("test batch processing") << collection << scenario << callNames;
+ 
+@@ -514,15 +514,12 @@ private Q_SLOTS:
+                  << "S: * OK [ UIDNEXT 9 ]"
+                  << "S: * OK [ HIGHESTMODSEQ 123456789 ]"
+                  << "S: A000005 OK select done"
+-                 << "C: A000006 UID SEARCH UID 1:9"
+-                 << "S: * SEARCH 1 2 3 4"
+-                 << "S: A000006 OK search done"
+-                 << "C: A000007 UID FETCH 1:4 (FLAGS UID)"
++                 << "C: A000006 FETCH 1:4 (FLAGS UID)"
+                  << "S: * 1 FETCH ( FLAGS (\\Seen) UID 1 )"
+                  << "S: * 2 FETCH ( FLAGS (\\Seen) UID 2 )"
+                  << "S: * 3 FETCH ( FLAGS (\\Seen) UID 3 )"
+                  << "S: * 4 FETCH ( FLAGS (\\Seen) UID 4 )"
+-                 << "S: A000007 OK fetch done";
++                 << "S: A000006 OK fetch done";
+         callNames.clear();
+         callNames << QStringLiteral("itemsRetrieved") << QStringLiteral("applyCollectionChanges") << QStringLiteral("itemsRetrievalDone");
+ 
+@@ -596,7 +593,7 @@ private Q_SLOTS:
+         task->start(&pool);
+ 
+         QTRY_COMPARE(state->calls().count(), callNames.size());
+-        qDebug() << state->calls();
++        // qDebug() << state->calls();
+         for (int i = 0; i < callNames.size(); i++) {
+             QString command = QString::fromUtf8(state->calls().at(i).first);
+             QVariant parameter = state->calls().at(i).second;
+diff --git a/resources/imap/retrieveitemstask.cpp b/resources/imap/retrieveitemstask.cpp
+index ee43142f80d5296954bc01f56d037d3b3c1e29b2..b3751e1b5c5b1b57fa293a38b93622f3d43877e8 100644
+--- a/resources/imap/retrieveitemstask.cpp
++++ b/resources/imap/retrieveitemstask.cpp
+@@ -357,11 +357,11 @@ void RetrieveItemsTask::prepareRetrieval()
+         scope.mode = KIMAP::FetchJob::FetchScope::Full;
+     }
+ 
+-    const qint64 realMessageCount = col.statistics().count();
++    m_localMessageCount = col.statistics().count();
+ 
+     qCDebug(IMAPRESOURCE_LOG) << "Starting message retrieval. Elapsed(ms): " << m_time.elapsed();
+     qCDebug(IMAPRESOURCE_LOG) << "UidValidity: " << m_uidValidity << "Local UidValidity: " << oldUidValidity;
+-    qCDebug(IMAPRESOURCE_LOG) << "MessageCount: " << m_messageCount << "Local message count: " << realMessageCount;
++    qCDebug(IMAPRESOURCE_LOG) << "MessageCount: " << m_messageCount << "Local message count: " << m_localMessageCount;
+     qCDebug(IMAPRESOURCE_LOG) << "UidNext: " << m_nextUid << "Local UidNext: " << oldNextUid;
+     qCDebug(IMAPRESOURCE_LOG) << "HighestModSeq: " << m_highestModSeq << "Local HighestModSeq: " << oldHighestModSeq;
+ 
+@@ -384,7 +384,7 @@ void RetrieveItemsTask::prepareRetrieval()
+         // Shortcut:
+         // If no messages are present on the server, clear local cash and finish
+         m_incremental = false;
+-        if (realMessageCount > 0) {
++        if (m_localMessageCount > 0) {
+             qCDebug(IMAPRESOURCE_LOG) << "No messages present so we are done, deleting local messages.";
+             itemsRetrieved(Akonadi::Item::List());
+         } else {
+@@ -401,15 +401,15 @@ void RetrieveItemsTask::prepareRetrieval()
+         }
+         qCDebug(IMAPRESOURCE_LOG) << "Fetching complete mailbox " << m_mailBox;
+         setTotalItems(m_messageCount);
+-        retrieveItems(KIMAP::ImapSet(1, m_nextUid), scope, false, true);
++        retrieveItems(KIMAP::ImapSet(1, m_messageCount), scope, false, false);
+     } else if (m_nextUid <= 0) {
+         // This is a compatibility codepath for Courier IMAP. It probably introduces problems, but at least it syncs.
+         // Since we don't have uidnext available, we simply use the messagecount. This will miss simultaneously added/removed messages.
+         // qCDebug(IMAPRESOURCE_LOG) << "Running courier imap compatibility codepath";
+-        if (m_messageCount > realMessageCount) {
++        if (m_messageCount > m_localMessageCount) {
+             // Get new messages
+-            retrieveItems(KIMAP::ImapSet(realMessageCount + 1, m_messageCount), scope, false, false);
+-        } else if (m_messageCount == realMessageCount) {
++            retrieveItems(KIMAP::ImapSet(m_localMessageCount + 1, m_messageCount), scope, false, false);
++        } else if (m_messageCount == m_localMessageCount) {
+             m_uidBasedFetch = false;
+             m_incremental = true;
+             setTotalItems(m_messageCount);
+@@ -427,23 +427,23 @@ void RetrieveItemsTask::prepareRetrieval()
+         KIMAP::ImapSet imapSet;
+         imapSet.add(m_messageUidsMissingBody);
+         retrieveItems(imapSet, scope, true, true);
+-    } else if (m_nextUid > oldNextUid && ((realMessageCount + m_nextUid - oldNextUid) == m_messageCount) && realMessageCount > 0) {
++    } else if (m_nextUid > oldNextUid && ((m_localMessageCount + m_nextUid - oldNextUid) == m_messageCount) && m_localMessageCount > 0) {
+         // Optimization:
+         // New messages are available, but we know no messages have been removed.
+         // Fetch new messages, and then check for changed flags and removed messages
+         // We can make an incremental update and use modseq.
+         qCDebug(IMAPRESOURCE_LOG) << "Incrementally fetching new messages: UidNext: " << m_nextUid << " Old UidNext: " << oldNextUid << " message count "
+-                                  << m_messageCount << realMessageCount;
+-        setTotalItems(qMax(1ll, m_messageCount - realMessageCount));
++                                  << m_messageCount << m_localMessageCount;
++        setTotalItems(qMax(1ll, m_messageCount - m_localMessageCount));
+         m_flagsChanged = !(m_highestModSeq == oldHighestModSeq);
+         retrieveItems(KIMAP::ImapSet(qMax(1, oldNextUid), m_nextUid), scope, true, true);
+-    } else if (m_nextUid > oldNextUid && m_messageCount > (realMessageCount + m_nextUid - oldNextUid) && realMessageCount > 0) {
++    } else if (m_nextUid > oldNextUid && m_messageCount > (m_localMessageCount + m_nextUid - oldNextUid) && m_localMessageCount > 0) {
+         // Error recovery:
+         // New messages are available, but not enough to justify the difference between the local and remote message count.
+         // This can be triggered if we i.e. clear the local cache, but the keep the annotations.
+         // If we didn't catch this case, we end up inserting flags only for every missing message.
+         qCWarning(IMAPRESOURCE_LOG) << m_mailBox << ": detected inconsistency in local cache, we're missing some messages. Server: " << m_messageCount
+-                                    << " Local: " << realMessageCount;
++                                    << " Local: " << m_localMessageCount;
+         qCWarning(IMAPRESOURCE_LOG) << m_mailBox << ": refetching complete mailbox";
+         setTotalItems(m_messageCount);
+         retrieveItems(KIMAP::ImapSet(1, m_nextUid), scope, false, true);
+@@ -452,7 +452,7 @@ void RetrieveItemsTask::prepareRetrieval()
+         qCDebug(IMAPRESOURCE_LOG) << "Fetching new messages: UidNext: " << m_nextUid << " Old UidNext: " << oldNextUid;
+         setTotalItems(m_messageCount);
+         retrieveItems(KIMAP::ImapSet(qMax(1, oldNextUid), m_nextUid), scope, false, true);
+-    } else if (m_messageCount == realMessageCount && oldNextUid == m_nextUid) {
++    } else if (m_messageCount == m_localMessageCount && oldNextUid == m_nextUid) {
+         // Optimization:
+         // We know no messages were added or removed (if the message count and uidnext is still the same)
+         // We only check the flags incrementally and can make use of modseq
+@@ -469,22 +469,24 @@ void RetrieveItemsTask::prepareRetrieval()
+         }
+         setTotalItems(m_messageCount);
+         listFlagsForImapSet(KIMAP::ImapSet(1, m_nextUid));
+-    } else if (m_messageCount > realMessageCount) {
++    } else if (m_messageCount > m_localMessageCount) {
+         // Error recovery:
+         // We didn't detect any new messages based on the uid, but according to the message count there are new ones.
+         // Our local cache is invalid and has to be refetched.
+         qCWarning(IMAPRESOURCE_LOG) << m_mailBox << ": detected inconsistency in local cache, we're missing some messages. Server: " << m_messageCount
+-                                    << " Local: " << realMessageCount;
++                                    << " Local: " << m_localMessageCount;
+         qCWarning(IMAPRESOURCE_LOG) << m_mailBox << ": refetching complete mailbox";
+         setTotalItems(m_messageCount);
+         retrieveItems(KIMAP::ImapSet(1, m_nextUid), scope, false, true);
+     } else {
+         // Shortcut:
+         // No new messages are available. Directly check for changed flags and removed messages.
+-        m_uidBasedFetch = true;
++        // Since we are checking all messages anyway, don't use UID FETCH to avoid searching for UIDs,
++        // we can do batching based on sequence numbers.
++        m_uidBasedFetch = false;
+         m_incremental = false;
+         setTotalItems(m_messageCount);
+-        listFlagsForImapSet(KIMAP::ImapSet(1, m_nextUid));
++        listFlagsForImapSet(KIMAP::ImapSet(1, m_messageCount));
+     }
+ }
+ 
+@@ -553,9 +555,13 @@ void RetrieveItemsTask::onRetrievalDone(KJob *job)
+         return;
+     }
+ 
+-    // Fetch flags of all items that were not fetched by the fetchJob. After
+-    // that /all/ items in the folder are synced.
+-    listFlagsForImapSet(KIMAP::ImapSet(1, alreadyFetchedBegin - 1));
++    // Fetch flags of all items that were not fetched by the fetchJob. The always fetches
++    // only new messages, so what remains are all messages that are cached locally.
++    // To avoid expensive UID SEARCH, we disable UID based fetching and just batch the flags
++    // fetch based on sequence numbers.
++    // After that /all/ items in the folder are synced.
++    m_uidBasedFetch = false;
++    listFlagsForImapSet(KIMAP::ImapSet(1, m_localMessageCount));
+ }
+ 
+ void RetrieveItemsTask::listFlagsForImapSet(const KIMAP::ImapSet &set)
+diff --git a/resources/imap/retrieveitemstask.h b/resources/imap/retrieveitemstask.h
+index 263347700cf16571f8a6e82ec74d9c6c15faf86e..984987a1f82b17d5ae66633d949b1a268fa3ad31 100644
+--- a/resources/imap/retrieveitemstask.h
++++ b/resources/imap/retrieveitemstask.h
+@@ -66,6 +66,7 @@ private:
+     bool m_fetchMissingBodies = false;
+     bool m_incremental = true;
+     qint64 m_localHighestModSeq = -1;
++    qint64 m_localMessageCount = -1;
+     BatchFetcher *m_batchFetcher = nullptr;
+     Akonadi::Collection m_modifiedCollection;
+     bool m_uidBasedFetch = true;
\ No newline at end of file
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..4f32b20
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+imap_avoid_doing_search.diff
\ No newline at end of file


More information about the Neon-commits mailing list