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 {