use std::borrow::Cow;
#[cfg(feature = "config")]
use serde::Deserialize;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "config", derive(Deserialize))]
#[non_exhaustive]
pub enum SmtpMode {
#[cfg_attr(feature = "config", serde(rename = "unencrypted"))]
Unencrypted,
#[cfg_attr(feature = "config", serde(rename = "starttls"))]
StartTls,
#[cfg_attr(feature = "config", serde(rename = "tls"))]
Tls,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "config", derive(Deserialize))]
pub struct Account<'input> {
pub smtp_host: Cow<'input, str>,
pub smtp_mode: SmtpMode,
pub from: Cow<'input, str>,
pub user: Cow<'input, str>,
pub password: Cow<'input, str>,
}
#[cfg(feature = "config")]
#[cfg_attr(docsrs, doc(cfg(feature = "config")))]
mod implementation {
use super::*;
use std::marker::PhantomData;
use std::path::Path;
use std::path::PathBuf;
use anyhow::Context as _;
use anyhow::Result;
use serde_json::from_slice as from_json;
use tokio::fs::read;
use crate::EmailOpts;
#[derive(Debug, Deserialize)]
pub struct Config {
pub accounts: Vec<Account<'static>>,
pub recipients: Vec<String>,
#[cfg(feature = "pgp")]
#[cfg_attr(docsrs, doc(cfg(feature = "pgp")))]
#[serde(alias = "pgp-keybox")]
pub pgp_keybox: Option<PathBuf>,
}
impl Config {
pub fn into_inputs(self) -> (Vec<Account<'static>>, Vec<String>, EmailOpts<'static>) {
let Self {
accounts,
recipients,
#[cfg(feature = "pgp")]
pgp_keybox,
} = self;
let opts = EmailOpts {
#[cfg(feature = "pgp")]
pgp_keybox: pgp_keybox.map(Cow::Owned),
_phantom: PhantomData,
};
(accounts, recipients, opts)
}
}
#[inline]
pub fn system_config_path() -> Result<Cow<'static, Path>> {
let path = Cow::Borrowed(Path::new("/etc/maily/config.json"));
Ok(path)
}
pub async fn system_config() -> Result<Config> {
let path = system_config_path().context("failed to retrieve path to system configuration")?;
let data = read(&path)
.await
.with_context(|| format!("failed to read configuration file `{}`", path.display()))?;
let config = from_json::<Config>(&data)
.with_context(|| format!("failed to parse `{}` contents as JSON", path.display()))?;
Ok(config)
}
}
#[cfg(feature = "config")]
pub use implementation::*;