| | |
| |
|
| | use std::env; |
| | use std::path::Path; |
| | use std::str::FromStr; |
| |
|
| | use anyhow::{Context as _, Result, bail, ensure}; |
| | use base64::Engine as _; |
| | use deltachat_contact_tools::{addr_cmp, sanitize_single_line}; |
| | use serde::{Deserialize, Serialize}; |
| | use strum::{EnumProperty, IntoEnumIterator}; |
| | use strum_macros::{AsRefStr, Display, EnumIter, EnumString}; |
| | use tokio::fs; |
| |
|
| | use crate::blob::BlobObject; |
| | use crate::context::Context; |
| | use crate::events::EventType; |
| | use crate::log::LogExt; |
| | use crate::mimefactory::RECOMMENDED_FILE_SIZE; |
| | use crate::provider::Provider; |
| | use crate::sync::{self, Sync::*, SyncData}; |
| | use crate::tools::get_abs_path; |
| | use crate::transport::{ConfiguredLoginParam, add_pseudo_transport, send_sync_transports}; |
| | use crate::{constants, stats}; |
| |
|
| | |
| | #[derive( |
| | Debug, |
| | Clone, |
| | Copy, |
| | PartialEq, |
| | Eq, |
| | Display, |
| | EnumString, |
| | AsRefStr, |
| | EnumIter, |
| | EnumProperty, |
| | PartialOrd, |
| | Ord, |
| | Serialize, |
| | Deserialize, |
| | )] |
| | #[strum(serialize_all = "snake_case")] |
| | pub enum Config { |
| | |
| | Addr, |
| |
|
| | |
| | MailServer, |
| |
|
| | |
| | MailUser, |
| |
|
| | |
| | MailPw, |
| |
|
| | |
| | MailPort, |
| |
|
| | |
| | MailSecurity, |
| |
|
| | |
| | |
| | |
| | |
| | ImapCertificateChecks, |
| |
|
| | |
| | SendServer, |
| |
|
| | |
| | SendUser, |
| |
|
| | |
| | SendPw, |
| |
|
| | |
| | SendPort, |
| |
|
| | |
| | SendSecurity, |
| |
|
| | |
| | |
| | |
| | SmtpCertificateChecks, |
| |
|
| | |
| | |
| | |
| | |
| | ServerFlags, |
| |
|
| | |
| | |
| | |
| | ProxyEnabled, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | ProxyUrl, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | Socks5Enabled, |
| |
|
| | |
| | |
| | |
| | Socks5Host, |
| |
|
| | |
| | |
| | |
| | Socks5Port, |
| |
|
| | |
| | |
| | |
| | Socks5User, |
| |
|
| | |
| | |
| | |
| | Socks5Password, |
| |
|
| | |
| | Displayname, |
| |
|
| | |
| | Selfstatus, |
| |
|
| | |
| | Selfavatar, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | #[strum(props(default = "0"))] |
| | BccSelf, |
| |
|
| | |
| | |
| | #[strum(props(default = "1"))] |
| | MdnsEnabled, |
| |
|
| | |
| | |
| | #[strum(props(default = "1"))] |
| | MvboxMove, |
| |
|
| | |
| | |
| | |
| | |
| | #[strum(props(default = "0"))] |
| | OnlyFetchMvbox, |
| |
|
| | |
| | #[strum(props(default = "2"))] |
| | ShowEmails, |
| |
|
| | |
| | #[strum(props(default = "0"))] |
| | MediaQuality, |
| |
|
| | |
| | |
| | #[strum(props(default = "1"))] |
| | FetchedExistingMsgs, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | DeleteServerAfter, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #[strum(props(default = "0"))] |
| | DeleteDeviceAfter, |
| |
|
| | |
| | |
| | DeleteToTrash, |
| |
|
| | |
| | ConfiguredAddr, |
| |
|
| | |
| | ConfiguredImapServers, |
| |
|
| | |
| | |
| | |
| | ConfiguredMailServer, |
| |
|
| | |
| | |
| | |
| | ConfiguredMailPort, |
| |
|
| | |
| | |
| | |
| | ConfiguredMailSecurity, |
| |
|
| | |
| | |
| | |
| | ConfiguredMailUser, |
| |
|
| | |
| | ConfiguredMailPw, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | ConfiguredImapCertificateChecks, |
| |
|
| | |
| | ConfiguredSmtpServers, |
| |
|
| | |
| | |
| | |
| | ConfiguredSendServer, |
| |
|
| | |
| | |
| | |
| | ConfiguredSendPort, |
| |
|
| | |
| | |
| | |
| | ConfiguredSendSecurity, |
| |
|
| | |
| | |
| | |
| | ConfiguredSendUser, |
| |
|
| | |
| | ConfiguredSendPw, |
| |
|
| | |
| | |
| | |
| | ConfiguredSmtpCertificateChecks, |
| |
|
| | |
| | ConfiguredServerFlags, |
| |
|
| | |
| | ConfiguredInboxFolder, |
| |
|
| | |
| | ConfiguredMvboxFolder, |
| |
|
| | |
| | ConfiguredTrashFolder, |
| |
|
| | |
| | ConfiguredTimestamp, |
| |
|
| | |
| | ConfiguredProvider, |
| |
|
| | |
| | Configured, |
| |
|
| | |
| | IsChatmail, |
| |
|
| | |
| | FixIsChatmail, |
| |
|
| | |
| | IsMuted, |
| |
|
| | |
| | |
| | PrivateTag, |
| |
|
| | |
| | #[strum(serialize = "sys.version")] |
| | SysVersion, |
| |
|
| | |
| | #[strum(serialize = "sys.msgsize_max_recommended")] |
| | SysMsgsizeMaxRecommended, |
| |
|
| | |
| | #[strum(serialize = "sys.config_keys")] |
| | SysConfigKeys, |
| |
|
| | |
| | Bot, |
| |
|
| | |
| | #[strum(props(default = "0"))] |
| | SkipStartMessages, |
| |
|
| | |
| | |
| | #[strum(props(default = "0"))] |
| | NotifyAboutWrongPw, |
| |
|
| | |
| | |
| | |
| | QuotaExceeding, |
| |
|
| | |
| | LastHousekeeping, |
| |
|
| | |
| | LastCantDecryptOutgoingMsgs, |
| |
|
| | |
| | #[strum(props(default = "60"))] |
| | ScanAllFoldersDebounceSecs, |
| |
|
| | |
| | |
| | |
| | #[strum(props(default = "0"))] |
| | DisableIdle, |
| |
|
| | |
| | DonationRequestNextCheck, |
| |
|
| | |
| | |
| | #[strum(props(default = "0"))] |
| | DownloadLimit, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #[strum(props(default = "1"))] |
| | SyncMsgs, |
| |
|
| | |
| | |
| | |
| | |
| | AuthservIdCandidates, |
| |
|
| | |
| | SignUnencrypted, |
| |
|
| | |
| | |
| | #[strum(props(default = "0"))] |
| | DebugLogging, |
| |
|
| | |
| | LastMsgId, |
| |
|
| | |
| | |
| | |
| | |
| | #[strum(props(default = "172800"))] |
| | GossipPeriod, |
| |
|
| | |
| | |
| | KeyId, |
| |
|
| | |
| | |
| | StatsSending, |
| |
|
| | |
| | StatsLastSent, |
| |
|
| | |
| | StatsLastUpdate, |
| |
|
| | |
| | |
| | StatsId, |
| |
|
| | |
| | StatsLastOldContactId, |
| |
|
| | |
| | WebxdcIntegration, |
| |
|
| | |
| | #[strum(props(default = "1"))] |
| | WebxdcRealtimeEnabled, |
| |
|
| | |
| | |
| | |
| | |
| | DeviceToken, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | EncryptedDeviceToken, |
| |
|
| | |
| | |
| | |
| | TestHooks, |
| |
|
| | |
| | FailOnReceivingFullMsg, |
| |
|
| | |
| | |
| | |
| | #[strum(props(default = "1"))] |
| | StdHeaderProtectionComposing, |
| |
|
| | |
| | |
| | |
| | #[strum(props(default = "1"))] |
| | WhoCanCallMe, |
| |
|
| | |
| | |
| | TeamProfile, |
| | } |
| |
|
| | impl Config { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | pub(crate) fn is_synced(&self) -> bool { |
| | matches!( |
| | self, |
| | Self::Displayname |
| | | Self::MdnsEnabled |
| | | Self::MvboxMove |
| | | Self::ShowEmails |
| | | Self::Selfavatar |
| | | Self::Selfstatus, |
| | ) |
| | } |
| |
|
| | |
| | pub(crate) fn needs_io_restart(&self) -> bool { |
| | matches!( |
| | self, |
| | Config::MvboxMove | Config::OnlyFetchMvbox | Config::ConfiguredAddr |
| | ) |
| | } |
| | } |
| |
|
| | impl Context { |
| | |
| | |
| | |
| | |
| | pub(crate) async fn config_exists(&self, key: Config) -> Result<bool> { |
| | Ok(self.sql.get_raw_config(key.as_ref()).await?.is_some()) |
| | } |
| |
|
| | |
| | pub(crate) async fn get_config_opt(&self, key: Config) -> Result<Option<String>> { |
| | let env_key = format!("DELTACHAT_{}", key.as_ref().to_uppercase()); |
| | if let Ok(value) = env::var(env_key) { |
| | return Ok(Some(value)); |
| | } |
| |
|
| | let value = match key { |
| | Config::Selfavatar => { |
| | let rel_path = self.sql.get_raw_config(key.as_ref()).await?; |
| | rel_path.map(|p| { |
| | get_abs_path(self, Path::new(&p)) |
| | .to_string_lossy() |
| | .into_owned() |
| | }) |
| | } |
| | Config::SysVersion => Some(constants::DC_VERSION_STR.to_string()), |
| | Config::SysMsgsizeMaxRecommended => Some(format!("{RECOMMENDED_FILE_SIZE}")), |
| | Config::SysConfigKeys => Some(get_config_keys_string()), |
| | _ => self.sql.get_raw_config(key.as_ref()).await?, |
| | }; |
| | Ok(value) |
| | } |
| |
|
| | |
| | pub async fn get_config(&self, key: Config) -> Result<Option<String>> { |
| | let value = self.get_config_opt(key).await?; |
| | if value.is_some() { |
| | return Ok(value); |
| | } |
| |
|
| | |
| | let val = match key { |
| | Config::ConfiguredInboxFolder => Some("INBOX".to_string()), |
| | Config::DeleteServerAfter => { |
| | match !Box::pin(self.get_config_bool(Config::BccSelf)).await? |
| | && Box::pin(self.is_chatmail()).await? |
| | { |
| | true => Some("1".to_string()), |
| | false => Some("0".to_string()), |
| | } |
| | } |
| | Config::Addr => self.get_config_opt(Config::ConfiguredAddr).await?, |
| | _ => key.get_str("default").map(|s| s.to_string()), |
| | }; |
| | Ok(val) |
| | } |
| |
|
| | |
| | |
| | pub(crate) async fn get_config_opt_parsed<T: FromStr>(&self, key: Config) -> Result<Option<T>> { |
| | self.get_config_opt(key) |
| | .await |
| | .map(|s: Option<String>| s.and_then(|s| s.parse().ok())) |
| | } |
| |
|
| | |
| | |
| | |
| | pub async fn get_config_parsed<T: FromStr>(&self, key: Config) -> Result<Option<T>> { |
| | self.get_config(key) |
| | .await |
| | .map(|s: Option<String>| s.and_then(|s| s.parse().ok())) |
| | } |
| |
|
| | |
| | pub async fn get_config_int(&self, key: Config) -> Result<i32> { |
| | Ok(self.get_config_parsed(key).await?.unwrap_or_default()) |
| | } |
| |
|
| | |
| | pub async fn get_config_u32(&self, key: Config) -> Result<u32> { |
| | Ok(self.get_config_parsed(key).await?.unwrap_or_default()) |
| | } |
| |
|
| | |
| | pub async fn get_config_i64(&self, key: Config) -> Result<i64> { |
| | Ok(self.get_config_parsed(key).await?.unwrap_or_default()) |
| | } |
| |
|
| | |
| | pub async fn get_config_u64(&self, key: Config) -> Result<u64> { |
| | Ok(self.get_config_parsed(key).await?.unwrap_or_default()) |
| | } |
| |
|
| | |
| | pub(crate) async fn get_config_bool_opt(&self, key: Config) -> Result<Option<bool>> { |
| | Ok(self |
| | .get_config_opt_parsed::<i32>(key) |
| | .await? |
| | .map(|x| x != 0)) |
| | } |
| |
|
| | |
| | pub async fn get_config_bool(&self, key: Config) -> Result<bool> { |
| | Ok(self |
| | .get_config(key) |
| | .await? |
| | .and_then(|s| s.parse::<i32>().ok()) |
| | .map(|x| x != 0) |
| | .unwrap_or_default()) |
| | } |
| |
|
| | |
| | pub(crate) async fn should_watch_mvbox(&self) -> Result<bool> { |
| | Ok(self.get_config_bool(Config::MvboxMove).await? |
| | || self.get_config_bool(Config::OnlyFetchMvbox).await? |
| | || !self.get_config_bool(Config::IsChatmail).await?) |
| | } |
| |
|
| | |
| | pub(crate) async fn should_send_sync_msgs(&self) -> Result<bool> { |
| | Ok(self.get_config_bool(Config::SyncMsgs).await? |
| | && self.get_config_bool(Config::BccSelf).await? |
| | && !self.get_config_bool(Config::Bot).await?) |
| | } |
| |
|
| | |
| | pub(crate) async fn should_request_mdns(&self) -> Result<bool> { |
| | match self.get_config_bool_opt(Config::MdnsEnabled).await? { |
| | Some(val) => Ok(val), |
| | None => Ok(!self.get_config_bool(Config::Bot).await?), |
| | } |
| | } |
| |
|
| | |
| | pub(crate) async fn should_send_mdns(&self) -> Result<bool> { |
| | self.get_config_bool(Config::MdnsEnabled).await |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | pub async fn get_config_delete_server_after(&self) -> Result<Option<i64>> { |
| | let val = match self |
| | .get_config_parsed::<i64>(Config::DeleteServerAfter) |
| | .await? |
| | .unwrap_or(0) |
| | { |
| | 0 => None, |
| | 1 => Some(0), |
| | x => Some(x), |
| | }; |
| | Ok(val) |
| | } |
| |
|
| | |
| | |
| | |
| | pub async fn get_configured_provider(&self) -> Result<Option<&'static Provider>> { |
| | let provider = ConfiguredLoginParam::load(self) |
| | .await? |
| | .and_then(|(_transport_id, param)| param.provider); |
| | Ok(provider) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | pub async fn get_config_delete_device_after(&self) -> Result<Option<i64>> { |
| | match self.get_config_int(Config::DeleteDeviceAfter).await? { |
| | 0 => Ok(None), |
| | x => Ok(Some(i64::from(x))), |
| | } |
| | } |
| |
|
| | |
| | pub(crate) async fn sync_config(&self, key: &Config, value: &str) -> Result<()> { |
| | let config_value; |
| | let value = match key { |
| | Config::Selfavatar if value.is_empty() => None, |
| | Config::Selfavatar => { |
| | config_value = BlobObject::store_from_base64(self, value)?; |
| | config_value.as_deref() |
| | } |
| | _ => Some(value), |
| | }; |
| | match key.is_synced() { |
| | true => self.set_config_ex(Nosync, *key, value).await, |
| | false => Ok(()), |
| | } |
| | } |
| |
|
| | fn check_config(key: Config, value: Option<&str>) -> Result<()> { |
| | match key { |
| | Config::Socks5Enabled |
| | | Config::ProxyEnabled |
| | | Config::BccSelf |
| | | Config::MdnsEnabled |
| | | Config::MvboxMove |
| | | Config::OnlyFetchMvbox |
| | | Config::DeleteToTrash |
| | | Config::Configured |
| | | Config::Bot |
| | | Config::NotifyAboutWrongPw |
| | | Config::SyncMsgs |
| | | Config::SignUnencrypted |
| | | Config::DisableIdle => { |
| | ensure!( |
| | matches!(value, None | Some("0") | Some("1")), |
| | "Boolean value must be either 0 or 1" |
| | ); |
| | } |
| | _ => (), |
| | } |
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | pub async fn set_config(&self, key: Config, value: Option<&str>) -> Result<()> { |
| | Self::check_config(key, value)?; |
| |
|
| | let n_transports = self.count_transports().await?; |
| | if n_transports > 1 |
| | && matches!( |
| | key, |
| | Config::MvboxMove | Config::OnlyFetchMvbox | Config::ShowEmails |
| | ) |
| | { |
| | bail!("Cannot reconfigure {key} when multiple transports are configured"); |
| | } |
| |
|
| | let _pause = match key.needs_io_restart() { |
| | true => self.scheduler.pause(self).await?, |
| | _ => Default::default(), |
| | }; |
| | if key == Config::StatsSending { |
| | let old_value = self.get_config(key).await?; |
| | let old_value = bool_from_config(old_value.as_deref()); |
| | let new_value = bool_from_config(value); |
| | stats::pre_sending_config_change(self, old_value, new_value).await?; |
| | } |
| | self.set_config_internal(key, value).await?; |
| | if key == Config::StatsSending { |
| | stats::maybe_send_stats(self).await?; |
| | } |
| | Ok(()) |
| | } |
| |
|
| | pub(crate) async fn set_config_internal(&self, key: Config, value: Option<&str>) -> Result<()> { |
| | self.set_config_ex(Sync, key, value).await |
| | } |
| |
|
| | pub(crate) async fn set_config_ex( |
| | &self, |
| | sync: sync::Sync, |
| | key: Config, |
| | mut value: Option<&str>, |
| | ) -> Result<()> { |
| | Self::check_config(key, value)?; |
| | let sync = sync == Sync && key.is_synced() && self.is_configured().await?; |
| | let better_value; |
| |
|
| | match key { |
| | Config::Selfavatar => { |
| | self.sql |
| | .execute("UPDATE contacts SET selfavatar_sent=0;", ()) |
| | .await?; |
| | match value { |
| | Some(path) => { |
| | let path = get_abs_path(self, Path::new(path)); |
| | let mut blob = BlobObject::create_and_deduplicate(self, &path, &path)?; |
| | blob.recode_to_avatar_size(self).await?; |
| | self.sql |
| | .set_raw_config(key.as_ref(), Some(blob.as_name())) |
| | .await?; |
| | if sync { |
| | let buf = fs::read(blob.to_abs_path()).await?; |
| | better_value = base64::engine::general_purpose::STANDARD.encode(buf); |
| | value = Some(&better_value); |
| | } |
| | } |
| | None => { |
| | self.sql.set_raw_config(key.as_ref(), None).await?; |
| | if sync { |
| | better_value = String::new(); |
| | value = Some(&better_value); |
| | } |
| | } |
| | } |
| | self.emit_event(EventType::SelfavatarChanged); |
| | } |
| | Config::DeleteDeviceAfter => { |
| | let ret = self.sql.set_raw_config(key.as_ref(), value).await; |
| | |
| | self.scheduler.interrupt_ephemeral_task().await; |
| | ret? |
| | } |
| | Config::Displayname => { |
| | if let Some(v) = value { |
| | better_value = sanitize_single_line(v); |
| | value = Some(&better_value); |
| | } |
| | self.sql.set_raw_config(key.as_ref(), value).await?; |
| | } |
| | Config::Addr => { |
| | self.sql |
| | .set_raw_config(key.as_ref(), value.map(|s| s.to_lowercase()).as_deref()) |
| | .await?; |
| | } |
| | Config::MvboxMove => { |
| | self.sql.set_raw_config(key.as_ref(), value).await?; |
| | self.sql |
| | .set_raw_config(constants::DC_FOLDERS_CONFIGURED_KEY, None) |
| | .await?; |
| | } |
| | Config::ConfiguredAddr => { |
| | let Some(addr) = value else { |
| | bail!("Cannot unset configured_addr"); |
| | }; |
| |
|
| | if !self.is_configured().await? { |
| | info!( |
| | self, |
| | "Creating a pseudo configured account which will not be able to send or receive messages. Only meant for tests!" |
| | ); |
| | add_pseudo_transport(self, addr).await?; |
| | self.sql |
| | .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(addr)) |
| | .await?; |
| | } else { |
| | self.sql |
| | .transaction(|transaction| { |
| | if transaction.query_row( |
| | "SELECT COUNT(*) FROM transports WHERE addr=?", |
| | (addr,), |
| | |row| { |
| | let res: i64 = row.get(0)?; |
| | Ok(res) |
| | }, |
| | )? == 0 |
| | { |
| | bail!("Address does not belong to any transport."); |
| | } |
| | transaction.execute( |
| | "UPDATE config SET value=? WHERE keyname='configured_addr'", |
| | (addr,), |
| | )?; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | transaction.execute("DELETE FROM smtp", ())?; |
| | transaction.execute("DELETE FROM imap_send", ())?; |
| |
|
| | Ok(()) |
| | }) |
| | .await?; |
| | send_sync_transports(self).await?; |
| | self.sql.uncache_raw_config("configured_addr").await; |
| | } |
| | } |
| | _ => { |
| | self.sql.set_raw_config(key.as_ref(), value).await?; |
| | } |
| | } |
| | if matches!( |
| | key, |
| | Config::Displayname | Config::Selfavatar | Config::PrivateTag |
| | ) { |
| | self.emit_event(EventType::AccountsItemChanged); |
| | } |
| | if key.is_synced() { |
| | self.emit_event(EventType::ConfigSynced { key }); |
| | } |
| | if !sync { |
| | return Ok(()); |
| | } |
| | let Some(val) = value else { |
| | return Ok(()); |
| | }; |
| | let val = val.to_string(); |
| | if self |
| | .add_sync_item(SyncData::Config { key, val }) |
| | .await |
| | .log_err(self) |
| | .is_err() |
| | { |
| | return Ok(()); |
| | } |
| | self.scheduler.interrupt_smtp().await; |
| | Ok(()) |
| | } |
| |
|
| | |
| | pub async fn set_config_u32(&self, key: Config, value: u32) -> Result<()> { |
| | self.set_config(key, Some(&value.to_string())).await?; |
| | Ok(()) |
| | } |
| |
|
| | |
| | pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> { |
| | self.set_config(key, from_bool(value)).await?; |
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | pub async fn set_ui_config(&self, key: &str, value: Option<&str>) -> Result<()> { |
| | ensure!(key.starts_with("ui."), "set_ui_config(): prefix missing."); |
| | self.sql.set_raw_config(key, value).await |
| | } |
| |
|
| | |
| | pub async fn get_ui_config(&self, key: &str) -> Result<Option<String>> { |
| | ensure!(key.starts_with("ui."), "get_ui_config(): prefix missing."); |
| | self.sql.get_raw_config(key).await |
| | } |
| | } |
| |
|
| | |
| | pub(crate) fn from_bool(val: bool) -> Option<&'static str> { |
| | Some(if val { "1" } else { "0" }) |
| | } |
| |
|
| | pub(crate) fn bool_from_config(config: Option<&str>) -> bool { |
| | config.is_some_and(|v| v.parse::<i32>().unwrap_or_default() != 0) |
| | } |
| |
|
| | |
| | impl Context { |
| | |
| | |
| | pub(crate) async fn is_self_addr(&self, addr: &str) -> Result<bool> { |
| | Ok(self |
| | .get_config(Config::ConfiguredAddr) |
| | .await? |
| | .iter() |
| | .any(|a| addr_cmp(addr, a)) |
| | || self |
| | .get_secondary_self_addrs() |
| | .await? |
| | .iter() |
| | .any(|a| addr_cmp(addr, a))) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | #[cfg(test)] |
| | pub(crate) async fn set_primary_self_addr(&self, primary_new: &str) -> Result<()> { |
| | self.quota.write().await.clear(); |
| |
|
| | self.sql |
| | .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(primary_new)) |
| | .await?; |
| | self.emit_event(EventType::ConnectivityChanged); |
| | Ok(()) |
| | } |
| |
|
| | |
| | pub(crate) async fn get_all_self_addrs(&self) -> Result<Vec<String>> { |
| | let primary_addrs = self.get_config(Config::ConfiguredAddr).await?.into_iter(); |
| | let secondary_addrs = self.get_secondary_self_addrs().await?.into_iter(); |
| |
|
| | Ok(primary_addrs.chain(secondary_addrs).collect()) |
| | } |
| |
|
| | |
| | pub(crate) async fn get_secondary_self_addrs(&self) -> Result<Vec<String>> { |
| | self.sql.query_map_vec("SELECT addr FROM transports WHERE addr NOT IN (SELECT value FROM config WHERE keyname='configured_addr')", (), |row| { |
| | let addr: String = row.get(0)?; |
| | Ok(addr) |
| | }).await |
| | } |
| |
|
| | |
| | |
| | pub async fn get_primary_self_addr(&self) -> Result<String> { |
| | self.get_config(Config::ConfiguredAddr) |
| | .await? |
| | .context("No self addr configured") |
| | } |
| | } |
| |
|
| | |
| | fn get_config_keys_string() -> String { |
| | let keys = Config::iter().fold(String::new(), |mut acc, key| { |
| | acc += key.as_ref(); |
| | acc += " "; |
| | acc |
| | }); |
| |
|
| | format!(" {keys} ") |
| | } |
| |
|
| | |
| | pub async fn get_all_ui_config_keys(context: &Context) -> Result<Vec<String>> { |
| | let ui_keys = context |
| | .sql |
| | .query_map_vec( |
| | "SELECT keyname FROM config WHERE keyname GLOB 'ui.*' ORDER BY config.id", |
| | (), |
| | |row| Ok(row.get::<_, String>(0)?), |
| | ) |
| | .await?; |
| | Ok(ui_keys) |
| | } |
| |
|
| | #[cfg(test)] |
| | mod config_tests; |
| |
|