refactor backend system, remove accouts flattening

This commit is contained in:
Clément DOUIN 2024-02-21 11:38:50 +01:00
parent 76ab833a62
commit 3e0cf0cfda
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
59 changed files with 377 additions and 1591 deletions

15
Cargo.lock generated
View file

@ -1217,7 +1217,7 @@ dependencies = [
[[package]] [[package]]
name = "email-lib" name = "email-lib"
version = "0.21.0" version = "0.21.0"
source = "git+https://git.sr.ht/~soywod/pimalaya#ca42096c5537cf15becbb12bf0935381a1ea2908" source = "git+https://git.sr.ht/~soywod/pimalaya#358717d3579ffacad2bbabd9d116a292473e38ae"
dependencies = [ dependencies = [
"advisory-lock", "advisory-lock",
"anyhow", "anyhow",
@ -1239,6 +1239,7 @@ dependencies = [
"mail-parser", "mail-parser",
"mail-send", "mail-send",
"maildirpp", "maildirpp",
"md5",
"mml-lib", "mml-lib",
"notify", "notify",
"notify-rust", "notify-rust",
@ -1246,11 +1247,11 @@ dependencies = [
"oauth-lib", "oauth-lib",
"once_cell", "once_cell",
"ouroboros 0.15.6", "ouroboros 0.15.6",
"paste",
"pgp-lib", "pgp-lib",
"process-lib", "process-lib",
"rayon", "rayon",
"regex", "regex",
"rusqlite",
"secret-lib", "secret-lib",
"serde", "serde",
"serde-xml-rs", "serde-xml-rs",
@ -1265,9 +1266,9 @@ dependencies = [
[[package]] [[package]]
name = "email-macros" name = "email-macros"
version = "0.0.1" version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c6354267c9a1db068b10ad982db9b8a82445f73f9bc9a57ed4924ddb913a065" checksum = "0f24a09fd651027f8764f8a12c12358715cb9bab622ab3125ede3dd6ae047c95"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.41", "syn 2.0.41",
@ -2962,6 +2963,12 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]] [[package]]
name = "pbkdf2" name = "pbkdf2"
version = "0.11.0" version = "0.11.0"

View file

@ -19,21 +19,14 @@ rustdoc-args = ["--cfg", "docsrs"]
# features documentation: # features documentation:
# https://pimalaya.org/himalaya/cli/latest/installation.html#cargo # https://pimalaya.org/himalaya/cli/latest/installation.html#cargo
default = [ default = [
"wizard",
"imap", "imap",
"maildir", "maildir",
# "notmuch", # "notmuch",
"smtp", "smtp",
"sendmail", "sendmail",
"account", "account-discovery",
"folder", "account-sync",
"envelope",
"flag",
"message",
"attachment",
"template",
# "pgp-commands", # "pgp-commands",
# "pgp-gpg", # "pgp-gpg",
@ -46,60 +39,8 @@ notmuch = ["email-lib/notmuch"]
smtp = ["email-lib/smtp"] smtp = ["email-lib/smtp"]
sendmail = ["email-lib/sendmail"] sendmail = ["email-lib/sendmail"]
wizard = ["email-lib/account-discovery"] account-discovery = ["email-lib/account-discovery"]
account = ["account-configure", "account-list", "account-sync"] account-sync = ["email-lib/account-sync"]
account-subcmd = []
account-configure = ["account-subcmd"]
account-list = ["account-subcmd"]
account-sync = ["account-subcmd", "email-lib/account-sync"]
folder = ["folder-add", "folder-list", "folder-expunge", "folder-purge", "folder-delete"]
folder-subcmd = []
folder-add = ["folder-subcmd", "email-lib/folder-add"]
folder-list = ["folder-subcmd", "email-lib/folder-list"]
folder-expunge = ["folder-subcmd", "email-lib/folder-expunge"]
folder-purge = ["folder-subcmd", "email-lib/folder-purge"]
folder-delete = ["folder-subcmd", "email-lib/folder-delete"]
envelope = ["envelope-list", "envelope-watch", "envelope-get"]
envelope-subcmd = []
envelope-list = ["envelope-subcmd", "email-lib/envelope-list"]
envelope-watch = ["envelope-subcmd", "email-lib/envelope-watch"]
envelope-get = ["envelope-subcmd", "email-lib/envelope-get"]
flag = ["flag-add", "flag-set", "flag-remove"]
flag-subcmd = []
flag-add = ["flag-subcmd", "email-lib/flag-add"]
flag-set = ["flag-subcmd", "email-lib/flag-set"]
flag-remove = ["flag-subcmd", "email-lib/flag-remove"]
message = ["message-read", "message-write", "message-mailto", "message-reply", "message-forward", "message-save", "message-send", "message-copy", "message-move", "message-delete"]
message-subcmd = []
message-add = ["email-lib/message-add"]
message-peek = ["email-lib/message-peek"]
message-get = ["email-lib/message-get"]
message-copy = ["message-subcmd", "email-lib/message-copy"]
message-move = ["message-subcmd", "email-lib/message-move"]
message-delete = ["message-subcmd", "email-lib/message-delete"]
message-read = ["message-add", "message-peek", "message-get"]
message-write = ["message-add", "message-send"]
message-mailto = ["message-add", "message-send"]
message-reply = ["message-get", "message-add", "message-send"]
message-forward = ["message-get", "message-add", "message-send"]
message-save = ["message-add"]
message-send = ["message-subcmd", "email-lib/message-send"]
attachment = ["attachment-download"]
attachment-subcmd = []
attachment-download = ["attachment-subcmd", "message-read"]
template = ["template-write", "template-reply", "template-forward", "template-save", "template-send"]
template-subcmd = []
template-write = ["template-subcmd"]
template-reply = ["template-subcmd", "email-lib/message-get"]
template-forward = ["template-subcmd", "email-lib/message-get"]
template-save = ["template-subcmd", "email-lib/message-add"]
template-send = ["template-subcmd", "email-lib/message-send"]
pgp = [] pgp = []
pgp-commands = ["email-lib/pgp-commands", "mml-lib/pgp-commands", "pgp"] pgp-commands = ["email-lib/pgp-commands", "mml-lib/pgp-commands", "pgp"]
@ -120,8 +61,7 @@ clap_mangen = "0.2"
console = "0.15.2" console = "0.15.2"
dialoguer = "0.10.2" dialoguer = "0.10.2"
dirs = "4.0" dirs = "4.0"
# email-lib = { version = "=0.21.0", default-features = false } email-lib = { version = "=0.21.0", default-features = false }
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
email_address = "0.2.4" email_address = "0.2.4"
env_logger = "0.8" env_logger = "0.8"
erased-serde = "0.3" erased-serde = "0.3"
@ -157,3 +97,6 @@ features = ["bundled"]
[target.'cfg(not(windows))'.dependencies.coredump] [target.'cfg(not(windows))'.dependencies.coredump]
version = "0.1" version = "0.1"
[patch.crates-io]
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }

View file

@ -1,6 +1,4 @@
#[cfg(feature = "account-configure")]
mod configure; mod configure;
#[cfg(feature = "account-list")]
mod list; mod list;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
mod sync; mod sync;
@ -10,12 +8,9 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "account-configure")]
use self::configure::AccountConfigureCommand;
#[cfg(feature = "account-list")]
use self::list::AccountListCommand;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use self::sync::AccountSyncCommand; use self::sync::AccountSyncCommand;
use self::{configure::AccountConfigureCommand, list::AccountListCommand};
/// Manage accounts. /// Manage accounts.
/// ///
@ -24,11 +19,9 @@ use self::sync::AccountSyncCommand;
/// file. This subcommand allows you to manage them. /// file. This subcommand allows you to manage them.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum AccountSubcommand { pub enum AccountSubcommand {
#[cfg(feature = "account-configure")]
#[command(alias = "cfg")] #[command(alias = "cfg")]
Configure(AccountConfigureCommand), Configure(AccountConfigureCommand),
#[cfg(feature = "account-list")]
#[command(alias = "lst")] #[command(alias = "lst")]
List(AccountListCommand), List(AccountListCommand),
@ -41,9 +34,7 @@ impl AccountSubcommand {
#[allow(unused)] #[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "account-configure")]
Self::Configure(cmd) => cmd.execute(printer, config).await, Self::Configure(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "account-list")]
Self::List(cmd) => cmd.execute(printer, config).await, Self::List(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Self::Sync(cmd) => cmd.execute(printer, config).await, Self::Sync(cmd) => cmd.execute(printer, config).await,

View file

@ -8,25 +8,22 @@ use anyhow::Result;
use clap::{ArgAction, Parser}; use clap::{ArgAction, Parser};
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
use email::imap::ImapContextBuilder; use email::imap::ImapContextBuilder;
#[cfg(feature = "account-sync")]
use email::maildir::config::MaildirConfig; use email::maildir::config::MaildirConfig;
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
use email::maildir::MaildirContextBuilder; use email::maildir::MaildirContextBuilder;
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
use email::notmuch::NotmuchContextBuilder; use email::notmuch::NotmuchContextBuilder;
use email::{ use email::{
account::{ account::{config::AccountConfig, sync::AccountSyncBuilder},
config::AccountConfig,
sync::{AccountSyncBuilder, AccountSyncProgressEvent},
},
backend::BackendBuilder, backend::BackendBuilder,
folder::sync::FolderSyncStrategy, folder::sync::config::FolderSyncStrategy,
sync::SyncEvent,
}; };
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle}; use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
use log::info; use log::info;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{BTreeSet, HashMap},
ops::Deref, ops::Deref,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -96,8 +93,8 @@ impl AccountSyncCommand {
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
info!("executing sync account command"); info!("executing sync account command");
let included_folders = HashSet::from_iter(self.include_folder); let included_folders = BTreeSet::from_iter(self.include_folder);
let excluded_folders = HashSet::from_iter(self.exclude_folder); let excluded_folders = BTreeSet::from_iter(self.exclude_folder);
let strategy = if !included_folders.is_empty() { let strategy = if !included_folders.is_empty() {
Some(FolderSyncStrategy::Include(included_folders)) Some(FolderSyncStrategy::Include(included_folders))
@ -116,26 +113,25 @@ impl AccountSyncCommand {
let backend_builder = let backend_builder =
AccountSyncBackendBuilder::new(toml_account_config, account_config.clone()).await?; AccountSyncBackendBuilder::new(toml_account_config, account_config.clone()).await?;
let sync_builder = AccountSyncBuilder::new(account_config.clone(), backend_builder.into()) let sync_builder = AccountSyncBuilder::new(backend_builder.into())?
.await? .with_dry_run(self.dry_run)
.with_some_folders_strategy(strategy) .with_some_folders_filter(strategy);
.with_dry_run(self.dry_run);
if self.dry_run { if self.dry_run {
let report = sync_builder.sync().await?; let report = sync_builder.sync().await?;
let mut hunks_count = report.folders_patch.len(); let mut hunks_count = report.folder.patch.len();
if !report.folders_patch.is_empty() { if !report.folder.patch.is_empty() {
printer.print_log("Folders patch:")?; printer.print_log("Folders patch:")?;
for (hunk, _) in report.folders_patch { for (hunk, _) in report.folder.patch {
printer.print_log(format!(" - {hunk}"))?; printer.print_log(format!(" - {hunk}"))?;
} }
printer.print_log("")?; printer.print_log("")?;
} }
if !report.emails_patch.is_empty() { if !report.email.patch.is_empty() {
printer.print_log("Envelopes patch:")?; printer.print_log("Envelopes patch:")?;
for (hunk, _) in report.emails_patch { for (hunk, _) in report.email.patch {
hunks_count += 1; hunks_count += 1;
printer.print_log(format!(" - {hunk}"))?; printer.print_log(format!(" - {hunk}"))?;
} }
@ -154,27 +150,27 @@ impl AccountSyncCommand {
let main_progress = multi.add( let main_progress = multi.add(
ProgressBar::new(100) ProgressBar::new(100)
.with_style(MAIN_PROGRESS_STYLE.clone()) .with_style(MAIN_PROGRESS_STYLE.clone())
.with_message("Synchronizing folders…"), .with_message("Listing folders…"),
); );
// Force the progress bar to show main_progress.tick();
main_progress.set_position(0);
let report = sync_builder let report = sync_builder
.with_on_progress(move |evt| { .with_handler(move |evt| {
use AccountSyncProgressEvent::*;
match evt { match evt {
ApplyFolderPatches(..) => { SyncEvent::ListedAllFolders => {
main_progress.inc(3); main_progress.set_message("Synchronizing folders…");
} }
ApplyEnvelopePatches(patches) => { SyncEvent::ProcessedAllFolderHunks => {
let mut envelopes_progresses = sub_progresses.lock().unwrap(); main_progress.set_message("Listing envelopes…");
let patches_len = }
patches.values().fold(0, |sum, patch| sum + patch.len()); SyncEvent::GeneratedEmailPatch(patches) => {
main_progress.set_length((110 * patches_len / 100) as u64); let patches_len = patches.values().flatten().count();
main_progress.set_position((5 * patches_len / 100) as u64); main_progress.set_length(patches_len as u64);
main_progress.set_message("Synchronizing envelopes…"); main_progress.set_position(0);
main_progress.set_message("Synchronizing emails…");
let mut envelopes_progresses = sub_progresses.lock().unwrap();
for (folder, patch) in patches { for (folder, patch) in patches {
let progress = ProgressBar::new(patch.len() as u64) let progress = ProgressBar::new(patch.len() as u64)
.with_style(SUB_PROGRESS_STYLE.clone()) .with_style(SUB_PROGRESS_STYLE.clone())
@ -184,7 +180,7 @@ impl AccountSyncCommand {
envelopes_progresses.insert(folder, progress.clone()); envelopes_progresses.insert(folder, progress.clone());
} }
} }
ApplyEnvelopeHunk(hunk) => { SyncEvent::ProcessedEmailHunk(hunk) => {
main_progress.inc(1); main_progress.inc(1);
let mut progresses = sub_progresses.lock().unwrap(); let mut progresses = sub_progresses.lock().unwrap();
if let Some(progress) = progresses.get_mut(hunk.folder()) { if let Some(progress) = progresses.get_mut(hunk.folder()) {
@ -196,31 +192,33 @@ impl AccountSyncCommand {
} }
} }
} }
ApplyEnvelopeCachePatch(_patch) => { SyncEvent::ProcessedAllEmailHunks => {
main_progress.set_length(100);
main_progress.set_position(95);
main_progress.set_message("Saving cache database…");
}
ExpungeFolders(folders) => {
let mut progresses = sub_progresses.lock().unwrap(); let mut progresses = sub_progresses.lock().unwrap();
for progress in progresses.values() { for progress in progresses.values() {
progress.finish_and_clear() progress.finish_and_clear()
} }
progresses.clear(); progresses.clear();
main_progress.set_length(100);
main_progress.set_position(100); main_progress.set_position(100);
main_progress main_progress.set_message("Expunging folders…");
.set_message(format!("Expunging {} folders…", folders.len())); }
SyncEvent::ExpungedAllFolders => {
main_progress.finish_and_clear();
}
_ => {
main_progress.tick();
} }
_ => (),
}; };
Ok(())
async { Ok(()) }
}) })
.sync() .sync()
.await?; .await?;
let folders_patch_err = report let folders_patch_err = report
.folders_patch .folder
.patch
.iter() .iter()
.filter_map(|(hunk, err)| err.as_ref().map(|err| (hunk, err))) .filter_map(|(hunk, err)| err.as_ref().map(|err| (hunk, err)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -232,15 +230,9 @@ impl AccountSyncCommand {
.try_for_each(|(hunk, err)| printer.print_log(format!(" - {hunk}: {err}")))?; .try_for_each(|(hunk, err)| printer.print_log(format!(" - {hunk}: {err}")))?;
} }
if let Some(err) = report.folders_cache_patch.1 {
printer.print_log("")?;
printer.print_log(format!(
"Error occurred while applying the folder cache patch: {err}"
))?;
}
let envelopes_patch_err = report let envelopes_patch_err = report
.emails_patch .email
.patch
.iter() .iter()
.filter_map(|(hunk, err)| err.as_ref().map(|err| (hunk, err))) .filter_map(|(hunk, err)| err.as_ref().map(|err| (hunk, err)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -252,13 +244,6 @@ impl AccountSyncCommand {
} }
} }
if let Some(err) = report.emails_cache_patch.1 {
printer.print_log("")?;
printer.print_log(format!(
"Error occurred while applying the envelopes cache patch: {err}"
))?;
}
printer.print(format!("Account {account_name} successfully synchronized!"))?; printer.print(format!("Account {account_name} successfully synchronized!"))?;
} }
@ -283,7 +268,6 @@ impl AccountSyncBackendBuilder {
let is_imap_used = used_backends.contains(&BackendKind::Imap); let is_imap_used = used_backends.contains(&BackendKind::Imap);
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
let is_maildir_used = used_backends.contains(&BackendKind::Maildir); let is_maildir_used = used_backends.contains(&BackendKind::Maildir);
#[cfg(feature = "account-sync")]
let is_maildir_for_sync_used = used_backends.contains(&BackendKind::MaildirForSync); let is_maildir_for_sync_used = used_backends.contains(&BackendKind::MaildirForSync);
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
let is_notmuch_used = used_backends.contains(&BackendKind::Notmuch); let is_notmuch_used = used_backends.contains(&BackendKind::Notmuch);
@ -300,7 +284,10 @@ impl AccountSyncBackendBuilder {
.filter(|_| is_imap_used) .filter(|_| is_imap_used)
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(|config| ImapContextBuilder::new(config).with_prebuilt_credentials()); .map(|config| {
ImapContextBuilder::new(account_config.clone(), config)
.with_prebuilt_credentials()
});
match builder { match builder {
Some(builder) => Some(builder.await?), Some(builder) => Some(builder.await?),
None => None, None => None,
@ -314,15 +301,14 @@ impl AccountSyncBackendBuilder {
.filter(|_| is_maildir_used) .filter(|_| is_maildir_used)
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(MaildirContextBuilder::new), .map(|mdir_config| MaildirContextBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "account-sync")]
maildir_for_sync: Some(MaildirConfig { maildir_for_sync: Some(MaildirConfig {
root_dir: account_config.get_sync_dir()?, root_dir: account_config.get_sync_dir()?,
}) })
.filter(|_| is_maildir_for_sync_used) .filter(|_| is_maildir_for_sync_used)
.map(Arc::new) .map(Arc::new)
.map(MaildirContextBuilder::new), .map(|mdir_config| MaildirContextBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
notmuch: toml_account_config notmuch: toml_account_config
@ -331,7 +317,9 @@ impl AccountSyncBackendBuilder {
.filter(|_| is_notmuch_used) .filter(|_| is_notmuch_used)
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(NotmuchContextBuilder::new), .map(|notmuch_config| {
NotmuchContextBuilder::new(account_config.clone(), notmuch_config)
}),
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
smtp: None, smtp: None,

View file

@ -60,7 +60,6 @@ pub struct TomlAccountConfig {
} }
impl TomlAccountConfig { impl TomlAccountConfig {
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
pub fn add_folder_kind(&self) -> Option<&BackendKind> { pub fn add_folder_kind(&self) -> Option<&BackendKind> {
self.folder self.folder
.as_ref() .as_ref()
@ -69,7 +68,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
pub fn list_folders_kind(&self) -> Option<&BackendKind> { pub fn list_folders_kind(&self) -> Option<&BackendKind> {
self.folder self.folder
.as_ref() .as_ref()
@ -78,7 +76,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
pub fn expunge_folder_kind(&self) -> Option<&BackendKind> { pub fn expunge_folder_kind(&self) -> Option<&BackendKind> {
self.folder self.folder
.as_ref() .as_ref()
@ -87,7 +84,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(feature = "folder-purge")]
pub fn purge_folder_kind(&self) -> Option<&BackendKind> { pub fn purge_folder_kind(&self) -> Option<&BackendKind> {
self.folder self.folder
.as_ref() .as_ref()
@ -96,7 +92,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
pub fn delete_folder_kind(&self) -> Option<&BackendKind> { pub fn delete_folder_kind(&self) -> Option<&BackendKind> {
self.folder self.folder
.as_ref() .as_ref()
@ -105,7 +100,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
pub fn get_envelope_kind(&self) -> Option<&BackendKind> { pub fn get_envelope_kind(&self) -> Option<&BackendKind> {
self.envelope self.envelope
.as_ref() .as_ref()
@ -114,7 +108,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
pub fn list_envelopes_kind(&self) -> Option<&BackendKind> { pub fn list_envelopes_kind(&self) -> Option<&BackendKind> {
self.envelope self.envelope
.as_ref() .as_ref()
@ -123,7 +116,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(feature = "envelope-watch")]
pub fn watch_envelopes_kind(&self) -> Option<&BackendKind> { pub fn watch_envelopes_kind(&self) -> Option<&BackendKind> {
self.envelope self.envelope
.as_ref() .as_ref()
@ -132,7 +124,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
pub fn add_flags_kind(&self) -> Option<&BackendKind> { pub fn add_flags_kind(&self) -> Option<&BackendKind> {
self.flag self.flag
.as_ref() .as_ref()
@ -141,7 +132,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
pub fn set_flags_kind(&self) -> Option<&BackendKind> { pub fn set_flags_kind(&self) -> Option<&BackendKind> {
self.flag self.flag
.as_ref() .as_ref()
@ -150,7 +140,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(feature = "flag-remove")]
pub fn remove_flags_kind(&self) -> Option<&BackendKind> { pub fn remove_flags_kind(&self) -> Option<&BackendKind> {
self.flag self.flag
.as_ref() .as_ref()
@ -159,7 +148,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "message-add"))]
pub fn add_message_kind(&self) -> Option<&BackendKind> { pub fn add_message_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -168,7 +156,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
pub fn peek_messages_kind(&self) -> Option<&BackendKind> { pub fn peek_messages_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -177,7 +164,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))]
pub fn get_messages_kind(&self) -> Option<&BackendKind> { pub fn get_messages_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -186,7 +172,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(feature = "message-copy")]
pub fn copy_messages_kind(&self) -> Option<&BackendKind> { pub fn copy_messages_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -195,7 +180,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))]
pub fn move_messages_kind(&self) -> Option<&BackendKind> { pub fn move_messages_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -204,7 +188,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(feature = "message-delete")]
pub fn delete_messages_kind(&self) -> Option<&BackendKind> { pub fn delete_messages_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -213,7 +196,6 @@ impl TomlAccountConfig {
.or(self.backend.as_ref()) .or(self.backend.as_ref())
} }
#[cfg(any(feature = "message-send", feature = "template-send"))]
pub fn send_message_kind(&self) -> Option<&BackendKind> { pub fn send_message_kind(&self) -> Option<&BackendKind> {
self.message self.message
.as_ref() .as_ref()
@ -233,17 +215,14 @@ impl TomlAccountConfig {
used_backends.extend(folder.get_used_backends()); used_backends.extend(folder.get_used_backends());
} }
#[cfg(feature = "envelope-subcmd")]
if let Some(ref envelope) = self.envelope { if let Some(ref envelope) = self.envelope {
used_backends.extend(envelope.get_used_backends()); used_backends.extend(envelope.get_used_backends());
} }
#[cfg(feature = "flag-subcmd")]
if let Some(ref flag) = self.flag { if let Some(ref flag) = self.flag {
used_backends.extend(flag.get_used_backends()); used_backends.extend(flag.get_used_backends());
} }
#[cfg(feature = "message-subcmd")]
if let Some(ref msg) = self.message { if let Some(ref msg) = self.message {
used_backends.extend(msg.get_used_backends()); used_backends.extend(msg.get_used_backends());
} }

View file

@ -1,7 +1,6 @@
pub mod arg; pub mod arg;
pub mod command; pub mod command;
pub mod config; pub mod config;
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;
use anyhow::Result; use anyhow::Result;

View file

@ -1,21 +1,20 @@
use std::str::FromStr;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use dialoguer::Confirm; use dialoguer::{Confirm, Input};
use dialoguer::Input;
use email::account; use email::account;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use email::account::sync::config::SyncConfig; use email::account::sync::config::SyncConfig;
use email_address::EmailAddress; use email_address::EmailAddress;
use std::str::FromStr;
#[allow(unused)]
use crate::backend::{self, config::BackendConfig, BackendKind};
#[cfg(feature = "message-send")]
use crate::message::config::{MessageConfig, MessageSendConfig};
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use crate::wizard_prompt; use crate::wizard_prompt;
use crate::{ui::THEME, wizard_warn}; use crate::{
backend::{self, config::BackendConfig, BackendKind},
message::config::{MessageConfig, MessageSendConfig},
ui::THEME,
wizard_warn,
};
use super::TomlAccountConfig; use super::TomlAccountConfig;
@ -95,32 +94,24 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
Some(BackendConfig::Smtp(smtp_config)) => { Some(BackendConfig::Smtp(smtp_config)) => {
config.smtp = Some(smtp_config); config.smtp = Some(smtp_config);
config.message = Some(MessageConfig {
#[cfg(feature = "message-send")] send: Some(MessageSendConfig {
{ backend: Some(BackendKind::Smtp),
config.message = Some(MessageConfig {
send: Some(MessageSendConfig {
backend: Some(BackendKind::Smtp),
..Default::default()
}),
..Default::default() ..Default::default()
}); }),
} ..Default::default()
});
} }
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
Some(BackendConfig::Sendmail(sendmail_config)) => { Some(BackendConfig::Sendmail(sendmail_config)) => {
config.sendmail = Some(sendmail_config); config.sendmail = Some(sendmail_config);
config.message = Some(MessageConfig {
#[cfg(feature = "message-send")] send: Some(MessageSendConfig {
{ backend: Some(BackendKind::Sendmail),
config.message = Some(MessageConfig {
send: Some(MessageSendConfig {
backend: Some(BackendKind::Sendmail),
..Default::default()
}),
..Default::default() ..Default::default()
}); }),
} ..Default::default()
});
} }
_ => (), _ => (),
}; };

View file

@ -1,53 +1,16 @@
pub mod config; pub mod config;
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
use email::envelope::get::GetEnvelope;
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
use email::envelope::list::ListEnvelopes;
#[cfg(feature = "envelope-watch")]
use email::envelope::watch::WatchEnvelopes;
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
use email::flag::add::AddFlags;
#[cfg(feature = "flag-remove")]
use email::flag::remove::RemoveFlags;
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
use email::flag::set::SetFlags;
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
use email::folder::add::AddFolder;
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
use email::folder::delete::DeleteFolder;
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
use email::folder::expunge::ExpungeFolder;
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
use email::folder::list::ListFolders;
#[cfg(feature = "folder-purge")]
use email::folder::purge::PurgeFolder;
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
use email::imap::{ImapContextBuilder, ImapContextSync}; use email::imap::{ImapContextBuilder, ImapContextSync};
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use email::maildir::config::MaildirConfig; use email::maildir::config::MaildirConfig;
#[cfg(any(feature = "account-sync", feature = "maildir"))] #[cfg(any(feature = "account-sync", feature = "maildir"))]
use email::maildir::{MaildirContextBuilder, MaildirContextSync}; use email::maildir::{MaildirContextBuilder, MaildirContextSync};
#[cfg(any(feature = "account-sync", feature = "message-add"))]
use email::message::add::AddMessage;
#[cfg(feature = "message-copy")]
use email::message::copy::CopyMessages;
#[cfg(feature = "message-delete")]
use email::message::delete::DeleteMessages;
#[cfg(any(feature = "account-sync", feature = "message-get"))]
use email::message::get::GetMessages;
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
use email::message::peek::PeekMessages;
#[cfg(any(feature = "account-sync", feature = "message-move"))]
use email::message::r#move::MoveMessages;
#[cfg(feature = "message-send")]
use email::message::send::SendMessage;
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
use email::notmuch::{NotmuchContextBuilder, NotmuchContextSync}; use email::notmuch::{NotmuchContextBuilder, NotmuchContextSync};
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
@ -57,17 +20,22 @@ use email::smtp::{SmtpContextBuilder, SmtpContextSync};
use email::{ use email::{
account::config::AccountConfig, account::config::AccountConfig,
backend::{ backend::{
macros::BackendContext, BackendFeatureBuilder, FindBackendSubcontext, MapBackendFeature, feature::BackendFeature, macros::BackendContext, mapper::SomeBackendContextBuilderMapper,
},
envelope::{get::GetEnvelope, list::ListEnvelopes, watch::WatchEnvelopes, Id, SingleId},
flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags, Flag, Flags},
folder::{
add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders,
purge::PurgeFolder,
},
message::{
add::AddMessage, copy::CopyMessages, delete::DeleteMessages, get::GetMessages,
peek::PeekMessages, r#move::MoveMessages, send::SendMessage, Messages,
}, },
envelope::{Id, SingleId},
flag::{Flag, Flags},
message::Messages,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(any(feature = "account-sync", feature = "envelope-list"))] use crate::{account::config::TomlAccountConfig, cache::IdMapper, envelope::Envelopes};
use crate::envelope::Envelopes;
use crate::{account::config::TomlAccountConfig, cache::IdMapper};
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -152,7 +120,10 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Imap)) .filter(|_| kinds.contains(&&BackendKind::Imap))
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(|config| ImapContextBuilder::new(config).with_prebuilt_credentials()); .map(|imap_config| {
ImapContextBuilder::new(account_config.clone(), imap_config)
.with_prebuilt_credentials()
});
match builder { match builder {
Some(builder) => Some(builder.await?), Some(builder) => Some(builder.await?),
None => None, None => None,
@ -166,7 +137,7 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Maildir)) .filter(|_| kinds.contains(&&BackendKind::Maildir))
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(MaildirContextBuilder::new), .map(|mdir_config| MaildirContextBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
maildir_for_sync: Some(MaildirConfig { maildir_for_sync: Some(MaildirConfig {
@ -174,7 +145,7 @@ impl BackendContextBuilder {
}) })
.filter(|_| kinds.contains(&&BackendKind::MaildirForSync)) .filter(|_| kinds.contains(&&BackendKind::MaildirForSync))
.map(Arc::new) .map(Arc::new)
.map(MaildirContextBuilder::new), .map(|mdir_config| MaildirContextBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
notmuch: toml_account_config notmuch: toml_account_config
@ -183,7 +154,9 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Notmuch)) .filter(|_| kinds.contains(&&BackendKind::Notmuch))
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(NotmuchContextBuilder::new), .map(|notmuch_config| {
NotmuchContextBuilder::new(account_config.clone(), notmuch_config)
}),
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
smtp: toml_account_config smtp: toml_account_config
@ -192,7 +165,7 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Smtp)) .filter(|_| kinds.contains(&&BackendKind::Smtp))
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(SmtpContextBuilder::new), .map(|smtp_config| SmtpContextBuilder::new(account_config.clone(), smtp_config)),
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
sendmail: toml_account_config sendmail: toml_account_config
@ -201,363 +174,347 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Sendmail)) .filter(|_| kinds.contains(&&BackendKind::Sendmail))
.map(Clone::clone) .map(Clone::clone)
.map(Arc::new) .map(Arc::new)
.map(SendmailContextBuilder::new), .map(|sendmail_config| {
SendmailContextBuilder::new(account_config.clone(), sendmail_config)
}),
}) })
} }
} }
#[async_trait] #[async_trait]
impl email::backend::BackendContextBuilder for BackendContextBuilder { impl email::backend::context::BackendContextBuilder for BackendContextBuilder {
type Context = BackendContext; type Context = BackendContext;
#[cfg(any(feature = "account-sync", feature = "folder-add"))] fn add_folder(&self) -> Option<BackendFeature<Self::Context, dyn AddFolder>> {
fn add_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn AddFolder> {
match self.toml_account_config.add_folder_kind() { match self.toml_account_config.add_folder_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.add_folder_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.add_folder_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.add_folder_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.add_folder_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_folder()?; let f = self.maildir_for_sync.as_ref()?.add_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.add_folder_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.add_folder_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-list"))] fn list_folders(&self) -> Option<BackendFeature<Self::Context, dyn ListFolders>> {
fn list_folders(&self) -> BackendFeatureBuilder<Self::Context, dyn ListFolders> {
match self.toml_account_config.list_folders_kind() { match self.toml_account_config.list_folders_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.list_folders_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.list_folders_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.list_folders_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.list_folders_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.list_folders()?; let f = self.maildir_for_sync.as_ref()?.list_folders()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.list_folders_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.list_folders_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))] fn expunge_folder(&self) -> Option<BackendFeature<Self::Context, dyn ExpungeFolder>> {
fn expunge_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn ExpungeFolder> {
match self.toml_account_config.expunge_folder_kind() { match self.toml_account_config.expunge_folder_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.expunge_folder_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.expunge_folder_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.expunge_folder_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.expunge_folder_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.expunge_folder()?; let f = self.maildir_for_sync.as_ref()?.expunge_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.expunge_folder_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.expunge_folder_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(feature = "folder-purge")] fn purge_folder(&self) -> Option<BackendFeature<Self::Context, dyn PurgeFolder>> {
fn purge_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn PurgeFolder> {
match self.toml_account_config.purge_folder_kind() { match self.toml_account_config.purge_folder_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.purge_folder_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.purge_folder_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.purge_folder_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.purge_folder_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.purge_folder()?; let f = self.maildir_for_sync.as_ref()?.purge_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.purge_folder_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.purge_folder_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-delete"))] fn delete_folder(&self) -> Option<BackendFeature<Self::Context, dyn DeleteFolder>> {
fn delete_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn DeleteFolder> {
match self.toml_account_config.delete_folder_kind() { match self.toml_account_config.delete_folder_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.delete_folder_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.delete_folder_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.delete_folder_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.delete_folder_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.delete_folder()?; let f = self.maildir_for_sync.as_ref()?.delete_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.delete_folder_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.delete_folder_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))] fn get_envelope(&self) -> Option<BackendFeature<Self::Context, dyn GetEnvelope>> {
fn list_envelopes(&self) -> BackendFeatureBuilder<Self::Context, dyn ListEnvelopes> {
match self.toml_account_config.list_envelopes_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.list_envelopes_from(self.imap.as_ref()),
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.list_envelopes_from(self.maildir.as_ref()),
#[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.list_envelopes()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.list_envelopes_from(self.notmuch.as_ref()),
_ => None,
}
}
#[cfg(feature = "envelope-watch")]
fn watch_envelopes(&self) -> BackendFeatureBuilder<Self::Context, dyn WatchEnvelopes> {
match self.toml_account_config.watch_envelopes_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.watch_envelopes_from(self.imap.as_ref()),
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.watch_envelopes_from(self.maildir.as_ref()),
#[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.watch_envelopes()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.watch_envelopes_from(self.notmuch.as_ref()),
_ => None,
}
}
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
fn get_envelope(&self) -> BackendFeatureBuilder<Self::Context, dyn GetEnvelope> {
match self.toml_account_config.get_envelope_kind() { match self.toml_account_config.get_envelope_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.get_envelope_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.get_envelope_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.get_envelope_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.get_envelope_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.get_envelope()?; let f = self.maildir_for_sync.as_ref()?.get_envelope()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.get_envelope_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.get_envelope_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "flag-add"))] fn list_envelopes(&self) -> Option<BackendFeature<Self::Context, dyn ListEnvelopes>> {
fn add_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn AddFlags> { match self.toml_account_config.list_envelopes_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.list_envelopes_with_some(&self.imap),
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.list_envelopes_with_some(&self.maildir),
#[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.list_envelopes()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.list_envelopes_with_some(&self.notmuch),
_ => None,
}
}
fn watch_envelopes(&self) -> Option<BackendFeature<Self::Context, dyn WatchEnvelopes>> {
match self.toml_account_config.watch_envelopes_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.watch_envelopes_with_some(&self.imap),
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.watch_envelopes_with_some(&self.maildir),
#[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.watch_envelopes()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.watch_envelopes_with_some(&self.notmuch),
_ => None,
}
}
fn add_flags(&self) -> Option<BackendFeature<Self::Context, dyn AddFlags>> {
match self.toml_account_config.add_flags_kind() { match self.toml_account_config.add_flags_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.add_flags_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.add_flags_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.add_flags_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.add_flags_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_flags()?; let f = self.maildir_for_sync.as_ref()?.add_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.add_flags_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.add_flags_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "flag-set"))] fn set_flags(&self) -> Option<BackendFeature<Self::Context, dyn SetFlags>> {
fn set_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn SetFlags> {
match self.toml_account_config.set_flags_kind() { match self.toml_account_config.set_flags_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.set_flags_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.set_flags_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.set_flags_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.set_flags_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.set_flags()?; let f = self.maildir_for_sync.as_ref()?.set_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.set_flags_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.set_flags_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(feature = "flag-remove")] fn remove_flags(&self) -> Option<BackendFeature<Self::Context, dyn RemoveFlags>> {
fn remove_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn RemoveFlags> {
match self.toml_account_config.remove_flags_kind() { match self.toml_account_config.remove_flags_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.remove_flags_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.remove_flags_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.remove_flags_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.remove_flags_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.remove_flags()?; let f = self.maildir_for_sync.as_ref()?.remove_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.remove_flags_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.remove_flags_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-add"))] fn add_message(&self) -> Option<BackendFeature<Self::Context, dyn AddMessage>> {
fn add_message(&self) -> BackendFeatureBuilder<Self::Context, dyn AddMessage> {
match self.toml_account_config.add_message_kind() { match self.toml_account_config.add_message_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.add_message_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.add_message_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.add_message_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.add_message_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_message()?; let f = self.maildir_for_sync.as_ref()?.add_message()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.add_message_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.add_message_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(feature = "message-send")] fn send_message(&self) -> Option<BackendFeature<Self::Context, dyn SendMessage>> {
fn send_message(&self) -> BackendFeatureBuilder<Self::Context, dyn SendMessage> {
match self.toml_account_config.send_message_kind() { match self.toml_account_config.send_message_kind() {
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => self.send_message_from(self.smtp.as_ref()), Some(BackendKind::Smtp) => self.send_message_with_some(&self.smtp),
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => self.send_message_from(self.sendmail.as_ref()), Some(BackendKind::Sendmail) => self.send_message_with_some(&self.sendmail),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-peek"))] fn peek_messages(&self) -> Option<BackendFeature<Self::Context, dyn PeekMessages>> {
fn peek_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn PeekMessages> {
match self.toml_account_config.peek_messages_kind() { match self.toml_account_config.peek_messages_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.peek_messages_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.peek_messages_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.peek_messages_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.peek_messages_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.peek_messages()?; let f = self.maildir_for_sync.as_ref()?.peek_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.peek_messages_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.peek_messages_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))] fn get_messages(&self) -> Option<BackendFeature<Self::Context, dyn GetMessages>> {
fn get_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn GetMessages> {
match self.toml_account_config.get_messages_kind() { match self.toml_account_config.get_messages_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.get_messages_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.get_messages_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.get_messages_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.get_messages_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.get_messages()?; let f = self.maildir_for_sync.as_ref()?.get_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.get_messages_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.get_messages_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(feature = "message-copy")] fn copy_messages(&self) -> Option<BackendFeature<Self::Context, dyn CopyMessages>> {
fn copy_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn CopyMessages> {
match self.toml_account_config.copy_messages_kind() { match self.toml_account_config.copy_messages_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.copy_messages_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.copy_messages_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.copy_messages_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.copy_messages_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.copy_messages()?; let f = self.maildir_for_sync.as_ref()?.copy_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.copy_messages_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.copy_messages_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))] fn move_messages(&self) -> Option<BackendFeature<Self::Context, dyn MoveMessages>> {
fn move_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn MoveMessages> {
match self.toml_account_config.move_messages_kind() { match self.toml_account_config.move_messages_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.move_messages_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.move_messages_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.move_messages_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.move_messages_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.move_messages()?; let f = self.maildir_for_sync.as_ref()?.move_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.move_messages_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.move_messages_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
#[cfg(feature = "message-delete")] fn delete_messages(&self) -> Option<BackendFeature<Self::Context, dyn DeleteMessages>> {
fn delete_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn DeleteMessages> {
match self.toml_account_config.delete_messages_kind() { match self.toml_account_config.delete_messages_kind() {
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
Some(BackendKind::Imap) => self.delete_messages_from(self.imap.as_ref()), Some(BackendKind::Imap) => self.delete_messages_with_some(&self.imap),
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => self.delete_messages_from(self.maildir.as_ref()), Some(BackendKind::Maildir) => self.delete_messages_with_some(&self.maildir),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
Some(BackendKind::MaildirForSync) => { Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.delete_messages()?; let f = self.maildir_for_sync.as_ref()?.delete_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?))) Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => self.delete_messages_from(self.notmuch.as_ref()), Some(BackendKind::Notmuch) => self.delete_messages_with_some(&self.notmuch),
_ => None, _ => None,
} }
} }
async fn build(self, config: Arc<AccountConfig>) -> Result<Self::Context> { async fn build(self) -> Result<Self::Context> {
let mut ctx = BackendContext::default(); let mut ctx = BackendContext::default();
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
if let Some(imap) = self.imap { if let Some(imap) = self.imap {
ctx.imap = Some(imap.build(config.clone()).await?); ctx.imap = Some(imap.build().await?);
} }
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
if let Some(maildir) = self.maildir { if let Some(maildir) = self.maildir {
ctx.maildir = Some(maildir.build(config.clone()).await?); ctx.maildir = Some(maildir.build().await?);
} }
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
if let Some(maildir) = self.maildir_for_sync { if let Some(maildir) = self.maildir_for_sync {
ctx.maildir_for_sync = Some(maildir.build(config.clone()).await?); ctx.maildir_for_sync = Some(maildir.build().await?);
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
if let Some(notmuch) = self.notmuch { if let Some(notmuch) = self.notmuch {
ctx.notmuch = Some(notmuch.build(config.clone()).await?); ctx.notmuch = Some(notmuch.build().await?);
} }
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
if let Some(smtp) = self.smtp { if let Some(smtp) = self.smtp {
ctx.smtp = Some(smtp.build(config.clone()).await?); ctx.smtp = Some(smtp.build().await?);
} }
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
if let Some(sendmail) = self.sendmail { if let Some(sendmail) = self.sendmail {
ctx.sendmail = Some(sendmail.build(config.clone()).await?); ctx.sendmail = Some(sendmail.build().await?);
} }
Ok(ctx) Ok(ctx)
@ -586,37 +543,37 @@ pub struct BackendContext {
} }
#[cfg(feature = "imap")] #[cfg(feature = "imap")]
impl FindBackendSubcontext<ImapContextSync> for BackendContext { impl AsRef<Option<ImapContextSync>> for BackendContext {
fn find_subcontext(&self) -> Option<&ImapContextSync> { fn as_ref(&self) -> &Option<ImapContextSync> {
self.imap.as_ref() &self.imap
} }
} }
#[cfg(feature = "maildir")] #[cfg(feature = "maildir")]
impl FindBackendSubcontext<MaildirContextSync> for BackendContext { impl AsRef<Option<MaildirContextSync>> for BackendContext {
fn find_subcontext(&self) -> Option<&MaildirContextSync> { fn as_ref(&self) -> &Option<MaildirContextSync> {
self.maildir.as_ref() &self.maildir
} }
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
impl FindBackendSubcontext<NotmuchContextSync> for BackendContext { impl AsRef<Option<NotmuchContextSync>> for BackendContext {
fn find_subcontext(&self) -> Option<&NotmuchContextSync> { fn as_ref(&self) -> &Option<NotmuchContextSync> {
self.notmuch.as_ref() &self.notmuch
} }
} }
#[cfg(feature = "smtp")] #[cfg(feature = "smtp")]
impl FindBackendSubcontext<SmtpContextSync> for BackendContext { impl AsRef<Option<SmtpContextSync>> for BackendContext {
fn find_subcontext(&self) -> Option<&SmtpContextSync> { fn as_ref(&self) -> &Option<SmtpContextSync> {
self.smtp.as_ref() &self.smtp
} }
} }
#[cfg(feature = "sendmail")] #[cfg(feature = "sendmail")]
impl FindBackendSubcontext<SendmailContextSync> for BackendContext { impl AsRef<Option<SendmailContextSync>> for BackendContext {
fn find_subcontext(&self) -> Option<&SendmailContextSync> { fn as_ref(&self) -> &Option<SendmailContextSync> {
self.sendmail.as_ref() &self.sendmail
} }
} }
@ -641,7 +598,7 @@ impl Backend {
.await?; .await?;
let mut backend_builder = let mut backend_builder =
email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder) email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder)
.with_default_features_disabled(); .without_features();
with_features(&mut backend_builder); with_features(&mut backend_builder);
@ -651,7 +608,6 @@ impl Backend {
}) })
} }
#[allow(unused)]
fn build_id_mapper( fn build_id_mapper(
&self, &self,
folder: &str, folder: &str,
@ -697,7 +653,6 @@ impl Backend {
Ok(id_mapper) Ok(id_mapper)
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
pub async fn list_envelopes( pub async fn list_envelopes(
&self, &self,
folder: &str, folder: &str,
@ -711,7 +666,6 @@ impl Backend {
Ok(envelopes) Ok(envelopes)
} }
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
pub async fn add_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> { pub async fn add_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.add_flags_kind(); let backend_kind = self.toml_account_config.add_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -719,7 +673,6 @@ impl Backend {
self.backend.add_flags(folder, &ids, flags).await self.backend.add_flags(folder, &ids, flags).await
} }
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
pub async fn add_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> { pub async fn add_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.add_flags_kind(); let backend_kind = self.toml_account_config.add_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -727,7 +680,6 @@ impl Backend {
self.backend.add_flag(folder, &ids, flag).await self.backend.add_flag(folder, &ids, flag).await
} }
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
pub async fn set_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> { pub async fn set_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.set_flags_kind(); let backend_kind = self.toml_account_config.set_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -735,7 +687,6 @@ impl Backend {
self.backend.set_flags(folder, &ids, flags).await self.backend.set_flags(folder, &ids, flags).await
} }
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
pub async fn set_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> { pub async fn set_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.set_flags_kind(); let backend_kind = self.toml_account_config.set_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -743,7 +694,6 @@ impl Backend {
self.backend.set_flag(folder, &ids, flag).await self.backend.set_flag(folder, &ids, flag).await
} }
#[cfg(feature = "flag-remove")]
pub async fn remove_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> { pub async fn remove_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.remove_flags_kind(); let backend_kind = self.toml_account_config.remove_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -751,7 +701,6 @@ impl Backend {
self.backend.remove_flags(folder, &ids, flags).await self.backend.remove_flags(folder, &ids, flags).await
} }
#[cfg(feature = "flag-remove")]
pub async fn remove_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> { pub async fn remove_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.remove_flags_kind(); let backend_kind = self.toml_account_config.remove_flags_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -759,7 +708,6 @@ impl Backend {
self.backend.remove_flag(folder, &ids, flag).await self.backend.remove_flag(folder, &ids, flag).await
} }
#[cfg(any(feature = "account-sync", feature = "message-add"))]
pub async fn add_message(&self, folder: &str, email: &[u8]) -> Result<SingleId> { pub async fn add_message(&self, folder: &str, email: &[u8]) -> Result<SingleId> {
let backend_kind = self.toml_account_config.add_message_kind(); let backend_kind = self.toml_account_config.add_message_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -768,7 +716,6 @@ impl Backend {
Ok(id) Ok(id)
} }
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
pub async fn peek_messages(&self, folder: &str, ids: &[usize]) -> Result<Messages> { pub async fn peek_messages(&self, folder: &str, ids: &[usize]) -> Result<Messages> {
let backend_kind = self.toml_account_config.get_messages_kind(); let backend_kind = self.toml_account_config.get_messages_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -776,7 +723,6 @@ impl Backend {
self.backend.peek_messages(folder, &ids).await self.backend.peek_messages(folder, &ids).await
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))]
pub async fn get_messages(&self, folder: &str, ids: &[usize]) -> Result<Messages> { pub async fn get_messages(&self, folder: &str, ids: &[usize]) -> Result<Messages> {
let backend_kind = self.toml_account_config.get_messages_kind(); let backend_kind = self.toml_account_config.get_messages_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -784,7 +730,6 @@ impl Backend {
self.backend.get_messages(folder, &ids).await self.backend.get_messages(folder, &ids).await
} }
#[cfg(feature = "message-copy")]
pub async fn copy_messages( pub async fn copy_messages(
&self, &self,
from_folder: &str, from_folder: &str,
@ -799,7 +744,6 @@ impl Backend {
.await .await
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))]
pub async fn move_messages( pub async fn move_messages(
&self, &self,
from_folder: &str, from_folder: &str,
@ -814,7 +758,6 @@ impl Backend {
.await .await
} }
#[cfg(feature = "message-delete")]
pub async fn delete_messages(&self, folder: &str, ids: &[usize]) -> Result<()> { pub async fn delete_messages(&self, folder: &str, ids: &[usize]) -> Result<()> {
let backend_kind = self.toml_account_config.delete_messages_kind(); let backend_kind = self.toml_account_config.delete_messages_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;

View file

@ -33,8 +33,8 @@ const SEND_MESSAGE_BACKEND_KINDS: &[BackendKind] = &[
]; ];
pub(crate) async fn configure( pub(crate) async fn configure(
#[allow(unused)] account_name: &str, account_name: &str,
#[allow(unused)] email: &str, email: &str,
autoconfig: Option<&AutoConfig>, autoconfig: Option<&AutoConfig>,
) -> Result<Option<BackendConfig>> { ) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME) let kind = Select::with_theme(&*THEME)
@ -60,8 +60,8 @@ pub(crate) async fn configure(
} }
pub(crate) async fn configure_sender( pub(crate) async fn configure_sender(
#[allow(unused)] account_name: &str, account_name: &str,
#[allow(unused)] email: &str, email: &str,
autoconfig: Option<&AutoConfig>, autoconfig: Option<&AutoConfig>,
) -> Result<Option<BackendConfig>> { ) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME) let kind = Select::with_theme(&*THEME)

View file

@ -2,25 +2,18 @@ use anyhow::Result;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(feature = "account-subcmd")]
use crate::account::command::AccountSubcommand;
#[cfg(feature = "envelope-subcmd")]
use crate::envelope::command::EnvelopeSubcommand;
#[cfg(feature = "flag-subcmd")]
use crate::flag::command::FlagSubcommand;
#[cfg(feature = "folder-subcmd")]
use crate::folder::command::FolderSubcommand;
#[cfg(feature = "attachment-subcmd")]
use crate::message::attachment::command::AttachmentSubcommand;
#[cfg(feature = "message-subcmd")]
use crate::message::command::MessageSubcommand;
#[cfg(feature = "template-subcmd")]
use crate::message::template::command::TemplateSubcommand;
#[allow(unused)]
use crate::{ use crate::{
account::command::AccountSubcommand,
completion::command::CompletionGenerateCommand, completion::command::CompletionGenerateCommand,
config::{self, TomlConfig}, config::{self, TomlConfig},
envelope::command::EnvelopeSubcommand,
flag::command::FlagSubcommand,
folder::command::FolderSubcommand,
manual::command::ManualGenerateCommand, manual::command::ManualGenerateCommand,
message::{
attachment::command::AttachmentSubcommand, command::MessageSubcommand,
template::command::TemplateSubcommand,
},
output::{ColorFmt, OutputFmt}, output::{ColorFmt, OutputFmt},
printer::Printer, printer::Printer,
}; };
@ -29,12 +22,8 @@ use crate::{
#[command(name = "himalaya", author, version, about)] #[command(name = "himalaya", author, version, about)]
#[command(propagate_version = true, infer_subcommands = true)] #[command(propagate_version = true, infer_subcommands = true)]
pub struct Cli { pub struct Cli {
#[cfg(feature = "envelope-list")]
#[command(subcommand)] #[command(subcommand)]
pub command: Option<HimalayaCommand>, pub command: Option<HimalayaCommand>,
#[cfg(not(feature = "envelope-list"))]
#[command(subcommand)]
pub command: HimalayaCommand,
/// Override the default configuration file path /// Override the default configuration file path
/// ///
@ -88,38 +77,31 @@ pub struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
pub enum HimalayaCommand { pub enum HimalayaCommand {
#[cfg(feature = "account-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "accounts")] #[command(alias = "accounts")]
Account(AccountSubcommand), Account(AccountSubcommand),
#[cfg(feature = "folder-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])] #[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])]
#[command(alias = "folders")] #[command(alias = "folders")]
Folder(FolderSubcommand), Folder(FolderSubcommand),
#[cfg(feature = "envelope-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "envelopes")] #[command(alias = "envelopes")]
Envelope(EnvelopeSubcommand), Envelope(EnvelopeSubcommand),
#[cfg(feature = "flag-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "flags")] #[command(alias = "flags")]
Flag(FlagSubcommand), Flag(FlagSubcommand),
#[cfg(feature = "message-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "messages", alias = "msgs", alias = "msg")] #[command(alias = "messages", alias = "msgs", alias = "msg")]
Message(MessageSubcommand), Message(MessageSubcommand),
#[cfg(feature = "attachment-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "attachments")] #[command(alias = "attachments")]
Attachment(AttachmentSubcommand), Attachment(AttachmentSubcommand),
#[cfg(feature = "template-subcmd")]
#[command(subcommand)] #[command(subcommand)]
#[command(alias = "templates", alias = "tpls", alias = "tpl")] #[command(alias = "templates", alias = "tpls", alias = "tpl")]
Template(TemplateSubcommand), Template(TemplateSubcommand),
@ -141,37 +123,30 @@ impl HimalayaCommand {
config_path: Option<&PathBuf>, config_path: Option<&PathBuf>,
) -> Result<()> { ) -> Result<()> {
match self { match self {
#[cfg(feature = "account-subcmd")]
Self::Account(cmd) => { Self::Account(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "folder-subcmd")]
Self::Folder(cmd) => { Self::Folder(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "envelope-subcmd")]
Self::Envelope(cmd) => { Self::Envelope(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "flag-subcmd")]
Self::Flag(cmd) => { Self::Flag(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "message-subcmd")]
Self::Message(cmd) => { Self::Message(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "attachment-subcmd")]
Self::Attachment(cmd) => { Self::Attachment(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await
} }
#[cfg(feature = "template-subcmd")]
Self::Template(cmd) => { Self::Template(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?; let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await cmd.execute(printer, &config).await

View file

@ -1,26 +0,0 @@
//! This module provides arguments related to the user config.
use clap::{Arg, ArgMatches};
const ARG_CONFIG: &str = "config";
/// Represents the config file path argument. This argument allows the
/// user to customize the config file path.
pub fn global_args() -> impl IntoIterator<Item = Arg> {
[Arg::new(ARG_CONFIG)
.help("Override the configuration file path")
.long_help(
"Override the configuration file path
If the file under the given path does not exist, the wizard will propose to create it.",
)
.long("config")
.short('c')
.global(true)
.value_name("path")]
}
/// Represents the config file path argument parser.
pub fn parse_global_arg(matches: &ArgMatches) -> Option<&str> {
matches.get_one::<String>(ARG_CONFIG).map(String::as_str)
}

View file

@ -1,12 +1,10 @@
pub mod args;
#[cfg(feature = "wizard")]
pub mod wizard; pub mod wizard;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use dirs::{config_dir, home_dir}; use dirs::{config_dir, home_dir};
use email::{ use email::{
account::config::AccountConfig, config::Config, envelope::config::EnvelopeConfig, account::config::AccountConfig, config::Config, envelope::config::EnvelopeConfig,
folder::config::FolderConfig, message::config::MessageConfig, flag::config::FlagConfig, folder::config::FolderConfig, message::config::MessageConfig,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -19,11 +17,9 @@ use std::{
}; };
use toml; use toml;
use crate::account::config::TomlAccountConfig;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
use crate::backend::BackendKind; use crate::backend::BackendKind;
#[cfg(feature = "wizard")] use crate::{account::config::TomlAccountConfig, wizard_prompt, wizard_warn};
use crate::{wizard_prompt, wizard_warn};
/// Represents the user config file. /// Represents the user config file.
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
@ -34,8 +30,6 @@ pub struct TomlConfig {
pub signature: Option<String>, pub signature: Option<String>,
pub signature_delim: Option<String>, pub signature_delim: Option<String>,
pub downloads_dir: Option<PathBuf>, pub downloads_dir: Option<PathBuf>,
#[serde(flatten)]
pub accounts: HashMap<String, TomlAccountConfig>, pub accounts: HashMap<String, TomlAccountConfig>,
} }
@ -50,7 +44,6 @@ impl TomlConfig {
toml::from_str(&content).context(format!("cannot parse config file at {path:?}")) toml::from_str(&content).context(format!("cannot parse config file at {path:?}"))
} }
#[cfg(feature = "wizard")]
/// Create and save a TOML configuration using the wizard. /// Create and save a TOML configuration using the wizard.
/// ///
/// If the user accepts the confirmation, the wizard starts and /// If the user accepts the confirmation, the wizard starts and
@ -83,10 +76,7 @@ impl TomlConfig {
pub async fn from_default_paths() -> Result<Self> { pub async fn from_default_paths() -> Result<Self> {
match Self::first_valid_default_path() { match Self::first_valid_default_path() {
Some(path) => Self::from_path(&path), Some(path) => Self::from_path(&path),
#[cfg(feature = "wizard")]
None => Self::from_wizard(Self::default_path()?).await, None => Self::from_wizard(Self::default_path()?).await,
#[cfg(not(feature = "wizard"))]
None => anyhow::bail!("cannot find configuration file from default locations"),
} }
} }
@ -105,7 +95,6 @@ impl TomlConfig {
pub async fn from_some_path_or_default(path: Option<impl Into<PathBuf>>) -> Result<Self> { pub async fn from_some_path_or_default(path: Option<impl Into<PathBuf>>) -> Result<Self> {
match path.map(Into::into) { match path.map(Into::into) {
Some(ref path) if path.exists() => Self::from_path(path), Some(ref path) if path.exists() => Self::from_path(path),
#[cfg(feature = "wizard")]
Some(path) => Self::from_wizard(path).await, Some(path) => Self::from_wizard(path).await,
_ => Self::from_default_paths().await, _ => Self::from_default_paths().await,
} }
@ -215,25 +204,28 @@ impl TomlConfig {
signature: config.signature, signature: config.signature,
signature_delim: config.signature_delim, signature_delim: config.signature_delim,
downloads_dir: config.downloads_dir, downloads_dir: config.downloads_dir,
folder: config.folder.map(|c| FolderConfig {
folder: config.folder.map(|#[allow(unused)] c| FolderConfig {
aliases: c.alias, aliases: c.alias,
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
list: c.list.map(|c| c.remote), list: c.list.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}), }),
envelope: config.envelope.map(|#[allow(unused)] c| EnvelopeConfig { envelope: config.envelope.map(|c| EnvelopeConfig {
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
list: c.list.map(|c| c.remote), list: c.list.map(|c| c.remote),
#[cfg(feature = "envelope-watch")]
watch: c.watch.map(|c| c.remote), watch: c.watch.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}), }),
message: config.message.map(|#[allow(unused)] c| MessageConfig { flag: config.flag.map(|c| FlagConfig {
#[cfg(any(feature = "account-sync", feature = "message-read"))] #[cfg(feature = "account-sync")]
sync: c.sync,
}),
message: config.message.map(|c| MessageConfig {
read: c.read.map(|c| c.remote), read: c.read.map(|c| c.remote),
#[cfg(any(feature = "account-sync", feature = "message-write"))]
write: c.write.map(|c| c.remote), write: c.write.map(|c| c.remote),
#[cfg(feature = "message-send")]
send: c.send.map(|c| c.remote), send: c.send.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}), }),
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
sync: config.sync, sync: config.sync,

View file

@ -1,791 +0,0 @@
#[cfg(feature = "pgp-commands")]
use email::account::CmdsPgpConfig;
#[cfg(feature = "pgp-gpg")]
use email::account::GpgConfig;
#[cfg(feature = "pgp")]
use email::account::PgpConfig;
#[cfg(feature = "pgp-native")]
use email::account::{NativePgpConfig, NativePgpSecretKey, SignedSecretKey};
#[cfg(feature = "notmuch")]
use email::backend::NotmuchConfig;
#[cfg(feature = "imap")]
use email::imap::config::{ImapAuthConfig, ImapConfig};
#[cfg(feature = "smtp")]
use email::smtp::config::{SmtpAuthConfig, SmtpConfig};
use email::{
account::config::{
oauth2::{OAuth2Config, OAuth2Method, OAuth2Scopes},
passwd::PasswdConfig,
},
email::config::{EmailHooks, EmailTextPlainFormat},
folder::sync::FolderSyncStrategy,
maildir::config::MaildirConfig,
sendmail::config::SendmailConfig,
};
use keyring::Entry;
use process::{Cmd, Pipeline, SingleCmd};
use secret::Secret;
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
use std::{collections::HashSet, ops::Deref, path::PathBuf};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Entry", from = "String")]
pub struct EntryDef(#[serde(getter = "Deref::deref")] String);
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SingleCmd", from = "String")]
pub struct SingleCmdDef(#[serde(getter = "Deref::deref")] String);
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Pipeline", from = "Vec<String>")]
pub struct PipelineDef(
#[serde(getter = "Deref::deref", serialize_with = "pipeline")] Vec<SingleCmd>,
);
// NOTE: did not find the way to do it with macros…
pub fn pipeline<S>(cmds: &Vec<SingleCmd>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = s.serialize_seq(Some(cmds.len()))?;
for cmd in cmds {
seq.serialize_element(&cmd.to_string())?;
}
seq.end()
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Cmd", untagged)]
pub enum CmdDef {
#[serde(with = "SingleCmdDef")]
SingleCmd(SingleCmd),
#[serde(with = "PipelineDef")]
Pipeline(Pipeline),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Option<Cmd>", from = "OptionCmd", into = "OptionCmd")]
pub struct OptionCmdDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionCmd {
#[serde(default, skip)]
is_some: bool,
#[serde(flatten, with = "CmdDef")]
inner: Cmd,
}
impl From<OptionCmd> for Option<Cmd> {
fn from(cmd: OptionCmd) -> Option<Cmd> {
if cmd.is_some {
Some(cmd.inner)
} else {
None
}
}
}
impl Into<OptionCmd> for Option<Cmd> {
fn into(self) -> OptionCmd {
match self {
Some(cmd) => OptionCmd {
is_some: true,
inner: cmd,
},
None => OptionCmd {
is_some: false,
inner: Default::default(),
},
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Secret", rename_all = "kebab-case")]
pub enum SecretDef {
Raw(String),
#[serde(with = "CmdDef")]
Cmd(Cmd),
#[serde(with = "EntryDef", rename = "keyring")]
KeyringEntry(Entry),
#[default]
Undefined,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Method")]
pub enum OAuth2MethodDef {
#[serde(rename = "xoauth2", alias = "XOAUTH2")]
XOAuth2,
#[serde(rename = "oauthbearer", alias = "OAUTHBEARER")]
OAuthBearer,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<ImapConfig>",
from = "OptionImapConfig",
into = "OptionImapConfig"
)]
pub struct OptionImapConfigDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionImapConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "ImapConfigDef")]
inner: ImapConfig,
}
impl From<OptionImapConfig> for Option<ImapConfig> {
fn from(config: OptionImapConfig) -> Option<ImapConfig> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
impl Into<OptionImapConfig> for Option<ImapConfig> {
fn into(self) -> OptionImapConfig {
match self {
Some(config) => OptionImapConfig {
is_none: false,
inner: config,
},
None => OptionImapConfig {
is_none: true,
inner: Default::default(),
},
}
}
}
#[cfg(feature = "imap")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "ImapConfig", rename_all = "kebab-case")]
pub struct ImapConfigDef {
pub host: String,
pub port: u16,
pub ssl: Option<bool>,
pub starttls: Option<bool>,
pub insecure: Option<bool>,
pub login: String,
#[serde(flatten, with = "ImapAuthConfigDef")]
pub auth: ImapAuthConfig,
pub notify_cmd: Option<String>,
pub notify_query: Option<String>,
pub watch_cmds: Option<Vec<String>>,
}
#[cfg(feature = "imap")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "ImapAuthConfig", tag = "auth")]
pub enum ImapAuthConfigDef {
#[serde(rename = "passwd", alias = "password", with = "ImapPasswdConfigDef")]
Passwd(#[serde(default)] PasswdConfig),
#[serde(rename = "oauth2", with = "ImapOAuth2ConfigDef")]
OAuth2(OAuth2Config),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "PasswdConfig")]
pub struct ImapPasswdConfigDef {
#[serde(
rename = "passwd",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub passwd: Secret,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Config")]
pub struct ImapOAuth2ConfigDef {
#[serde(rename = "imap-oauth2-method", with = "OAuth2MethodDef", default)]
pub method: OAuth2Method,
#[serde(rename = "imap-oauth2-client-id")]
pub client_id: String,
#[serde(
rename = "imap-oauth2-client-secret",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub client_secret: Secret,
#[serde(rename = "imap-oauth2-auth-url")]
pub auth_url: String,
#[serde(rename = "imap-oauth2-token-url")]
pub token_url: String,
#[serde(
rename = "imap-oauth2-access-token",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub access_token: Secret,
#[serde(
rename = "imap-oauth2-refresh-token",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub refresh_token: Secret,
#[serde(flatten, with = "ImapOAuth2ScopesDef")]
pub scopes: OAuth2Scopes,
#[serde(rename = "imap-oauth2-pkce", default)]
pub pkce: bool,
#[serde(
rename = "imap-oauth2-redirect-host",
default = "OAuth2Config::default_redirect_host"
)]
pub redirect_host: String,
#[serde(
rename = "imap-oauth2-redirect-port",
default = "OAuth2Config::default_redirect_port"
)]
pub redirect_port: u16,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Scopes")]
pub enum ImapOAuth2ScopesDef {
#[serde(rename = "imap-oauth2-scope")]
Scope(String),
#[serde(rename = "imap-oauth2-scopes")]
Scopes(Vec<String>),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<MaildirConfig>",
from = "OptionMaildirConfig",
into = "OptionMaildirConfig"
)]
pub struct OptionMaildirConfigDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionMaildirConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "MaildirConfigDef")]
inner: MaildirConfig,
}
impl From<OptionMaildirConfig> for Option<MaildirConfig> {
fn from(config: OptionMaildirConfig) -> Option<MaildirConfig> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
impl Into<OptionMaildirConfig> for Option<MaildirConfig> {
fn into(self) -> OptionMaildirConfig {
match self {
Some(config) => OptionMaildirConfig {
is_none: false,
inner: config,
},
None => OptionMaildirConfig {
is_none: true,
inner: Default::default(),
},
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "MaildirConfig", rename_all = "kebab-case")]
pub struct MaildirConfigDef {
#[serde(rename = "maildir-root-dir")]
pub root_dir: PathBuf,
}
#[cfg(feature = "notmuch")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<NotmuchConfig>",
from = "OptionNotmuchConfig",
into = "OptionNotmuchConfig"
)]
pub struct OptionNotmuchConfigDef;
#[cfg(feature = "notmuch")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionNotmuchConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "NotmuchConfigDef")]
inner: NotmuchConfig,
}
#[cfg(feature = "notmuch")]
impl From<OptionNotmuchConfig> for Option<NotmuchConfig> {
fn from(config: OptionNotmuchConfig) -> Option<NotmuchConfig> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
#[cfg(feature = "notmuch")]
impl Into<OptionNotmuchConfig> for Option<NotmuchConfig> {
fn into(self) -> OptionNotmuchConfig {
match self {
Some(config) => OptionNotmuchConfig {
is_none: false,
inner: config,
},
None => OptionNotmuchConfig {
is_none: true,
inner: Default::default(),
},
}
}
}
#[cfg(feature = "notmuch")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "NotmuchConfig", rename_all = "kebab-case")]
pub struct NotmuchConfigDef {
#[serde(rename = "notmuch-db-path")]
pub db_path: PathBuf,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<EmailTextPlainFormat>",
from = "OptionEmailTextPlainFormat",
into = "OptionEmailTextPlainFormat"
)]
pub struct OptionEmailTextPlainFormatDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionEmailTextPlainFormat {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "EmailTextPlainFormatDef")]
inner: EmailTextPlainFormat,
}
impl From<OptionEmailTextPlainFormat> for Option<EmailTextPlainFormat> {
fn from(fmt: OptionEmailTextPlainFormat) -> Option<EmailTextPlainFormat> {
if fmt.is_none {
None
} else {
Some(fmt.inner)
}
}
}
impl Into<OptionEmailTextPlainFormat> for Option<EmailTextPlainFormat> {
fn into(self) -> OptionEmailTextPlainFormat {
match self {
Some(config) => OptionEmailTextPlainFormat {
is_none: false,
inner: config,
},
None => OptionEmailTextPlainFormat {
is_none: true,
inner: Default::default(),
},
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "EmailTextPlainFormat",
tag = "type",
content = "width",
rename_all = "kebab-case"
)]
pub enum EmailTextPlainFormatDef {
#[default]
Auto,
Flowed,
Fixed(usize),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<SmtpConfig>",
from = "OptionSmtpConfig",
into = "OptionSmtpConfig"
)]
pub struct OptionSmtpConfigDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
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> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
impl Into<OptionSmtpConfig> for Option<SmtpConfig> {
fn into(self) -> OptionSmtpConfig {
match self {
Some(config) => OptionSmtpConfig {
is_none: false,
inner: config,
},
None => OptionSmtpConfig {
is_none: true,
inner: Default::default(),
},
}
}
}
#[cfg(feature = "smtp")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SmtpConfig")]
struct SmtpConfigDef {
pub host: String,
pub port: u16,
pub ssl: Option<bool>,
pub starttls: Option<bool>,
pub insecure: Option<bool>,
pub login: String,
#[serde(flatten, with = "SmtpAuthConfigDef")]
pub auth: SmtpAuthConfig,
}
#[cfg(feature = "smtp")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SmtpAuthConfig", tag = "auth")]
pub enum SmtpAuthConfigDef {
#[serde(rename = "passwd", alias = "password", with = "SmtpPasswdConfigDef")]
Passwd(#[serde(default)] PasswdConfig),
#[serde(rename = "oauth2", with = "SmtpOAuth2ConfigDef")]
OAuth2(OAuth2Config),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "PasswdConfig", default)]
pub struct SmtpPasswdConfigDef {
#[serde(
rename = "passwd",
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub passwd: Secret,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Config", rename_all = "kebab-case")]
pub struct SmtpOAuth2ConfigDef {
#[serde(with = "OAuth2MethodDef", default)]
pub method: OAuth2Method,
pub client_id: String,
#[serde(
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub client_secret: Secret,
pub auth_url: String,
pub token_url: String,
#[serde(
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub access_token: Secret,
#[serde(
with = "SecretDef",
default,
skip_serializing_if = "Secret::is_undefined"
)]
pub refresh_token: Secret,
#[serde(flatten, with = "SmtpOAuth2ScopesDef")]
pub scopes: OAuth2Scopes,
#[serde(default)]
pub pkce: bool,
#[serde(default = "OAuth2Config::default_redirect_host")]
pub redirect_host: String,
#[serde(default = "OAuth2Config::default_redirect_port")]
pub redirect_port: u16,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "OAuth2Scopes")]
pub enum SmtpOAuth2ScopesDef {
#[serde(rename = "smtp-oauth2-scope")]
Scope(String),
#[serde(rename = "smtp-oauth2-scopes")]
Scopes(Vec<String>),
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<SendmailConfig>",
from = "OptionSendmailConfig",
into = "OptionSendmailConfig"
)]
pub struct OptionSendmailConfigDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionSendmailConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "SendmailConfigDef")]
inner: SendmailConfig,
}
impl From<OptionSendmailConfig> for Option<SendmailConfig> {
fn from(config: OptionSendmailConfig) -> Option<SendmailConfig> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
impl Into<OptionSendmailConfig> for Option<SendmailConfig> {
fn into(self) -> OptionSendmailConfig {
match self {
Some(config) => OptionSendmailConfig {
is_none: false,
inner: config,
},
None => OptionSendmailConfig {
is_none: true,
inner: Default::default(),
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "SendmailConfig", rename_all = "kebab-case")]
pub struct SendmailConfigDef {
#[serde(with = "CmdDef", default = "sendmail_default_cmd")]
cmd: Cmd,
}
fn sendmail_default_cmd() -> Cmd {
Cmd::from("/usr/sbin/sendmail")
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<EmailHooks>",
from = "OptionEmailHooks",
into = "OptionEmailHooks"
)]
pub struct OptionEmailHooksDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionEmailHooks {
#[serde(default, skip)]
is_none: bool,
#[serde(
flatten,
skip_serializing_if = "EmailHooks::is_empty",
with = "EmailHooksDef"
)]
inner: EmailHooks,
}
impl From<OptionEmailHooks> for Option<EmailHooks> {
fn from(hooks: OptionEmailHooks) -> Option<EmailHooks> {
if hooks.is_none {
None
} else {
Some(hooks.inner)
}
}
}
impl Into<OptionEmailHooks> for Option<EmailHooks> {
fn into(self) -> OptionEmailHooks {
match self {
Some(hooks) => OptionEmailHooks {
is_none: false,
inner: hooks,
},
None => OptionEmailHooks {
is_none: true,
inner: Default::default(),
},
}
}
}
/// Represents the email hooks. Useful for doing extra email
/// processing before or after sending it.
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "EmailHooks", rename_all = "kebab-case")]
pub struct EmailHooksDef {
/// Represents the hook called just before sending an email.
#[serde(default, with = "OptionCmdDef")]
pub pre_send: Option<Cmd>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(
remote = "Option<FolderSyncStrategy>",
from = "OptionFolderSyncStrategy",
into = "OptionFolderSyncStrategy"
)]
pub struct OptionFolderSyncStrategyDef;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionFolderSyncStrategy {
#[serde(default, skip)]
is_some: bool,
#[serde(
flatten,
skip_serializing_if = "FolderSyncStrategy::is_default",
with = "FolderSyncStrategyDef"
)]
inner: FolderSyncStrategy,
}
impl From<OptionFolderSyncStrategy> for Option<FolderSyncStrategy> {
fn from(option: OptionFolderSyncStrategy) -> Option<FolderSyncStrategy> {
if option.is_some {
Some(option.inner)
} else {
None
}
}
}
impl Into<OptionFolderSyncStrategy> for Option<FolderSyncStrategy> {
fn into(self) -> OptionFolderSyncStrategy {
match self {
Some(strategy) => OptionFolderSyncStrategy {
is_some: true,
inner: strategy,
},
None => OptionFolderSyncStrategy {
is_some: false,
inner: Default::default(),
},
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "FolderSyncStrategy", rename_all = "kebab-case")]
pub enum FolderSyncStrategyDef {
#[default]
All,
#[serde(alias = "only")]
Include(HashSet<String>),
#[serde(alias = "except")]
#[serde(alias = "ignore")]
Exclude(HashSet<String>),
}
#[cfg(feature = "pgp")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "Option<PgpConfig>", from = "OptionPgpConfig")]
pub struct OptionPgpConfigDef;
#[cfg(feature = "pgp")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct OptionPgpConfig {
#[serde(default, skip)]
is_none: bool,
#[serde(flatten, with = "PgpConfigDef")]
inner: PgpConfig,
}
#[cfg(feature = "pgp")]
impl From<OptionPgpConfig> for Option<PgpConfig> {
fn from(config: OptionPgpConfig) -> Option<PgpConfig> {
if config.is_none {
None
} else {
Some(config.inner)
}
}
}
#[cfg(feature = "pgp")]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "PgpConfig", tag = "backend", rename_all = "kebab-case")]
pub enum PgpConfigDef {
#[cfg(feature = "pgp-commands")]
#[serde(with = "CmdsPgpConfigDef", alias = "commands")]
Cmds(CmdsPgpConfig),
#[cfg(feature = "pgp-gpg")]
#[serde(with = "GpgConfigDef")]
Gpg(GpgConfig),
#[cfg(feature = "pgp-native")]
#[serde(with = "NativePgpConfigDef")]
Native(NativePgpConfig),
}
#[cfg(feature = "pgp-gpg")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "GpgConfig", rename_all = "kebab-case")]
pub struct GpgConfigDef;
#[cfg(feature = "pgp-commands")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "CmdsPgpConfig", rename_all = "kebab-case")]
pub struct CmdsPgpConfigDef {
#[serde(default, with = "OptionCmdDef")]
encrypt_cmd: Option<Cmd>,
#[serde(default)]
encrypt_recipient_fmt: Option<String>,
#[serde(default)]
encrypt_recipients_sep: Option<String>,
#[serde(default, with = "OptionCmdDef")]
decrypt_cmd: Option<Cmd>,
#[serde(default, with = "OptionCmdDef")]
sign_cmd: Option<Cmd>,
#[serde(default, with = "OptionCmdDef")]
verify_cmd: Option<Cmd>,
}
#[cfg(feature = "pgp-native")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "NativePgpConfig", rename_all = "kebab-case")]
pub struct NativePgpConfigDef {
#[serde(default, with = "NativePgpSecretKeyDef")]
secret_key: NativePgpSecretKey,
#[serde(default, with = "SecretDef")]
secret_key_passphrase: Secret,
#[serde(default = "NativePgpConfig::default_wkd")]
wkd: bool,
#[serde(default = "NativePgpConfig::default_key_servers")]
key_servers: Vec<String>,
}
#[cfg(feature = "pgp-native")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(remote = "NativePgpSecretKey", rename_all = "kebab-case")]
pub enum NativePgpSecretKeyDef {
#[default]
None,
#[serde(skip)]
Raw(SignedSecretKey),
Path(PathBuf),
#[serde(with = "EntryDef")]
Keyring(Entry),
}

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -82,7 +83,7 @@ impl ListEnvelopesCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
list_envelopes_kind, list_envelopes_kind,
|builder| builder.set_list_envelopes(Some(None)), |builder| builder.set_list_envelopes(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,6 +1,4 @@
#[cfg(feature = "envelope-list")]
pub mod list; pub mod list;
#[cfg(feature = "envelope-watch")]
pub mod watch; pub mod watch;
use anyhow::Result; use anyhow::Result;
@ -8,10 +6,7 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "envelope-list")] use self::{list::ListEnvelopesCommand, watch::WatchEnvelopesCommand};
use self::list::ListEnvelopesCommand;
#[cfg(feature = "envelope-watch")]
use self::watch::WatchEnvelopesCommand;
/// Manage envelopes. /// Manage envelopes.
/// ///
@ -21,11 +16,9 @@ use self::watch::WatchEnvelopesCommand;
/// manage them. /// manage them.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum EnvelopeSubcommand { pub enum EnvelopeSubcommand {
#[cfg(feature = "envelope-list")]
#[command(alias = "lst")] #[command(alias = "lst")]
List(ListEnvelopesCommand), List(ListEnvelopesCommand),
#[cfg(feature = "envelope-watch")]
#[command()] #[command()]
Watch(WatchEnvelopesCommand), Watch(WatchEnvelopesCommand),
} }
@ -34,9 +27,7 @@ impl EnvelopeSubcommand {
#[allow(unused)] #[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "envelope-list")]
Self::List(cmd) => cmd.execute(printer, config).await, Self::List(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "envelope-watch")]
Self::Watch(cmd) => cmd.execute(printer, config).await, Self::Watch(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, envelope::watch::WatchEnvelopes};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -43,7 +44,7 @@ impl WatchEnvelopesCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
watch_envelopes_kind, watch_envelopes_kind,
|builder| builder.set_watch_envelopes(Some(None)), |builder| builder.set_watch_envelopes(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,3 +1,5 @@
#[cfg(feature = "account-sync")]
use email::envelope::sync::config::EnvelopeSyncConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
@ -5,30 +7,25 @@ use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct EnvelopeConfig { pub struct EnvelopeConfig {
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
pub list: Option<ListEnvelopesConfig>, pub list: Option<ListEnvelopesConfig>,
#[cfg(feature = "envelope-watch")]
pub watch: Option<WatchEnvelopesConfig>, pub watch: Option<WatchEnvelopesConfig>,
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
pub get: Option<GetEnvelopeConfig>, pub get: Option<GetEnvelopeConfig>,
#[cfg(feature = "account-sync")]
pub sync: Option<EnvelopeSyncConfig>,
} }
impl EnvelopeConfig { impl EnvelopeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
if let Some(list) = &self.list { if let Some(list) = &self.list {
kinds.extend(list.get_used_backends()); kinds.extend(list.get_used_backends());
} }
#[cfg(feature = "envelope-watch")]
if let Some(watch) = &self.watch { if let Some(watch) = &self.watch {
kinds.extend(watch.get_used_backends()); kinds.extend(watch.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
if let Some(get) = &self.get { if let Some(get) = &self.get {
kinds.extend(get.get_used_backends()); kinds.extend(get.get_used_backends());
} }
@ -37,7 +34,6 @@ impl EnvelopeConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct ListEnvelopesConfig { pub struct ListEnvelopesConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -46,7 +42,6 @@ pub struct ListEnvelopesConfig {
pub remote: email::envelope::list::config::EnvelopeListConfig, pub remote: email::envelope::list::config::EnvelopeListConfig,
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
impl ListEnvelopesConfig { impl ListEnvelopesConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -59,7 +54,6 @@ impl ListEnvelopesConfig {
} }
} }
#[cfg(feature = "envelope-watch")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct WatchEnvelopesConfig { pub struct WatchEnvelopesConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -68,7 +62,6 @@ pub struct WatchEnvelopesConfig {
pub remote: email::envelope::watch::config::WatchEnvelopeConfig, pub remote: email::envelope::watch::config::WatchEnvelopeConfig,
} }
#[cfg(feature = "envelope-watch")]
impl WatchEnvelopesConfig { impl WatchEnvelopesConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -81,13 +74,11 @@ impl WatchEnvelopesConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct GetEnvelopeConfig { pub struct GetEnvelopeConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "envelope-get"))]
impl GetEnvelopeConfig { impl GetEnvelopeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -51,7 +52,7 @@ impl FlagAddCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
add_flags_kind, add_flags_kind,
|builder| builder.set_add_flags(Some(None)), |builder| builder.set_add_flags(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,8 +1,5 @@
#[cfg(feature = "flag-add")]
mod add; mod add;
#[cfg(feature = "flag-remove")]
mod remove; mod remove;
#[cfg(feature = "flag-set")]
mod set; mod set;
use anyhow::Result; use anyhow::Result;
@ -10,12 +7,7 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "flag-add")] use self::{add::FlagAddCommand, remove::FlagRemoveCommand, set::FlagSetCommand};
use self::add::FlagAddCommand;
#[cfg(feature = "flag-remove")]
use self::remove::FlagRemoveCommand;
#[cfg(feature = "flag-set")]
use self::set::FlagSetCommand;
/// Manage flags. /// Manage flags.
/// ///
@ -25,17 +17,14 @@ use self::set::FlagSetCommand;
/// synchronization does not take care of them yet). /// synchronization does not take care of them yet).
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum FlagSubcommand { pub enum FlagSubcommand {
#[cfg(feature = "flag-add")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(alias = "create")] #[command(alias = "create")]
Add(FlagAddCommand), Add(FlagAddCommand),
#[cfg(feature = "flag-set")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(aliases = ["update", "change", "replace"])] #[command(aliases = ["update", "change", "replace"])]
Set(FlagSetCommand), Set(FlagSetCommand),
#[cfg(feature = "flag-remove")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(aliases = ["rm", "delete", "del"])] #[command(aliases = ["rm", "delete", "del"])]
Remove(FlagRemoveCommand), Remove(FlagRemoveCommand),
@ -45,11 +34,8 @@ impl FlagSubcommand {
#[allow(unused)] #[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "flag-add")]
Self::Add(cmd) => cmd.execute(printer, config).await, Self::Add(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "flag-set")]
Self::Set(cmd) => cmd.execute(printer, config).await, Self::Set(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "flag-remove")]
Self::Remove(cmd) => cmd.execute(printer, config).await, Self::Remove(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -51,7 +52,7 @@ impl FlagRemoveCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
remove_flags_kind, remove_flags_kind,
|builder| builder.set_remove_flags(Some(None)), |builder| builder.set_remove_flags(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -51,7 +52,7 @@ impl FlagSetCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
set_flags_kind, set_flags_kind,
|builder| builder.set_set_flags(Some(None)), |builder| builder.set_set_flags(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,3 +1,5 @@
#[cfg(feature = "account-sync")]
use email::flag::sync::config::FlagSyncConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
@ -5,30 +7,25 @@ use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FlagConfig { pub struct FlagConfig {
#[cfg(feature = "flag-add")]
pub add: Option<FlagAddConfig>, pub add: Option<FlagAddConfig>,
#[cfg(feature = "flag-set")]
pub set: Option<FlagSetConfig>, pub set: Option<FlagSetConfig>,
#[cfg(feature = "flag-remove")]
pub remove: Option<FlagRemoveConfig>, pub remove: Option<FlagRemoveConfig>,
#[cfg(feature = "account-sync")]
pub sync: Option<FlagSyncConfig>,
} }
impl FlagConfig { impl FlagConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
#[cfg(feature = "flag-add")]
if let Some(add) = &self.add { if let Some(add) = &self.add {
kinds.extend(add.get_used_backends()); kinds.extend(add.get_used_backends());
} }
#[cfg(feature = "flag-set")]
if let Some(set) = &self.set { if let Some(set) = &self.set {
kinds.extend(set.get_used_backends()); kinds.extend(set.get_used_backends());
} }
#[cfg(feature = "flag-remove")]
if let Some(remove) = &self.remove { if let Some(remove) = &self.remove {
kinds.extend(remove.get_used_backends()); kinds.extend(remove.get_used_backends());
} }
@ -37,13 +34,11 @@ impl FlagConfig {
} }
} }
#[cfg(feature = "flag-add")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FlagAddConfig { pub struct FlagAddConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "flag-add")]
impl FlagAddConfig { impl FlagAddConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -56,13 +51,11 @@ impl FlagAddConfig {
} }
} }
#[cfg(feature = "flag-set")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FlagSetConfig { pub struct FlagSetConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "flag-set")]
impl FlagSetConfig { impl FlagSetConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -75,13 +68,11 @@ impl FlagSetConfig {
} }
} }
#[cfg(feature = "flag-remove")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FlagRemoveConfig { pub struct FlagRemoveConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "flag-remove")]
impl FlagRemoveConfig { impl FlagRemoveConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();

View file

@ -30,7 +30,6 @@ pub struct Envelope {
pub date: String, pub date: String,
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
impl Table for Envelope { impl Table for Envelope {
fn head() -> Row { fn head() -> Row {
Row::new() Row::new()
@ -76,12 +75,10 @@ impl Table for Envelope {
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
/// Represents the list of envelopes. /// Represents the list of envelopes.
#[derive(Clone, Debug, Default, Serialize)] #[derive(Clone, Debug, Default, Serialize)]
pub struct Envelopes(Vec<Envelope>); pub struct Envelopes(Vec<Envelope>);
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
impl Envelopes { impl Envelopes {
pub fn from_backend( pub fn from_backend(
config: &AccountConfig, config: &AccountConfig,
@ -108,7 +105,6 @@ impl Envelopes {
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
impl ops::Deref for Envelopes { impl ops::Deref for Envelopes {
type Target = Vec<Envelope>; type Target = Vec<Envelope>;
@ -117,7 +113,6 @@ impl ops::Deref for Envelopes {
} }
} }
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
impl PrintTable for Envelopes { impl PrintTable for Envelopes {
fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writer)?; writeln!(writer)?;

View file

@ -1,5 +1,6 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
use std::{fs, path::PathBuf}; use std::{fs, path::PathBuf};
use uuid::Uuid; use uuid::Uuid;
@ -51,7 +52,7 @@ impl AttachmentDownloadCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
get_messages_kind, get_messages_kind,
|builder| builder.set_get_messages(Some(None)), |builder| builder.set_get_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,12 +1,10 @@
#[cfg(feature = "attachment-download")] mod download;
pub mod download;
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "attachment-download")]
use self::download::AttachmentDownloadCommand; use self::download::AttachmentDownloadCommand;
/// Manage attachments. /// Manage attachments.
@ -16,16 +14,13 @@ use self::download::AttachmentDownloadCommand;
/// body. /// body.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum AttachmentSubcommand { pub enum AttachmentSubcommand {
#[cfg(feature = "attachment-download")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
Download(AttachmentDownloadCommand), Download(AttachmentDownloadCommand),
} }
impl AttachmentSubcommand { impl AttachmentSubcommand {
#[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "attachment-download")]
Self::Download(cmd) => cmd.execute(printer, config).await, Self::Download(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -53,7 +54,7 @@ impl MessageCopyCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
copy_messages_kind, copy_messages_kind,
|builder| builder.set_copy_messages(Some(None)), |builder| builder.set_copy_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -51,7 +52,7 @@ impl MessageDeleteCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
delete_messages_kind, delete_messages_kind,
|builder| builder.set_delete_messages(Some(None)), |builder| builder.set_delete_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -63,8 +64,8 @@ impl MessageForwardCommand {
account_config.clone(), account_config.clone(),
add_message_kind.into_iter().chain(send_message_kind), add_message_kind.into_iter().chain(send_message_kind),
|builder| { |builder| {
builder.set_add_message(Some(None)); builder.set_add_message(BackendFeatureSource::Context);
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
}, },
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::{debug, info}; use log::{debug, info};
use mail_builder::MessageBuilder; use mail_builder::MessageBuilder;
use url::Url; use url::Url;
@ -58,8 +59,8 @@ impl MessageMailtoCommand {
account_config.clone(), account_config.clone(),
add_message_kind.into_iter().chain(send_message_kind), add_message_kind.into_iter().chain(send_message_kind),
|builder| { |builder| {
builder.set_add_message(Some(None)); builder.set_add_message(BackendFeatureSource::Context);
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
}, },
) )
.await?; .await?;

View file

@ -1,22 +1,12 @@
#[cfg(feature = "message-copy")]
pub mod copy; pub mod copy;
#[cfg(feature = "message-delete")]
pub mod delete; pub mod delete;
#[cfg(feature = "message-forward")]
pub mod forward; pub mod forward;
#[cfg(feature = "message-mailto")]
pub mod mailto; pub mod mailto;
#[cfg(feature = "message-move")]
pub mod r#move; pub mod r#move;
#[cfg(feature = "message-read")]
pub mod read; pub mod read;
#[cfg(feature = "message-reply")]
pub mod reply; pub mod reply;
#[cfg(feature = "message-save")]
pub mod save; pub mod save;
#[cfg(feature = "message-send")]
pub mod send; pub mod send;
#[cfg(feature = "message-write")]
pub mod write; pub mod write;
use anyhow::Result; use anyhow::Result;
@ -24,26 +14,12 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "message-copy")] use self::{
use self::copy::MessageCopyCommand; copy::MessageCopyCommand, delete::MessageDeleteCommand, forward::MessageForwardCommand,
#[cfg(feature = "message-delete")] mailto::MessageMailtoCommand, r#move::MessageMoveCommand, read::MessageReadCommand,
use self::delete::MessageDeleteCommand; reply::MessageReplyCommand, save::MessageSaveCommand, send::MessageSendCommand,
#[cfg(feature = "message-forward")] write::MessageWriteCommand,
use self::forward::MessageForwardCommand; };
#[cfg(feature = "message-mailto")]
use self::mailto::MessageMailtoCommand;
#[cfg(feature = "message-move")]
use self::r#move::MessageMoveCommand;
#[cfg(feature = "message-read")]
use self::read::MessageReadCommand;
#[cfg(feature = "message-reply")]
use self::reply::MessageReplyCommand;
#[cfg(feature = "message-save")]
use self::save::MessageSaveCommand;
#[cfg(feature = "message-send")]
use self::send::MessageSendCommand;
#[cfg(feature = "message-write")]
use self::write::MessageWriteCommand;
/// Manage messages. /// Manage messages.
/// ///
@ -53,43 +29,33 @@ use self::write::MessageWriteCommand;
/// subcommand allows you to manage them. /// subcommand allows you to manage them.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum MessageSubcommand { pub enum MessageSubcommand {
#[cfg(feature = "message-read")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
Read(MessageReadCommand), Read(MessageReadCommand),
#[cfg(feature = "message-write")]
#[command(aliases = ["add", "create", "new", "compose"])] #[command(aliases = ["add", "create", "new", "compose"])]
Write(MessageWriteCommand), Write(MessageWriteCommand),
#[cfg(feature = "message-reply")]
#[command()] #[command()]
Reply(MessageReplyCommand), Reply(MessageReplyCommand),
#[cfg(feature = "message-forward")]
#[command(aliases = ["fwd", "fd"])] #[command(aliases = ["fwd", "fd"])]
Forward(MessageForwardCommand), Forward(MessageForwardCommand),
#[cfg(feature = "message-mailto")]
#[command()] #[command()]
Mailto(MessageMailtoCommand), Mailto(MessageMailtoCommand),
#[cfg(feature = "message-save")]
Save(MessageSaveCommand), Save(MessageSaveCommand),
#[cfg(feature = "message-send")]
Send(MessageSendCommand), Send(MessageSendCommand),
#[cfg(feature = "message-copy")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(aliases = ["cpy", "cp"])] #[command(aliases = ["cpy", "cp"])]
Copy(MessageCopyCommand), Copy(MessageCopyCommand),
#[cfg(feature = "message-move")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(alias = "mv")] #[command(alias = "mv")]
Move(MessageMoveCommand), Move(MessageMoveCommand),
#[cfg(feature = "message-delete")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(aliases = ["remove", "rm"])] #[command(aliases = ["remove", "rm"])]
Delete(MessageDeleteCommand), Delete(MessageDeleteCommand),
@ -99,25 +65,15 @@ impl MessageSubcommand {
#[allow(unused)] #[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "message-read")]
Self::Read(cmd) => cmd.execute(printer, config).await, Self::Read(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-write")]
Self::Write(cmd) => cmd.execute(printer, config).await, Self::Write(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-reply")]
Self::Reply(cmd) => cmd.execute(printer, config).await, Self::Reply(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-forward")]
Self::Forward(cmd) => cmd.execute(printer, config).await, Self::Forward(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-mailto")]
Self::Mailto(cmd) => cmd.execute(printer, config).await, Self::Mailto(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-save")]
Self::Save(cmd) => cmd.execute(printer, config).await, Self::Save(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-send")]
Self::Send(cmd) => cmd.execute(printer, config).await, Self::Send(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-copy")]
Self::Copy(cmd) => cmd.execute(printer, config).await, Self::Copy(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-move")]
Self::Move(cmd) => cmd.execute(printer, config).await, Self::Move(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "message-delete")]
Self::Delete(cmd) => cmd.execute(printer, config).await, Self::Delete(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -54,7 +55,7 @@ impl MessageMoveCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
move_messages_kind, move_messages_kind,
|builder| builder.set_move_messages(Some(None)), |builder| builder.set_move_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
use mml::message::FilterParts; use mml::message::FilterParts;
@ -96,7 +97,7 @@ impl MessageReadCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
get_messages_kind, get_messages_kind,
|builder| builder.set_get_messages(Some(None)), |builder| builder.set_get_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -65,8 +66,8 @@ impl MessageReplyCommand {
account_config.clone(), account_config.clone(),
add_message_kind.into_iter().chain(send_message_kind), add_message_kind.into_iter().chain(send_message_kind),
|builder| { |builder| {
builder.set_add_message(Some(None)); builder.set_add_message(BackendFeatureSource::Context);
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
}, },
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
use std::io::{self, BufRead, IsTerminal}; use std::io::{self, BufRead, IsTerminal};
@ -48,7 +49,7 @@ impl MessageSaveCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
add_message_kind, add_message_kind,
|builder| builder.set_add_message(Some(None)), |builder| builder.set_add_message(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, message::send::SendMessageThenSaveCopy};
use log::info; use log::info;
use std::io::{self, BufRead, IsTerminal}; use std::io::{self, BufRead, IsTerminal};
@ -37,10 +38,7 @@ impl MessageSendCommand {
self.cache.disable, self.cache.disable,
)?; )?;
let send_message_kind = toml_account_config.send_message_kind(); let send_message_kind = toml_account_config.send_message_kind().into_iter().chain(
#[cfg(feature = "message-add")]
let send_message_kind = send_message_kind.into_iter().chain(
toml_account_config toml_account_config
.add_message_kind() .add_message_kind()
.filter(|_| account_config.should_save_copy_sent_message()), .filter(|_| account_config.should_save_copy_sent_message()),
@ -51,9 +49,8 @@ impl MessageSendCommand {
account_config, account_config,
send_message_kind, send_message_kind,
|builder| { |builder| {
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
#[cfg(feature = "message-add")] builder.set_add_message(BackendFeatureSource::Context);
builder.set_add_message(Some(None));
}, },
) )
.await?; .await?;
@ -69,7 +66,7 @@ impl MessageSendCommand {
.join("\r\n") .join("\r\n")
}; };
backend.send_message(msg.as_bytes()).await?; backend.send_message_then_save_copy(msg.as_bytes()).await?;
printer.print("Message successfully sent!") printer.print("Message successfully sent!")
} }

View file

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::message::Message; use email::{backend::feature::BackendFeatureSource, message::Message};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -54,8 +54,8 @@ impl MessageWriteCommand {
account_config.clone(), account_config.clone(),
add_message_kind.into_iter().chain(send_message_kind), add_message_kind.into_iter().chain(send_message_kind),
|builder| { |builder| {
builder.set_add_message(Some(None)); builder.set_add_message(BackendFeatureSource::Context);
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
}, },
) )
.await?; .await?;

View file

@ -1,3 +1,5 @@
#[cfg(feature = "account-sync")]
use email::message::sync::config::MessageSyncConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
@ -5,53 +7,41 @@ use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageConfig { pub struct MessageConfig {
#[cfg(any(feature = "account-sync", feature = "message-add"))]
pub write: Option<MessageAddConfig>, pub write: Option<MessageAddConfig>,
#[cfg(any(feature = "message-send", feature = "template-send"))]
pub send: Option<MessageSendConfig>, pub send: Option<MessageSendConfig>,
#[cfg(feature = "account-sync")]
pub peek: Option<MessagePeekConfig>, pub peek: Option<MessagePeekConfig>,
#[cfg(any(feature = "account-sync", feature = "message-get"))]
pub read: Option<MessageGetConfig>, pub read: Option<MessageGetConfig>,
#[cfg(feature = "message-copy")]
pub copy: Option<MessageCopyConfig>, pub copy: Option<MessageCopyConfig>,
#[cfg(any(feature = "account-sync", feature = "message-move"))]
pub r#move: Option<MessageMoveConfig>, pub r#move: Option<MessageMoveConfig>,
#[cfg(feature = "message-delete")]
pub delete: Option<MessageDeleteConfig>, pub delete: Option<MessageDeleteConfig>,
#[cfg(feature = "account-sync")]
pub sync: Option<MessageSyncConfig>,
} }
impl MessageConfig { impl MessageConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
#[cfg(any(feature = "account-sync", feature = "message-add"))]
if let Some(add) = &self.write { if let Some(add) = &self.write {
kinds.extend(add.get_used_backends()); kinds.extend(add.get_used_backends());
} }
#[cfg(any(feature = "message-send", feature = "template-send"))]
if let Some(send) = &self.send { if let Some(send) = &self.send {
kinds.extend(send.get_used_backends()); kinds.extend(send.get_used_backends());
} }
#[cfg(feature = "account-sync")]
if let Some(peek) = &self.peek { if let Some(peek) = &self.peek {
kinds.extend(peek.get_used_backends()); kinds.extend(peek.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))]
if let Some(get) = &self.read { if let Some(get) = &self.read {
kinds.extend(get.get_used_backends()); kinds.extend(get.get_used_backends());
} }
#[cfg(feature = "message-copy")]
if let Some(copy) = &self.copy { if let Some(copy) = &self.copy {
kinds.extend(copy.get_used_backends()); kinds.extend(copy.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))]
if let Some(move_) = &self.r#move { if let Some(move_) = &self.r#move {
kinds.extend(move_.get_used_backends()); kinds.extend(move_.get_used_backends());
} }
@ -60,7 +50,6 @@ impl MessageConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-add"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageAddConfig { pub struct MessageAddConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -69,7 +58,6 @@ pub struct MessageAddConfig {
pub remote: email::message::add::config::MessageWriteConfig, pub remote: email::message::add::config::MessageWriteConfig,
} }
#[cfg(any(feature = "account-sync", feature = "message-add"))]
impl MessageAddConfig { impl MessageAddConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -82,7 +70,6 @@ impl MessageAddConfig {
} }
} }
#[cfg(any(feature = "message-send", feature = "template-send"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageSendConfig { pub struct MessageSendConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -91,7 +78,6 @@ pub struct MessageSendConfig {
pub remote: email::message::send::config::MessageSendConfig, pub remote: email::message::send::config::MessageSendConfig,
} }
#[cfg(any(feature = "message-send", feature = "template-send"))]
impl MessageSendConfig { impl MessageSendConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -104,13 +90,11 @@ impl MessageSendConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessagePeekConfig { pub struct MessagePeekConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
impl MessagePeekConfig { impl MessagePeekConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -123,7 +107,6 @@ impl MessagePeekConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageGetConfig { pub struct MessageGetConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -132,7 +115,6 @@ pub struct MessageGetConfig {
pub remote: email::message::get::config::MessageReadConfig, pub remote: email::message::get::config::MessageReadConfig,
} }
#[cfg(any(feature = "account-sync", feature = "message-get"))]
impl MessageGetConfig { impl MessageGetConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -145,13 +127,11 @@ impl MessageGetConfig {
} }
} }
#[cfg(feature = "message-copy")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageCopyConfig { pub struct MessageCopyConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "message-copy")]
impl MessageCopyConfig { impl MessageCopyConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -164,13 +144,11 @@ impl MessageCopyConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageMoveConfig { pub struct MessageMoveConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "message-move"))]
impl MessageMoveConfig { impl MessageMoveConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -183,13 +161,11 @@ impl MessageMoveConfig {
} }
} }
#[cfg(feature = "message-delete")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageDeleteConfig { pub struct MessageDeleteConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "message-delete")]
impl MessageDeleteConfig { impl MessageDeleteConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();

View file

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -59,7 +60,7 @@ impl TemplateForwardCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
get_messages_kind, get_messages_kind,
|builder| builder.set_get_messages(Some(None)), |builder| builder.set_get_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,29 +1,18 @@
#[cfg(feature = "template-forward")] mod forward;
pub mod forward; mod reply;
#[cfg(feature = "template-reply")] mod save;
pub mod reply; mod send;
#[cfg(feature = "template-save")] mod write;
pub mod save;
#[cfg(feature = "template-send")]
pub mod send;
#[cfg(feature = "template-write")]
pub mod write;
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "template-forward")] use self::{
use self::forward::TemplateForwardCommand; forward::TemplateForwardCommand, reply::TemplateReplyCommand, save::TemplateSaveCommand,
#[cfg(feature = "template-reply")] send::TemplateSendCommand, write::TemplateWriteCommand,
use self::reply::TemplateReplyCommand; };
#[cfg(feature = "template-save")]
use self::save::TemplateSaveCommand;
#[cfg(feature = "template-send")]
use self::send::TemplateSendCommand;
#[cfg(feature = "template-write")]
use self::write::TemplateWriteCommand;
/// Manage templates. /// Manage templates.
/// ///
@ -36,41 +25,30 @@ use self::write::TemplateWriteCommand;
/// <https://crates.io/crates/mml-lib>. /// <https://crates.io/crates/mml-lib>.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum TemplateSubcommand { pub enum TemplateSubcommand {
#[cfg(feature = "template-write")]
#[command(aliases = ["add", "create", "new", "compose"])] #[command(aliases = ["add", "create", "new", "compose"])]
Write(TemplateWriteCommand), Write(TemplateWriteCommand),
#[cfg(feature = "template-reply")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
Reply(TemplateReplyCommand), Reply(TemplateReplyCommand),
#[cfg(feature = "template-forward")]
#[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
#[command(alias = "fwd")] #[command(alias = "fwd")]
Forward(TemplateForwardCommand), Forward(TemplateForwardCommand),
#[cfg(feature = "template-save")]
#[command()] #[command()]
Save(TemplateSaveCommand), Save(TemplateSaveCommand),
#[cfg(feature = "template-send")]
#[command()] #[command()]
Send(TemplateSendCommand), Send(TemplateSendCommand),
} }
impl TemplateSubcommand { impl TemplateSubcommand {
#[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "template-write")]
Self::Write(cmd) => cmd.execute(printer, config).await, Self::Write(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "template-reply")]
Self::Reply(cmd) => cmd.execute(printer, config).await, Self::Reply(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "template-forward")]
Self::Forward(cmd) => cmd.execute(printer, config).await, Self::Forward(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "template-save")]
Self::Save(cmd) => cmd.execute(printer, config).await, Self::Save(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "template-send")]
Self::Send(cmd) => cmd.execute(printer, config).await, Self::Send(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -64,7 +65,7 @@ impl TemplateReplyCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
get_messages_kind, get_messages_kind,
|builder| builder.set_get_messages(Some(None)), |builder| builder.set_get_messages(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info; use log::info;
use mml::MmlCompilerBuilder; use mml::MmlCompilerBuilder;
use std::io::{self, BufRead, IsTerminal}; use std::io::{self, BufRead, IsTerminal};
@ -52,7 +53,7 @@ impl TemplateSaveCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
add_message_kind, add_message_kind,
|builder| builder.set_add_message(Some(None)), |builder| builder.set_add_message(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, message::send::SendMessageThenSaveCopy};
use log::info; use log::info;
use mml::MmlCompilerBuilder; use mml::MmlCompilerBuilder;
use std::io::{self, BufRead, IsTerminal}; use std::io::{self, BufRead, IsTerminal};
@ -40,10 +41,7 @@ impl TemplateSendCommand {
self.cache.disable, self.cache.disable,
)?; )?;
let send_message_kind = toml_account_config.send_message_kind(); let send_message_kind = toml_account_config.send_message_kind().into_iter().chain(
#[cfg(feature = "message-add")]
let send_message_kind = send_message_kind.into_iter().chain(
toml_account_config toml_account_config
.add_message_kind() .add_message_kind()
.filter(|_| account_config.should_save_copy_sent_message()), .filter(|_| account_config.should_save_copy_sent_message()),
@ -54,9 +52,8 @@ impl TemplateSendCommand {
account_config.clone(), account_config.clone(),
send_message_kind, send_message_kind,
|builder| { |builder| {
builder.set_send_message(Some(None)); builder.set_send_message(BackendFeatureSource::Context);
#[cfg(feature = "message-add")] builder.set_add_message(BackendFeatureSource::Context);
builder.set_add_message(Some(None));
}, },
) )
.await?; .await?;
@ -80,7 +77,7 @@ impl TemplateSendCommand {
let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?; let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend.send_message(&msg).await?; backend.send_message_then_save_copy(&msg).await?;
printer.print("Message successfully sent!") printer.print("Message successfully sent!")
} }

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, folder::add::AddFolder};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -43,7 +44,7 @@ impl AddFolderCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
add_folder_kind, add_folder_kind,
|builder| builder.set_add_folder(Some(None)), |builder| builder.set_add_folder(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use dialoguer::Confirm; use dialoguer::Confirm;
use email::{backend::feature::BackendFeatureSource, folder::delete::DeleteFolder};
use log::info; use log::info;
use std::process; use std::process;
@ -56,7 +57,7 @@ impl FolderDeleteCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
delete_folder_kind, delete_folder_kind,
|builder| builder.set_delete_folder(Some(None)), |builder| builder.set_delete_folder(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, folder::expunge::ExpungeFolder};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -44,7 +45,7 @@ impl FolderExpungeCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
expunge_folder_kind, expunge_folder_kind,
|builder| builder.set_expunge_folder(Some(None)), |builder| builder.set_expunge_folder(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use email::{backend::feature::BackendFeatureSource, folder::list::ListFolders};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -45,7 +46,7 @@ impl FolderListCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config.clone(), account_config.clone(),
list_folders_kind, list_folders_kind,
|builder| builder.set_list_folders(Some(None)), |builder| builder.set_list_folders(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,12 +1,7 @@
#[cfg(feature = "folder-add")]
mod add; mod add;
#[cfg(feature = "folder-delete")]
mod delete; mod delete;
#[cfg(feature = "folder-expunge")]
mod expunge; mod expunge;
#[cfg(feature = "folder-list")]
mod list; mod list;
#[cfg(feature = "folder-purge")]
mod purge; mod purge;
use anyhow::Result; use anyhow::Result;
@ -14,16 +9,10 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer}; use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "folder-add")] use self::{
use self::add::AddFolderCommand; add::AddFolderCommand, delete::FolderDeleteCommand, expunge::FolderExpungeCommand,
#[cfg(feature = "folder-delete")] list::FolderListCommand, purge::FolderPurgeCommand,
use self::delete::FolderDeleteCommand; };
#[cfg(feature = "folder-expunge")]
use self::expunge::FolderExpungeCommand;
#[cfg(feature = "folder-list")]
use self::list::FolderListCommand;
#[cfg(feature = "folder-purge")]
use self::purge::FolderPurgeCommand;
/// Manage folders. /// Manage folders.
/// ///
@ -31,23 +20,18 @@ use self::purge::FolderPurgeCommand;
/// emails. This subcommand allows you to manage them. /// emails. This subcommand allows you to manage them.
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum FolderSubcommand { pub enum FolderSubcommand {
#[cfg(feature = "folder-add")]
#[command(visible_alias = "create", alias = "new")] #[command(visible_alias = "create", alias = "new")]
Add(AddFolderCommand), Add(AddFolderCommand),
#[cfg(feature = "folder-list")]
#[command(alias = "lst")] #[command(alias = "lst")]
List(FolderListCommand), List(FolderListCommand),
#[cfg(feature = "folder-expunge")]
#[command()] #[command()]
Expunge(FolderExpungeCommand), Expunge(FolderExpungeCommand),
#[cfg(feature = "folder-purge")]
#[command()] #[command()]
Purge(FolderPurgeCommand), Purge(FolderPurgeCommand),
#[cfg(feature = "folder-delete")]
#[command(alias = "remove", alias = "rm")] #[command(alias = "remove", alias = "rm")]
Delete(FolderDeleteCommand), Delete(FolderDeleteCommand),
} }
@ -56,15 +40,10 @@ impl FolderSubcommand {
#[allow(unused)] #[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self { match self {
#[cfg(feature = "folder-add")]
Self::Add(cmd) => cmd.execute(printer, config).await, Self::Add(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "folder-list")]
Self::List(cmd) => cmd.execute(printer, config).await, Self::List(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "folder-expunge")]
Self::Expunge(cmd) => cmd.execute(printer, config).await, Self::Expunge(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "folder-purge")]
Self::Purge(cmd) => cmd.execute(printer, config).await, Self::Purge(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "folder-delete")]
Self::Delete(cmd) => cmd.execute(printer, config).await, Self::Delete(cmd) => cmd.execute(printer, config).await,
} }
} }

View file

@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use dialoguer::Confirm; use dialoguer::Confirm;
use email::{backend::feature::BackendFeatureSource, folder::purge::PurgeFolder};
use log::info; use log::info;
use std::process; use std::process;
@ -56,7 +57,7 @@ impl FolderPurgeCommand {
toml_account_config.clone(), toml_account_config.clone(),
account_config, account_config,
purge_folder_kind, purge_folder_kind,
|builder| builder.set_purge_folder(Some(None)), |builder| builder.set_purge_folder(BackendFeatureSource::Context),
) )
.await?; .await?;

View file

@ -1,3 +1,5 @@
#[cfg(feature = "account-sync")]
use email::folder::sync::config::FolderSyncConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -7,45 +9,35 @@ use crate::backend::BackendKind;
pub struct FolderConfig { pub struct FolderConfig {
#[serde(alias = "aliases")] #[serde(alias = "aliases")]
pub alias: Option<HashMap<String, String>>, pub alias: Option<HashMap<String, String>>,
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
pub add: Option<FolderAddConfig>, pub add: Option<FolderAddConfig>,
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
pub list: Option<FolderListConfig>, pub list: Option<FolderListConfig>,
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
pub expunge: Option<FolderExpungeConfig>, pub expunge: Option<FolderExpungeConfig>,
#[cfg(feature = "folder-purge")]
pub purge: Option<FolderPurgeConfig>, pub purge: Option<FolderPurgeConfig>,
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
pub delete: Option<FolderDeleteConfig>, pub delete: Option<FolderDeleteConfig>,
#[cfg(feature = "account-sync")]
pub sync: Option<FolderSyncConfig>,
} }
impl FolderConfig { impl FolderConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
if let Some(add) = &self.add { if let Some(add) = &self.add {
kinds.extend(add.get_used_backends()); kinds.extend(add.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
if let Some(list) = &self.list { if let Some(list) = &self.list {
kinds.extend(list.get_used_backends()); kinds.extend(list.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
if let Some(expunge) = &self.expunge { if let Some(expunge) = &self.expunge {
kinds.extend(expunge.get_used_backends()); kinds.extend(expunge.get_used_backends());
} }
#[cfg(feature = "folder-purge")]
if let Some(purge) = &self.purge { if let Some(purge) = &self.purge {
kinds.extend(purge.get_used_backends()); kinds.extend(purge.get_used_backends());
} }
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
if let Some(delete) = &self.delete { if let Some(delete) = &self.delete {
kinds.extend(delete.get_used_backends()); kinds.extend(delete.get_used_backends());
} }
@ -54,13 +46,11 @@ impl FolderConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderAddConfig { pub struct FolderAddConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
impl FolderAddConfig { impl FolderAddConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -73,7 +63,6 @@ impl FolderAddConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderListConfig { pub struct FolderListConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
@ -82,7 +71,6 @@ pub struct FolderListConfig {
pub remote: email::folder::list::config::FolderListConfig, pub remote: email::folder::list::config::FolderListConfig,
} }
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
impl FolderListConfig { impl FolderListConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -95,13 +83,11 @@ impl FolderListConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderExpungeConfig { pub struct FolderExpungeConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
impl FolderExpungeConfig { impl FolderExpungeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -114,13 +100,11 @@ impl FolderExpungeConfig {
} }
} }
#[cfg(feature = "folder-purge")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderPurgeConfig { pub struct FolderPurgeConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(feature = "folder-purge")]
impl FolderPurgeConfig { impl FolderPurgeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();
@ -133,13 +117,11 @@ impl FolderPurgeConfig {
} }
} }
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderDeleteConfig { pub struct FolderDeleteConfig {
pub backend: Option<BackendKind>, pub backend: Option<BackendKind>,
} }
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
impl FolderDeleteConfig { impl FolderDeleteConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> { pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default(); let mut kinds = HashSet::default();

View file

@ -1,29 +1,22 @@
pub mod arg; pub mod arg;
#[cfg(feature = "folder-subcmd")]
pub mod command; pub mod command;
pub mod config; pub mod config;
#[cfg(feature = "folder-subcmd")]
use anyhow::Result; use anyhow::Result;
#[cfg(feature = "folder-subcmd")]
use serde::Serialize; use serde::Serialize;
#[cfg(feature = "folder-subcmd")]
use std::ops; use std::ops;
#[cfg(feature = "folder-subcmd")]
use crate::{ use crate::{
printer::{PrintTable, PrintTableOpts, WriteColor}, printer::{PrintTable, PrintTableOpts, WriteColor},
ui::{Cell, Row, Table}, ui::{Cell, Row, Table},
}; };
#[cfg(feature = "folder-subcmd")]
#[derive(Clone, Debug, Default, Serialize)] #[derive(Clone, Debug, Default, Serialize)]
pub struct Folder { pub struct Folder {
pub name: String, pub name: String,
pub desc: String, pub desc: String,
} }
#[cfg(feature = "folder-subcmd")]
impl From<&email::folder::Folder> for Folder { impl From<&email::folder::Folder> for Folder {
fn from(folder: &email::folder::Folder) -> Self { fn from(folder: &email::folder::Folder) -> Self {
Folder { Folder {
@ -33,7 +26,6 @@ impl From<&email::folder::Folder> for Folder {
} }
} }
#[cfg(feature = "folder-subcmd")]
impl Table for Folder { impl Table for Folder {
fn head() -> Row { fn head() -> Row {
Row::new() Row::new()
@ -48,11 +40,9 @@ impl Table for Folder {
} }
} }
#[cfg(feature = "folder-subcmd")]
#[derive(Clone, Debug, Default, Serialize)] #[derive(Clone, Debug, Default, Serialize)]
pub struct Folders(Vec<Folder>); pub struct Folders(Vec<Folder>);
#[cfg(feature = "folder-subcmd")]
impl ops::Deref for Folders { impl ops::Deref for Folders {
type Target = Vec<Folder>; type Target = Vec<Folder>;
@ -61,14 +51,12 @@ impl ops::Deref for Folders {
} }
} }
#[cfg(feature = "folder-subcmd")]
impl From<email::folder::Folders> for Folders { impl From<email::folder::Folders> for Folders {
fn from(folders: email::folder::Folders) -> Self { fn from(folders: email::folder::Folders) -> Self {
Folders(folders.iter().map(Folder::from).collect()) Folders(folders.iter().map(Folder::from).collect())
} }
} }
#[cfg(feature = "folder-subcmd")]
impl PrintTable for Folders { impl PrintTable for Folders {
fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writer)?; writeln!(writer)?;

View file

@ -1,2 +1 @@
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;

View file

@ -1,2 +1 @@
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;

View file

@ -1,21 +1,18 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use env_logger::{Builder as LoggerBuilder, Env, DEFAULT_FILTER_ENV}; use env_logger::{Builder as LoggerBuilder, Env, DEFAULT_FILTER_ENV};
#[cfg(any(feature = "envelope-list", feature = "message-mailto"))] use himalaya::{
use himalaya::config::TomlConfig; cli::Cli, config::TomlConfig, envelope::command::list::ListEnvelopesCommand,
#[cfg(feature = "envelope-list")] message::command::mailto::MessageMailtoCommand, printer::StdoutPrinter,
use himalaya::envelope::command::list::ListEnvelopesCommand; };
#[cfg(feature = "message-mailto")] use log::{debug, trace};
use himalaya::message::command::mailto::MessageMailtoCommand;
use himalaya::{cli::Cli, printer::StdoutPrinter};
use log::{debug, warn};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
if let Err((_, err)) = coredump::register_panic_handler() { if let Err((_, err)) = coredump::register_panic_handler() {
warn!("cannot register coredump panic handler: {err}"); debug!("cannot register coredump panic handler: {err}");
debug!("{err:?}"); trace!("{err:?}");
} }
LoggerBuilder::new() LoggerBuilder::new()
@ -23,7 +20,6 @@ async fn main() -> Result<()> {
.format_timestamp(None) .format_timestamp(None)
.init(); .init();
#[cfg(feature = "message-mailto")]
// if the first argument starts by "mailto:", execute straight the // if the first argument starts by "mailto:", execute straight the
// mailto message command // mailto message command
if let Some(ref url) = std::env::args() if let Some(ref url) = std::env::args()
@ -41,20 +37,13 @@ async fn main() -> Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
let mut printer = StdoutPrinter::new(cli.output, cli.color); let mut printer = StdoutPrinter::new(cli.output, cli.color);
#[cfg(feature = "envelope-list")]
match cli.command { match cli.command {
Some(cmd) => return cmd.execute(&mut printer, cli.config_path.as_ref()).await, Some(cmd) => cmd.execute(&mut printer, cli.config_path.as_ref()).await,
None => { None => {
let config = TomlConfig::from_some_path_or_default(cli.config_path.as_ref()).await?; let config = TomlConfig::from_some_path_or_default(cli.config_path.as_ref()).await?;
return ListEnvelopesCommand::default() ListEnvelopesCommand::default()
.execute(&mut printer, &config) .execute(&mut printer, &config)
.await; .await
} }
} }
#[cfg(not(feature = "envelope-list"))]
return cli
.command
.execute(&mut printer, cli.config_path.as_ref())
.await;
} }

View file

@ -1,2 +1 @@
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;

View file

@ -1,2 +1 @@
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;

View file

@ -1,2 +1 @@
#[cfg(feature = "wizard")]
pub(crate) mod wizard; pub(crate) mod wizard;

View file

@ -38,11 +38,9 @@ pub fn pre_edit() -> Result<PreEditChoice> {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum PostEditChoice { pub enum PostEditChoice {
#[cfg(feature = "message-send")]
Send, Send,
Edit, Edit,
LocalDraft, LocalDraft,
#[cfg(feature = "message-add")]
RemoteDraft, RemoteDraft,
Discard, Discard,
} }
@ -50,11 +48,9 @@ pub enum PostEditChoice {
impl ToString for PostEditChoice { impl ToString for PostEditChoice {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
#[cfg(feature = "message-send")]
Self::Send => "Send it".into(), Self::Send => "Send it".into(),
Self::Edit => "Edit it again".into(), Self::Edit => "Edit it again".into(),
Self::LocalDraft => "Save it as local draft".into(), Self::LocalDraft => "Save it as local draft".into(),
#[cfg(feature = "message-add")]
Self::RemoteDraft => "Save it as remote draft".into(), Self::RemoteDraft => "Save it as remote draft".into(),
Self::Discard => "Discard it".into(), Self::Discard => "Discard it".into(),
} }
@ -63,11 +59,9 @@ impl ToString for PostEditChoice {
pub fn post_edit() -> Result<PostEditChoice> { pub fn post_edit() -> Result<PostEditChoice> {
let choices = [ let choices = [
#[cfg(feature = "message-send")]
PostEditChoice::Send, PostEditChoice::Send,
PostEditChoice::Edit, PostEditChoice::Edit,
PostEditChoice::LocalDraft, PostEditChoice::LocalDraft,
#[cfg(feature = "message-add")]
PostEditChoice::RemoteDraft, PostEditChoice::RemoteDraft,
PostEditChoice::Discard, PostEditChoice::Discard,
]; ];

View file

@ -2,14 +2,11 @@ use anyhow::{Context, Result};
use email::{ use email::{
account::config::AccountConfig, account::config::AccountConfig,
email::utils::{local_draft_path, remove_local_draft}, email::utils::{local_draft_path, remove_local_draft},
};
#[cfg(feature = "message-add")]
use email::{
flag::{Flag, Flags}, flag::{Flag, Flags},
folder::DRAFTS, folder::DRAFTS,
message::{add::AddMessage, send::SendMessageThenSaveCopy},
}; };
use log::debug; use log::debug;
#[cfg(any(feature = "message-send", feature = "template-send"))]
use mml::MmlCompilerBuilder; use mml::MmlCompilerBuilder;
use process::SingleCmd; use process::SingleCmd;
use std::{env, fs, sync::Arc}; use std::{env, fs, sync::Arc};
@ -82,7 +79,6 @@ pub async fn edit_tpl_with_editor<P: Printer>(
loop { loop {
match choice::post_edit() { match choice::post_edit() {
#[cfg(feature = "message-send")]
Ok(PostEditChoice::Send) => { Ok(PostEditChoice::Send) => {
printer.print_log("Sending email…")?; printer.print_log("Sending email…")?;
@ -94,7 +90,7 @@ pub async fn edit_tpl_with_editor<P: Printer>(
let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?; let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend.send_message(&email).await?; backend.send_message_then_save_copy(&email).await?;
remove_local_draft()?; remove_local_draft()?;
printer.print("Done!")?; printer.print("Done!")?;
@ -108,7 +104,6 @@ pub async fn edit_tpl_with_editor<P: Printer>(
printer.print("Email successfully saved locally")?; printer.print("Email successfully saved locally")?;
break; break;
} }
#[cfg(feature = "message-add")]
Ok(PostEditChoice::RemoteDraft) => { Ok(PostEditChoice::RemoteDraft) => {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut compiler = MmlCompilerBuilder::new(); let mut compiler = MmlCompilerBuilder::new();

View file

@ -3,7 +3,6 @@ use std::io;
use super::THEME; use super::THEME;
#[allow(unused)]
pub(crate) fn passwd(prompt: &str) -> io::Result<String> { pub(crate) fn passwd(prompt: &str) -> io::Result<String> {
Password::with_theme(&*THEME) Password::with_theme(&*THEME)
.with_prompt(prompt) .with_prompt(prompt)
@ -14,7 +13,6 @@ pub(crate) fn passwd(prompt: &str) -> io::Result<String> {
.interact() .interact()
} }
#[allow(unused)]
pub(crate) fn secret(prompt: &str) -> io::Result<String> { pub(crate) fn secret(prompt: &str) -> io::Result<String> {
Password::with_theme(&*THEME) Password::with_theme(&*THEME)
.with_prompt(prompt) .with_prompt(prompt)