git.lucas.co / cce-mail
mail client (IMAP/SMTP)
git clone https://git.lucas.co/cce-mail.git

commitb4999eaa83216924a399c40abfd65a75a920c439
parent6ba257b3ff
authorLucas Galante <[email protected]>
date2026-08-31 14:38
fix: adopt an unflagged folder named Archive into the archive slot

iCloud lists a plain-CREATEd "Archive" with no \Archive special-use — the
flag rides on CREATE (USE (\Archive)), which only Apple's own clients send —
so discovery left the slot local and the switcher showed two Archive rows,
the empty local one beside the real server folder. When no \All/\Archive
mailbox was flagged, a selectable folder literally named "Archive" now fills
the slot; a flagged folder still wins over the name.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/main.rs | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/src/main.rs b/src/main.rs
index e72dc5b..1c7da2c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1936,6 +1936,18 @@ fn resolve_folders(entries: Vec<(String, Option<&str>)>) -> Vec<FolderInfo> {
         }
     }
 
+    // A folder literally named "Archive" fills the slot when nothing was
+    // flagged: iCloud leaves a plain-CREATEd Archive without \Archive (the
+    // flag rides on CREATE (USE (\Archive)), which only Apple's own clients
+    // send), and without this the switcher shows the local archive beside the
+    // server's — two rows named Archive claiming one meaning.
+    if !folders.iter().any(|f| f.tag == TAG_ARCHIVE && f.is_server_backed()) {
+        if let Some(i) = custom.iter().position(|f| f.mailbox.eq_ignore_ascii_case("archive")) {
+            let named = custom.remove(i);
+            adopt(&mut folders, TAG_ARCHIVE, &named.mailbox, true);
+        }
+    }
+
     custom.sort_by(|a, b| a.label.to_lowercase().cmp(&b.label.to_lowercase()));
     folders.extend(custom);
     folders
@@ -6422,6 +6434,25 @@ mod tests {
         assert!(f.iter().any(|f| f.tag == "Sent" && f.mailbox == "Sent"));
     }
 
+    #[test]
+    fn resolve_folders_adopts_an_archive_by_name_when_nothing_is_flagged() {
+        // iCloud lists a plain-CREATEd "Archive" with no \Archive flag; the
+        // slot adopts it by name rather than showing two Archive rows.
+        let f = resolve_folders(vec![("INBOX".into(), None), ("Archive".into(), None)]);
+        let archive = f.iter().find(|f| f.tag == TAG_ARCHIVE).unwrap();
+        assert_eq!(archive.mailbox, "Archive");
+        assert_eq!(f.iter().filter(|f| f.label == "Archive").count(), 1);
+
+        // A flagged folder still wins over the name.
+        let f = resolve_folders(vec![
+            ("Archive".into(), None),
+            ("Everything".into(), Some("all")),
+        ]);
+        let archive = f.iter().find(|f| f.tag == TAG_ARCHIVE).unwrap();
+        assert_eq!(archive.mailbox, "Everything");
+        assert!(f.iter().any(|f| f.tag == "Archive"), "the named folder stays custom");
+    }
+
     #[test]
     fn discovered_folders_resolve_to_their_own_mailbox() {
         // A custom folder's uid only means anything in its own mailbox, so