mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 13:36:30 +03:00
This effectively reverts https://github.com/deltachat/deltachat-core-rust/pull/964 for chat.rs, which in that PR was thought to fix something. So maybe something is still broken? But after improving tests the previous code seems to be correct. - Update Python bindings to not always use dc_prepare_msg path when sending messages with attachements. When using dc_prepare_msg the blobs need to be created in the blobdir since they will not get copied and many tests where not doing this. - Add a test that ensures that calling dc_prepare_msg with a file **not** in the blobdir fails. - Add a test that ensures that calling dc_send_msg directly with a file **not** in the blobdir copies the file to the blobdir. This test cheats a little by knowing what the filename in the blobdir will be which is implementation-dependent and thus a bit brittle. But for now it proves correct behaviour so let's go with this. - Improve the test_forward_increation test to ensure that the in-creation file only has it's final state before calling dc_send_msg. This checks the correct file data is sent out and not the preparing data, this fails with the chat.rs changes in #964 (reverted here to make this work again). Also fix the test to actually create the in-creation file in the blobdir. - Fix test_send_file_twice_unicode_filename_mangling to not use in-creation. It was not creating it's files in the blobdir and that is an error when using in-creation and it didn't seem it was trying to test something about the in-creation logic (which is tested in test_increation.py already). - Fix Message._msgtate code which presumably was not used before? - Rename `BlobObject::create_from_path` to `BlobObject::new_from_path`. All the `BlobObject::create*` calls now always create new files which is much more consistent. APIs should do what is obious.
229 lines
6.6 KiB
Rust
229 lines
6.6 KiB
Rust
//! # Key-value configuration management
|
|
|
|
use strum::{EnumProperty, IntoEnumIterator};
|
|
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
|
|
|
|
use crate::blob::BlobObject;
|
|
use crate::constants::DC_VERSION_STR;
|
|
use crate::context::Context;
|
|
use crate::dc_tools::*;
|
|
use crate::job::*;
|
|
use crate::stock::StockMessage;
|
|
|
|
/// 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,
|
|
ImapCertificateChecks,
|
|
SendServer,
|
|
SendUser,
|
|
SendPw,
|
|
SendPort,
|
|
SmtpCertificateChecks,
|
|
ServerFlags,
|
|
|
|
#[strum(props(default = "INBOX"))]
|
|
ImapFolder,
|
|
|
|
Displayname,
|
|
Selfstatus,
|
|
Selfavatar,
|
|
|
|
#[strum(props(default = "0"))]
|
|
BccSelf,
|
|
|
|
#[strum(props(default = "1"))]
|
|
E2eeEnabled,
|
|
|
|
#[strum(props(default = "1"))]
|
|
MdnsEnabled,
|
|
|
|
#[strum(props(default = "1"))]
|
|
InboxWatch,
|
|
|
|
#[strum(props(default = "1"))]
|
|
SentboxWatch,
|
|
|
|
#[strum(props(default = "1"))]
|
|
MvboxWatch,
|
|
|
|
#[strum(props(default = "1"))]
|
|
MvboxMove,
|
|
|
|
#[strum(props(default = "0"))] // also change ShowEmails.default() on changes
|
|
ShowEmails,
|
|
|
|
SaveMimeHeaders,
|
|
ConfiguredAddr,
|
|
ConfiguredMailServer,
|
|
ConfiguredMailUser,
|
|
ConfiguredMailPw,
|
|
ConfiguredMailPort,
|
|
ConfiguredMailSecurity,
|
|
ConfiguredImapCertificateChecks,
|
|
ConfiguredSendServer,
|
|
ConfiguredSendUser,
|
|
ConfiguredSendPw,
|
|
ConfiguredSendPort,
|
|
ConfiguredSmtpCertificateChecks,
|
|
ConfiguredServerFlags,
|
|
ConfiguredSendSecurity,
|
|
ConfiguredE2EEEnabled,
|
|
Configured,
|
|
|
|
#[strum(serialize = "sys.version")]
|
|
SysVersion,
|
|
|
|
#[strum(serialize = "sys.msgsize_max_recommended")]
|
|
SysMsgsizeMaxRecommended,
|
|
|
|
#[strum(serialize = "sys.config_keys")]
|
|
SysConfigKeys,
|
|
}
|
|
|
|
impl Context {
|
|
/// Get a configuration key. Returns `None` if no value is set, and no default value found.
|
|
pub fn get_config(&self, key: Config) -> Option<String> {
|
|
let value = match key {
|
|
Config::Selfavatar => {
|
|
let rel_path = self.sql.get_raw_config(self, key);
|
|
rel_path.map(|p| dc_get_abs_path(self, &p).to_string_lossy().into_owned())
|
|
}
|
|
Config::SysVersion => Some((&*DC_VERSION_STR).clone()),
|
|
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
|
|
Config::SysConfigKeys => Some(get_config_keys_string()),
|
|
_ => self.sql.get_raw_config(self, key),
|
|
};
|
|
|
|
if value.is_some() {
|
|
return value;
|
|
}
|
|
|
|
// Default values
|
|
match key {
|
|
Config::Selfstatus => Some(self.stock_str(StockMessage::StatusLine).into_owned()),
|
|
_ => key.get_str("default").map(|s| s.to_string()),
|
|
}
|
|
}
|
|
|
|
pub fn get_config_int(&self, key: Config) -> i32 {
|
|
self.get_config(key)
|
|
.and_then(|s| s.parse().ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
pub fn get_config_bool(&self, key: Config) -> bool {
|
|
self.get_config_int(key) != 0
|
|
}
|
|
|
|
/// 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>) -> crate::sql::Result<()> {
|
|
match key {
|
|
Config::Selfavatar if value.is_some() => {
|
|
let blob = BlobObject::new_from_path(&self, value.unwrap())?;
|
|
self.sql.set_raw_config(self, key, Some(blob.as_name()))
|
|
}
|
|
Config::InboxWatch => {
|
|
let ret = self.sql.set_raw_config(self, key, value);
|
|
interrupt_inbox_idle(self, true);
|
|
ret
|
|
}
|
|
Config::SentboxWatch => {
|
|
let ret = self.sql.set_raw_config(self, key, value);
|
|
interrupt_sentbox_idle(self);
|
|
ret
|
|
}
|
|
Config::MvboxWatch => {
|
|
let ret = self.sql.set_raw_config(self, key, value);
|
|
interrupt_mvbox_idle(self);
|
|
ret
|
|
}
|
|
Config::Selfstatus => {
|
|
let def = self.stock_str(StockMessage::StatusLine);
|
|
let val = if value.is_none() || value.unwrap() == def {
|
|
None
|
|
} else {
|
|
value
|
|
};
|
|
|
|
self.sql.set_raw_config(self, key, val)
|
|
}
|
|
_ => self.sql.set_raw_config(self, key, value),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns all available configuration keys concated together.
|
|
fn get_config_keys_string() -> String {
|
|
let keys = Config::iter().fold(String::new(), |mut acc, key| {
|
|
acc += key.as_ref();
|
|
acc += " ";
|
|
acc
|
|
});
|
|
|
|
format!(" {} ", keys)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
use std::str::FromStr;
|
|
use std::string::ToString;
|
|
|
|
use crate::test_utils::*;
|
|
|
|
#[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!(Config::SysConfigKeys.to_string(), "sys.config_keys");
|
|
assert_eq!(
|
|
Config::from_str("sys.config_keys"),
|
|
Ok(Config::SysConfigKeys)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_default_prop() {
|
|
assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_selfavatar() -> failure::Fallible<()> {
|
|
let t = dummy_context();
|
|
let avatar_src = t.dir.path().join("avatar.jpg");
|
|
std::fs::write(&avatar_src, b"avatar")?;
|
|
let avatar_blob = t.ctx.get_blobdir().join("avatar.jpg");
|
|
assert!(!avatar_blob.exists());
|
|
t.ctx
|
|
.set_config(Config::Selfavatar, Some(&avatar_src.to_str().unwrap()))?;
|
|
assert!(avatar_blob.exists());
|
|
assert_eq!(std::fs::read(&avatar_blob)?, b"avatar");
|
|
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);
|
|
assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string()));
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_selfavatar_in_blobdir() -> failure::Fallible<()> {
|
|
let t = dummy_context();
|
|
let avatar_src = t.ctx.get_blobdir().join("avatar.jpg");
|
|
std::fs::write(&avatar_src, b"avatar")?;
|
|
t.ctx
|
|
.set_config(Config::Selfavatar, Some(&avatar_src.to_str().unwrap()))?;
|
|
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);
|
|
assert_eq!(avatar_cfg, avatar_src.to_str().map(|s| s.to_string()));
|
|
Ok(())
|
|
}
|
|
}
|