diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 842cb7460..f145416d9 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -151,13 +151,7 @@ pub unsafe extern "C" fn dc_set_config( let context = &*context; let key = dc_tools::as_str(key); let value = as_opt_str(value); - if key.starts_with(".ui") { - return context.set_ui_config(key, value).is_ok() as libc::c_int; - } - match config::Config::from_str(key) { - Ok(key) => context.set_config(key, value).is_ok() as libc::c_int, - Err(_) => 0, - } + context.set_config_from_str(key, value).is_ok() as libc::c_int } #[no_mangle] @@ -173,14 +167,7 @@ pub unsafe extern "C" fn dc_get_config( let context = &*context; let key = dc_tools::as_str(key); - if key.starts_with(".ui") { - return context.get_ui_config(key).unwrap_or_default().strdup(); - } - let key = config::Config::from_str(key).expect("invalid key"); - - // TODO: Translating None to NULL would be more sensible than translating None - // to "", as it is now. - context.get_config(key).unwrap_or_default().strdup() + context.get_config_from_str(key).unwrap_or_default().strdup() } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 3df2ab041..5922afa1d 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -550,9 +550,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E } "get" => { ensure!(!arg1.is_empty(), "Argument missing."); - let key = config::Config::from_str(&arg1)?; - let val = context.get_config(key); - println!("{}={:?}", key, val); + let val = context.get_config_from_str(&arg1); + println!("{}={:?}", &arg1.to_string(), val); } "info" => { println!("{}", to_string(dc_get_info(context))); diff --git a/examples/repl/main.rs b/examples/repl/main.rs index 616386ff9..8daac20a5 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -495,7 +495,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc>) -> Result { - if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) { + if let Some(addr) = ctx.read().unwrap().get_config(&config::Config::Addr) { let oauth2_url = dc_get_oauth2_url( &ctx.read().unwrap(), &addr, diff --git a/src/config.rs b/src/config.rs index 698cc312e..ea2cb7feb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use strum::{EnumProperty, IntoEnumIterator}; use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString}; @@ -8,9 +10,11 @@ use crate::error::Error; use crate::job::*; use crate::stock::StockMessage; +pub const CONFIG_UI_PREFIX: &str = "ui."; + /// The available configuration keys. #[derive( - Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty, + Debug, Clone, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty, )] #[strum(serialize_all = "snake_case")] pub enum Config { @@ -65,11 +69,17 @@ pub enum Config { SysMsgsizeMaxRecommended, #[strum(serialize = "sys.config_keys")] SysConfigKeys, + Ui(String) } impl Context { + + pub fn get_config_from_str(&self, key: &str) -> Option { + self.get_config(&config_from_str(key)) + } + /// Get a configuration key. Returns `None` if no value is set, and no default value found. - pub fn get_config(&self, key: Config) -> Option { + pub fn get_config(&self, key: &Config) -> Option { let value = match key { Config::Selfavatar => { let rel_path = self.sql.get_config(self, key); @@ -78,6 +88,7 @@ impl Context { Config::SysVersion => Some((&*DC_VERSION_STR).clone()), Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)), Config::SysConfigKeys => Some(get_config_keys_string()), + Config::Ui(key) => self.sql.get_config(self, format!("{}{}", CONFIG_UI_PREFIX, key)), _ => self.sql.get_config(self, key), }; @@ -92,6 +103,13 @@ impl Context { } } + pub fn set_config_from_str(&self, key: &str, value: Option<&str>) -> Result<(), &str> { + if self.sql.set_config(self, config_from_str(key), value).is_err() { + return Err("Sql error"); + } + Ok(()) + } + /// Set the given config key. /// If `None` is passed as a value the value is cleared and set to the default if there is one. pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> { @@ -125,27 +143,14 @@ impl Context { }; self.sql.set_config(self, key, val) - } + }, + Config::Ui(key) => { + let key = format!("{}{}", CONFIG_UI_PREFIX, key); + self.sql.set_config(self, key, value) + }, _ => self.sql.set_config(self, key, value), } } - - pub fn set_ui_config(&self, key: &str, value: Option<&str>) -> Result<(), &str> { - if !key.starts_with("ui.") { - return Err("Ui config key has to be prefixed with 'ui.'"); - } - - if self.sql.set_config(self, key, value).is_err() { - return Err("Sql error"); - } - Ok(()) - } - pub fn get_ui_config(&self, key: &str) -> Option { - if key.starts_with("ui.") { - return self.sql.get_config(self, key); - } - None - } } /// Returns all available configuration keys concated together. @@ -159,12 +164,23 @@ fn get_config_keys_string() -> String { format!(" {} ", keys) } +fn config_from_str(key: &str) -> Result { + if key.starts_with(CONFIG_UI_PREFIX) { + Config::Ui(key[CONFIG_UI_PREFIX.len()-1..].to_string()) + } else { + if let Ok(config) = Config::from_str(key) { + config + } else { + Err("invalid key") + } + } +} + #[cfg(test)] mod tests { use super::*; - - use std::str::FromStr; use std::string::ToString; + use crate::test_utils::*; #[test] fn test_to_string() { @@ -182,4 +198,20 @@ mod tests { fn test_default_prop() { assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX")); } + + #[test] + fn test_config_from_str() { + assert_eq!(config_from_str("addr"), Config::Addr); + assert_eq!(config_from_str("addrxyz"), None); + } + + #[test] + fn test_get_config_from_str() { + let t = dummy_context(); + assert_eq!(t.ctx.set_config_from_str("addr", Some("foo@bar.bar")), Ok(())); + assert_eq!(t.ctx.get_config_from_str("addr").unwrap(), "foo@bar.bar"); + + assert_eq!(t.ctx.set_config_from_str("ui.desktop.some_string", Some("foobar")), Ok(())); + assert_eq!(t.ctx.get_config_from_str("ui.desktop.some_string").unwrap(), "foobar"); + } } diff --git a/src/contact.rs b/src/contact.rs index c67a46a2f..db65c7b82 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -146,7 +146,7 @@ impl Contact { name: context.stock_str(StockMessage::SelfMsg).into(), authname: "".into(), addr: context - .get_config(Config::ConfiguredAddr) + .get_config(&Config::ConfiguredAddr) .unwrap_or_default(), blocked: false, origin: Origin::Unknown, @@ -257,7 +257,7 @@ impl Contact { let addr_normalized = addr_normalize(addr.as_ref()); let addr_self = context - .get_config(Config::ConfiguredAddr) + .get_config(&Config::ConfiguredAddr) .unwrap_or_default(); if addr_normalized == addr_self { @@ -295,7 +295,7 @@ impl Contact { let addr = addr_normalize(addr.as_ref()); let addr_self = context - .get_config(Config::ConfiguredAddr) + .get_config(&Config::ConfiguredAddr) .unwrap_or_default(); if addr == addr_self { @@ -456,7 +456,7 @@ impl Contact { query: Option>, ) -> Result> { let self_addr = context - .get_config(Config::ConfiguredAddr) + .get_config(&Config::ConfiguredAddr) .unwrap_or_default(); let mut add_self = false; @@ -499,7 +499,7 @@ impl Contact { }, )?; - let self_name = context.get_config(Config::Displayname).unwrap_or_default(); + let self_name = context.get_config(&Config::Displayname).unwrap_or_default(); let self_name2 = context.stock_str(StockMessage::SelfMsg); if let Some(query) = query { @@ -765,7 +765,7 @@ impl Contact { /// using dc_set_config(context, "selfavatar", image). pub fn get_profile_image(&self, context: &Context) -> Option { if self.id == DC_CONTACT_ID_SELF { - if let Some(p) = context.get_config(Config::Selfavatar) { + if let Some(p) = context.get_config(&Config::Selfavatar) { return Some(PathBuf::from(p)); } } @@ -1026,7 +1026,7 @@ pub fn addr_cmp(addr1: impl AsRef, addr2: impl AsRef) -> bool { pub fn addr_equals_self(context: &Context, addr: impl AsRef) -> bool { if !addr.as_ref().is_empty() { let normalized_addr = addr_normalize(addr.as_ref()); - if let Some(self_addr) = context.get_config(Config::ConfiguredAddr) { + if let Some(self_addr) = context.get_config(&Config::ConfiguredAddr) { return normalized_addr == self_addr; } } diff --git a/src/e2ee.rs b/src/e2ee.rs index d752ed78f..221544742 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -1025,7 +1025,7 @@ unsafe fn contains_report(mime: *mut mailmime) -> bool { /// [Config::ConfiguredAddr] is configured, this address is returned. pub fn ensure_secret_key_exists(context: &Context) -> Result { let self_addr = context - .get_config(Config::ConfiguredAddr) + .get_config(&Config::ConfiguredAddr) .ok_or(format_err!(concat!( "Failed to get self address, ", "cannot ensure secret key if not configured." diff --git a/tests/stress.rs b/tests/stress.rs index 6a307955a..bf3b22ee3 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -128,7 +128,7 @@ unsafe fn stress_functions(context: &Context) { free(fn1 as *mut libc::c_void); } - let res = context.get_config(config::Config::SysConfigKeys).unwrap(); + let res = context.get_config(&config::Config::SysConfigKeys).unwrap(); assert!(!res.contains(" probably_never_a_key ")); assert!(res.contains(" addr "));