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

View file

@ -19,21 +19,14 @@ rustdoc-args = ["--cfg", "docsrs"]
# features documentation:
# https://pimalaya.org/himalaya/cli/latest/installation.html#cargo
default = [
"wizard",
"imap",
"maildir",
# "notmuch",
"smtp",
"sendmail",
"account",
"folder",
"envelope",
"flag",
"message",
"attachment",
"template",
"account-discovery",
"account-sync",
# "pgp-commands",
# "pgp-gpg",
@ -46,60 +39,8 @@ notmuch = ["email-lib/notmuch"]
smtp = ["email-lib/smtp"]
sendmail = ["email-lib/sendmail"]
wizard = ["email-lib/account-discovery"]
account = ["account-configure", "account-list", "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"]
account-discovery = ["email-lib/account-discovery"]
account-sync = ["email-lib/account-sync"]
pgp = []
pgp-commands = ["email-lib/pgp-commands", "mml-lib/pgp-commands", "pgp"]
@ -120,8 +61,7 @@ clap_mangen = "0.2"
console = "0.15.2"
dialoguer = "0.10.2"
dirs = "4.0"
# email-lib = { version = "=0.21.0", default-features = false }
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
email-lib = { version = "=0.21.0", default-features = false }
email_address = "0.2.4"
env_logger = "0.8"
erased-serde = "0.3"
@ -157,3 +97,6 @@ features = ["bundled"]
[target.'cfg(not(windows))'.dependencies.coredump]
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;
#[cfg(feature = "account-list")]
mod list;
#[cfg(feature = "account-sync")]
mod sync;
@ -10,12 +8,9 @@ use clap::Subcommand;
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")]
use self::sync::AccountSyncCommand;
use self::{configure::AccountConfigureCommand, list::AccountListCommand};
/// Manage accounts.
///
@ -24,11 +19,9 @@ use self::sync::AccountSyncCommand;
/// file. This subcommand allows you to manage them.
#[derive(Debug, Subcommand)]
pub enum AccountSubcommand {
#[cfg(feature = "account-configure")]
#[command(alias = "cfg")]
Configure(AccountConfigureCommand),
#[cfg(feature = "account-list")]
#[command(alias = "lst")]
List(AccountListCommand),
@ -41,9 +34,7 @@ impl AccountSubcommand {
#[allow(unused)]
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
match self {
#[cfg(feature = "account-configure")]
Self::Configure(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "account-list")]
Self::List(cmd) => cmd.execute(printer, config).await,
#[cfg(feature = "account-sync")]
Self::Sync(cmd) => cmd.execute(printer, config).await,

View file

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

View file

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

View file

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

View file

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

View file

@ -1,53 +1,16 @@
pub mod config;
#[cfg(feature = "wizard")]
pub(crate) mod wizard;
use anyhow::Result;
use async_trait::async_trait;
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")]
use email::imap::{ImapContextBuilder, ImapContextSync};
#[cfg(feature = "account-sync")]
use email::maildir::config::MaildirConfig;
#[cfg(any(feature = "account-sync", feature = "maildir"))]
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")]
use email::notmuch::{NotmuchContextBuilder, NotmuchContextSync};
#[cfg(feature = "sendmail")]
@ -57,17 +20,22 @@ use email::smtp::{SmtpContextBuilder, SmtpContextSync};
use email::{
account::config::AccountConfig,
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};
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
use crate::envelope::Envelopes;
use crate::{account::config::TomlAccountConfig, cache::IdMapper};
use crate::{account::config::TomlAccountConfig, cache::IdMapper, envelope::Envelopes};
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
@ -152,7 +120,10 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Imap))
.map(Clone::clone)
.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 {
Some(builder) => Some(builder.await?),
None => None,
@ -166,7 +137,7 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Maildir))
.map(Clone::clone)
.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 {
@ -174,7 +145,7 @@ impl BackendContextBuilder {
})
.filter(|_| kinds.contains(&&BackendKind::MaildirForSync))
.map(Arc::new)
.map(MaildirContextBuilder::new),
.map(|mdir_config| MaildirContextBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "notmuch")]
notmuch: toml_account_config
@ -183,7 +154,9 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Notmuch))
.map(Clone::clone)
.map(Arc::new)
.map(NotmuchContextBuilder::new),
.map(|notmuch_config| {
NotmuchContextBuilder::new(account_config.clone(), notmuch_config)
}),
#[cfg(feature = "smtp")]
smtp: toml_account_config
@ -192,7 +165,7 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Smtp))
.map(Clone::clone)
.map(Arc::new)
.map(SmtpContextBuilder::new),
.map(|smtp_config| SmtpContextBuilder::new(account_config.clone(), smtp_config)),
#[cfg(feature = "sendmail")]
sendmail: toml_account_config
@ -201,363 +174,347 @@ impl BackendContextBuilder {
.filter(|_| kinds.contains(&&BackendKind::Sendmail))
.map(Clone::clone)
.map(Arc::new)
.map(SendmailContextBuilder::new),
.map(|sendmail_config| {
SendmailContextBuilder::new(account_config.clone(), sendmail_config)
}),
})
}
}
#[async_trait]
impl email::backend::BackendContextBuilder for BackendContextBuilder {
impl email::backend::context::BackendContextBuilder for BackendContextBuilder {
type Context = BackendContext;
#[cfg(any(feature = "account-sync", feature = "folder-add"))]
fn add_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn AddFolder> {
fn add_folder(&self) -> Option<BackendFeature<Self::Context, dyn AddFolder>> {
match self.toml_account_config.add_folder_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
fn list_folders(&self) -> BackendFeatureBuilder<Self::Context, dyn ListFolders> {
fn list_folders(&self) -> Option<BackendFeature<Self::Context, dyn ListFolders>> {
match self.toml_account_config.list_folders_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.list_folders()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "folder-expunge"))]
fn expunge_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn ExpungeFolder> {
fn expunge_folder(&self) -> Option<BackendFeature<Self::Context, dyn ExpungeFolder>> {
match self.toml_account_config.expunge_folder_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.expunge_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(feature = "folder-purge")]
fn purge_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn PurgeFolder> {
fn purge_folder(&self) -> Option<BackendFeature<Self::Context, dyn PurgeFolder>> {
match self.toml_account_config.purge_folder_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.purge_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "folder-delete"))]
fn delete_folder(&self) -> BackendFeatureBuilder<Self::Context, dyn DeleteFolder> {
fn delete_folder(&self) -> Option<BackendFeature<Self::Context, dyn DeleteFolder>> {
match self.toml_account_config.delete_folder_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.delete_folder()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
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> {
fn get_envelope(&self) -> Option<BackendFeature<Self::Context, dyn GetEnvelope>> {
match self.toml_account_config.get_envelope_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.get_envelope()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
fn add_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn AddFlags> {
fn list_envelopes(&self) -> Option<BackendFeature<Self::Context, dyn ListEnvelopes>> {
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() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
fn set_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn SetFlags> {
fn set_flags(&self) -> Option<BackendFeature<Self::Context, dyn SetFlags>> {
match self.toml_account_config.set_flags_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.set_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(feature = "flag-remove")]
fn remove_flags(&self) -> BackendFeatureBuilder<Self::Context, dyn RemoveFlags> {
fn remove_flags(&self) -> Option<BackendFeature<Self::Context, dyn RemoveFlags>> {
match self.toml_account_config.remove_flags_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.remove_flags()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "message-add"))]
fn add_message(&self) -> BackendFeatureBuilder<Self::Context, dyn AddMessage> {
fn add_message(&self) -> Option<BackendFeature<Self::Context, dyn AddMessage>> {
match self.toml_account_config.add_message_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.add_message()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(feature = "message-send")]
fn send_message(&self) -> BackendFeatureBuilder<Self::Context, dyn SendMessage> {
fn send_message(&self) -> Option<BackendFeature<Self::Context, dyn SendMessage>> {
match self.toml_account_config.send_message_kind() {
#[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")]
Some(BackendKind::Sendmail) => self.send_message_from(self.sendmail.as_ref()),
Some(BackendKind::Sendmail) => self.send_message_with_some(&self.sendmail),
_ => None,
}
}
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
fn peek_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn PeekMessages> {
fn peek_messages(&self) -> Option<BackendFeature<Self::Context, dyn PeekMessages>> {
match self.toml_account_config.peek_messages_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.peek_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "message-get"))]
fn get_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn GetMessages> {
fn get_messages(&self) -> Option<BackendFeature<Self::Context, dyn GetMessages>> {
match self.toml_account_config.get_messages_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.get_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(feature = "message-copy")]
fn copy_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn CopyMessages> {
fn copy_messages(&self) -> Option<BackendFeature<Self::Context, dyn CopyMessages>> {
match self.toml_account_config.copy_messages_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.copy_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(any(feature = "account-sync", feature = "message-move"))]
fn move_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn MoveMessages> {
fn move_messages(&self) -> Option<BackendFeature<Self::Context, dyn MoveMessages>> {
match self.toml_account_config.move_messages_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.move_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
#[cfg(feature = "message-delete")]
fn delete_messages(&self) -> BackendFeatureBuilder<Self::Context, dyn DeleteMessages> {
fn delete_messages(&self) -> Option<BackendFeature<Self::Context, dyn DeleteMessages>> {
match self.toml_account_config.delete_messages_kind() {
#[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")]
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")]
Some(BackendKind::MaildirForSync) => {
let f = self.maildir_for_sync.as_ref()?.delete_messages()?;
Some(Arc::new(move |ctx| f(ctx.maildir_for_sync.as_ref()?)))
}
#[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,
}
}
async fn build(self, config: Arc<AccountConfig>) -> Result<Self::Context> {
async fn build(self) -> Result<Self::Context> {
let mut ctx = BackendContext::default();
#[cfg(feature = "imap")]
if let Some(imap) = self.imap {
ctx.imap = Some(imap.build(config.clone()).await?);
ctx.imap = Some(imap.build().await?);
}
#[cfg(feature = "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")]
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")]
if let Some(notmuch) = self.notmuch {
ctx.notmuch = Some(notmuch.build(config.clone()).await?);
ctx.notmuch = Some(notmuch.build().await?);
}
#[cfg(feature = "smtp")]
if let Some(smtp) = self.smtp {
ctx.smtp = Some(smtp.build(config.clone()).await?);
ctx.smtp = Some(smtp.build().await?);
}
#[cfg(feature = "sendmail")]
if let Some(sendmail) = self.sendmail {
ctx.sendmail = Some(sendmail.build(config.clone()).await?);
ctx.sendmail = Some(sendmail.build().await?);
}
Ok(ctx)
@ -586,37 +543,37 @@ pub struct BackendContext {
}
#[cfg(feature = "imap")]
impl FindBackendSubcontext<ImapContextSync> for BackendContext {
fn find_subcontext(&self) -> Option<&ImapContextSync> {
self.imap.as_ref()
impl AsRef<Option<ImapContextSync>> for BackendContext {
fn as_ref(&self) -> &Option<ImapContextSync> {
&self.imap
}
}
#[cfg(feature = "maildir")]
impl FindBackendSubcontext<MaildirContextSync> for BackendContext {
fn find_subcontext(&self) -> Option<&MaildirContextSync> {
self.maildir.as_ref()
impl AsRef<Option<MaildirContextSync>> for BackendContext {
fn as_ref(&self) -> &Option<MaildirContextSync> {
&self.maildir
}
}
#[cfg(feature = "notmuch")]
impl FindBackendSubcontext<NotmuchContextSync> for BackendContext {
fn find_subcontext(&self) -> Option<&NotmuchContextSync> {
self.notmuch.as_ref()
impl AsRef<Option<NotmuchContextSync>> for BackendContext {
fn as_ref(&self) -> &Option<NotmuchContextSync> {
&self.notmuch
}
}
#[cfg(feature = "smtp")]
impl FindBackendSubcontext<SmtpContextSync> for BackendContext {
fn find_subcontext(&self) -> Option<&SmtpContextSync> {
self.smtp.as_ref()
impl AsRef<Option<SmtpContextSync>> for BackendContext {
fn as_ref(&self) -> &Option<SmtpContextSync> {
&self.smtp
}
}
#[cfg(feature = "sendmail")]
impl FindBackendSubcontext<SendmailContextSync> for BackendContext {
fn find_subcontext(&self) -> Option<&SendmailContextSync> {
self.sendmail.as_ref()
impl AsRef<Option<SendmailContextSync>> for BackendContext {
fn as_ref(&self) -> &Option<SendmailContextSync> {
&self.sendmail
}
}
@ -641,7 +598,7 @@ impl Backend {
.await?;
let mut backend_builder =
email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder)
.with_default_features_disabled();
.without_features();
with_features(&mut backend_builder);
@ -651,7 +608,6 @@ impl Backend {
})
}
#[allow(unused)]
fn build_id_mapper(
&self,
folder: &str,
@ -697,7 +653,6 @@ impl Backend {
Ok(id_mapper)
}
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
pub async fn list_envelopes(
&self,
folder: &str,
@ -711,7 +666,6 @@ impl Backend {
Ok(envelopes)
}
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
pub async fn add_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.add_flags_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
}
#[cfg(any(feature = "account-sync", feature = "flag-add"))]
pub async fn add_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.add_flags_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
}
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
pub async fn set_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.set_flags_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
}
#[cfg(any(feature = "account-sync", feature = "flag-set"))]
pub async fn set_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.set_flags_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
}
#[cfg(feature = "flag-remove")]
pub async fn remove_flags(&self, folder: &str, ids: &[usize], flags: &Flags) -> Result<()> {
let backend_kind = self.toml_account_config.remove_flags_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
}
#[cfg(feature = "flag-remove")]
pub async fn remove_flag(&self, folder: &str, ids: &[usize], flag: Flag) -> Result<()> {
let backend_kind = self.toml_account_config.remove_flags_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
}
#[cfg(any(feature = "account-sync", feature = "message-add"))]
pub async fn add_message(&self, folder: &str, email: &[u8]) -> Result<SingleId> {
let backend_kind = self.toml_account_config.add_message_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -768,7 +716,6 @@ impl Backend {
Ok(id)
}
#[cfg(any(feature = "account-sync", feature = "message-peek"))]
pub async fn peek_messages(&self, folder: &str, ids: &[usize]) -> Result<Messages> {
let backend_kind = self.toml_account_config.get_messages_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -776,7 +723,6 @@ impl Backend {
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> {
let backend_kind = self.toml_account_config.get_messages_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?;
@ -784,7 +730,6 @@ impl Backend {
self.backend.get_messages(folder, &ids).await
}
#[cfg(feature = "message-copy")]
pub async fn copy_messages(
&self,
from_folder: &str,
@ -799,7 +744,6 @@ impl Backend {
.await
}
#[cfg(any(feature = "account-sync", feature = "message-move"))]
pub async fn move_messages(
&self,
from_folder: &str,
@ -814,7 +758,6 @@ impl Backend {
.await
}
#[cfg(feature = "message-delete")]
pub async fn delete_messages(&self, folder: &str, ids: &[usize]) -> Result<()> {
let backend_kind = self.toml_account_config.delete_messages_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(
#[allow(unused)] account_name: &str,
#[allow(unused)] email: &str,
account_name: &str,
email: &str,
autoconfig: Option<&AutoConfig>,
) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME)
@ -60,8 +60,8 @@ pub(crate) async fn configure(
}
pub(crate) async fn configure_sender(
#[allow(unused)] account_name: &str,
#[allow(unused)] email: &str,
account_name: &str,
email: &str,
autoconfig: Option<&AutoConfig>,
) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME)

View file

@ -2,25 +2,18 @@ use anyhow::Result;
use clap::{Parser, Subcommand};
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::{
account::command::AccountSubcommand,
completion::command::CompletionGenerateCommand,
config::{self, TomlConfig},
envelope::command::EnvelopeSubcommand,
flag::command::FlagSubcommand,
folder::command::FolderSubcommand,
manual::command::ManualGenerateCommand,
message::{
attachment::command::AttachmentSubcommand, command::MessageSubcommand,
template::command::TemplateSubcommand,
},
output::{ColorFmt, OutputFmt},
printer::Printer,
};
@ -29,12 +22,8 @@ use crate::{
#[command(name = "himalaya", author, version, about)]
#[command(propagate_version = true, infer_subcommands = true)]
pub struct Cli {
#[cfg(feature = "envelope-list")]
#[command(subcommand)]
pub command: Option<HimalayaCommand>,
#[cfg(not(feature = "envelope-list"))]
#[command(subcommand)]
pub command: HimalayaCommand,
/// Override the default configuration file path
///
@ -88,38 +77,31 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
pub enum HimalayaCommand {
#[cfg(feature = "account-subcmd")]
#[command(subcommand)]
#[command(alias = "accounts")]
Account(AccountSubcommand),
#[cfg(feature = "folder-subcmd")]
#[command(subcommand)]
#[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])]
#[command(alias = "folders")]
Folder(FolderSubcommand),
#[cfg(feature = "envelope-subcmd")]
#[command(subcommand)]
#[command(alias = "envelopes")]
Envelope(EnvelopeSubcommand),
#[cfg(feature = "flag-subcmd")]
#[command(subcommand)]
#[command(alias = "flags")]
Flag(FlagSubcommand),
#[cfg(feature = "message-subcmd")]
#[command(subcommand)]
#[command(alias = "messages", alias = "msgs", alias = "msg")]
Message(MessageSubcommand),
#[cfg(feature = "attachment-subcmd")]
#[command(subcommand)]
#[command(alias = "attachments")]
Attachment(AttachmentSubcommand),
#[cfg(feature = "template-subcmd")]
#[command(subcommand)]
#[command(alias = "templates", alias = "tpls", alias = "tpl")]
Template(TemplateSubcommand),
@ -141,37 +123,30 @@ impl HimalayaCommand {
config_path: Option<&PathBuf>,
) -> Result<()> {
match self {
#[cfg(feature = "account-subcmd")]
Self::Account(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "folder-subcmd")]
Self::Folder(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "envelope-subcmd")]
Self::Envelope(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "flag-subcmd")]
Self::Flag(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "message-subcmd")]
Self::Message(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "attachment-subcmd")]
Self::Attachment(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "template-subcmd")]
Self::Template(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).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;
use anyhow::{anyhow, Context, Result};
use dirs::{config_dir, home_dir};
use email::{
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};
@ -19,11 +17,9 @@ use std::{
};
use toml;
use crate::account::config::TomlAccountConfig;
#[cfg(feature = "account-sync")]
use crate::backend::BackendKind;
#[cfg(feature = "wizard")]
use crate::{wizard_prompt, wizard_warn};
use crate::{account::config::TomlAccountConfig, wizard_prompt, wizard_warn};
/// Represents the user config file.
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
@ -34,8 +30,6 @@ pub struct TomlConfig {
pub signature: Option<String>,
pub signature_delim: Option<String>,
pub downloads_dir: Option<PathBuf>,
#[serde(flatten)]
pub accounts: HashMap<String, TomlAccountConfig>,
}
@ -50,7 +44,6 @@ impl TomlConfig {
toml::from_str(&content).context(format!("cannot parse config file at {path:?}"))
}
#[cfg(feature = "wizard")]
/// Create and save a TOML configuration using the wizard.
///
/// If the user accepts the confirmation, the wizard starts and
@ -83,10 +76,7 @@ impl TomlConfig {
pub async fn from_default_paths() -> Result<Self> {
match Self::first_valid_default_path() {
Some(path) => Self::from_path(&path),
#[cfg(feature = "wizard")]
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> {
match path.map(Into::into) {
Some(ref path) if path.exists() => Self::from_path(path),
#[cfg(feature = "wizard")]
Some(path) => Self::from_wizard(path).await,
_ => Self::from_default_paths().await,
}
@ -215,25 +204,28 @@ impl TomlConfig {
signature: config.signature,
signature_delim: config.signature_delim,
downloads_dir: config.downloads_dir,
folder: config.folder.map(|#[allow(unused)] c| FolderConfig {
folder: config.folder.map(|c| FolderConfig {
aliases: c.alias,
#[cfg(any(feature = "account-sync", feature = "folder-list"))]
list: c.list.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}),
envelope: config.envelope.map(|#[allow(unused)] c| EnvelopeConfig {
#[cfg(any(feature = "account-sync", feature = "envelope-list"))]
envelope: config.envelope.map(|c| EnvelopeConfig {
list: c.list.map(|c| c.remote),
#[cfg(feature = "envelope-watch")]
watch: c.watch.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}),
message: config.message.map(|#[allow(unused)] c| MessageConfig {
#[cfg(any(feature = "account-sync", feature = "message-read"))]
flag: config.flag.map(|c| FlagConfig {
#[cfg(feature = "account-sync")]
sync: c.sync,
}),
message: config.message.map(|c| MessageConfig {
read: c.read.map(|c| c.remote),
#[cfg(any(feature = "account-sync", feature = "message-write"))]
write: c.write.map(|c| c.remote),
#[cfg(feature = "message-send")]
send: c.send.map(|c| c.remote),
#[cfg(feature = "account-sync")]
sync: c.sync,
}),
#[cfg(feature = "account-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 clap::Parser;
use email::backend::feature::BackendFeatureSource;
use log::info;
#[cfg(feature = "account-sync")]
@ -82,7 +83,7 @@ impl ListEnvelopesCommand {
toml_account_config.clone(),
account_config.clone(),
list_envelopes_kind,
|builder| builder.set_list_envelopes(Some(None)),
|builder| builder.set_list_envelopes(BackendFeatureSource::Context),
)
.await?;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use anyhow::Result;
use clap::Parser;
use email::{backend::feature::BackendFeatureSource, message::send::SendMessageThenSaveCopy};
use log::info;
use mml::MmlCompilerBuilder;
use std::io::{self, BufRead, IsTerminal};
@ -40,10 +41,7 @@ impl TemplateSendCommand {
self.cache.disable,
)?;
let send_message_kind = toml_account_config.send_message_kind();
#[cfg(feature = "message-add")]
let send_message_kind = send_message_kind.into_iter().chain(
let send_message_kind = toml_account_config.send_message_kind().into_iter().chain(
toml_account_config
.add_message_kind()
.filter(|_| account_config.should_save_copy_sent_message()),
@ -54,9 +52,8 @@ impl TemplateSendCommand {
account_config.clone(),
send_message_kind,
|builder| {
builder.set_send_message(Some(None));
#[cfg(feature = "message-add")]
builder.set_add_message(Some(None));
builder.set_send_message(BackendFeatureSource::Context);
builder.set_add_message(BackendFeatureSource::Context);
},
)
.await?;
@ -80,7 +77,7 @@ impl TemplateSendCommand {
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!")
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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