Skip to content

Commit

Permalink
init backend override with list envelopes and send message
Browse files Browse the repository at this point in the history
  • Loading branch information
soywod committed Nov 26, 2023
1 parent cec658a commit 1f88b27
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 75 deletions.
23 changes: 20 additions & 3 deletions config.sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,26 @@ email = "example@localhost"
# listing envelopes or copying messages.
backend = "imap"

imap.host = "imap.gmail.com"
imap.port = 993
# 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.Some.passwd.cmd = "pass show gmail"
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"

106 changes: 76 additions & 30 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ 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,
};
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,
Expand All @@ -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>,
Expand Down Expand Up @@ -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()
Expand All @@ -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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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))
}
Expand Down
58 changes: 18 additions & 40 deletions src/config/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}
}
}
Expand All @@ -356,25 +356,19 @@ 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,
}

#[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),
Expand All @@ -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"
Expand All @@ -395,50 +389,38 @@ 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"
)]
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,
}

Expand Down Expand Up @@ -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,
}

Expand Down
10 changes: 8 additions & 2 deletions src/domain/account/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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")]
Expand Down
13 changes: 13 additions & 0 deletions src/domain/email/envelope/config.rs
Original file line number Diff line number Diff line change
@@ -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>,
}
1 change: 1 addition & 0 deletions src/domain/email/envelope/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod config;
13 changes: 13 additions & 0 deletions src/domain/email/message/config.rs
Original file line number Diff line number Diff line change
@@ -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>,
}
1 change: 1 addition & 0 deletions src/domain/email/message/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod config;
2 changes: 2 additions & 0 deletions src/domain/email/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod args;
pub mod envelope;
pub mod handlers;
pub mod message;

0 comments on commit 1f88b27

Please sign in to comment.