From 4cf89fdf8ec183b4f5fe9fb9bd7863c549f8649e Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 8 Sep 2025 15:23:32 -0300 Subject: [PATCH 1/2] feat: Remove Config::SentboxWatch (#7178) The motivation is to reduce code complexity, get rid of the extra IMAP connection and cases when messages are added to chats by Inbox and Sentbox loops in parallel which leads to various message sorting bugs, particularly to outgoing messages breaking sorting of incoming ones which are fetched later, but may have a smaller "Date". --- python/src/deltachat/testplugin.py | 1 - python/tests/test_1_online.py | 14 +++++++------ scripts/update-provider-database.sh | 2 +- src/config.rs | 25 ++-------------------- src/configure.rs | 1 - src/context.rs | 8 -------- src/imap.rs | 6 +----- src/imap/imap_tests.rs | 8 -------- src/imap/scan_folders.rs | 3 --- src/provider/data.rs | 21 +++++-------------- src/scheduler.rs | 32 +++++++++++++---------------- src/scheduler/connectivity.rs | 3 +-- src/tests/verified_chats.rs | 6 +++--- 13 files changed, 35 insertions(+), 95 deletions(-) diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index 15bdb6035b..1c160b6655 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -523,7 +523,6 @@ def prepare_account_from_liveconfig(self, configdict) -> Account: assert "addr" in configdict and "mail_pw" in configdict, configdict configdict.setdefault("bcc_self", False) configdict.setdefault("mvbox_move", False) - configdict.setdefault("sentbox_watch", False) configdict.setdefault("sync_msgs", False) configdict.setdefault("delete_server_after", 0) ac.update_config(configdict) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index c8526e68d6..ab86e3a3a6 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -269,19 +269,21 @@ def test_enable_mvbox_move(acfactory, lp): assert ac2._evtracker.wait_next_incoming_message().text == "message1" -def test_mvbox_sentbox_threads(acfactory, lp): +def test_mvbox_thread_and_sentbox(acfactory, lp): lp.sec("ac1: start with mvbox thread") - ac1 = acfactory.new_online_configuring_account(mvbox_move=True, sentbox_watch=False) + ac1 = acfactory.new_online_configuring_account(mvbox_move=True) - lp.sec("ac2: start without mvbox/sentbox threads") - ac2 = acfactory.new_online_configuring_account(mvbox_move=False, sentbox_watch=False) + lp.sec("ac2: start without a mvbox thread") + ac2 = acfactory.new_online_configuring_account(mvbox_move=False) lp.sec("ac2 and ac1: waiting for configuration") acfactory.bring_accounts_online() - lp.sec("ac1: create and configure sentbox") + lp.sec("ac1: create sentbox") ac1.direct_imap.create_folder("Sent") - ac1.set_config("sentbox_watch", "1") + ac1.set_config("scan_all_folders_debounce_secs", "0") + ac1.stop_io() + ac1.start_io() lp.sec("ac1: send message and wait for ac2 to receive it") acfactory.get_accepted_chat(ac1, ac2).send_text("message1") diff --git a/scripts/update-provider-database.sh b/scripts/update-provider-database.sh index eaed2d97ff..4ad079fe8e 100755 --- a/scripts/update-provider-database.sh +++ b/scripts/update-provider-database.sh @@ -6,7 +6,7 @@ set -euo pipefail export TZ=UTC # Provider database revision. -REV=1cce91c1f1065b47e4f307d6fe2f4cca68c74d2e +REV=d041136c19a48b493823b46d472f12b9ee94ae80 CORE_ROOT="$PWD" TMP="$(mktemp -d)" diff --git a/src/config.rs b/src/config.rs index 02ad57374f..a953966c09 100644 --- a/src/config.rs +++ b/src/config.rs @@ -156,10 +156,6 @@ pub enum Config { #[strum(props(default = "1"))] MdnsEnabled, - /// True if "Sent" folder should be watched for changes. - #[strum(props(default = "0"))] - SentboxWatch, - /// True if chat messages should be moved to a separate folder. Auto-sent messages like sync /// ones are moved there anyway. #[strum(props(default = "1"))] @@ -476,10 +472,7 @@ impl Config { /// Whether the config option needs an IO scheduler restart to take effect. pub(crate) fn needs_io_restart(&self) -> bool { - matches!( - self, - Config::MvboxMove | Config::OnlyFetchMvbox | Config::SentboxWatch - ) + matches!(self, Config::MvboxMove | Config::OnlyFetchMvbox) } } @@ -605,15 +598,6 @@ impl Context { || !self.get_config_bool(Config::IsChatmail).await?) } - /// Returns true if sentbox ("Sent" folder) should be watched. - pub(crate) async fn should_watch_sentbox(&self) -> Result { - Ok(self.get_config_bool(Config::SentboxWatch).await? - && self - .get_config(Config::ConfiguredSentboxFolder) - .await? - .is_some()) - } - /// Returns true if sync messages should be sent. pub(crate) async fn should_send_sync_msgs(&self) -> Result { Ok(self.get_config_bool(Config::SyncMsgs).await? @@ -702,7 +686,6 @@ impl Context { | Config::ProxyEnabled | Config::BccSelf | Config::MdnsEnabled - | Config::SentboxWatch | Config::MvboxMove | Config::OnlyFetchMvbox | Config::DeleteToTrash @@ -732,11 +715,7 @@ impl Context { true => self.scheduler.pause(self).await?, _ => Default::default(), }; - self.set_config_internal(key, value).await?; - if key == Config::SentboxWatch { - self.last_full_folder_scan.lock().await.take(); - } - Ok(()) + self.set_config_internal(key, value).await } pub(crate) async fn set_config_internal(&self, key: Config, value: Option<&str>) -> Result<()> { diff --git a/src/configure.rs b/src/configure.rs index a4fcf4062b..b5fe0f46a6 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -555,7 +555,6 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result ctx.get_config_bool(Config::IsChatmail).await?, }; if is_chatmail { - ctx.set_config(Config::SentboxWatch, None).await?; ctx.set_config(Config::MvboxMove, Some("0")).await?; ctx.set_config(Config::OnlyFetchMvbox, None).await?; ctx.set_config(Config::ShowEmails, None).await?; diff --git a/src/context.rs b/src/context.rs index c94780a8dd..87740158ac 100644 --- a/src/context.rs +++ b/src/context.rs @@ -849,7 +849,6 @@ impl Context { Err(err) => format!(""), }; - let sentbox_watch = self.get_config_int(Config::SentboxWatch).await?; let mvbox_move = self.get_config_int(Config::MvboxMove).await?; let only_fetch_mvbox = self.get_config_int(Config::OnlyFetchMvbox).await?; let folders_configured = self @@ -954,7 +953,6 @@ impl Context { .await? .to_string(), ); - res.insert("sentbox_watch", sentbox_watch.to_string()); res.insert("mvbox_move", mvbox_move.to_string()); res.insert("only_fetch_mvbox", only_fetch_mvbox.to_string()); res.insert( @@ -1428,12 +1426,6 @@ impl Context { Ok(inbox.as_deref() == Some(folder_name)) } - /// Returns true if given folder name is the name of the "sent" folder. - pub async fn is_sentbox(&self, folder_name: &str) -> Result { - let sentbox = self.get_config(Config::ConfiguredSentboxFolder).await?; - Ok(sentbox.as_deref() == Some(folder_name)) - } - /// Returns true if given folder name is the name of the "DeltaChat" folder. pub async fn is_mvbox(&self, folder_name: &str) -> Result { let mvbox = self.get_config(Config::ConfiguredMvboxFolder).await?; diff --git a/src/imap.rs b/src/imap.rs index ea6d907362..1310bf2432 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1971,7 +1971,7 @@ 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: + // the inbox where we wouldn't fetch it again: || context.get_config_bool(Config::OnlyFetchMvbox).await? { Ok(Some(Config::ConfiguredMvboxFolder)) @@ -2524,10 +2524,6 @@ async fn should_ignore_folder( if !context.get_config_bool(Config::OnlyFetchMvbox).await? { return Ok(false); } - if context.is_sentbox(folder).await? { - // Still respect the SentboxWatch setting. - return Ok(!context.get_config_bool(Config::SentboxWatch).await?); - } Ok(!(context.is_mvbox(folder).await? || folder_meaning == FolderMeaning::Spam)) } diff --git a/src/imap/imap_tests.rs b/src/imap/imap_tests.rs index 60637045de..421f7e1482 100644 --- a/src/imap/imap_tests.rs +++ b/src/imap/imap_tests.rs @@ -183,10 +183,6 @@ const COMBINATIONS_ACCEPTED_CHAT: &[(&str, bool, bool, &str)] = &[ ("INBOX", false, true, "INBOX"), ("INBOX", true, false, "INBOX"), ("INBOX", true, true, "DeltaChat"), - ("Sent", false, false, "Sent"), - ("Sent", false, true, "Sent"), - ("Sent", true, false, "Sent"), - ("Sent", true, true, "DeltaChat"), ("Spam", false, false, "INBOX"), // Move classical emails in accepted chats from Spam to Inbox, not 100% sure on this, we could also just never move non-chat-msgs ("Spam", false, true, "INBOX"), ("Spam", true, false, "INBOX"), // Move classical emails in accepted chats from Spam to Inbox, not 100% sure on this, we could also just never move non-chat-msgs @@ -199,10 +195,6 @@ const COMBINATIONS_REQUEST: &[(&str, bool, bool, &str)] = &[ ("INBOX", false, true, "INBOX"), ("INBOX", true, false, "INBOX"), ("INBOX", true, true, "DeltaChat"), - ("Sent", false, false, "Sent"), - ("Sent", false, true, "Sent"), - ("Sent", true, false, "Sent"), - ("Sent", true, true, "DeltaChat"), ("Spam", false, false, "Spam"), ("Spam", false, true, "INBOX"), ("Spam", true, false, "Spam"), diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index 860c27568d..d123cfc968 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -108,9 +108,6 @@ impl Imap { pub(crate) async fn get_watched_folder_configs(context: &Context) -> Result> { let mut res = vec![Config::ConfiguredInboxFolder]; - if context.get_config_bool(Config::SentboxWatch).await? { - res.push(Config::ConfiguredSentboxFolder); - } if context.should_watch_mvbox().await? { res.push(Config::ConfiguredMvboxFolder); } diff --git a/src/provider/data.rs b/src/provider/data.rs index 1e328b9ff8..bfd359f325 100644 --- a/src/provider/data.rs +++ b/src/provider/data.rs @@ -510,10 +510,6 @@ static P_FIVE_CHAT: Provider = Provider { key: Config::BccSelf, value: "1", }, - ConfigDefault { - key: Config::SentboxWatch, - value: "0", - }, ConfigDefault { key: Config::MvboxMove, value: "0", @@ -1084,10 +1080,6 @@ static P_NAUTA_CU: Provider = Provider { key: Config::DeleteServerAfter, value: "1", }, - ConfigDefault { - key: Config::SentboxWatch, - value: "0", - }, ConfigDefault { key: Config::MvboxMove, value: "0", @@ -1629,10 +1621,6 @@ static P_TESTRUN: Provider = Provider { key: Config::BccSelf, value: "1", }, - ConfigDefault { - key: Config::SentboxWatch, - value: "0", - }, ConfigDefault { key: Config::MvboxMove, value: "0", @@ -1898,11 +1886,11 @@ static P_WKPB_DE: Provider = Provider { oauth2_authorizer: None, }; -// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, ymail.com, rocketmail.com, yahoodns.net +// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, myyahoo.com, ymail.com, rocketmail.com, yahoodns.net static P_YAHOO: Provider = Provider { id: "yahoo", status: Status::Preparation, - before_login_hint: "To use your Yahoo email address you have to create an \"App-Password\" in the account security screen.", + before_login_hint: "To use your Yahoo email address you have to create an app password in the Yahoo account security screen.", after_login_hint: "", overview_page: "https://providers.delta.chat/yahoo", server: &[ @@ -2041,7 +2029,7 @@ static P_ZOHO: Provider = Provider { oauth2_authorizer: None, }; -pub(crate) static PROVIDER_DATA: [(&str, &Provider); 533] = [ +pub(crate) static PROVIDER_DATA: [(&str, &Provider); 534] = [ ("163.com", &P_163), ("aktivix.org", &P_AKTIVIX_ORG), ("aliyun.com", &P_ALIYUN), @@ -2560,6 +2548,7 @@ pub(crate) static PROVIDER_DATA: [(&str, &Provider); 533] = [ ("yahoo.com.ar", &P_YAHOO), ("yahoo.com.br", &P_YAHOO), ("yahoo.com.mx", &P_YAHOO), + ("myyahoo.com", &P_YAHOO), ("ymail.com", &P_YAHOO), ("rocketmail.com", &P_YAHOO), ("yahoodns.net", &P_YAHOO), @@ -2658,4 +2647,4 @@ pub(crate) static PROVIDER_IDS: LazyLock = - LazyLock::new(|| chrono::NaiveDate::from_ymd_opt(2025, 9, 4).unwrap()); + LazyLock::new(|| chrono::NaiveDate::from_ymd_opt(2025, 9, 10).unwrap()); diff --git a/src/scheduler.rs b/src/scheduler.rs index 621a799eb0..a7f855cd1f 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -254,7 +254,7 @@ impl SchedulerState { } } - /// Interrupt optional boxes (mvbox, sentbox) loops. + /// Interrupt optional boxes (mvbox currently) loops. pub(crate) async fn interrupt_oboxes(&self) { let inner = self.inner.read().await; if let InnerSchedulerState::Started(ref scheduler) = *inner { @@ -333,7 +333,7 @@ struct SchedBox { #[derive(Debug)] pub(crate) struct Scheduler { inbox: SchedBox, - /// Optional boxes -- mvbox, sentbox. + /// Optional boxes -- mvbox. oboxes: Vec, smtp: SmtpConnectionState, smtp_handle: task::JoinHandle<()>, @@ -878,22 +878,18 @@ impl Scheduler { }; start_recvs.push(inbox_start_recv); - for (meaning, should_watch) in [ - (FolderMeaning::Mvbox, ctx.should_watch_mvbox().await), - (FolderMeaning::Sent, ctx.should_watch_sentbox().await), - ] { - if should_watch? { - let (conn_state, handlers) = ImapConnectionState::new(ctx).await?; - let (start_send, start_recv) = oneshot::channel(); - let ctx = ctx.clone(); - let handle = task::spawn(simple_imap_loop(ctx, start_send, handlers, meaning)); - oboxes.push(SchedBox { - meaning, - conn_state, - handle, - }); - start_recvs.push(start_recv); - } + if ctx.should_watch_mvbox().await? { + let (conn_state, handlers) = ImapConnectionState::new(ctx).await?; + let (start_send, start_recv) = oneshot::channel(); + let ctx = ctx.clone(); + let meaning = FolderMeaning::Mvbox; + let handle = task::spawn(simple_imap_loop(ctx, start_send, handlers, meaning)); + oboxes.push(SchedBox { + meaning, + conn_state, + handle, + }); + start_recvs.push(start_recv); } let smtp_handle = { diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index 64dfccc7a0..1e2ede5bff 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -90,7 +90,7 @@ impl DetailedConnectivity { DetailedConnectivity::Preparing => Some(Connectivity::Working), // Just don't return a connectivity, probably the folder is configured not to be - // watched or there is e.g. no "Sent" folder, so we are not interested in it + // watched, so we are not interested in it. DetailedConnectivity::NotConfigured => None, DetailedConnectivity::Idle => Some(Connectivity::Connected), @@ -378,7 +378,6 @@ impl Context { // Add e.g. // Incoming messages // - "Inbox": Connected - // - "Sent": Connected // ============================================================================================= let watched_folders = get_watched_folder_configs(self).await?; diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 2a85dbc026..407c46d191 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -278,8 +278,8 @@ async fn test_degrade_verified_oneonone_chat() -> Result<()> { Ok(()) } -/// Alice is offline for some time. -/// When she comes online, first her inbox is synced and then her sentbox. +/// Alice is offline for some time. mvbox_move is 0. +/// When she comes online, first her inbox is synced and then her mvbox. /// This test tests that the messages are still in the right order. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_old_message_4() -> Result<()> { @@ -317,7 +317,7 @@ async fn test_old_message_4() -> Result<()> { } /// Alice is offline for some time. -/// When they come online, first their sentbox is synced and then their inbox. +/// When they come online, first their mvbox is synced and then their inbox. /// This test tests that the messages are still in the right order. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_old_message_5() -> Result<()> { From c0b2f587d9eb910a11c8a4139be756b6fc16dada Mon Sep 17 00:00:00 2001 From: iequidoo Date: Thu, 11 Sep 2025 13:42:11 -0300 Subject: [PATCH 2/2] feat: Remove `Config::ConfiguredSentboxFolder` and everything related It's used in `fetch_existing_msgs()`, but we can remove it and tell users that they need to move/copy messages from Sentbox to Inbox so that Delta Chat adds all contacts from them. This way users will be also informed that Delta Chat needs users to CC/BCC/To themselves to see messages sent from other MUAs. --- python/tests/test_1_online.py | 44 +++++++++++------------------------ src/config.rs | 3 --- src/context.rs | 5 ---- src/imap.rs | 44 ++--------------------------------- src/imap/imap_tests.rs | 14 ----------- src/imap/scan_folders.rs | 24 +++++++------------ src/sql/migrations.rs | 11 ++++----- 7 files changed, 30 insertions(+), 115 deletions(-) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index ab86e3a3a6..484c17ddf4 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -269,7 +269,7 @@ def test_enable_mvbox_move(acfactory, lp): assert ac2._evtracker.wait_next_incoming_message().text == "message1" -def test_mvbox_thread_and_sentbox(acfactory, lp): +def test_mvbox_thread_and_trash(acfactory, lp): lp.sec("ac1: start with mvbox thread") ac1 = acfactory.new_online_configuring_account(mvbox_move=True) @@ -279,8 +279,8 @@ def test_mvbox_thread_and_sentbox(acfactory, lp): lp.sec("ac2 and ac1: waiting for configuration") acfactory.bring_accounts_online() - lp.sec("ac1: create sentbox") - ac1.direct_imap.create_folder("Sent") + lp.sec("ac1: create trash") + ac1.direct_imap.create_folder("Trash") ac1.set_config("scan_all_folders_debounce_secs", "0") ac1.stop_io() ac1.start_io() @@ -290,7 +290,7 @@ def test_mvbox_thread_and_sentbox(acfactory, lp): assert ac2._evtracker.wait_next_incoming_message().text == "message1" assert ac1.get_config("configured_mvbox_folder") == "DeltaChat" - while ac1.get_config("configured_sentbox_folder") != "Sent": + while ac1.get_config("configured_trash_folder") != "Trash": ac1._evtracker.get_matching("DC_EVENT_CONNECTIVITY_CHANGED") @@ -834,9 +834,9 @@ def test_no_draft_if_cant_send(acfactory): def test_dont_show_emails(acfactory, lp): """Most mailboxes have a "Drafts" folder where constantly new emails appear but we don't actually want to show them. - So: If it's outgoing AND there is no Received header AND it's not in the sentbox, then ignore the email. + So: If it's outgoing AND there is no Received header, then ignore the email. - If the draft email is sent out later (i.e. moved to "Sent"), it must be shown. + If the draft email is sent out and received later (i.e. it's in "Inbox"), it must be shown. Also, test that unknown emails in the Spam folder are not shown.""" ac1 = acfactory.new_online_configuring_account() @@ -845,7 +845,6 @@ def test_dont_show_emails(acfactory, lp): acfactory.wait_configured(ac1) ac1.direct_imap.create_folder("Drafts") - ac1.direct_imap.create_folder("Sent") ac1.direct_imap.create_folder("Spam") ac1.direct_imap.create_folder("Junk") @@ -861,21 +860,7 @@ def test_dont_show_emails(acfactory, lp): Message-ID: Content-Type: text/plain; charset=utf-8 - message in Drafts that is moved to Sent later - """.format( - ac1.get_config("configured_addr"), - ), - ) - ac1.direct_imap.append( - "Sent", - """ - From: ac1 <{}> - Subject: subj - To: alice@example.org - Message-ID: - Content-Type: text/plain; charset=utf-8 - - message in Sent + message in Drafts received later """.format( ac1.get_config("configured_addr"), ), @@ -955,14 +940,13 @@ def test_dont_show_emails(acfactory, lp): lp.sec("All prepared, now let DC find the message") ac1.start_io() - msg = ac1._evtracker.wait_next_messages_changed() - # Wait until each folder was scanned, this is necessary for this test to test what it should test: ac1._evtracker.wait_idle_inbox_ready() - assert msg.text == "subj – message in Sent" + fresh_msgs = list(ac1.get_fresh_messages()) + msg = fresh_msgs[0] chat_msgs = msg.chat.get_messages() - assert len(chat_msgs) == 2 + assert len(chat_msgs) == 1 assert any(msg.text == "subj – Actually interesting message in Spam" for msg in chat_msgs) assert not any("unknown.address" in c.get_name() for c in ac1.get_chats()) @@ -970,16 +954,16 @@ def test_dont_show_emails(acfactory, lp): assert ac1.direct_imap.get_uid_by_message_id("spam.message@junk.org") ac1.stop_io() - lp.sec("'Send out' the draft, i.e. move it to the Sent folder, and wait for DC to display it this time") + lp.sec("'Send out' the draft by moving it to Inbox, and wait for DC to display it this time") ac1.direct_imap.select_folder("Drafts") uid = ac1.direct_imap.get_uid_by_message_id("aepiors@example.org") - ac1.direct_imap.conn.move(uid, "Sent") + ac1.direct_imap.conn.move(uid, "Inbox") ac1.start_io() msg2 = ac1._evtracker.wait_next_messages_changed() - assert msg2.text == "subj – message in Drafts that is moved to Sent later" - assert len(msg.chat.get_messages()) == 3 + assert msg2.text == "subj – message in Drafts received later" + assert len(msg.chat.get_messages()) == 2 def test_bot(acfactory, lp): diff --git a/src/config.rs b/src/config.rs index a953966c09..5aefd204f2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -281,9 +281,6 @@ pub enum Config { /// Configured folder for chat messages. ConfiguredMvboxFolder, - /// Configured "Sent" folder. - ConfiguredSentboxFolder, - /// Configured "Trash" folder. ConfiguredTrashFolder, diff --git a/src/context.rs b/src/context.rs index 87740158ac..debf7605e2 100644 --- a/src/context.rs +++ b/src/context.rs @@ -861,10 +861,6 @@ impl Context { .get_config(Config::ConfiguredInboxFolder) .await? .unwrap_or_else(|| "".to_string()); - let configured_sentbox_folder = self - .get_config(Config::ConfiguredSentboxFolder) - .await? - .unwrap_or_else(|| "".to_string()); let configured_mvbox_folder = self .get_config(Config::ConfiguredMvboxFolder) .await? @@ -960,7 +956,6 @@ impl Context { folders_configured.to_string(), ); res.insert("configured_inbox_folder", configured_inbox_folder); - res.insert("configured_sentbox_folder", configured_sentbox_folder); res.insert("configured_mvbox_folder", configured_mvbox_folder); res.insert("configured_trash_folder", configured_trash_folder); res.insert("mdns_enabled", mdns_enabled.to_string()); diff --git a/src/imap.rs b/src/imap.rs index 1310bf2432..0d71e9a647 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -144,7 +144,6 @@ pub enum FolderMeaning { Spam, Inbox, Mvbox, - Sent, Trash, Drafts, @@ -164,7 +163,6 @@ impl FolderMeaning { FolderMeaning::Spam => None, FolderMeaning::Inbox => Some(Config::ConfiguredInboxFolder), FolderMeaning::Mvbox => Some(Config::ConfiguredMvboxFolder), - FolderMeaning::Sent => Some(Config::ConfiguredSentboxFolder), FolderMeaning::Trash => Some(Config::ConfiguredTrashFolder), FolderMeaning::Drafts => None, FolderMeaning::Virtual => None, @@ -790,9 +788,6 @@ impl Imap { context: &Context, session: &mut Session, ) -> Result<()> { - add_all_recipients_as_contacts(context, session, Config::ConfiguredSentboxFolder) - .await - .context("failed to get recipients from the sentbox")?; add_all_recipients_as_contacts(context, session, Config::ConfiguredMvboxFolder) .await .context("failed to get recipients from the movebox")?; @@ -1980,7 +1975,7 @@ async fn spam_target_folder_cfg( } } -/// Returns `ConfiguredInboxFolder`, `ConfiguredMvboxFolder` or `ConfiguredSentboxFolder` if +/// Returns `ConfiguredInboxFolder` or `ConfiguredMvboxFolder` if /// the message needs to be moved from `folder`. Otherwise returns `None`. pub async fn target_folder_cfg( context: &Context, @@ -2067,38 +2062,6 @@ async fn needs_move_to_mvbox( // but sth. different in others - a hard job. fn get_folder_meaning_by_name(folder_name: &str) -> FolderMeaning { // source: - const SENT_NAMES: &[&str] = &[ - "sent", - "sentmail", - "sent objects", - "gesendet", - "Sent Mail", - "Sendte e-mails", - "Enviados", - "Messages envoyés", - "Messages envoyes", - "Posta inviata", - "Verzonden berichten", - "Wyslane", - "E-mails enviados", - "Correio enviado", - "Enviada", - "Enviado", - "Gönderildi", - "Inviati", - "Odeslaná pošta", - "Sendt", - "Skickat", - "Verzonden", - "Wysłane", - "Éléments envoyés", - "Απεσταλμένα", - "Отправленные", - "寄件備份", - "已发送邮件", - "送信済み", - "보낸편지함", - ]; const SPAM_NAMES: &[&str] = &[ "spam", "junk", @@ -2163,9 +2126,7 @@ fn get_folder_meaning_by_name(folder_name: &str) -> FolderMeaning { ]; let lower = folder_name.to_lowercase(); - if SENT_NAMES.iter().any(|s| s.to_lowercase() == lower) { - FolderMeaning::Sent - } else if SPAM_NAMES.iter().any(|s| s.to_lowercase() == lower) { + if SPAM_NAMES.iter().any(|s| s.to_lowercase() == lower) { FolderMeaning::Spam } else if DRAFT_NAMES.iter().any(|s| s.to_lowercase() == lower) { FolderMeaning::Drafts @@ -2180,7 +2141,6 @@ fn get_folder_meaning_by_attrs(folder_attrs: &[NameAttribute]) -> FolderMeaning for attr in folder_attrs { match attr { NameAttribute::Trash => return FolderMeaning::Trash, - NameAttribute::Sent => return FolderMeaning::Sent, NameAttribute::Junk => return FolderMeaning::Spam, NameAttribute::Drafts => return FolderMeaning::Drafts, NameAttribute::All | NameAttribute::Flagged => return FolderMeaning::Virtual, diff --git a/src/imap/imap_tests.rs b/src/imap/imap_tests.rs index 421f7e1482..304b9b5e20 100644 --- a/src/imap/imap_tests.rs +++ b/src/imap/imap_tests.rs @@ -3,17 +3,6 @@ use crate::test_utils::TestContext; #[test] fn test_get_folder_meaning_by_name() { - assert_eq!(get_folder_meaning_by_name("Gesendet"), FolderMeaning::Sent); - assert_eq!(get_folder_meaning_by_name("GESENDET"), FolderMeaning::Sent); - assert_eq!(get_folder_meaning_by_name("gesendet"), FolderMeaning::Sent); - assert_eq!( - get_folder_meaning_by_name("Messages envoyés"), - FolderMeaning::Sent - ); - assert_eq!( - get_folder_meaning_by_name("mEsSaGes envoyÉs"), - FolderMeaning::Sent - ); assert_eq!(get_folder_meaning_by_name("xxx"), FolderMeaning::Unknown); assert_eq!(get_folder_meaning_by_name("SPAM"), FolderMeaning::Spam); assert_eq!(get_folder_meaning_by_name("Trash"), FolderMeaning::Trash); @@ -119,9 +108,6 @@ async fn check_target_folder_combination( t.ctx .set_config(Config::ConfiguredMvboxFolder, Some("DeltaChat")) .await?; - t.ctx - .set_config(Config::ConfiguredSentboxFolder, Some("Sent")) - .await?; t.ctx .set_config(Config::MvboxMove, Some(if mvbox_move { "1" } else { "0" })) .await?; diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index d123cfc968..0d743e2d28 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -84,21 +84,15 @@ impl Imap { } } - // Set configs for necessary folders. Or reset if the folder was deleted. - for conf in [ - Config::ConfiguredSentboxFolder, - Config::ConfiguredTrashFolder, - ] { - let val = folder_configs.get(&conf).map(|s| s.as_str()); - let interrupt = conf == Config::ConfiguredTrashFolder - && val.is_some() - && context.get_config(conf).await?.is_none(); - context.set_config_internal(conf, val).await?; - if interrupt { - // `Imap::fetch_move_delete()` is possible now for other folders (NB: we are in the - // Inbox loop). - context.scheduler.interrupt_oboxes().await; - } + // Set config for the Trash folder. Or reset if the folder was deleted. + let conf = Config::ConfiguredTrashFolder; + let val = folder_configs.get(&conf).map(|s| s.as_str()); + let interrupt = val.is_some() && context.get_config(conf).await?.is_none(); + context.set_config_internal(conf, val).await?; + if interrupt { + // `Imap::fetch_move_delete()`, particularly message deletion, is possible now for other + // folders (NB: we are in the Inbox loop). + context.scheduler.interrupt_oboxes().await; } info!(context, "Found folders: {folder_names:?}."); diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 4a7c40e911..3ddbe1e9c8 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -401,19 +401,18 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#, .await?; } if dbversion < 73 { - use Config::*; sql.execute( r#" CREATE TABLE imap_sync (folder TEXT PRIMARY KEY, uidvalidity INTEGER DEFAULT 0, uid_next INTEGER DEFAULT 0);"#, () ) .await?; - for c in &[ - ConfiguredInboxFolder, - ConfiguredSentboxFolder, - ConfiguredMvboxFolder, + for c in [ + "configured_inbox_folder", + "configured_sentbox_folder", + "configured_mvbox_folder", ] { - if let Some(folder) = context.get_config(*c).await? { + if let Some(folder) = context.sql.get_raw_config(c).await? { let (uid_validity, last_seen_uid) = imap::get_config_last_seen_uid(context, &folder).await?; if last_seen_uid > 0 {