diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 9a064acf2..3c3beb448 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -492,6 +492,9 @@ char* dc_get_blobdir (const dc_context_t* context); * - `fetch_existing_msgs` = 1=fetch most recent existing messages on configure (default), * 0=do not fetch existing messages on configure. * In both cases, existing recipients are added to the contact database. + * - `disable_idle` = 1=disable IMAP IDLE even if the server supports it, + * 0=use IMAP IDLE if the server supports it. + * This is a developer option used for testing polling used as an IDLE fallback. * - `download_limit` = Messages up to this number of bytes are downloaded automatically. * For larger messages, only the header is downloaded and a placeholder is shown. * These messages can be downloaded fully using dc_download_full_msg() later. diff --git a/src/config.rs b/src/config.rs index da21f91d9..2d1a74ae3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -286,6 +286,12 @@ pub enum Config { #[strum(props(default = "60"))] ScanAllFoldersDebounceSecs, + /// Whether to avoid using IMAP IDLE even if the server supports it. + /// + /// This is a developer option for testing "fake idle". + #[strum(props(default = "0"))] + DisableIdle, + /// Defines the max. size (in bytes) of messages downloaded automatically. /// 0 = no limit. #[strum(props(default = "0"))] @@ -479,7 +485,8 @@ impl Context { | Config::Bot | Config::NotifyAboutWrongPw | Config::SendSyncMsgs - | Config::SignUnencrypted => { + | Config::SignUnencrypted + | Config::DisableIdle => { ensure!( matches!(value, None | Some("0") | Some("1")), "Boolean value must be either 0 or 1" diff --git a/src/context.rs b/src/context.rs index d7aac82d1..fa6214965 100644 --- a/src/context.rs +++ b/src/context.rs @@ -579,6 +579,7 @@ impl Context { let mdns_enabled = self.get_config_int(Config::MdnsEnabled).await?; let bcc_self = self.get_config_int(Config::BccSelf).await?; let send_sync_msgs = self.get_config_int(Config::SendSyncMsgs).await?; + let disable_idle = self.get_config_bool(Config::DisableIdle).await?; let prv_key_cnt = self.sql.count("SELECT COUNT(*) FROM keypairs;", ()).await?; @@ -691,6 +692,7 @@ impl Context { ); res.insert("bcc_self", bcc_self.to_string()); res.insert("send_sync_msgs", send_sync_msgs.to_string()); + res.insert("disable_idle", disable_idle.to_string()); res.insert("private_key_count", prv_key_cnt.to_string()); res.insert("public_key_count", pub_key_cnt.to_string()); res.insert("fingerprint", fingerprint_str); diff --git a/src/imap/idle.rs b/src/imap/idle.rs index fbce499b7..1cdc60bc9 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -7,7 +7,9 @@ use futures_lite::FutureExt; use super::session::Session; use super::Imap; +use crate::config::Config; use crate::imap::{client::IMAP_TIMEOUT, FolderMeaning}; +use crate::log::LogExt; use crate::{context::Context, scheduler::InterruptInfo}; const IDLE_TIMEOUT: Duration = Duration::from_secs(23 * 60); @@ -21,6 +23,10 @@ impl Session { ) -> Result<(Self, InterruptInfo)> { use futures::future::FutureExt; + if context.get_config_bool(Config::DisableIdle).await? { + bail!("IMAP IDLE is disabled"); + } + if !self.can_idle() { bail!("IMAP server does not have IDLE capability"); } @@ -163,7 +169,14 @@ impl Imap { continue; } if let Some(session) = &self.session { - if session.can_idle() { + if session.can_idle() + && !context + .get_config_bool(Config::DisableIdle) + .await + .context("Failed to get disable_idle config") + .log_err(context) + .unwrap_or_default() + { // we only fake-idled because network was gone during IDLE, probably break InterruptInfo::new(false); } diff --git a/src/scheduler.rs b/src/scheduler.rs index 796222702..ff863910f 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -574,6 +574,19 @@ async fn fetch_idle( .await; } + if ctx + .get_config_bool(Config::DisableIdle) + .await + .context("Failed to get disable_idle config") + .log_err(ctx) + .unwrap_or_default() + { + info!(ctx, "IMAP IDLE is disabled, going to fake idle."); + return connection + .fake_idle(ctx, Some(watch_folder), folder_meaning) + .await; + } + info!(ctx, "IMAP session supports IDLE, using it."); match session .idle(