refactor: cleanup config values and move to their own file

This commit is contained in:
dignifiedquire
2019-07-14 23:57:05 +02:00
parent 6e73b3728d
commit 668c647fdd
10 changed files with 230 additions and 174 deletions

View File

@@ -39,6 +39,8 @@ rusqlite = { version = "0.19", features = ["bundled"] }
addr = "0.2.0"
r2d2_sqlite = "0.11.0"
r2d2 = "0.8.5"
strum = "0.15.0"
strum_macros = "0.15.0"
[dev-dependencies]
tempfile = "3.0"

View File

@@ -91,7 +91,7 @@ pub unsafe extern "C" fn dc_set_config(
assert!(!key.is_null(), "invalid key");
let context = &*context;
context::dc_set_config(context, dc_tools::as_str(key), as_opt_str(value))
config::set(context, dc_tools::as_str(key), as_opt_str(value))
}
#[no_mangle]
@@ -103,7 +103,7 @@ pub unsafe extern "C" fn dc_get_config(
assert!(!key.is_null(), "invalid key");
let context = &*context;
into_cstring(context::dc_get_config(context, dc_tools::as_str(key)))
into_cstring(config::get(context, dc_tools::as_str(key)))
}
#[no_mangle]

View File

@@ -1,3 +1,4 @@
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_array::*;
@@ -481,7 +482,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
},
"auth" => {
if 0 == S_IS_AUTH {
let is_pw = dc_get_config(context, "mail_pw");
let is_pw = config::get(context, "mail_pw");
if arg1 == is_pw {
S_IS_AUTH = 1;
} else {
@@ -602,13 +603,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"set" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
ensure!(
0 != dc_set_config(context, &arg1, Some(&arg2)),
0 != config::set(context, &arg1, Some(&arg2)),
"Set config failed"
);
}
"get" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
let val = dc_get_config(context, &arg1);
let val = config::get(context, &arg1);
println!("{}={}", arg1, val);
}
"info" => {

View File

@@ -17,6 +17,7 @@ use std::borrow::Cow::{self, Borrowed, Owned};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_configure::*;
@@ -514,7 +515,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
dc_configure(&ctx.read().unwrap());
}
"oauth2" => {
let addr = dc_get_config(&ctx.read().unwrap(), "addr");
let addr = config::get(&ctx.read().unwrap(), "addr");
if addr.is_empty() {
println!("oauth2: set addr first.");
} else {

View File

@@ -5,6 +5,7 @@ use std::sync::{Arc, RwLock};
use std::{thread, time};
use tempfile::tempdir;
use deltachat::config;
use deltachat::constants::Event;
use deltachat::context::*;
use deltachat::dc_chat::*;
@@ -85,8 +86,8 @@ fn main() {
let args = std::env::args().collect::<Vec<String>>();
assert_eq!(args.len(), 2, "missing password");
let pw = args[1].clone();
dc_set_config(&ctx, "addr", Some("d@testrun.org"));
dc_set_config(&ctx, "mail_pw", Some(&pw));
config::set(&ctx, "addr", Some("d@testrun.org"));
config::set(&ctx, "mail_pw", Some(&pw));
dc_configure(&ctx);
thread::sleep(duration);

212
src/config.rs Normal file
View File

@@ -0,0 +1,212 @@
use std::str::FromStr;
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
use crate::dc_job::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::sql;
use crate::x::*;
/// The available configuration keys.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty,
)]
#[strum(serialize_all = "snake_case")]
pub enum Config {
Addr,
MailServer,
MailUser,
MailPw,
MailPort,
SendServer,
SendUser,
SendPw,
SendPort,
ServerFlags,
#[strum(props(default = "INBOX"))]
ImapFolder,
Displayname,
Selfstatus,
Selfavatar,
#[strum(props(default = "1"))]
E2eeEnabled,
#[strum(props(default = "1"))]
MdnsEnabled,
InboxWatch,
#[strum(props(default = "1"))]
SentboxWatch,
#[strum(props(default = "1"))]
MvboxWatch,
#[strum(props(default = "1"))]
MvboxMove,
#[strum(props(default = "0"))]
ShowEmails,
SaveMimeHeaders,
ConfiguredAddr,
ConfiguredMailServer,
ConfiguredMailUser,
ConfiguredMailPw,
ConfiguredMailPort,
ConfiguredSendServer,
ConfiguredSendUser,
ConfiguredSendPw,
ConfiguredSendPort,
ConfiguredServerFlags,
Configured,
}
// deprecated
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter)]
pub enum SysConfig {
#[strum(serialize = "sys.version")]
Version,
#[strum(serialize = "sys.msgsize_max_recommended")]
MsgsizeMaxRecommended,
#[strum(serialize = "sys.config_keys")]
ConfigKeys,
}
/// Get a configuration key.
/// Returns "" when the key is invalid, or no default was found.
pub fn get(context: &Context, key: impl AsRef<str>) -> String {
let key = key.as_ref();
if key.starts_with("sys.") {
return get_sys_config_str(key);
}
match Config::from_str(key) {
Ok(config_key) => {
let value = match config_key {
Config::Selfavatar => {
let rel_path = sql::get_config(context, &context.sql, key, None);
rel_path.map(|p| {
let v = unsafe { dc_get_abs_path(context, to_cstring(p).as_ptr()) };
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
}
_ => sql::get_config(context, &context.sql, key, None),
};
if value.is_some() {
return value.unwrap();
}
// Default values
match config_key {
Config::Selfstatus => {
let s = unsafe { dc_stock_str(context, 13) };
let res = to_string(s);
unsafe { free(s as *mut _) };
res
}
_ => config_key
.get_str("default")
.unwrap_or_default()
.to_string(),
}
}
Err(_) => "".into(),
}
}
fn get_sys_config_str(key: impl AsRef<str>) -> String {
match SysConfig::from_str(key.as_ref()) {
Ok(SysConfig::Version) => std::str::from_utf8(DC_VERSION_STR).unwrap().into(),
Ok(SysConfig::MsgsizeMaxRecommended) => format!("{}", 24 * 1024 * 1024 / 4 * 3),
Ok(SysConfig::ConfigKeys) => get_config_keys_str(),
Err(_) => "".into(),
}
}
fn get_config_keys_str() -> String {
let keys = Config::iter().fold(String::new(), |mut acc, key| {
acc += key.as_ref();
acc += " ";
acc
});
let sys_keys = SysConfig::iter().fold(String::new(), |mut acc, key| {
acc += key.as_ref();
acc += " ";
acc
});
format!(" {} {} ", keys, sys_keys)
}
/// Set the given config key.
/// Returns `1` on success and `0` on failure.
pub fn set(context: &Context, key: impl AsRef<str>, value: Option<&str>) -> libc::c_int {
let mut ret = 0;
// regular keys
match Config::from_str(key.as_ref()) {
Ok(Config::Selfavatar) if value.is_some() => {
let mut rel_path = unsafe { dc_strdup(to_cstring(value.unwrap()).as_ptr()) };
if 0 != unsafe { dc_make_rel_and_copy(context, &mut rel_path) } {
ret = sql::set_config(context, &context.sql, key, Some(as_str(rel_path)));
}
unsafe { free(rel_path as *mut libc::c_void) };
}
Ok(Config::InboxWatch) => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_imap_idle(context) };
}
Ok(Config::SentboxWatch) => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_sentbox_idle(context) };
}
Ok(Config::MvboxWatch) => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_mvbox_idle(context) };
}
Ok(Config::Selfstatus) => {
let def = unsafe { dc_stock_str(context, 13) };
let val = if value.is_none() || value.unwrap() == as_str(def) {
None
} else {
value
};
ret = sql::set_config(context, &context.sql, key, val);
unsafe { free(def as *mut libc::c_void) };
}
Ok(_) => {
ret = sql::set_config(context, &context.sql, key, value);
}
Err(_) => {}
}
ret
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use std::string::ToString;
#[test]
fn test_to_string() {
assert_eq!(Config::MailServer.to_string(), "mail_server");
assert_eq!(Config::from_str("mail_server"), Ok(Config::MailServer));
assert_eq!(SysConfig::ConfigKeys.to_string(), "sys.config_keys");
assert_eq!(
SysConfig::from_str("sys.config_keys"),
Ok(SysConfig::ConfigKeys)
);
}
#[test]
fn test_default_prop() {
assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX"));
}
}

View File

@@ -11,7 +11,6 @@ use crate::dc_lot::dc_lot_t;
use crate::dc_move::*;
use crate::dc_msg::*;
use crate::dc_receive_imf::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::imap::*;
use crate::key::*;
@@ -20,49 +19,6 @@ use crate::sql::{self, Sql};
use crate::types::*;
use crate::x::*;
const CONFIG_KEYS: [&'static str; 33] = [
"addr",
"mail_server",
"mail_user",
"mail_pw",
"mail_port",
"send_server",
"send_user",
"send_pw",
"send_port",
"server_flags",
"imap_folder",
"displayname",
"selfstatus",
"selfavatar",
"e2ee_enabled",
"mdns_enabled",
"inbox_watch",
"sentbox_watch",
"mvbox_watch",
"mvbox_move",
"show_emails",
"save_mime_headers",
"configured_addr",
"configured_mail_server",
"configured_mail_user",
"configured_mail_pw",
"configured_mail_port",
"configured_send_server",
"configured_send_user",
"configured_send_pw",
"configured_send_port",
"configured_server_flags",
"configured",
];
// deprecated
const SYS_CONFIG_KEYS: [&'static str; 3] = [
"sys.version",
"sys.msgsize_max_recommended",
"sys.config_keys",
];
#[repr(C)]
pub struct Context {
pub userdata: *mut libc::c_void,
@@ -412,129 +368,10 @@ pub unsafe fn dc_get_blobdir(context: &Context) -> *mut libc::c_char {
dc_strdup(*context.blobdir.clone().read().unwrap())
}
pub fn dc_set_config(context: &Context, key: impl AsRef<str>, value: Option<&str>) -> libc::c_int {
let mut ret = 0;
if !is_settable_config_key(key.as_ref()) {
return 0;
}
match key.as_ref() {
"selfavatar" if value.is_some() => {
let mut rel_path = unsafe { dc_strdup(to_cstring(value.unwrap()).as_ptr()) };
if 0 != unsafe { dc_make_rel_and_copy(context, &mut rel_path) } {
ret = sql::set_config(context, &context.sql, key, Some(as_str(rel_path)));
}
unsafe { free(rel_path as *mut libc::c_void) };
}
"inbox_watch" => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_imap_idle(context) };
}
"sentbox_watch" => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_sentbox_idle(context) };
}
"mvbox_watch" => {
ret = sql::set_config(context, &context.sql, key, value);
unsafe { dc_interrupt_mvbox_idle(context) };
}
"selfstatus" => {
let def = unsafe { dc_stock_str(context, 13) };
let val = if value.is_none() || value.unwrap() == as_str(def) {
None
} else {
value
};
ret = sql::set_config(context, &context.sql, key, val);
unsafe { free(def as *mut libc::c_void) };
}
_ => {
ret = sql::set_config(context, &context.sql, key, value);
}
}
ret
}
/* ******************************************************************************
* INI-handling, Information
******************************************************************************/
fn is_settable_config_key(key: impl AsRef<str>) -> bool {
CONFIG_KEYS
.into_iter()
.find(|c| **c == key.as_ref())
.is_some()
}
pub fn dc_get_config(context: &Context, key: impl AsRef<str>) -> String {
if key.as_ref().starts_with("sys") {
return get_sys_config_str(key.as_ref());
}
if !is_gettable_config_key(key.as_ref()) {
return "".into();
}
let value = match key.as_ref() {
"selfavatar" => {
let rel_path = sql::get_config(context, &context.sql, key.as_ref(), None);
rel_path.map(|p| {
let v = unsafe { dc_get_abs_path(context, to_cstring(p).as_ptr()) };
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
}
_ => sql::get_config(context, &context.sql, key.as_ref(), None),
};
if value.is_some() {
return value.unwrap();
}
match key.as_ref() {
"e2ee_enabled" => "1".into(),
"mdns_enabled" => "1".into(),
"imap_folder" => "INBOX".into(),
"inbox_watch" => "1".into(),
"sentbox_watch" | "mvbox_watch" | "mvbox_move" => "1".into(),
"show_emails" => "0".into(),
"selfstatus" => {
let s = unsafe { dc_stock_str(context, 13) };
let res = to_string(s);
unsafe { free(s as *mut _) };
res
}
_ => "".into(),
}
}
fn is_gettable_config_key(key: impl AsRef<str>) -> bool {
SYS_CONFIG_KEYS
.into_iter()
.find(|c| **c == key.as_ref())
.is_some()
|| is_settable_config_key(key)
}
fn get_sys_config_str(key: impl AsRef<str>) -> String {
match key.as_ref() {
"sys.version" => std::str::from_utf8(DC_VERSION_STR).unwrap().into(),
"sys.msgsize_max_recommended" => format!("{}", 24 * 1024 * 1024 / 4 * 3),
"sys.config_keys" => get_config_keys_str(),
_ => "".into(),
}
}
fn get_config_keys_str() -> String {
let keys = &CONFIG_KEYS[..].join(" ");
let sys_keys = &SYS_CONFIG_KEYS[..].join(" ");
format!(" {} {} ", keys, sys_keys)
}
pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let unset = "0";
let l = dc_loginparam_read(context, &context.sql, "");

View File

@@ -1,7 +1,7 @@
use crate::aheader::EncryptPreference;
use crate::config;
use crate::constants::Event;
use crate::context::Context;
use crate::context::*;
use crate::dc_array::*;
use crate::dc_e2ee::*;
use crate::dc_loginparam::*;
@@ -882,7 +882,7 @@ pub fn dc_contact_get_profile_image(contact: *const dc_contact_t) -> *mut libc::
}
if unsafe { (*contact).id } == 1 {
let avatar = dc_get_config(unsafe { (*contact).context }, "selfavatar");
let avatar = config::get(unsafe { (*contact).context }, "selfavatar");
if !avatar.is_empty() {
image_abs = unsafe { dc_strdup(to_cstring(avatar).as_ptr()) };
}

View File

@@ -21,6 +21,7 @@ extern crate rusqlite;
mod log;
pub mod aheader;
pub mod config;
pub mod constants;
pub mod context;
pub mod error;

View File

@@ -6,6 +6,7 @@ use std::ffi::CString;
use mmime::mailimf_types::*;
use tempfile::{tempdir, TempDir};
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_array::*;
@@ -247,7 +248,7 @@ unsafe fn stress_functions(context: &Context) {
free(fn1 as *mut libc::c_void);
}
let res = dc_get_config(context, "sys.config_keys");
let res = config::get(context, "sys.config_keys");
assert!(!res.contains(" probably_never_a_key "));
assert!(res.contains(" addr "));