From aaf1ab6822438d692c2f37bd1e5409a52329fe7b Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 30 Sep 2025 01:35:51 -0300 Subject: [PATCH 1/3] feat: Revert "Don't fetch messages from unknown folders (#7190)" This reverts commit 2260156c40ebbb4b29cf5809f7fa8368ff57052b. Some users still want to get messages from all folders as reported by @gerryfrancis. --- python/tests/test_1_online.py | 23 ++++++++--------------- src/imap.rs | 5 +---- src/imap/scan_folders.rs | 1 - 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 33909b8dbf..c8526e68d6 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -1755,12 +1755,12 @@ def test_group_quote(acfactory, lp): "xyz", False, "xyz", - ), # Test that emails aren't found in a random folder + ), # Test that emails are recognized in a random folder but not moved ( - "Spam", + "xyz", True, "DeltaChat", - ), # ...emails are moved from the spam folder to "DeltaChat" + ), # ...emails are found in a random folder and moved to DeltaChat ( "Spam", False, @@ -1785,7 +1785,7 @@ def test_scan_folders(acfactory, lp, folder, move, expected_destination): ac1.stop_io() assert folder in ac1.direct_imap.list_folders() - lp.sec("Send a message to from ac2 to ac1 and manually move it to `folder`") + lp.sec("Send a message to from ac2 to ac1 and manually move it to the mvbox") ac1.direct_imap.select_config_folder("inbox") with ac1.direct_imap.idle() as idle1: acfactory.get_accepted_chat(ac2, ac1).send_text("hello") @@ -1795,17 +1795,10 @@ def test_scan_folders(acfactory, lp, folder, move, expected_destination): lp.sec("start_io() and see if DeltaChat finds the message (" + variant + ")") ac1.set_config("scan_all_folders_debounce_secs", "0") ac1.start_io() - chat = ac1.create_chat(ac2) - n_msgs = 1 # "Messages are end-to-end encrypted." - if folder == "Spam": - msg = ac1._evtracker.wait_next_incoming_message() - assert msg.text == "hello" - n_msgs += 1 - else: - ac1._evtracker.wait_idle_inbox_ready() - assert len(chat.get_messages()) == n_msgs - - # The message has reached its destination. + msg = ac1._evtracker.wait_next_incoming_message() + assert msg.text == "hello" + + # The message has been downloaded, which means it has reached its destination. ac1.direct_imap.select_folder(expected_destination) assert len(ac1.direct_imap.get_all_messages()) == 1 if folder != expected_destination: diff --git a/src/imap.rs b/src/imap.rs index e10be9e4ae..782b6c0070 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -825,10 +825,7 @@ impl Session { .context("listing folders for resync")?; for folder in all_folders { let folder_meaning = get_folder_meaning(&folder); - if !matches!( - folder_meaning, - FolderMeaning::Virtual | FolderMeaning::Unknown - ) { + if folder_meaning != FolderMeaning::Virtual { self.resync_folder_uids(context, folder.name(), folder_meaning) .await?; } diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index 9b22c613af..b578038e76 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -74,7 +74,6 @@ impl Imap { // Don't scan folders that are watched anyway if !watched_folders.contains(&folder.name().to_string()) && folder_meaning != FolderMeaning::Trash - && folder_meaning != FolderMeaning::Unknown { self.fetch_move_delete(context, session, folder.name(), folder_meaning) .await From 1007265cc79f13fe5d6178c50a76300337595677 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 30 Sep 2025 13:34:44 -0300 Subject: [PATCH 2/3] feat: Always watch Inbox if MvboxMove is set (#7187) If `OnlyFetchMvbox` is enabled, `MvboxMove` ("Move automatically to DeltaChat folder") makes no sense: useful messages from "Spam" are moved anyway to "DeltaChat" (see `imap::spam_target_folder_cfg()`) and Inbox messages aren't fetched and moved. Then `MvboxMove` can mean "Move Inbox and all scanned folders' messages to DeltaChat", so if it's enabled, Inbox is watched too, so the user can configure fetching only from "Inbox", "DeltaChat" and "Spam" which was unachievable before and helps e.g. for the Gmail case which has many virtual folders and the whole folder scanning process is really slow (and useless for most users): https://github.com/chatmail/core/issues/7178#issuecomment-3266343253. This may also be useful if the user has another messenger, e.g. a Delta Chat fork who moves messages to "ZetaChat": this folder shouldn't be scanned, but Inbox should be. Mvbox is watched anyway, this should just be made clear to users (if not already). For existing users accidentally having both options enabled "MvboxMove" is disabled in a migration to not cause watching Inbox. Having both options disabled means that we don't separate chat messages from non-chat ones, scanning all folders is fine in this case. --- src/config.rs | 4 ++-- src/imap.rs | 9 ++++++--- src/imap/scan_folders.rs | 6 +++++- src/sql/migrations.rs | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/config.rs b/src/config.rs index fa5acc0bd8..66568fbb64 100644 --- a/src/config.rs +++ b/src/config.rs @@ -165,10 +165,10 @@ pub enum Config { #[strum(props(default = "1"))] MvboxMove, - /// Watch for new messages in the "Mvbox" (aka DeltaChat folder) only. + /// Only watch the mvbox (aka DeltaChat folder) and, if `MvboxMove` is set, Inbox. /// /// This will not entirely disable other folders, e.g. the spam folder will also still - /// be watched for new messages. + /// be scanned for new messages. #[strum(props(default = "0"))] OnlyFetchMvbox, diff --git a/src/imap.rs b/src/imap.rs index 782b6c0070..2a6cc218e0 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -2053,9 +2053,9 @@ async fn spam_target_folder_cfg( } if needs_move_to_mvbox(context, headers).await? - // If OnlyFetchMvbox is set, we don't want to move the message to - // the inbox or sentbox where we wouldn't fetch it again: - || context.get_config_bool(Config::OnlyFetchMvbox).await? + // Don't move the message to Inbox if we won't fetch the message again there. + || (context.get_config_bool(Config::OnlyFetchMvbox).await? + && !context.get_config_bool(Config::MvboxMove).await?) { Ok(Some(Config::ConfiguredMvboxFolder)) } else { @@ -2587,6 +2587,9 @@ async fn should_ignore_folder( // Still respect the SentboxWatch setting. return Ok(!context.get_config_bool(Config::SentboxWatch).await?); } + if context.is_inbox(folder).await? { + return Ok(!context.get_config_bool(Config::MvboxMove).await?); + } Ok(!(context.is_mvbox(folder).await? || folder_meaning == FolderMeaning::Spam)) } diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index b578038e76..3e496cff37 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -71,9 +71,13 @@ impl Imap { _ => folder_meaning, }; - // Don't scan folders that are watched anyway if !watched_folders.contains(&folder.name().to_string()) + // Inbox shouldn't be scanned, getting messages from Inbox delayed doesn't make + // sense, the user should enable watching it instead. + && folder_meaning != FolderMeaning::Inbox && folder_meaning != FolderMeaning::Trash + && (folder_meaning != FolderMeaning::Unknown + || !context.get_config_bool(Config::OnlyFetchMvbox).await?) { self.fetch_move_delete(context, session, folder.name(), folder_meaning) .await diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 4a7c40e911..6a68c96661 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -1261,6 +1261,20 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint); .await?; } + inc_and_check(&mut migration_version, 134)?; + if dbversion < migration_version { + // `MvboxMove` now means "watch Inbox also and move chat messages from it". Preserve the old + // behavior for `OnlyFetchMvbox` users. + sql.execute_migration( + "INSERT OR REPLACE INTO config (keyname, value) + SELECT 'mvbox_move', '0' + FROM config WHERE keyname='only_fetch_mvbox' AND value!='0' + ", + migration_version, + ) + .await?; + } + let new_version = sql .get_raw_config_int(VERSION_CFG) .await? From 851b479fcb6d11bac5456f3483f319533fda1730 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 30 Sep 2025 14:45:13 -0300 Subject: [PATCH 3/3] feat: Enable OnlyFetchMvbox by default (#7190) This is a replacement for 2260156c40ebbb4b29cf5809f7fa8368ff57052b "feat: Don't fetch messages from unknown folders", but limited to the case with `MvboxMove` enabled. It's enabled by default, so most users still gain from not fetching messages from unknown folders. --- src/config.rs | 2 +- src/imap/imap_tests.rs | 3 ++- src/sql/migrations.rs | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index 66568fbb64..11d7d92d58 100644 --- a/src/config.rs +++ b/src/config.rs @@ -169,7 +169,7 @@ pub enum Config { /// /// This will not entirely disable other folders, e.g. the spam folder will also still /// be scanned for new messages. - #[strum(props(default = "0"))] + #[strum(props(default = "1"))] OnlyFetchMvbox, /// Whether to show classic emails or only chat messages. diff --git a/src/imap/imap_tests.rs b/src/imap/imap_tests.rs index 60637045de..1f191091e0 100644 --- a/src/imap/imap_tests.rs +++ b/src/imap/imap_tests.rs @@ -122,8 +122,9 @@ async fn check_target_folder_combination( t.ctx .set_config(Config::ConfiguredSentboxFolder, Some("Sent")) .await?; + t.ctx.set_config_bool(Config::MvboxMove, mvbox_move).await?; t.ctx - .set_config(Config::MvboxMove, Some(if mvbox_move { "1" } else { "0" })) + .set_config_bool(Config::OnlyFetchMvbox, mvbox_move) .await?; if accepted_chat { diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 6a68c96661..b61c2e28a0 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -1275,6 +1275,20 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint); .await?; } + inc_and_check(&mut migration_version, 135)?; + if dbversion < migration_version { + // `OnlyFetchMvbox` is now 1 by default to avoid scanning unknown folders. But if the user + // disabled `MvboxMove`, we have to keep `OnlyFetchMvbox` unset so that Inbox is watched. + sql.execute_migration( + "INSERT OR IGNORE INTO config (keyname, value) + SELECT 'only_fetch_mvbox', '0' + FROM config WHERE keyname='mvbox_move' AND value='0' + ", + migration_version, + ) + .await?; + } + let new_version = sql .get_raw_config_int(VERSION_CFG) .await?