diff --git a/src/config.rs b/src/config.rs index 71a967be5..a112cc798 100644 --- a/src/config.rs +++ b/src/config.rs @@ -57,7 +57,7 @@ pub enum ConfigItem { E2eeEnabled(String), ImapCertificateChecks(String), ImapFolder(String), - InboxWatch(String), + InboxWatch(bool), MailPort(String), MailPw(String), MailServer(String), @@ -109,7 +109,7 @@ impl ConfigKey { Self::BccSelf => Some(ConfigItem::BccSelf(String::from("1"))), Self::E2eeEnabled => Some(ConfigItem::E2eeEnabled(String::from("1"))), Self::ImapFolder => Some(ConfigItem::ImapFolder(String::from("INBOX"))), - Self::InboxWatch => Some(ConfigItem::InboxWatch(String::from("1"))), + Self::InboxWatch => Some(ConfigItem::InboxWatch(true)), Self::MdnsEnabled => Some(ConfigItem::MdnsEnabled(String::from("1"))), Self::MvboxMove => Some(ConfigItem::MvboxMove(String::from("1"))), Self::MvboxWatch => Some(ConfigItem::MvboxWatch(String::from("1"))), @@ -137,6 +137,7 @@ impl rusqlite::types::ToSql for ConfigItem { .map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?; rusqlite::types::Value::Text(rel_path.to_string_lossy().into_owned()) } + ConfigItem::InboxWatch(value) => rusqlite::types::Value::Integer(*value as i64), ConfigItem::Addr(value) | ConfigItem::BccSelf(value) | ConfigItem::Configured(value) @@ -159,7 +160,6 @@ impl rusqlite::types::ToSql for ConfigItem { | ConfigItem::E2eeEnabled(value) | ConfigItem::ImapCertificateChecks(value) | ConfigItem::ImapFolder(value) - | ConfigItem::InboxWatch(value) | ConfigItem::MailPort(value) | ConfigItem::MailPw(value) | ConfigItem::MailServer(value) @@ -225,6 +225,39 @@ impl Context { .map(|s| s.to_string()) .ok() }; + let to_int = |raw: rusqlite::types::ValueRef| -> Option { + match raw { + // Current way this is stored. + rusqlite::types::ValueRef::Integer(val) => Some(val), + // Backward compatibility. + rusqlite::types::ValueRef::Text(val) => std::str::from_utf8(val) + .map_err(|e| { + warn!(self, "ConfigItem {}; not UTF-8: {}", key, e); + }) + .ok() + .and_then(|v| match v.parse::() { + Ok(i) => Some(i), + Err(e) => { + warn!(self, "ConfigItem {}; not parsed as int: {}", key, e); + None + } + }), + _ => { + warn!(self, "ConfigItem {}; bad SQLite type: {:?}", key, raw); + None + } + } + }; + let to_bool = |raw: rusqlite::types::ValueRef| -> Option { + to_int(raw).and_then(|i| match i { + 0 => Some(false), + 1 => Some(true), + v => { + warn!(self, "ConfigItem {}; bad bool value: {}", key, v); + None + } + }) + }; match key { ConfigKey::Addr => to_string(raw).map(|val| ConfigItem::Addr(val)), ConfigKey::BccSelf => to_string(raw).map(|val| ConfigItem::BccSelf(val)), @@ -278,7 +311,7 @@ impl Context { to_string(raw).map(|val| ConfigItem::ImapCertificateChecks(val)) } ConfigKey::ImapFolder => to_string(raw).map(|val| ConfigItem::ImapFolder(val)), - ConfigKey::InboxWatch => to_string(raw).map(|val| ConfigItem::InboxWatch(val)), + ConfigKey::InboxWatch => to_bool(raw).map(|val| ConfigItem::InboxWatch(val)), ConfigKey::MailPort => to_string(raw).map(|val| ConfigItem::MailPort(val)), ConfigKey::MailPw => to_string(raw).map(|val| ConfigItem::MailPw(val)), ConfigKey::MailServer => to_string(raw).map(|val| ConfigItem::MailServer(val)), @@ -371,6 +404,9 @@ impl Context { pub fn get_config(&self, key: Config) -> Option { if let Some(item) = self.get_config_item(key) { let value = match item { + // Bool values. + ConfigItem::InboxWatch(value) => format!("{}", value as u32), + // String values. ConfigItem::Addr(value) | ConfigItem::BccSelf(value) | ConfigItem::Configured(value) @@ -393,7 +429,6 @@ impl Context { | ConfigItem::E2eeEnabled(value) | ConfigItem::ImapCertificateChecks(value) | ConfigItem::ImapFolder(value) - | ConfigItem::InboxWatch(value) | ConfigItem::MailPort(value) | ConfigItem::MailPw(value) | ConfigItem::MailServer(value) @@ -481,7 +516,14 @@ impl Context { ConfigKey::E2eeEnabled => ConfigItem::E2eeEnabled(v), ConfigKey::ImapCertificateChecks => ConfigItem::ImapCertificateChecks(v), ConfigKey::ImapFolder => ConfigItem::ImapFolder(v), - ConfigKey::InboxWatch => ConfigItem::InboxWatch(v), + ConfigKey::InboxWatch => { + let val = match v.parse::() { + Ok(0) => false, + Ok(1) => true, + _ => bail!("set_config for {}: not a bool: {}", key, v), + }; + ConfigItem::InboxWatch(val) + } ConfigKey::MailPort => ConfigItem::MailPort(v), ConfigKey::MailPw => ConfigItem::MailPw(v), ConfigKey::MailServer => ConfigItem::MailServer(v), @@ -643,4 +685,48 @@ mod tests { assert_eq!(avatar_cfg, avatar_src.to_str().map(|s| s.to_string())); Ok(()) } + + #[test] + fn test_config_item_bool() { + let t = test_context(Some(Box::new(logging_cb))); + + // Backwards compatible value. + t.ctx + .sql + .execute( + "INSERT INTO config (keyname, value) VALUES (?, ?)", + params![ConfigKey::InboxWatch.to_string(), "0"], + ) + .unwrap(); + let item = t.ctx.get_config_item(ConfigKey::InboxWatch).unwrap(); + assert_eq!(item, ConfigItem::InboxWatch(false)); + t.ctx + .sql + .execute( + "UPDATE config SET value=? WHERE keyname=?", + params!["1", ConfigKey::InboxWatch.to_string()], + ) + .unwrap(); + let item = t.ctx.get_config_item(ConfigKey::InboxWatch).unwrap(); + assert_eq!(item, ConfigItem::InboxWatch(true)); + t.ctx + .sql + .execute( + "UPDATE config SET value=? WHERE keyname=?", + params!["bad", ConfigKey::InboxWatch.to_string()], + ) + .unwrap(); + let item = t.ctx.get_config_item(ConfigKey::InboxWatch); + assert!(item.is_none()); + + // Normal value. + t.ctx.set_config_item(ConfigItem::InboxWatch(true)).unwrap(); + let item = t.ctx.get_config_item(ConfigKey::InboxWatch).unwrap(); + assert_eq!(item, ConfigItem::InboxWatch(true)); + t.ctx + .set_config_item(ConfigItem::InboxWatch(false)) + .unwrap(); + let item = t.ctx.get_config_item(ConfigKey::InboxWatch).unwrap(); + assert_eq!(item, ConfigItem::InboxWatch(false)); + } } diff --git a/src/context.rs b/src/context.rs index 963e1e98e..ccebbc7a7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Condvar, Mutex, RwLock}; use libc::uintptr_t; use crate::chat::*; -use crate::config::Config; +use crate::config::{Config, ConfigItem, ConfigKey}; use crate::constants::*; use crate::contact::*; use crate::error::*; @@ -269,7 +269,6 @@ impl Context { "".into() }; - let inbox_watch = self.get_config_int(Config::InboxWatch); let sentbox_watch = self.get_config_int(Config::SentboxWatch); let mvbox_watch = self.get_config_int(Config::MvboxWatch); let mvbox_move = self.get_config_int(Config::MvboxMove); @@ -299,7 +298,9 @@ impl Context { res.insert("is_configured", is_configured.to_string()); res.insert("entered_account_settings", l.to_string()); res.insert("used_account_settings", l2.to_string()); - res.insert("inbox_watch", inbox_watch.to_string()); + if let Some(ConfigItem::InboxWatch(val)) = self.get_config_item(ConfigKey::InboxWatch) { + res.insert("inbox_watch", val.to_string()); + } res.insert("sentbox_watch", sentbox_watch.to_string()); res.insert("mvbox_watch", mvbox_watch.to_string()); res.insert("mvbox_move", mvbox_move.to_string()); diff --git a/src/job.rs b/src/job.rs index 207478640..40fb84eb7 100644 --- a/src/job.rs +++ b/src/job.rs @@ -5,7 +5,7 @@ use rand::{thread_rng, Rng}; use crate::blob::BlobObject; use crate::chat; -use crate::config::Config; +use crate::config::{Config, ConfigItem, ConfigKey}; use crate::configure::*; use crate::constants::*; use crate::context::Context; @@ -368,7 +368,12 @@ pub fn job_kill_action(context: &Context, action: Action) -> bool { } pub fn perform_inbox_fetch(context: &Context) { - let use_network = context.get_config_bool(Config::InboxWatch); + let use_network = + if let Some(ConfigItem::InboxWatch(val)) = context.get_config_item(ConfigKey::InboxWatch) { + val + } else { + false + }; context .inbox_thread @@ -405,7 +410,12 @@ pub fn perform_inbox_idle(context: &Context) { ); return; } - let use_network = context.get_config_bool(Config::InboxWatch); + let use_network = + if let Some(ConfigItem::InboxWatch(val)) = context.get_config_item(Config::InboxWatch) { + val + } else { + false + }; context .inbox_thread