From 97853c3660153f9661cc4c32e19e13939140b280 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Mon, 31 Jan 2022 13:39:48 +0100 Subject: [PATCH] Flub/watch mvbox only (#3028) * Make set_config() look a bit nicer * Add OnlyFetchMvbox option * Add test for the config * Add option to only watch mvbox This is supposed to support having a server-side rule which moves emails to the mvbox already. The new option makes sure the mvbox is wathched and also makes sure no messages are feched from folders other than the mvbox and the spam folder if enabled. It does not interact with the other settings. * Fixup ignore conditions * Cleanup some bits * Watch the mvbox when `WatchMvboxOnly` is set * Rename back to only_fetch_mvbox (flub said it's OK for him) * typo * clippy, more typos Co-authored-by: Hocuri --- CHANGELOG.md | 3 +++ deltachat-ffi/deltachat.h | 6 ++++++ src/config.rs | 24 +++++++++++++++--------- src/configure.rs | 2 +- src/context.rs | 2 ++ src/imap.rs | 26 +++++++++++++++++++++++++- src/imap/idle.rs | 1 - src/imap/scan_folders.rs | 26 ++++++++++++++------------ src/scheduler.rs | 2 +- src/scheduler/connectivity.rs | 20 +++++--------------- 10 files changed, 72 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b747891d..947a633a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +### API changes +- added `only_fetch_mvbox` config #3028 + ### Changes - don't watch Sent folder by default #3025 - use webxdc app name in chatlist/quotes/replies etc. #3027 diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 391ce1af8..680972413 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -343,6 +343,12 @@ char* dc_get_blobdir (const dc_context_t* context); * and watch the `DeltaChat` folder for updates (default), * 0=do not move chat-messages * changes require restarting IO by calling dc_stop_io() and then dc_start_io(). + * - `only_fetch_mvbox` + * = 1=Do not fetch messages from folders other than the + * `DeltaChat` folder. Messages will still be fetched from the + * spam folder and `sendbox_watch` will also still be respected + * if enabled. + * 0=watch all folders normally (default) * - `show_emails` = DC_SHOW_EMAILS_OFF (0)= * show direct replies to chats only (default), * DC_SHOW_EMAILS_ACCEPTED_CONTACTS (1)= diff --git a/src/config.rs b/src/config.rs index 7ab9a4852..8239d2af1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -74,6 +74,13 @@ pub enum Config { #[strum(props(default = "0"))] SentboxMove, // If `MvboxMove` is true, this config is ignored. Currently only used in tests. + /// Watch for new messages in the "Mvbox" (aka DeltaChat folder) only. + /// + /// This will not entirely disable other folders, e.g. the spam folder will also still + /// be watched for new messages. + #[strum(props(default = "0"))] + OnlyFetchMvbox, + #[strum(props(default = "0"))] // also change ShowEmails.default() on changes ShowEmails, @@ -225,6 +232,11 @@ impl Context { Ok(self.get_config_int(key).await? != 0) } + pub(crate) async fn should_watch_mvbox(&self) -> Result { + Ok(self.get_config_bool(Config::MvboxMove).await? + || self.get_config_bool(Config::OnlyFetchMvbox).await?) + } + /// Gets configured "delete_server_after" value. /// /// `None` means never delete the message, `Some(0)` means delete @@ -281,31 +293,25 @@ impl Context { } } self.emit_event(EventType::SelfavatarChanged); - Ok(()) } Config::DeleteDeviceAfter => { - let ret = self - .sql - .set_raw_config(key, value) - .await - .map_err(Into::into); + let ret = self.sql.set_raw_config(key, value).await; // Force chatlist reload to delete old messages immediately. self.emit_event(EventType::MsgsChanged { msg_id: MsgId::new(0), chat_id: ChatId::new(0), }); - ret + ret? } Config::Displayname => { let value = value.map(improve_single_line_input); self.sql.set_raw_config(key, value.as_deref()).await?; - Ok(()) } _ => { self.sql.set_raw_config(key, value).await?; - Ok(()) } } + Ok(()) } pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> { diff --git a/src/configure.rs b/src/configure.rs index 4d86997e7..8adb30a65 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -443,7 +443,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> { progress!(ctx, 900); - let create_mvbox = ctx.get_config_bool(Config::MvboxMove).await?; + let create_mvbox = ctx.should_watch_mvbox().await?; imap.configure_folders(ctx, create_mvbox).await?; diff --git a/src/context.rs b/src/context.rs index 3ed0278fd..93262e564 100644 --- a/src/context.rs +++ b/src/context.rs @@ -358,6 +358,7 @@ impl Context { let sentbox_watch = self.get_config_int(Config::SentboxWatch).await?; let mvbox_move = self.get_config_int(Config::MvboxMove).await?; let sentbox_move = self.get_config_int(Config::SentboxMove).await?; + let only_fetch_mvbox = self.get_config_int(Config::OnlyFetchMvbox).await?; let folders_configured = self .sql .get_raw_config_int("folders_configured") @@ -422,6 +423,7 @@ impl Context { res.insert("sentbox_watch", sentbox_watch.to_string()); res.insert("mvbox_move", mvbox_move.to_string()); res.insert("sentbox_move", sentbox_move.to_string()); + res.insert("only_fetch_mvbox", only_fetch_mvbox.to_string()); res.insert("folders_configured", folders_configured.to_string()); res.insert("configured_sentbox_folder", configured_sentbox_folder); res.insert("configured_mvbox_folder", configured_mvbox_folder); diff --git a/src/imap.rs b/src/imap.rs index b36b448f8..2b2cc705f 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -664,6 +664,11 @@ impl Imap { folder: &str, fetch_existing_msgs: bool, ) -> Result { + if should_ignore_folder(context, folder).await? { + info!(context, "Not fetching from {}", folder); + return Ok(false); + } + let new_emails = self.select_with_uidvalidity(context, folder).await?; if !new_emails && !fetch_existing_msgs { @@ -1636,7 +1641,11 @@ async fn spam_target_folder( } } - if needs_move_to_mvbox(context, headers).await? { + if needs_move_to_mvbox(context, headers).await? + // 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? + { Ok(Some(Config::ConfiguredMvboxFolder)) } else if needs_move_to_sentbox(context, folder, headers).await? { Ok(Some(Config::ConfiguredSentboxFolder)) @@ -2118,6 +2127,21 @@ pub async fn get_config_last_seen_uid(context: &Context, folder: &str) -> Result } } +/// Whether to ignore fetching messages from a folder. +/// +/// This caters for the [`Config::OnlyFetchMvbox`] setting which means mails from folders +/// not explicitly watched should not be fetched. +async fn should_ignore_folder(context: &Context, folder: &str) -> Result { + 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? || context.is_spam_folder(folder).await?)) +} + /// Builds a list of sequence/uid sets. The returned sets have each no more than around 1000 /// characters because according to /// command lines should not be much more than 1000 chars (servers should allow at least 8000 chars) diff --git a/src/imap/idle.rs b/src/imap/idle.rs index ffff87070..f325c3648 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -157,7 +157,6 @@ impl Imap { // in anything. If so, we behave as if IDLE had data but // will have already fetched the messages so perform_*_fetch // will not find any new. - match self.fetch_new_messages(context, &watch_folder, false).await { Ok(res) => { info!(context, "fetch_new_messages returned {:?}", res); diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index bf0e38480..221943f65 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -103,20 +103,22 @@ 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); + } + Ok(res) +} + pub(crate) async fn get_watched_folders(context: &Context) -> Result> { let mut res = Vec::new(); - if let Some(inbox_folder) = context.get_config(Config::ConfiguredInboxFolder).await? { - res.push(inbox_folder); - } - let folder_watched_configured = &[ - (Config::SentboxWatch, Config::ConfiguredSentboxFolder), - (Config::MvboxMove, Config::ConfiguredMvboxFolder), - ]; - for (watched, configured) in folder_watched_configured { - if context.get_config_bool(*watched).await? { - if let Some(folder) = context.get_config(*configured).await? { - res.push(folder); - } + for folder_config in get_watched_folder_configs(context).await? { + if let Some(folder) = context.get_config(folder_config).await? { + res.push(folder); } } Ok(res) diff --git a/src/scheduler.rs b/src/scheduler.rs index 0cbfd5e92..ade60194a 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -378,7 +378,7 @@ impl Scheduler { })) }; - if ctx.get_config_bool(Config::MvboxMove).await? { + if ctx.should_watch_mvbox().await? { let ctx = ctx.clone(); mvbox_handle = Some(task::spawn(async move { simple_imap_loop( diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index 63fd249ef..513f8bc33 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -5,6 +5,7 @@ use async_std::sync::{Mutex, RwLockReadGuard}; use crate::dc_tools::time; use crate::events::EventType; +use crate::imap::scan_folders::get_watched_folder_configs; use crate::quota::{ QUOTA_ERROR_THRESHOLD_PERCENTAGE, QUOTA_MAX_AGE_SECONDS, QUOTA_WARN_THRESHOLD_PERCENTAGE, }; @@ -362,17 +363,14 @@ impl Context { [ ( Config::ConfiguredInboxFolder, - None, inbox.state.connectivity.clone(), ), ( Config::ConfiguredMvboxFolder, - Some(Config::MvboxMove), mvbox.state.connectivity.clone(), ), ( Config::ConfiguredSentboxFolder, - Some(Config::SentboxWatch), sentbox.state.connectivity.clone(), ), ], @@ -391,20 +389,12 @@ impl Context { // - "Sent": Connected // ============================================================================================= + let watched_folders = get_watched_folder_configs(self).await?; ret += &format!("

{}

    ", stock_str::incoming_messages(self).await); - for (folder, watch, state) in &folders_states { - let w = if let Some(watch_config) = *watch { - self.get_config(watch_config) - .await - .ok_or_log(self) - .flatten() - == Some("1".to_string()) - } else { - true - }; - + for (folder, state) in &folders_states { let mut folder_added = false; - if w { + + if watched_folders.contains(folder) { let f = self.get_config(*folder).await.ok_or_log(self).flatten(); if let Some(foldername) = f {