init backend override with list envelopes and send message

This commit is contained in:
Clément DOUIN 2023-11-26 12:16:07 +01:00
parent cec658aff4
commit 1f88b27468
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
9 changed files with 154 additions and 77 deletions

View file

@ -10,9 +10,26 @@ email = "example@localhost"
# listing envelopes or copying messages.
backend = "imap"
imap.host = "imap.gmail.com"
imap.port = 993
imap.login = "example@localhost"
imap.auth = "passwd"
# imap.Some.passwd.cmd = "pass show gmail"
# Override the backend used for sending messages.
message.send.backend = "smtp"
# IMAP config
imap.host = "localhost"
imap.port = 3143
imap.login = "example@localhost"
imap.ssl = false
imap.starttls = false
imap.insecure = true
imap.auth = "passwd"
imap.passwd.raw = "example"
# SMTP config
smtp.host = "localhost"
smtp.port = 3025
smtp.login = "example@localhost"
smtp.ssl = false
smtp.starttls = false
smtp.insecure = true
smtp.auth = "passwd"
smtp.passwd.raw = "example"

View file

@ -10,7 +10,10 @@ use email::smtp::{SmtpClientBuilder, SmtpClientSync};
use email::{
account::AccountConfig,
config::Config,
folder::list::{imap::ListFoldersImap, maildir::ListFoldersMaildir},
email::{
envelope::list::{imap::ListEnvelopesImap, maildir::ListEnvelopesMaildir},
message::send_raw::{sendmail::SendRawMessageSendmail, smtp::SendRawMessageSmtp},
},
maildir::{MaildirSessionBuilder, MaildirSessionSync},
sendmail::SendmailContext,
};
@ -18,11 +21,9 @@ use serde::{Deserialize, Serialize};
use crate::config::DeserializedConfig;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum BackendKind {
#[default]
None,
Maildir,
#[cfg(feature = "imap-backend")]
Imap,
@ -35,8 +36,6 @@ pub enum BackendKind {
#[derive(Clone, Default)]
pub struct BackendContextBuilder {
account_config: AccountConfig,
#[cfg(feature = "imap-backend")]
imap: Option<ImapSessionBuilder>,
maildir: Option<MaildirSessionBuilder>,
@ -93,7 +92,7 @@ pub struct BackendBuilder(pub email::backend::BackendBuilder<BackendContextBuild
impl BackendBuilder {
pub async fn new(config: DeserializedConfig, account_name: Option<&str>) -> Result<Self> {
let (account_name, deserialized_account_config) = match account_name {
let (account_name, mut deserialized_account_config) = match account_name {
Some("default") | Some("") | None => config
.accounts
.iter()
@ -111,6 +110,25 @@ impl BackendBuilder {
.ok_or_else(|| anyhow!("cannot find account {name}")),
}?;
println!(
"deserialized_account_config: {:#?}",
deserialized_account_config
);
#[cfg(feature = "imap-backend")]
if let Some(imap_config) = deserialized_account_config.imap.as_mut() {
imap_config
.auth
.replace_undefined_keyring_entries(&account_name);
}
#[cfg(feature = "smtp-sender")]
if let Some(smtp_config) = deserialized_account_config.smtp.as_mut() {
smtp_config
.auth
.replace_undefined_keyring_entries(&account_name);
}
let config = Config {
display_name: config.display_name,
signature_delim: config.signature_delim,
@ -166,10 +184,9 @@ impl BackendBuilder {
)),
};
let account_config = config.account(account_name)?;
let account_config = config.account(&account_name)?;
let backend_ctx_builder = BackendContextBuilder {
account_config: account_config.clone(),
maildir: deserialized_account_config
.maildir
.as_ref()
@ -199,28 +216,57 @@ impl BackendBuilder {
..Default::default()
};
let backend_builder =
email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder)
.with_list_folders(move |ctx| {
println!(
"deserialized_account_config: {:#?}",
deserialized_account_config
);
match deserialized_account_config.backend {
BackendKind::Maildir if ctx.maildir.is_some() => {
ListFoldersMaildir::new(ctx.maildir.as_ref().unwrap())
}
#[cfg(feature = "imap-backend")]
BackendKind::Imap if ctx.imap.is_some() => {
ListFoldersImap::new(ctx.imap.as_ref().unwrap())
}
#[cfg(feature = "notmuch-backend")]
BackendKind::Notmuch if ctx.notmuch.is_some() => {
ListFoldersNotmuch::new(ctx.notmuch.as_ref().unwrap())
}
_ => None,
}
let mut backend_builder =
email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder);
let list_envelopes = deserialized_account_config
.envelope
.as_ref()
.and_then(|envelope| envelope.list.as_ref())
.and_then(|send| send.backend.as_ref())
.or_else(|| deserialized_account_config.backend.as_ref());
match list_envelopes {
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "imap-backend")]
Some(BackendKind::Imap) => {
backend_builder = backend_builder
.with_list_envelopes(|ctx| ctx.imap.as_ref().and_then(ListEnvelopesImap::new));
}
#[cfg(feature = "notmuch-backend")]
Some(BackendKind::Notmuch) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.notmuch.as_ref().and_then(ListEnvelopesNotmuch::new)
});
}
_ => (),
}
let send_msg = deserialized_account_config
.message
.as_ref()
.and_then(|msg| msg.send.as_ref())
.and_then(|send| send.backend.as_ref())
.or_else(|| deserialized_account_config.backend.as_ref());
match send_msg {
#[cfg(feature = "smtp-sender")]
Some(BackendKind::Smtp) => {
backend_builder = backend_builder.with_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
});
}
Some(BackendKind::Sendmail) => {
backend_builder = backend_builder.with_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
});
}
_ => (),
}
Ok(Self(backend_builder))
}

View file

@ -160,7 +160,7 @@ pub enum ImapAuthConfigDef {
#[serde(remote = "PasswdConfig")]
pub struct ImapPasswdConfigDef {
#[serde(
rename = "imap-passwd",
rename = "passwd",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
@ -335,19 +335,19 @@ pub enum EmailTextPlainFormatDef {
pub struct OptionSmtpConfigDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OptionSmtpConfig {
#[default]
#[serde(skip_serializing)]
None,
Some(#[serde(with = "SmtpConfigDef")] SmtpConfig),
pub struct OptionSmtpConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "SmtpConfigDef")]
inner: SmtpConfig,
}
impl From<OptionSmtpConfig> for Option<SmtpConfig> {
fn from(config: OptionSmtpConfig) -> Option<SmtpConfig> {
match config {
OptionSmtpConfig::None => None,
OptionSmtpConfig::Some(config) => Some(config),
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
@ -356,17 +356,11 @@ impl From<OptionSmtpConfig> for Option<SmtpConfig> {
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SmtpConfig")]
struct SmtpConfigDef {
#[serde(rename = "smtp-host")]
pub host: String,
#[serde(rename = "smtp-port")]
pub port: u16,
#[serde(rename = "smtp-ssl")]
pub ssl: Option<bool>,
#[serde(rename = "smtp-starttls")]
pub starttls: Option<bool>,
#[serde(rename = "smtp-insecure")]
pub insecure: Option<bool>,
#[serde(rename = "smtp-login")]
pub login: String,
#[serde(flatten, with = "SmtpAuthConfigDef")]
pub auth: SmtpAuthConfig,
@ -374,7 +368,7 @@ struct SmtpConfigDef {
#[cfg(feature = "smtp-sender")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SmtpAuthConfig", tag = "smtp-auth")]
#[serde(remote = "SmtpAuthConfig", tag = "auth")]
pub enum SmtpAuthConfigDef {
#[serde(rename = "passwd", alias = "password", with = "SmtpPasswdConfigDef")]
Passwd(#[serde(default)] PasswdConfig),
@ -386,7 +380,7 @@ pub enum SmtpAuthConfigDef {
#[serde(remote = "PasswdConfig", default)]
pub struct SmtpPasswdConfigDef {
#[serde(
rename = "smtp-passwd",
rename = "passwd",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
@ -395,32 +389,26 @@ pub struct SmtpPasswdConfigDef {
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Config")]
#[serde(remote = "OAuth2Config", rename_all = "kebab-case")]
pub struct SmtpOAuth2ConfigDef {
#[serde(rename = "smtp-oauth2-method", with = "OAuth2MethodDef", default)]
#[serde(with = "OAuth2MethodDef", default)]
pub method: OAuth2Method,
#[serde(rename = "smtp-oauth2-client-id")]
pub client_id: String,
#[serde(
rename = "smtp-oauth2-client-secret",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub client_secret: Secret,
#[serde(rename = "smtp-oauth2-auth-url")]
pub auth_url: String,
#[serde(rename = "smtp-oauth2-token-url")]
pub token_url: String,
#[serde(
rename = "smtp-oauth2-access-token",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub access_token: Secret,
#[serde(
rename = "smtp-oauth2-refresh-token",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
@ -428,17 +416,11 @@ pub struct SmtpOAuth2ConfigDef {
pub refresh_token: Secret,
#[serde(flatten, with = "SmtpOAuth2ScopesDef")]
pub scopes: OAuth2Scopes,
#[serde(rename = "smtp-oauth2-pkce", default)]
#[serde(default)]
pub pkce: bool,
#[serde(
rename = "imap-oauth2-redirect-host",
default = "OAuth2Config::default_redirect_host"
)]
#[serde(default = "OAuth2Config::default_redirect_host")]
pub redirect_host: String,
#[serde(
rename = "imap-oauth2-redirect-port",
default = "OAuth2Config::default_redirect_port"
)]
#[serde(default = "OAuth2Config::default_redirect_port")]
pub redirect_port: u16,
}
@ -476,11 +458,7 @@ impl From<OptionSendmailConfig> for Option<SendmailConfig> {
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SendmailConfig", rename_all = "kebab-case")]
pub struct SendmailConfigDef {
#[serde(
rename = "sendmail-cmd",
with = "CmdDef",
default = "sendmail_default_cmd"
)]
#[serde(with = "CmdDef", default = "sendmail_default_cmd")]
cmd: Cmd,
}

View file

@ -18,7 +18,10 @@ use email::{
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf};
use crate::{backend::BackendKind, config::prelude::*};
use crate::{
backend::BackendKind, config::prelude::*, email::envelope::config::EnvelopeConfig,
message::config::MessageConfig,
};
/// Represents all existing kind of account config.
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
@ -51,7 +54,10 @@ pub struct DeserializedAccountConfig {
#[serde(default, with = "OptionFolderSyncStrategyDef")]
pub sync_folders_strategy: Option<FolderSyncStrategy>,
pub backend: BackendKind,
pub backend: Option<BackendKind>,
pub envelope: Option<EnvelopeConfig>,
pub message: Option<MessageConfig>,
#[cfg(feature = "imap-backend")]
#[serde(default, with = "OptionImapConfigDef")]

View file

@ -0,0 +1,13 @@
use ::serde::{Deserialize, Serialize};
use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct EnvelopeConfig {
pub list: Option<EnvelopeListConfig>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct EnvelopeListConfig {
pub backend: Option<BackendKind>,
}

View file

@ -0,0 +1 @@
pub mod config;

View file

@ -0,0 +1,13 @@
use ::serde::{Deserialize, Serialize};
use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageConfig {
pub send: Option<MessageSendConfig>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageSendConfig {
pub backend: Option<BackendKind>,
}

View file

@ -0,0 +1 @@
pub mod config;

View file

@ -1,2 +1,4 @@
pub mod args;
pub mod envelope;
pub mod handlers;
pub mod message;