add one cargo feature per backend feature

This commit is contained in:
Clément DOUIN 2024-01-07 23:48:45 +01:00
parent 9ffac16e05
commit a6b863759c
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
55 changed files with 1248 additions and 598 deletions

View file

@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added one cargo feature per backend feature:
- TODO
### Changed
- Renamed `folder create` to `folder add` in order to better match types. An alias has been set up, so both `create` and `add` still work.
### Fixed
- Fixed default command: running `himalaya` without argument lists envelopes, as it used to be in previous versions.

10
Cargo.lock generated
View file

@ -1216,9 +1216,8 @@ dependencies = [
[[package]]
name = "email-lib"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e4c31e26febefc822561fe388677cec106bbf0a7fe16608e7638daa3d1da9d9"
version = "0.19.6"
source = "git+https://git.sr.ht/~soywod/pimalaya#2933075a179bfff3349987e9620185799eeba907"
dependencies = [
"advisory-lock",
"anyhow",
@ -1235,7 +1234,6 @@ dependencies = [
"mail-parser",
"mail-send",
"maildirpp",
"md5",
"mml-lib",
"notify",
"notify-rust",
@ -1248,8 +1246,6 @@ dependencies = [
"rayon",
"regex",
"rusqlite",
"rustls 0.22.1",
"rustls-native-certs",
"secret-lib",
"serde",
"shellexpand-utils",
@ -1259,8 +1255,6 @@ dependencies = [
"tree_magic_mini",
"urlencoding",
"utf7-imap",
"uuid",
"webpki-roots 0.25.3",
]
[[package]]

View file

@ -17,24 +17,79 @@ rustdoc-args = ["--cfg", "docsrs"]
[features]
default = [
"maildir",
"imap",
"maildir",
# "notmuch",
"smtp",
"sendmail",
"account",
"folder",
"envelope",
"flag",
"message",
"attachment",
"template",
"sync",
# "pgp-commands",
# "pgp-gpg",
# "pgp-native",
]
maildir = ["email-lib/maildir"]
imap = ["email-lib/imap"]
maildir = ["email-lib/maildir"]
notmuch = ["email-lib/notmuch"]
smtp = ["email-lib/smtp"]
sendmail = ["email-lib/sendmail"]
account = ["account-configure", "account-list"]
account-command = []
account-configure = ["account-command"]
account-list = ["account-command"]
folder = ["folder-add", "folder-list", "folder-expunge", "folder-purge", "folder-delete"]
folder-command = []
folder-add = ["folder-command", "email-lib/folder-add"]
folder-list = ["folder-command", "email-lib/folder-list"]
folder-expunge = ["folder-command", "email-lib/folder-expunge"]
folder-purge = ["folder-command", "email-lib/folder-purge"]
folder-delete = ["folder-command", "email-lib/folder-delete"]
envelope = ["envelope-list", "envelope-watch", "envelope-get"]
envelope-command = []
envelope-list = ["envelope-command", "email-lib/envelope-list"]
envelope-watch = ["envelope-command", "email-lib/envelope-watch"]
envelope-get = ["envelope-command", "email-lib/envelope-get"]
flag = ["flag-add", "flag-set", "flag-remove"]
flag-command = []
flag-add = ["flag-command", "email-lib/flag-add"]
flag-set = ["flag-command", "email-lib/flag-set"]
flag-remove = ["flag-command", "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-command = []
message-add = ["email-lib/message-add"]
message-peek = ["email-lib/message-peek"]
message-get = ["email-lib/message-get"]
message-copy = ["message-command", "email-lib/message-copy"]
message-move = ["message-command", "email-lib/message-move"]
message-delete = ["message-command", "email-lib/message-delete"]
message-send = ["message-command", "email-lib/message-send"]
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"]
attachment = ["attachment-download"]
attachment-command = []
attachment-download = ["attachment-command", "message-read"]
template = ["template-write", "template-reply", "template-forward", "template-save", "template-send"]
template-command = []
template-write = ["template-command"]
template-reply = ["template-command", "email-lib/message-get"]
template-forward = ["template-command", "email-lib/message-get"]
template-save = ["template-command", "email-lib/message-add"]
template-send = ["template-command", "email-lib/message-send"]
sync = ["account-command", "email-lib/sync"]
pgp = []
pgp-commands = ["pgp", "mml-lib/pgp-commands", "email-lib/pgp-commands"]
pgp-gpg = ["pgp", "mml-lib/pgp-gpg", "email-lib/pgp-gpg"]
pgp-native = ["pgp", "mml-lib/pgp-native", "email-lib/pgp-native"]
pgp-commands = ["email-lib/pgp-commands", "mml-lib/pgp-commands", "pgp"]
pgp-gpg = ["email-lib/pgp-gpg", "mml-lib/pgp-gpg", "pgp"]
pgp-native = ["email-lib/pgp-native", "mml-lib/pgp-native", "pgp"]
[dev-dependencies]
async-trait = "0.1"
@ -50,7 +105,8 @@ clap_mangen = "0.2"
console = "0.15.2"
dialoguer = "0.10.2"
dirs = "4.0"
email-lib = { version = "=0.19.5", default-features = false }
# email-lib = { version = "=0.19.6", default-features = false }
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
email_address = "0.2.4"
env_logger = "0.8"
erased-serde = "0.3"

View file

@ -4,16 +4,13 @@ use clap::Parser;
use email::imap::config::ImapAuthConfig;
#[cfg(feature = "smtp")]
use email::smtp::config::SmtpAuthConfig;
use log::{debug, info, warn};
use log::info;
#[cfg(any(feature = "imap", feature = "smtp"))]
use log::{debug, warn};
use crate::{
account::arg::name::AccountNameArg,
config::{
wizard::{prompt_passwd, prompt_secret},
TomlConfig,
},
printer::Printer,
};
#[cfg(any(feature = "imap", feature = "smtp"))]
use crate::config::wizard::{prompt_passwd, prompt_secret};
use crate::{account::arg::name::AccountNameArg, config::TomlConfig, printer::Printer};
/// Configure an account.
///

View file

@ -1,5 +1,8 @@
#[cfg(feature = "account-configure")]
mod configure;
#[cfg(feature = "account-list")]
mod list;
#[cfg(feature = "sync")]
mod sync;
use anyhow::Result;
@ -7,9 +10,12 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
use self::{
configure::AccountConfigureCommand, list::AccountListCommand, sync::AccountSyncCommand,
};
#[cfg(feature = "account-configure")]
use self::configure::AccountConfigureCommand;
#[cfg(feature = "account-list")]
use self::list::AccountListCommand;
#[cfg(feature = "sync")]
use self::sync::AccountSyncCommand;
/// Manage accounts.
///
@ -18,21 +24,28 @@ use self::{
/// 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),
#[cfg(feature = "sync")]
#[command(alias = "synchronize", alias = "synchronise")]
Sync(AccountSyncCommand),
}
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 = "sync")]
Self::Sync(cmd) => cmd.execute(printer, config).await,
}
}

View file

@ -5,14 +5,16 @@
#[cfg(feature = "pgp")]
use email::account::config::pgp::PgpConfig;
#[cfg(feature = "sync")]
use email::account::sync::config::SyncConfig;
#[cfg(feature = "imap")]
use email::imap::config::ImapConfig;
#[cfg(feature = "maildir")]
use email::maildir::config::MaildirConfig;
#[cfg(feature = "sendmail")]
use email::sendmail::config::SendmailConfig;
#[cfg(feature = "smtp")]
use email::smtp::config::SmtpConfig;
use email::{
account::sync::config::SyncConfig, maildir::config::MaildirConfig,
sendmail::config::SendmailConfig,
};
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, path::PathBuf};
@ -33,6 +35,7 @@ pub struct TomlAccountConfig {
pub downloads_dir: Option<PathBuf>,
pub backend: Option<BackendKind>,
#[cfg(feature = "sync")]
pub sync: Option<SyncConfig>,
#[cfg(feature = "pgp")]
pub pgp: Option<PgpConfig>,
@ -55,6 +58,7 @@ pub struct TomlAccountConfig {
}
impl TomlAccountConfig {
#[cfg(feature = "folder-add")]
pub fn add_folder_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
@ -63,6 +67,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "folder-list")]
pub fn list_folders_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
@ -71,6 +76,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "folder-expunge")]
pub fn expunge_folder_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
@ -79,6 +85,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "folder-purge")]
pub fn purge_folder_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
@ -87,6 +94,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "folder-delete")]
pub fn delete_folder_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
@ -95,6 +103,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "envelope-get")]
pub fn get_envelope_kind(&self) -> Option<&BackendKind> {
self.envelope
.as_ref()
@ -103,6 +112,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "envelope-list")]
pub fn list_envelopes_kind(&self) -> Option<&BackendKind> {
self.envelope
.as_ref()
@ -111,6 +121,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "envelope-watch")]
pub fn watch_envelopes_kind(&self) -> Option<&BackendKind> {
self.envelope
.as_ref()
@ -119,6 +130,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "flag-add")]
pub fn add_flags_kind(&self) -> Option<&BackendKind> {
self.flag
.as_ref()
@ -127,6 +139,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "flag-set")]
pub fn set_flags_kind(&self) -> Option<&BackendKind> {
self.flag
.as_ref()
@ -135,6 +148,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "flag-remove")]
pub fn remove_flags_kind(&self) -> Option<&BackendKind> {
self.flag
.as_ref()
@ -143,7 +157,8 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
pub fn add_raw_message_kind(&self) -> Option<&BackendKind> {
#[cfg(feature = "message-add")]
pub fn add_message_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
.and_then(|msg| msg.write.as_ref())
@ -151,6 +166,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "message-peek")]
pub fn peek_messages_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
@ -159,6 +175,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "message-get")]
pub fn get_messages_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
@ -167,6 +184,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "message-copy")]
pub fn copy_messages_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
@ -175,6 +193,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "message-move")]
pub fn move_messages_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
@ -183,6 +202,7 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
#[cfg(feature = "message-delete")]
pub fn delete_messages_kind(&self) -> Option<&BackendKind> {
self.flag
.as_ref()
@ -191,7 +211,8 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
pub fn send_raw_message_kind(&self) -> Option<&BackendKind> {
#[cfg(any(feature = "message-send", feature = "template-send"))]
pub fn send_message_kind(&self) -> Option<&BackendKind> {
self.message
.as_ref()
.and_then(|msg| msg.send.as_ref())
@ -199,14 +220,6 @@ impl TomlAccountConfig {
.or_else(|| self.backend.as_ref())
}
pub fn get_watch_message_kind(&self) -> Option<&BackendKind> {
self.envelope
.as_ref()
.and_then(|envelope| envelope.watch.as_ref())
.and_then(|watch| watch.backend.as_ref())
.or_else(|| self.backend.as_ref())
}
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut used_backends = HashSet::default();
@ -218,14 +231,17 @@ impl TomlAccountConfig {
used_backends.extend(folder.get_used_backends());
}
#[cfg(feature = "envelope-command")]
if let Some(ref envelope) = self.envelope {
used_backends.extend(envelope.get_used_backends());
}
#[cfg(feature = "flag-command")]
if let Some(ref flag) = self.flag {
used_backends.extend(flag.get_used_backends());
}
#[cfg(feature = "message-command")]
if let Some(ref msg) = self.message {
used_backends.extend(msg.get_used_backends());
}

View file

@ -83,6 +83,7 @@ impl From<Iter<'_, String, TomlAccountConfig>> for Accounts {
fn from(map: Iter<'_, String, TomlAccountConfig>) -> Self {
let mut accounts: Vec<_> = map
.map(|(name, account)| {
#[allow(unused_mut)]
let mut backends = String::new();
#[cfg(feature = "imap")]
@ -90,6 +91,7 @@ impl From<Iter<'_, String, TomlAccountConfig>> for Accounts {
backends.push_str("imap");
}
#[cfg(feature = "maildir")]
if account.maildir.is_some() {
if !backends.is_empty() {
backends.push_str(", ")

View file

@ -1,13 +1,19 @@
use anyhow::{bail, Result};
use dialoguer::{Confirm, Input};
#[cfg(feature = "sync")]
use dialoguer::Confirm;
use dialoguer::Input;
#[cfg(feature = "sync")]
use email::account::sync::config::SyncConfig;
use email_address::EmailAddress;
#[cfg(feature = "message-send")]
use crate::message::config::{MessageConfig, MessageSendConfig};
#[cfg(feature = "sync")]
use crate::wizard_prompt;
#[allow(unused)]
use crate::{
backend::{self, config::BackendConfig, BackendKind},
config::wizard::THEME,
message::config::{MessageConfig, MessageSendConfig},
wizard_prompt,
};
use super::TomlAccountConfig;
@ -46,15 +52,16 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
);
match backend::wizard::configure(&account_name, &config.email).await? {
Some(BackendConfig::Maildir(mdir_config)) => {
config.maildir = Some(mdir_config);
config.backend = Some(BackendKind::Maildir);
}
#[cfg(feature = "imap")]
Some(BackendConfig::Imap(imap_config)) => {
config.imap = Some(imap_config);
config.backend = Some(BackendKind::Imap);
}
#[cfg(feature = "maildir")]
Some(BackendConfig::Maildir(mdir_config)) => {
config.maildir = Some(mdir_config);
config.backend = Some(BackendKind::Maildir);
}
#[cfg(feature = "notmuch")]
Some(BackendConfig::Notmuch(notmuch_config)) => {
config.notmuch = Some(notmuch_config);
@ -64,43 +71,55 @@ pub(crate) async fn configure() -> Result<Option<(String, TomlAccountConfig)>> {
};
match backend::wizard::configure_sender(&account_name, &config.email).await? {
Some(BackendConfig::Sendmail(sendmail_config)) => {
config.sendmail = Some(sendmail_config);
config.message = Some(MessageConfig {
send: Some(MessageSendConfig {
backend: Some(BackendKind::Sendmail),
..Default::default()
}),
..Default::default()
});
}
#[cfg(feature = "smtp")]
Some(BackendConfig::Smtp(smtp_config)) => {
config.smtp = Some(smtp_config);
config.message = Some(MessageConfig {
send: Some(MessageSendConfig {
backend: Some(BackendKind::Smtp),
#[cfg(feature = "message-send")]
{
config.message = Some(MessageConfig {
send: Some(MessageSendConfig {
backend: Some(BackendKind::Smtp),
..Default::default()
}),
..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()
}),
..Default::default()
});
}
}
_ => (),
};
let should_configure_sync = Confirm::new()
.with_prompt(wizard_prompt!(
"Do you need an offline access to your account?"
))
.default(false)
.interact_opt()?
.unwrap_or_default();
#[cfg(feature = "sync")]
{
let should_configure_sync = Confirm::new()
.with_prompt(wizard_prompt!(
"Do you need an offline access to your account?"
))
.default(false)
.interact_opt()?
.unwrap_or_default();
if should_configure_sync {
config.sync = Some(SyncConfig {
enable: Some(true),
..Default::default()
});
if should_configure_sync {
config.sync = Some(SyncConfig {
enable: Some(true),
..Default::default()
});
}
}
Ok(Some((account_name, config)))

View file

@ -1,19 +1,24 @@
#[cfg(feature = "imap")]
use email::imap::config::ImapConfig;
#[cfg(feature = "maildir")]
use email::maildir::config::MaildirConfig;
#[cfg(feature = "notmuch")]
use email::notmuch::config::NotmuchConfig;
#[cfg(feature = "sendmail")]
use email::sendmail::config::SendmailConfig;
#[cfg(feature = "smtp")]
use email::smtp::config::SmtpConfig;
use email::{maildir::config::MaildirConfig, sendmail::config::SendmailConfig};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BackendConfig {
Maildir(MaildirConfig),
#[cfg(feature = "imap")]
Imap(ImapConfig),
#[cfg(feature = "maildir")]
Maildir(MaildirConfig),
#[cfg(feature = "notmuch")]
Notmuch(NotmuchConfig),
#[cfg(feature = "smtp")]
Smtp(SmtpConfig),
#[cfg(feature = "sendmail")]
Sendmail(SendmailConfig),
}

View file

@ -5,76 +5,128 @@ use anyhow::Result;
use async_trait::async_trait;
use std::ops::Deref;
use email::account::config::AccountConfig;
#[cfg(all(feature = "envelope-get", feature = "imap"))]
use email::envelope::get::imap::GetEnvelopeImap;
#[cfg(all(feature = "envelope-get", feature = "maildir"))]
use email::envelope::get::maildir::GetEnvelopeMaildir;
#[cfg(all(feature = "envelope-list", feature = "imap"))]
use email::envelope::list::imap::ListEnvelopesImap;
#[cfg(all(feature = "envelope-list", feature = "maildir"))]
use email::envelope::list::maildir::ListEnvelopesMaildir;
#[cfg(all(feature = "envelope-watch", feature = "imap"))]
use email::envelope::watch::imap::WatchImapEnvelopes;
#[cfg(all(feature = "envelope-watch", feature = "maildir"))]
use email::envelope::watch::maildir::WatchMaildirEnvelopes;
#[cfg(feature = "message-add")]
use email::envelope::SingleId;
#[cfg(all(feature = "flag-add", feature = "imap"))]
use email::flag::add::imap::AddFlagsImap;
#[cfg(all(feature = "flag-add", feature = "maildir"))]
use email::flag::add::maildir::AddFlagsMaildir;
#[cfg(all(feature = "flag-remove", feature = "imap"))]
use email::flag::remove::imap::RemoveFlagsImap;
#[cfg(all(feature = "flag-remove", feature = "maildir"))]
use email::flag::remove::maildir::RemoveFlagsMaildir;
#[cfg(all(feature = "flag-set", feature = "imap"))]
use email::flag::set::imap::SetFlagsImap;
#[cfg(all(feature = "flag-set", feature = "maildir"))]
use email::flag::set::maildir::SetFlagsMaildir;
#[cfg(all(feature = "folder-add", feature = "imap"))]
use email::folder::add::imap::AddFolderImap;
#[cfg(all(feature = "folder-add", feature = "maildir"))]
use email::folder::add::maildir::AddFolderMaildir;
#[cfg(all(feature = "folder-delete", feature = "imap"))]
use email::folder::delete::imap::DeleteFolderImap;
#[cfg(all(feature = "folder-delete", feature = "maildir"))]
use email::folder::delete::maildir::DeleteFolderMaildir;
#[cfg(all(feature = "folder-expunge", feature = "imap"))]
use email::folder::expunge::imap::ExpungeFolderImap;
#[cfg(all(feature = "folder-expunge", feature = "maildir"))]
use email::folder::expunge::maildir::ExpungeFolderMaildir;
#[cfg(all(feature = "folder-list", feature = "imap"))]
use email::folder::list::imap::ListFoldersImap;
#[cfg(all(feature = "folder-list", feature = "maildir"))]
use email::folder::list::maildir::ListFoldersMaildir;
#[cfg(all(feature = "folder-purge", feature = "imap"))]
use email::folder::purge::imap::PurgeFolderImap;
#[cfg(feature = "imap")]
use email::imap::{ImapSessionBuilder, ImapSessionSync};
#[cfg(feature = "sync")]
use email::maildir::config::MaildirConfig;
#[cfg(feature = "maildir")]
use email::maildir::{MaildirSessionBuilder, MaildirSessionSync};
#[cfg(all(feature = "message-add", feature = "maildir"))]
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
#[cfg(all(feature = "message-copy", feature = "imap"))]
use email::message::copy::imap::CopyMessagesImap;
#[cfg(all(feature = "message-copy", feature = "maildir"))]
use email::message::copy::maildir::CopyMessagesMaildir;
#[cfg(all(feature = "message-get", feature = "imap"))]
use email::message::get::imap::GetMessagesImap;
#[cfg(all(feature = "message-move", feature = "imap"))]
use email::message::move_::imap::MoveMessagesImap;
#[cfg(all(feature = "message-move", feature = "maildir"))]
use email::message::move_::maildir::MoveMessagesMaildir;
#[cfg(all(feature = "message-peek", feature = "imap"))]
use email::message::peek::imap::PeekMessagesImap;
#[cfg(all(feature = "message-peek", feature = "maildir"))]
use email::message::peek::maildir::PeekMessagesMaildir;
#[cfg(any(feature = "message-peek", feature = "message-get"))]
use email::message::Messages;
#[cfg(all(feature = "message-add", feature = "imap"))]
use email::message::{add::imap::AddMessageImap, add_with_flags::imap::AddMessageWithFlagsImap};
#[cfg(feature = "sendmail")]
use email::sendmail::SendmailContext;
#[cfg(feature = "smtp")]
use email::smtp::{SmtpClientBuilder, SmtpClientSync};
#[cfg(any(feature = "flag-command"))]
use email::{
account::config::AccountConfig,
envelope::{
get::{imap::GetEnvelopeImap, maildir::GetEnvelopeMaildir},
list::{imap::ListEnvelopesImap, maildir::ListEnvelopesMaildir},
watch::{imap::WatchImapEnvelopes, maildir::WatchMaildirEnvelopes},
Id, SingleId,
},
flag::{
add::{imap::AddFlagsImap, maildir::AddFlagsMaildir},
remove::{imap::RemoveFlagsImap, maildir::RemoveFlagsMaildir},
set::{imap::SetFlagsImap, maildir::SetFlagsMaildir},
Flag, Flags,
},
folder::{
add::{imap::AddFolderImap, maildir::AddFolderMaildir},
delete::{imap::DeleteFolderImap, maildir::DeleteFolderMaildir},
expunge::{imap::ExpungeFolderImap, maildir::ExpungeFolderMaildir},
list::{imap::ListFoldersImap, maildir::ListFoldersMaildir},
purge::imap::PurgeFolderImap,
},
maildir::{config::MaildirConfig, MaildirSessionBuilder, MaildirSessionSync},
message::{
add_raw::imap::AddRawMessageImap,
add_raw_with_flags::{
imap::AddRawMessageWithFlagsImap, maildir::AddRawMessageWithFlagsMaildir,
},
copy::{imap::CopyMessagesImap, maildir::CopyMessagesMaildir},
get::imap::GetMessagesImap,
move_::{imap::MoveMessagesImap, maildir::MoveMessagesMaildir},
peek::{imap::PeekMessagesImap, maildir::PeekMessagesMaildir},
Messages,
},
sendmail::SendmailContext,
envelope::Id,
flag::{Flag, Flags},
};
use serde::{Deserialize, Serialize};
use crate::{account::config::TomlAccountConfig, cache::IdMapper, envelope::Envelopes};
#[cfg(feature = "envelope-list")]
use crate::envelope::Envelopes;
use crate::{account::config::TomlAccountConfig, cache::IdMapper};
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum BackendKind {
Maildir,
#[serde(skip_deserializing)]
MaildirForSync,
#[cfg(feature = "imap")]
Imap,
#[cfg(feature = "maildir")]
Maildir,
#[cfg(feature = "sync")]
#[serde(skip_deserializing)]
MaildirForSync,
#[cfg(feature = "notmuch")]
Notmuch,
#[cfg(feature = "smtp")]
Smtp,
#[cfg(feature = "sendmail")]
Sendmail,
None,
}
impl ToString for BackendKind {
fn to_string(&self) -> String {
let kind = match self {
Self::Maildir => "Maildir",
Self::MaildirForSync => "Maildir",
#[cfg(feature = "imap")]
Self::Imap => "IMAP",
#[cfg(feature = "maildir")]
Self::Maildir => "Maildir",
#[cfg(feature = "sync")]
Self::MaildirForSync => "Maildir",
#[cfg(feature = "notmuch")]
Self::Notmuch => "Notmuch",
#[cfg(feature = "smtp")]
Self::Smtp => "SMTP",
#[cfg(feature = "sendmail")]
Self::Sendmail => "Sendmail",
Self::None => "None",
};
kind.to_string()
@ -83,34 +135,26 @@ impl ToString for BackendKind {
#[derive(Clone, Default)]
pub struct BackendContextBuilder {
pub maildir: Option<MaildirSessionBuilder>,
pub maildir_for_sync: Option<MaildirSessionBuilder>,
#[cfg(feature = "imap")]
pub imap: Option<ImapSessionBuilder>,
#[cfg(feature = "maildir")]
pub maildir: Option<MaildirSessionBuilder>,
#[cfg(feature = "sync")]
pub maildir_for_sync: Option<MaildirSessionBuilder>,
#[cfg(feature = "smtp")]
pub smtp: Option<SmtpClientBuilder>,
#[cfg(feature = "sendmail")]
pub sendmail: Option<SendmailContext>,
}
impl BackendContextBuilder {
#[allow(unused)]
pub async fn new(
toml_account_config: &TomlAccountConfig,
account_config: &AccountConfig,
kinds: Vec<&BackendKind>,
) -> Result<Self> {
Ok(Self {
maildir: toml_account_config
.maildir
.as_ref()
.filter(|_| kinds.contains(&&BackendKind::Maildir))
.map(|mdir_config| {
MaildirSessionBuilder::new(account_config.clone(), mdir_config.clone())
}),
maildir_for_sync: Some(MaildirConfig {
root_dir: account_config.get_sync_dir()?,
})
.filter(|_| kinds.contains(&&BackendKind::MaildirForSync))
.map(|mdir_config| MaildirSessionBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "imap")]
imap: {
let ctx_builder = toml_account_config
@ -126,6 +170,20 @@ impl BackendContextBuilder {
None => None,
}
},
#[cfg(feature = "maildir")]
maildir: toml_account_config
.maildir
.as_ref()
.filter(|_| kinds.contains(&&BackendKind::Maildir))
.map(|mdir_config| {
MaildirSessionBuilder::new(account_config.clone(), mdir_config.clone())
}),
#[cfg(feature = "sync")]
maildir_for_sync: Some(MaildirConfig {
root_dir: account_config.get_sync_dir()?,
})
.filter(|_| kinds.contains(&&BackendKind::MaildirForSync))
.map(|mdir_config| MaildirSessionBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "notmuch")]
notmuch: toml_account_config
.notmuch
@ -159,21 +217,24 @@ impl email::backend::BackendContextBuilder for BackendContextBuilder {
type Context = BackendContext;
async fn build(self) -> Result<Self::Context> {
#[allow(unused_mut)]
let mut ctx = BackendContext::default();
if let Some(maildir) = self.maildir {
ctx.maildir = Some(maildir.build().await?);
}
if let Some(maildir) = self.maildir_for_sync {
ctx.maildir_for_sync = Some(maildir.build().await?);
}
#[cfg(feature = "imap")]
if let Some(imap) = self.imap {
ctx.imap = Some(imap.build().await?);
}
#[cfg(feature = "maildir")]
if let Some(maildir) = self.maildir {
ctx.maildir = Some(maildir.build().await?);
}
#[cfg(feature = "sync")]
if let Some(maildir) = self.maildir_for_sync {
ctx.maildir_for_sync = Some(maildir.build().await?);
}
#[cfg(feature = "notmuch")]
if let Some(notmuch) = self.notmuch {
ctx.notmuch = Some(notmuch.build().await?);
@ -184,6 +245,7 @@ impl email::backend::BackendContextBuilder for BackendContextBuilder {
ctx.smtp = Some(smtp.build().await?);
}
#[cfg(feature = "sendmail")]
if let Some(sendmail) = self.sendmail {
ctx.sendmail = Some(sendmail.build().await?);
}
@ -194,12 +256,15 @@ impl email::backend::BackendContextBuilder for BackendContextBuilder {
#[derive(Default)]
pub struct BackendContext {
pub maildir: Option<MaildirSessionSync>,
pub maildir_for_sync: Option<MaildirSessionSync>,
#[cfg(feature = "imap")]
pub imap: Option<ImapSessionSync>,
#[cfg(feature = "maildir")]
pub maildir: Option<MaildirSessionSync>,
#[cfg(feature = "sync")]
pub maildir_for_sync: Option<MaildirSessionSync>,
#[cfg(feature = "smtp")]
pub smtp: Option<SmtpClientSync>,
#[cfg(feature = "sendmail")]
pub sendmail: Option<SendmailContext>,
}
@ -213,27 +278,17 @@ impl BackendBuilder {
toml_account_config: TomlAccountConfig,
account_config: AccountConfig,
) -> Result<Self> {
#[allow(unused)]
let used_backends = toml_account_config.get_used_backends();
let is_maildir_used = used_backends.contains(&BackendKind::Maildir);
let is_maildir_for_sync_used = used_backends.contains(&BackendKind::MaildirForSync);
#[cfg(feature = "imap")]
let is_imap_used = used_backends.contains(&BackendKind::Imap);
#[cfg(feature = "maildir")]
let is_maildir_used = used_backends.contains(&BackendKind::Maildir);
#[cfg(feature = "sync")]
let is_maildir_for_sync_used = used_backends.contains(&BackendKind::MaildirForSync);
let backend_ctx_builder = BackendContextBuilder {
maildir: toml_account_config
.maildir
.as_ref()
.filter(|_| is_maildir_used)
.map(|mdir_config| {
MaildirSessionBuilder::new(account_config.clone(), mdir_config.clone())
}),
maildir_for_sync: Some(MaildirConfig {
root_dir: account_config.get_sync_dir()?,
})
.filter(|_| is_maildir_for_sync_used)
.map(|mdir_config| MaildirSessionBuilder::new(account_config.clone(), mdir_config)),
#[cfg(feature = "imap")]
imap: {
let ctx_builder = toml_account_config
@ -250,17 +305,35 @@ impl BackendBuilder {
None => None,
}
},
#[cfg(feature = "maildir")]
maildir: toml_account_config
.maildir
.as_ref()
.filter(|_| is_maildir_used)
.map(|mdir_config| {
MaildirSessionBuilder::new(account_config.clone(), mdir_config.clone())
}),
#[cfg(feature = "sync")]
maildir_for_sync: Some(MaildirConfig {
root_dir: account_config.get_sync_dir()?,
})
.filter(|_| is_maildir_for_sync_used)
.map(|mdir_config| MaildirSessionBuilder::new(account_config.clone(), mdir_config)),
..Default::default()
};
#[allow(unused_mut)]
let mut backend_builder =
email::backend::BackendBuilder::new(account_config.clone(), backend_ctx_builder);
#[cfg(feature = "folder-add")]
match toml_account_config.add_folder_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder
.with_add_folder(|ctx| ctx.maildir.as_ref().and_then(AddFolderMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_add_folder(|ctx| {
ctx.maildir_for_sync
@ -281,12 +354,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "folder-list")]
match toml_account_config.list_folders_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_list_folders(|ctx| {
ctx.maildir.as_ref().and_then(ListFoldersMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_list_folders(|ctx| {
ctx.maildir_for_sync
@ -308,12 +384,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "folder-expunge")]
match toml_account_config.expunge_folder_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_expunge_folder(|ctx| {
ctx.maildir.as_ref().and_then(ExpungeFolderMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_expunge_folder(|ctx| {
ctx.maildir_for_sync
@ -335,13 +414,16 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "folder-purge")]
match toml_account_config.purge_folder_kind() {
// TODO
// #[cfg(feature = "maildir")]
// Some(BackendKind::Maildir) => {
// backend_builder = backend_builder
// .with_purge_folder(|ctx| ctx.maildir.as_ref().and_then(PurgeFolderMaildir::new));
// }
// TODO
// #[cfg(feature = "sync")]
// Some(BackendKind::MaildirForSync) => {
// backend_builder = backend_builder
// .with_purge_folder(|ctx| ctx.maildir_for_sync.as_ref().and_then(PurgeFolderMaildir::new));
@ -360,12 +442,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "folder-delete")]
match toml_account_config.delete_folder_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_delete_folder(|ctx| {
ctx.maildir.as_ref().and_then(DeleteFolderMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_delete_folder(|ctx| {
ctx.maildir_for_sync
@ -387,12 +472,45 @@ impl BackendBuilder {
_ => (),
}
match toml_account_config.backend {
#[cfg(feature = "envelope-list")]
match toml_account_config.list_envelopes_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
backend_builder = backend_builder
.with_list_envelopes(|ctx| ctx.imap.as_ref().and_then(ListEnvelopesImap::new));
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.notmuch.as_ref().and_then(ListEnvelopesNotmuch::new)
});
}
_ => (),
}
#[cfg(feature = "envelope-watch")]
match toml_account_config.watch_envelopes_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(WatchMaildirEnvelopes::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
ctx.maildir_for_sync
@ -415,12 +533,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "envelope-get")]
match toml_account_config.get_envelope_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_get_envelope(|ctx| {
ctx.maildir.as_ref().and_then(GetEnvelopeMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_get_envelope(|ctx| {
ctx.maildir_for_sync
@ -442,38 +563,14 @@ impl BackendBuilder {
_ => (),
}
match toml_account_config.list_envelopes_kind() {
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(ListEnvelopesMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
backend_builder = backend_builder
.with_list_envelopes(|ctx| ctx.imap.as_ref().and_then(ListEnvelopesImap::new));
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => {
backend_builder = backend_builder.with_list_envelopes(|ctx| {
ctx.notmuch.as_ref().and_then(ListEnvelopesNotmuch::new)
});
}
_ => (),
}
#[cfg(feature = "flag-add")]
match toml_account_config.add_flags_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder
.with_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_add_flags(|ctx| {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
@ -492,11 +589,14 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "flag-set")]
match toml_account_config.set_flags_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder
.with_set_flags(|ctx| ctx.maildir.as_ref().and_then(SetFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_set_flags(|ctx| {
ctx.maildir_for_sync.as_ref().and_then(SetFlagsMaildir::new)
@ -515,12 +615,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "flag-remove")]
match toml_account_config.remove_flags_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_remove_flags(|ctx| {
ctx.maildir.as_ref().and_then(RemoveFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_remove_flags(|ctx| {
ctx.maildir_for_sync
@ -542,29 +645,32 @@ impl BackendBuilder {
_ => (),
}
match toml_account_config.add_raw_message_kind() {
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "message-add")]
match toml_account_config.add_message_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
backend_builder = backend_builder
.with_add_raw_message(|ctx| ctx.imap.as_ref().and_then(AddRawMessageImap::new))
.with_add_raw_message_with_flags(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageWithFlagsImap::new)
.with_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new))
.with_add_message_with_flags(|ctx| {
ctx.imap.as_ref().and_then(AddMessageWithFlagsImap::new)
});
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "notmuch")]
Some(BackendKind::Notmuch) => {
backend_builder = backend_builder.with_add_raw_message(|ctx| {
@ -574,12 +680,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "message-peek")]
match toml_account_config.peek_messages_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_peek_messages(|ctx| {
ctx.maildir.as_ref().and_then(PeekMessagesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_peek_messages(|ctx| {
ctx.maildir_for_sync
@ -601,6 +710,7 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "message-get")]
match toml_account_config.get_messages_kind() {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
@ -616,12 +726,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "message-copy")]
match toml_account_config.copy_messages_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_copy_messages(|ctx| {
ctx.maildir.as_ref().and_then(CopyMessagesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_copy_messages(|ctx| {
ctx.maildir_for_sync
@ -643,12 +756,15 @@ impl BackendBuilder {
_ => (),
}
#[cfg(feature = "message-move")]
match toml_account_config.move_messages_kind() {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
backend_builder = backend_builder.with_move_messages(|ctx| {
ctx.maildir.as_ref().and_then(MoveMessagesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
backend_builder = backend_builder.with_move_messages(|ctx| {
ctx.maildir_for_sync
@ -699,6 +815,7 @@ impl Into<email::backend::BackendBuilder<BackendContextBuilder>> for BackendBuil
}
pub struct Backend {
#[allow(unused)]
toml_account_config: TomlAccountConfig,
backend: email::backend::Backend<BackendContext>,
}
@ -724,14 +841,17 @@ impl Backend {
})
}
#[allow(unused)]
fn build_id_mapper(
&self,
folder: &str,
backend_kind: Option<&BackendKind>,
) -> Result<IdMapper> {
#[allow(unused_mut)]
let mut id_mapper = IdMapper::Dummy;
match backend_kind {
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
if let Some(mdir_config) = &self.toml_account_config.maildir {
id_mapper = IdMapper::new(
@ -741,6 +861,7 @@ impl Backend {
)?;
}
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
id_mapper = IdMapper::new(
&self.backend.account_config,
@ -764,6 +885,7 @@ impl Backend {
Ok(id_mapper)
}
#[cfg(feature = "envelope-list")]
pub async fn list_envelopes(
&self,
folder: &str,
@ -777,6 +899,7 @@ impl Backend {
Ok(envelopes)
}
#[cfg(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)?;
@ -784,6 +907,15 @@ impl Backend {
self.backend.add_flags(folder, &ids, flags).await
}
#[cfg(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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.add_flag(folder, &ids, flag).await
}
#[cfg(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)?;
@ -791,6 +923,15 @@ impl Backend {
self.backend.set_flags(folder, &ids, flags).await
}
#[cfg(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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
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)?;
@ -798,6 +939,24 @@ 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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.remove_flag(folder, &ids, flag).await
}
#[cfg(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)?;
let id = self.backend.add_message(folder, email).await?;
id_mapper.create_alias(&*id)?;
Ok(id)
}
#[cfg(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)?;
@ -805,6 +964,7 @@ impl Backend {
self.backend.peek_messages(folder, &ids).await
}
#[cfg(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)?;
@ -812,6 +972,7 @@ impl Backend {
self.backend.get_messages(folder, &ids).await
}
#[cfg(feature = "message-copy")]
pub async fn copy_messages(
&self,
from_folder: &str,
@ -826,6 +987,7 @@ impl Backend {
.await
}
#[cfg(feature = "message-move")]
pub async fn move_messages(
&self,
from_folder: &str,
@ -840,41 +1002,13 @@ 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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.delete_messages(folder, &ids).await
}
pub async fn add_raw_message(&self, folder: &str, email: &[u8]) -> Result<SingleId> {
let backend_kind = self.toml_account_config.add_raw_message_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?;
let id = self.backend.add_raw_message(folder, email).await?;
id_mapper.create_alias(&*id)?;
Ok(id)
}
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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.add_flag(folder, &ids, flag).await
}
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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.set_flag(folder, &ids, flag).await
}
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)?;
let ids = Id::multiple(id_mapper.get_ids(ids)?);
self.backend.remove_flag(folder, &ids, flag).await
}
}
impl Deref for Backend {

View file

@ -1,19 +1,24 @@
use anyhow::Result;
use dialoguer::Select;
use crate::config::wizard::THEME;
#[cfg(feature = "imap")]
use crate::imap;
#[cfg(feature = "maildir")]
use crate::maildir;
#[cfg(feature = "notmuch")]
use crate::notmuch;
#[cfg(feature = "sendmail")]
use crate::sendmail;
#[cfg(feature = "smtp")]
use crate::smtp;
use crate::{config::wizard::THEME, maildir, sendmail};
use super::{config::BackendConfig, BackendKind};
const DEFAULT_BACKEND_KINDS: &[BackendKind] = &[
#[cfg(feature = "imap")]
BackendKind::Imap,
#[cfg(feature = "maildir")]
BackendKind::Maildir,
#[cfg(feature = "notmuch")]
BackendKind::Notmuch,
@ -22,10 +27,14 @@ const DEFAULT_BACKEND_KINDS: &[BackendKind] = &[
const SEND_MESSAGE_BACKEND_KINDS: &[BackendKind] = &[
#[cfg(feature = "smtp")]
BackendKind::Smtp,
#[cfg(feature = "sendmail")]
BackendKind::Sendmail,
];
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Option<BackendConfig>> {
pub(crate) async fn configure(
#[allow(unused)] account_name: &str,
#[allow(unused)] email: &str,
) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME)
.with_prompt("Default email backend")
.items(DEFAULT_BACKEND_KINDS)
@ -34,11 +43,12 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Option<
.and_then(|idx| DEFAULT_BACKEND_KINDS.get(idx).map(Clone::clone));
let config = match kind {
Some(kind) if kind == BackendKind::Maildir => Some(maildir::wizard::configure()?),
#[cfg(feature = "imap")]
Some(kind) if kind == BackendKind::Imap => {
Some(imap::wizard::configure(account_name, email).await?)
}
#[cfg(feature = "maildir")]
Some(kind) if kind == BackendKind::Maildir => Some(maildir::wizard::configure()?),
#[cfg(feature = "notmuch")]
Some(kind) if kind == BackendKind::Notmuch => Some(notmuch::wizard::configure()?),
_ => None,
@ -48,8 +58,8 @@ pub(crate) async fn configure(account_name: &str, email: &str) -> Result<Option<
}
pub(crate) async fn configure_sender(
account_name: &str,
email: &str,
#[allow(unused)] account_name: &str,
#[allow(unused)] email: &str,
) -> Result<Option<BackendConfig>> {
let kind = Select::with_theme(&*THEME)
.with_prompt("Backend for sending messages")
@ -59,11 +69,12 @@ pub(crate) async fn configure_sender(
.and_then(|idx| SEND_MESSAGE_BACKEND_KINDS.get(idx).map(Clone::clone));
let config = match kind {
Some(kind) if kind == BackendKind::Sendmail => Some(sendmail::wizard::configure()?),
#[cfg(feature = "smtp")]
Some(kind) if kind == BackendKind::Smtp => {
Some(smtp::wizard::configure(account_name, email).await?)
}
#[cfg(feature = "sendmail")]
Some(kind) if kind == BackendKind::Sendmail => Some(sendmail::wizard::configure()?),
_ => None,
};

View file

@ -2,18 +2,25 @@ use anyhow::Result;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[cfg(feature = "account-command")]
use crate::account::command::AccountSubcommand;
#[cfg(feature = "envelope-command")]
use crate::envelope::command::EnvelopeSubcommand;
#[cfg(feature = "flag-command")]
use crate::flag::command::FlagSubcommand;
#[cfg(feature = "folder-command")]
use crate::folder::command::FolderSubcommand;
#[cfg(feature = "attachment-command")]
use crate::message::attachment::command::AttachmentSubcommand;
#[cfg(feature = "message-command")]
use crate::message::command::MessageSubcommand;
#[cfg(feature = "template-command")]
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,
};
@ -22,8 +29,12 @@ 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
///
@ -77,31 +88,38 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
pub enum HimalayaCommand {
#[cfg(feature = "account-command")]
#[command(subcommand)]
#[command(alias = "accounts")]
Account(AccountSubcommand),
#[cfg(feature = "folder-command")]
#[command(subcommand)]
#[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])]
#[command(alias = "folders")]
Folder(FolderSubcommand),
#[cfg(feature = "envelope-command")]
#[command(subcommand)]
#[command(alias = "envelopes")]
Envelope(EnvelopeSubcommand),
#[cfg(feature = "flag-command")]
#[command(subcommand)]
#[command(alias = "flags")]
Flag(FlagSubcommand),
#[cfg(feature = "message-command")]
#[command(subcommand)]
#[command(alias = "messages", alias = "msgs", alias = "msg")]
Message(MessageSubcommand),
#[cfg(feature = "attachment-command")]
#[command(subcommand)]
#[command(alias = "attachments")]
Attachment(AttachmentSubcommand),
#[cfg(feature = "template-command")]
#[command(subcommand)]
#[command(alias = "templates", alias = "tpls", alias = "tpl")]
Template(TemplateSubcommand),
@ -116,36 +134,44 @@ pub enum HimalayaCommand {
}
impl HimalayaCommand {
#[allow(unused)]
pub async fn execute(
self,
printer: &mut impl Printer,
config_path: Option<&PathBuf>,
) -> Result<()> {
match self {
#[cfg(feature = "account-command")]
Self::Account(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "folder-command")]
Self::Folder(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "envelope-command")]
Self::Envelope(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "flag-command")]
Self::Flag(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "message-command")]
Self::Message(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "attachment-command")]
Self::Attachment(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await
}
#[cfg(feature = "template-command")]
Self::Template(cmd) => {
let config = TomlConfig::from_some_path_or_default(config_path).await?;
cmd.execute(printer, &config).await

View file

@ -8,6 +8,7 @@ use email::{
account::config::AccountConfig, config::Config, envelope::config::EnvelopeConfig,
folder::config::FolderConfig, message::config::MessageConfig,
};
use serde::{Deserialize, Serialize};
use shellexpand_utils::{canonicalize, expand};
use std::{
@ -18,7 +19,9 @@ use std::{
};
use toml;
use crate::{account::config::TomlAccountConfig, backend::BackendKind, wizard_prompt, wizard_warn};
#[cfg(feature = "sync")]
use crate::backend::BackendKind;
use crate::{account::config::TomlAccountConfig, wizard_prompt, wizard_warn};
/// Represents the user config file.
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
@ -132,6 +135,7 @@ impl TomlConfig {
&self,
account_name: Option<&str>,
) -> Result<(String, TomlAccountConfig)> {
#[allow(unused_mut)]
let (account_name, mut toml_account_config) = match account_name {
Some("default") | Some("") | None => self
.accounts
@ -171,11 +175,13 @@ impl TomlConfig {
pub fn into_account_configs(
self,
account_name: Option<&str>,
disable_cache: bool,
#[cfg(feature = "sync")] disable_cache: bool,
) -> Result<(TomlAccountConfig, AccountConfig)> {
#[cfg_attr(not(feature = "sync"), allow(unused_mut))]
let (account_name, mut toml_account_config) =
self.into_toml_account_config(account_name)?;
#[cfg(feature = "sync")]
if let Some(true) = toml_account_config.sync.as_ref().and_then(|c| c.enable) {
if !disable_cache {
toml_account_config.backend = Some(BackendKind::MaildirForSync);
@ -200,19 +206,29 @@ impl TomlConfig {
signature_delim: config.signature_delim,
downloads_dir: config.downloads_dir,
folder: config.folder.map(|c| FolderConfig {
folder: config.folder.map(|#[allow(unused)] c| FolderConfig {
aliases: c.alias,
#[cfg(feature = "folder-list")]
list: c.list.map(|c| c.remote),
..Default::default()
}),
envelope: config.envelope.map(|c| EnvelopeConfig {
envelope: config.envelope.map(|#[allow(unused)] c| EnvelopeConfig {
#[cfg(feature = "envelope-list")]
list: c.list.map(|c| c.remote),
#[cfg(feature = "envelope-watch")]
watch: c.watch.map(|c| c.remote),
..Default::default()
}),
message: config.message.map(|c| MessageConfig {
message: config.message.map(|#[allow(unused)] c| MessageConfig {
#[cfg(feature = "message-read")]
read: c.read.map(|c| c.remote),
#[cfg(feature = "message-write")]
write: c.write.map(|c| c.remote),
#[cfg(feature = "message-send")]
send: c.send.map(|c| c.remote),
..Default::default()
}),
#[cfg(feature = "sync")]
sync: config.sync,
#[cfg(feature = "pgp")]
pgp: config.pgp,

View file

@ -172,6 +172,7 @@ fn set_tables_dotted<'a>(item: &'a mut Item, keys: impl IntoIterator<Item = &'a
}
}
#[allow(unused)]
pub(crate) fn prompt_passwd(prompt: &str) -> io::Result<String> {
Password::with_theme(&*THEME)
.with_prompt(prompt)
@ -182,6 +183,7 @@ pub(crate) fn prompt_passwd(prompt: &str) -> io::Result<String> {
.interact()
}
#[allow(unused)]
pub(crate) fn prompt_secret(prompt: &str) -> io::Result<String> {
Password::with_theme(&*THEME)
.with_prompt(prompt)

View file

@ -8,10 +8,11 @@ use email::envelope::list::maildir::ListEnvelopesMaildir;
use email::envelope::list::notmuch::ListEnvelopesNotmuch;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameOptionalArg,
printer::{PrintTableOpts, Printer},
@ -43,6 +44,7 @@ pub struct ListEnvelopesCommand {
#[command(flatten)]
pub table: TableMaxWidthFlag,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -57,6 +59,7 @@ impl Default for ListEnvelopesCommand {
page: 1,
page_size: Default::default(),
table: Default::default(),
#[cfg(feature = "sync")]
cache: Default::default(),
account: Default::default(),
}
@ -69,6 +72,7 @@ impl ListEnvelopesCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -85,11 +89,19 @@ impl ListEnvelopesCommand {
&account_config,
list_envelopes_kind,
|builder| match list_envelopes_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_list_envelopes(|ctx| {
ctx.imap.as_ref().and_then(ListEnvelopesImap::new)
});
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_list_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_list_envelopes(|ctx| {
ctx.maildir_for_sync
@ -97,12 +109,6 @@ impl ListEnvelopesCommand {
.and_then(ListEnvelopesMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_list_envelopes(|ctx| {
ctx.imap.as_ref().and_then(ListEnvelopesImap::new)
});
}
_ => (),
},
)

View file

@ -1,4 +1,6 @@
#[cfg(feature = "envelope-list")]
pub mod list;
#[cfg(feature = "envelope-watch")]
pub mod watch;
use anyhow::Result;
@ -6,7 +8,10 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
use self::{list::ListEnvelopesCommand, watch::WatchEnvelopesCommand};
#[cfg(feature = "envelope-list")]
use self::list::ListEnvelopesCommand;
#[cfg(feature = "envelope-watch")]
use self::watch::WatchEnvelopesCommand;
/// Manage envelopes.
///
@ -16,17 +21,22 @@ use self::{list::ListEnvelopesCommand, 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),
}
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

@ -8,10 +8,11 @@ use email::envelope::watch::maildir::WatchMaildirEnvelopes;
use email::envelope::watch::notmuch::WatchNotmuchEnvelopes;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameOptionalFlag,
printer::Printer,
@ -26,6 +27,7 @@ pub struct WatchEnvelopesCommand {
#[command(flatten)]
pub folder: FolderNameOptionalFlag,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -40,6 +42,7 @@ impl WatchEnvelopesCommand {
let folder = &self.folder.name;
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -50,11 +53,19 @@ impl WatchEnvelopesCommand {
&account_config,
watch_envelopes_kind,
|builder| match watch_envelopes_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_watch_envelopes(|ctx| {
ctx.imap.as_ref().and_then(WatchImapEnvelopes::new)
});
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_watch_envelopes(|ctx| {
ctx.maildir.as_ref().and_then(WatchMaildirEnvelopes::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_watch_envelopes(|ctx| {
ctx.maildir_for_sync
@ -62,12 +73,6 @@ impl WatchEnvelopesCommand {
.and_then(WatchMaildirEnvelopes::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_watch_envelopes(|ctx| {
ctx.imap.as_ref().and_then(WatchImapEnvelopes::new)
});
}
_ => (),
},
)

View file

@ -5,31 +5,39 @@ use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct EnvelopeConfig {
#[cfg(feature = "envelope-list")]
pub list: Option<ListEnvelopesConfig>,
#[cfg(feature = "envelope-watch")]
pub watch: Option<WatchEnvelopesConfig>,
#[cfg(feature = "envelope-get")]
pub get: Option<GetEnvelopeConfig>,
}
impl EnvelopeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default();
#[cfg(feature = "envelope-list")]
if let Some(list) = &self.list {
kinds.extend(list.get_used_backends());
}
if let Some(get) = &self.get {
kinds.extend(get.get_used_backends());
}
#[cfg(feature = "envelope-watch")]
if let Some(watch) = &self.watch {
kinds.extend(watch.get_used_backends());
}
#[cfg(feature = "envelope-get")]
if let Some(get) = &self.get {
kinds.extend(get.get_used_backends());
}
kinds
}
}
#[cfg(feature = "envelope-list")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct ListEnvelopesConfig {
pub backend: Option<BackendKind>,
@ -38,6 +46,7 @@ pub struct ListEnvelopesConfig {
pub remote: email::envelope::list::config::EnvelopeListConfig,
}
#[cfg(feature = "envelope-list")]
impl ListEnvelopesConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -50,6 +59,7 @@ impl ListEnvelopesConfig {
}
}
#[cfg(feature = "envelope-watch")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct WatchEnvelopesConfig {
pub backend: Option<BackendKind>,
@ -58,6 +68,7 @@ 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();
@ -70,11 +81,13 @@ impl WatchEnvelopesConfig {
}
}
#[cfg(feature = "envelope-get")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct GetEnvelopeConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "envelope-get")]
impl GetEnvelopeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();

View file

@ -8,10 +8,11 @@ use email::flag::add::maildir::AddFlagsMaildir;
use email::flag::add::notmuch::AddFlagsNotmuch;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameOptionalFlag,
@ -30,6 +31,7 @@ pub struct FlagAddCommand {
#[command(flatten)]
pub args: IdsAndFlagsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -45,6 +47,7 @@ impl FlagAddCommand {
let (ids, flags) = into_tuple(&self.args.ids_and_flags);
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -55,19 +58,21 @@ impl FlagAddCommand {
&account_config,
add_flags_kind,
|builder| match add_flags_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_flags(|ctx| ctx.imap.as_ref().and_then(AddFlagsImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_flags(|ctx| {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_flags(|ctx| ctx.imap.as_ref().and_then(AddFlagsImap::new));
}
_ => (),
},
)

View file

@ -1,5 +1,8 @@
#[cfg(feature = "flag-add")]
mod add;
#[cfg(feature = "flag-remove")]
mod remove;
#[cfg(feature = "flag-set")]
mod set;
use anyhow::Result;
@ -7,7 +10,12 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
use self::{add::FlagAddCommand, remove::FlagRemoveCommand, set::FlagSetCommand};
#[cfg(feature = "flag-add")]
use self::add::FlagAddCommand;
#[cfg(feature = "flag-remove")]
use self::remove::FlagRemoveCommand;
#[cfg(feature = "flag-set")]
use self::set::FlagSetCommand;
/// Manage flags.
///
@ -17,24 +25,31 @@ use self::{add::FlagAddCommand, remove::FlagRemoveCommand, 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),
}
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

@ -8,10 +8,11 @@ use email::flag::remove::maildir::RemoveFlagsMaildir;
use email::flag::remove::notmuch::RemoveFlagsNotmuch;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameOptionalFlag,
@ -30,6 +31,7 @@ pub struct FlagRemoveCommand {
#[command(flatten)]
pub args: IdsAndFlagsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -45,6 +47,7 @@ impl FlagRemoveCommand {
let (ids, flags) = into_tuple(&self.args.ids_and_flags);
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -55,11 +58,18 @@ impl FlagRemoveCommand {
&account_config,
remove_flags_kind,
|builder| match remove_flags_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_remove_flags(|ctx| ctx.imap.as_ref().and_then(RemoveFlagsImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_remove_flags(|ctx| {
ctx.maildir.as_ref().and_then(RemoveFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_remove_flags(|ctx| {
ctx.maildir_for_sync
@ -67,11 +77,6 @@ impl FlagRemoveCommand {
.and_then(RemoveFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_remove_flags(|ctx| ctx.imap.as_ref().and_then(RemoveFlagsImap::new));
}
_ => (),
},
)

View file

@ -8,10 +8,11 @@ use email::flag::set::maildir::SetFlagsMaildir;
use email::flag::set::notmuch::SetFlagsNotmuch;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameOptionalFlag,
@ -30,6 +31,7 @@ pub struct FlagSetCommand {
#[command(flatten)]
pub args: IdsAndFlagsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -45,6 +47,7 @@ impl FlagSetCommand {
let (ids, flags) = into_tuple(&self.args.ids_and_flags);
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -55,19 +58,21 @@ impl FlagSetCommand {
&account_config,
set_flags_kind,
|builder| match set_flags_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_set_flags(|ctx| ctx.imap.as_ref().and_then(SetFlagsImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder
.set_set_flags(|ctx| ctx.maildir.as_ref().and_then(SetFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_set_flags(|ctx| {
ctx.maildir_for_sync.as_ref().and_then(SetFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_set_flags(|ctx| ctx.imap.as_ref().and_then(SetFlagsImap::new));
}
_ => (),
},
)

View file

@ -5,23 +5,30 @@ 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>,
}
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());
}
@ -30,11 +37,13 @@ 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();
@ -47,11 +56,13 @@ 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();
@ -64,11 +75,13 @@ 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

@ -3,14 +3,19 @@ pub mod command;
pub mod config;
pub mod flag;
#[cfg(feature = "envelope-list")]
use anyhow::Result;
#[cfg(feature = "envelope-list")]
use email::account::config::AccountConfig;
use serde::Serialize;
#[cfg(feature = "envelope-list")]
use std::ops;
use crate::flag::Flags;
#[cfg(feature = "envelope-list")]
use crate::{
cache::IdMapper,
flag::{Flag, Flags},
flag::Flag,
printer::{PrintTable, PrintTableOpts, WriteColor},
ui::{Cell, Row, Table},
};
@ -30,6 +35,7 @@ pub struct Envelope {
pub date: String,
}
#[cfg(feature = "envelope-list")]
impl Table for Envelope {
fn head() -> Row {
Row::new()
@ -75,10 +81,12 @@ impl Table for Envelope {
}
}
#[cfg(feature = "envelope-list")]
/// Represents the list of envelopes.
#[derive(Clone, Debug, Default, Serialize)]
pub struct Envelopes(Vec<Envelope>);
#[cfg(feature = "envelope-list")]
impl Envelopes {
pub fn from_backend(
config: &AccountConfig,
@ -105,6 +113,7 @@ impl Envelopes {
}
}
#[cfg(feature = "envelope-list")]
impl ops::Deref for Envelopes {
type Target = Vec<Envelope>;
@ -113,6 +122,7 @@ impl ops::Deref for Envelopes {
}
}
#[cfg(feature = "envelope-list")]
impl PrintTable for Envelopes {
fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writer)?;

View file

@ -1,17 +1,18 @@
use anyhow::{Context, Result};
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::{get::imap::GetMessagesImap, peek::imap::PeekMessagesImap};
use email::message::get::imap::GetMessagesImap;
#[cfg(feature = "maildir")]
use email::{flag::add::maildir::AddFlagsMaildir, message::peek::maildir::PeekMessagesMaildir};
use log::info;
use std::{fs, path::PathBuf};
use uuid::Uuid;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::FolderNameOptionalFlag,
@ -30,6 +31,7 @@ pub struct AttachmentDownloadCommand {
#[command(flatten)]
pub envelopes: EnvelopeIdsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -46,6 +48,7 @@ impl AttachmentDownloadCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -56,6 +59,12 @@ impl AttachmentDownloadCommand {
&account_config,
get_messages_kind,
|builder| match get_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_peek_messages(|ctx| {
ctx.maildir.as_ref().and_then(PeekMessagesMaildir::new)
@ -63,6 +72,7 @@ impl AttachmentDownloadCommand {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_peek_messages(|ctx| {
ctx.maildir_for_sync
@ -73,13 +83,6 @@ impl AttachmentDownloadCommand {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_peek_messages(|ctx| ctx.imap.as_ref().and_then(PeekMessagesImap::new));
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
_ => (),
},
)

View file

@ -1,3 +1,4 @@
#[cfg(feature = "attachment-download")]
pub mod download;
use anyhow::Result;
@ -5,6 +6,7 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
#[cfg(feature = "attachment-download")]
use self::download::AttachmentDownloadCommand;
/// Manage attachments.
@ -14,13 +16,16 @@ 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

@ -6,10 +6,11 @@ use email::message::copy::imap::CopyMessagesImap;
use email::message::copy::maildir::CopyMessagesMaildir;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::{SourceFolderNameOptionalFlag, TargetFolderNameArg},
@ -28,6 +29,7 @@ pub struct MessageCopyCommand {
#[command(flatten)]
pub envelopes: EnvelopeIdsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -45,6 +47,7 @@ impl MessageCopyCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -55,11 +58,18 @@ impl MessageCopyCommand {
&account_config,
copy_messages_kind,
|builder| match copy_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_copy_messages(|ctx| ctx.imap.as_ref().and_then(CopyMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_copy_messages(|ctx| {
ctx.maildir.as_ref().and_then(CopyMessagesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_copy_messages(|ctx| {
ctx.maildir_for_sync
@ -67,11 +77,6 @@ impl MessageCopyCommand {
.and_then(CopyMessagesMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_copy_messages(|ctx| ctx.imap.as_ref().and_then(CopyMessagesImap::new));
}
_ => (),
},
)

View file

@ -6,10 +6,11 @@ use email::{flag::add::imap::AddFlagsImap, message::move_::imap::MoveMessagesIma
use email::{flag::add::maildir::AddFlagsMaildir, message::move_::maildir::MoveMessagesMaildir};
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::FolderNameOptionalFlag,
@ -30,6 +31,7 @@ pub struct MessageDeleteCommand {
#[command(flatten)]
pub envelopes: EnvelopeIdsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -46,6 +48,7 @@ impl MessageDeleteCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -56,6 +59,13 @@ impl MessageDeleteCommand {
&account_config,
delete_messages_kind,
|builder| match delete_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_move_messages(|ctx| ctx.imap.as_ref().and_then(MoveMessagesImap::new));
builder.set_add_flags(|ctx| ctx.imap.as_ref().and_then(AddFlagsImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_move_messages(|ctx| {
ctx.maildir.as_ref().and_then(MoveMessagesMaildir::new)
@ -63,6 +73,7 @@ impl MessageDeleteCommand {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_move_messages(|ctx| {
ctx.maildir_for_sync
@ -73,12 +84,6 @@ impl MessageDeleteCommand {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_move_messages(|ctx| ctx.imap.as_ref().and_then(MoveMessagesImap::new));
builder.set_add_flags(|ctx| ctx.imap.as_ref().and_then(AddFlagsImap::new));
}
_ => (),
},
)

View file

@ -1,19 +1,20 @@
use anyhow::{anyhow, Result};
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameOptionalFlag,
@ -42,6 +43,7 @@ pub struct MessageForwardCommand {
#[command(flatten)]
pub body: MessageRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -57,11 +59,12 @@ impl MessageForwardCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let send_message_kind = toml_account_config.send_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -69,24 +72,25 @@ impl MessageForwardCommand {
add_message_kind.into_iter().chain(send_message_kind),
|builder| {
match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder
.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -95,14 +99,14 @@ impl MessageForwardCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),

View file

@ -1,21 +1,22 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use log::{debug, info};
use mail_builder::MessageBuilder;
use url::Url;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
printer::Printer,
ui::editor,
@ -33,6 +34,7 @@ pub struct MessageMailtoCommand {
#[arg()]
pub url: Url,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -44,6 +46,7 @@ impl MessageMailtoCommand {
pub fn new(url: &str) -> Result<Self> {
Ok(Self {
url: Url::parse(url)?,
#[cfg(feature = "sync")]
cache: Default::default(),
account: Default::default(),
})
@ -54,11 +57,12 @@ impl MessageMailtoCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let send_message_kind = toml_account_config.send_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -66,24 +70,25 @@ impl MessageMailtoCommand {
add_message_kind.into_iter().chain(send_message_kind),
|builder| {
match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder
.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -92,14 +97,14 @@ impl MessageMailtoCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),

View file

@ -1,12 +1,22 @@
#[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 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;
@ -14,12 +24,26 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
use self::{
copy::MessageCopyCommand, delete::MessageDeleteCommand, forward::MessageForwardCommand,
mailto::MessageMailtoCommand, move_::MessageMoveCommand, read::MessageReadCommand,
reply::MessageReplyCommand, save::MessageSaveCommand, send::MessageSendCommand,
write::MessageWriteCommand,
};
#[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::move_::MessageMoveCommand;
#[cfg(feature = "message-read")]
use self::read::MessageReadCommand;
#[cfg(feature = "message-reply")]
use self::reply::MessageReplyCommand;
#[cfg(feature = "message-save")]
use self::save::MessageSaveCommand;
#[cfg(feature = "message-send")]
use self::send::MessageSendCommand;
#[cfg(feature = "message-write")]
use self::write::MessageWriteCommand;
/// Manage messages.
///
@ -29,52 +53,73 @@ use self::{
/// 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")]
#[command(arg_required_else_help = true)]
Save(MessageSaveCommand),
#[cfg(feature = "message-send")]
#[command(arg_required_else_help = true)]
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),
}
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

@ -6,10 +6,11 @@ use email::message::move_::imap::MoveMessagesImap;
use email::message::move_::maildir::MoveMessagesMaildir;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::{SourceFolderNameOptionalFlag, TargetFolderNameArg},
@ -28,6 +29,7 @@ pub struct MessageMoveCommand {
#[command(flatten)]
pub envelopes: EnvelopeIdsArgs,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -45,6 +47,7 @@ impl MessageMoveCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -55,11 +58,18 @@ impl MessageMoveCommand {
&account_config,
move_messages_kind,
|builder| match move_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_move_messages(|ctx| ctx.imap.as_ref().and_then(MoveMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_move_messages(|ctx| {
ctx.maildir.as_ref().and_then(MoveMessagesMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_move_messages(|ctx| {
ctx.maildir_for_sync
@ -67,11 +77,6 @@ impl MessageMoveCommand {
.and_then(MoveMessagesMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_move_messages(|ctx| ctx.imap.as_ref().and_then(MoveMessagesImap::new));
}
_ => (),
},
)

View file

@ -7,10 +7,11 @@ use email::{flag::add::maildir::AddFlagsMaildir, message::peek::maildir::PeekMes
use log::info;
use mml::message::FilterParts;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::FolderNameOptionalFlag,
@ -74,6 +75,7 @@ pub struct MessageReadCommand {
#[arg(conflicts_with = "no_headers")]
pub headers: Vec<String>,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -90,6 +92,7 @@ impl MessageReadCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -100,6 +103,14 @@ impl MessageReadCommand {
&account_config,
get_messages_kind,
|builder| match get_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_peek_messages(|ctx| ctx.imap.as_ref().and_then(PeekMessagesImap::new));
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_peek_messages(|ctx| {
ctx.maildir.as_ref().and_then(PeekMessagesMaildir::new)
@ -107,6 +118,7 @@ impl MessageReadCommand {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_peek_messages(|ctx| {
ctx.maildir_for_sync
@ -117,13 +129,6 @@ impl MessageReadCommand {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_peek_messages(|ctx| ctx.imap.as_ref().and_then(PeekMessagesImap::new));
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
_ => (),
},
)

View file

@ -2,19 +2,20 @@ use anyhow::{anyhow, Result};
use clap::Parser;
use email::flag::Flag;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameOptionalFlag,
@ -46,6 +47,7 @@ pub struct MessageReplyCommand {
#[command(flatten)]
pub body: MessageRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -60,11 +62,12 @@ impl MessageReplyCommand {
let folder = &self.folder.name;
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let send_message_kind = toml_account_config.send_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -72,24 +75,25 @@ impl MessageReplyCommand {
add_message_kind.into_iter().chain(send_message_kind),
|builder| {
match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder
.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -98,14 +102,14 @@ impl MessageReplyCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),
@ -128,7 +132,7 @@ impl MessageReplyCommand {
.await?;
editor::edit_tpl_with_editor(&account_config, printer, &backend, tpl).await?;
// TODO: let backend.send_reply_raw_message adding the flag
// TODO: let backend.send_reply_message adding the flag
backend.add_flag(&folder, &[id], Flag::Answered).await
}
}

View file

@ -1,16 +1,17 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
use log::info;
use std::io::{self, BufRead, IsTerminal};
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameOptionalFlag,
message::arg::MessageRawArg,
@ -28,6 +29,7 @@ pub struct MessageSaveCommand {
#[command(flatten)]
pub message: MessageRawArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -43,34 +45,35 @@ impl MessageSaveCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let backend = Backend::new(
&toml_account_config,
&account_config,
add_message_kind,
|builder| match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -91,7 +94,7 @@ impl MessageSaveCommand {
.join("\r\n")
};
backend.add_raw_message(folder, msg.as_bytes()).await?;
backend.add_message(folder, msg.as_bytes()).await?;
printer.print(format!("Message successfully saved to {folder}!"))
}

View file

@ -1,16 +1,17 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use log::info;
use std::io::{self, BufRead, IsTerminal};
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
message::arg::MessageRawArg,
printer::Printer,
@ -25,6 +26,7 @@ pub struct MessageSendCommand {
#[command(flatten)]
pub message: MessageRawArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -38,10 +40,11 @@ impl MessageSendCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let send_message_kind = toml_account_config.send_raw_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -51,14 +54,14 @@ impl MessageSendCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),
@ -78,7 +81,7 @@ impl MessageSendCommand {
.join("\r\n")
};
backend.send_raw_message(msg.as_bytes()).await?;
backend.send_message(msg.as_bytes()).await?;
printer.print("Message successfully sent!")
}

View file

@ -1,20 +1,21 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use email::message::Message;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
printer::Printer,
@ -35,6 +36,7 @@ pub struct MessageWriteCommand {
#[command(flatten)]
pub body: MessageRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -48,11 +50,12 @@ impl MessageWriteCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let send_message_kind = toml_account_config.send_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -60,24 +63,25 @@ impl MessageWriteCommand {
add_message_kind.into_iter().chain(send_message_kind),
|builder| {
match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder
.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -86,14 +90,14 @@ impl MessageWriteCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),

View file

@ -5,39 +5,52 @@ use crate::backend::BackendKind;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageConfig {
#[cfg(any(feature = "message-add", feature = "message-write"))]
pub write: Option<MessageAddConfig>,
#[cfg(any(feature = "message-send", feature = "template-send"))]
pub send: Option<MessageSendConfig>,
#[cfg(feature = "message-peek")]
pub peek: Option<MessagePeekConfig>,
#[cfg(any(feature = "message-get", feature = "message-read"))]
pub read: Option<MessageGetConfig>,
#[cfg(feature = "message-copy")]
pub copy: Option<MessageCopyConfig>,
#[cfg(feature = "message-move")]
#[serde(rename = "move")]
pub move_: Option<MessageMoveConfig>,
}
impl MessageConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default();
#[cfg(any(feature = "message-add", feature = "message-write"))]
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 = "message-peek")]
if let Some(peek) = &self.peek {
kinds.extend(peek.get_used_backends());
}
#[cfg(any(feature = "message-get", feature = "message-read"))]
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(feature = "message-move")]
if let Some(move_) = &self.move_ {
kinds.extend(move_.get_used_backends());
}
@ -46,14 +59,16 @@ impl MessageConfig {
}
}
#[cfg(any(feature = "message-add", feature = "message-write"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageAddConfig {
pub backend: Option<BackendKind>,
#[serde(flatten)]
pub remote: email::message::add_raw::config::MessageWriteConfig,
pub remote: email::message::add::config::MessageWriteConfig,
}
#[cfg(any(feature = "message-add", feature = "message-write"))]
impl MessageAddConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -66,14 +81,16 @@ 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>,
#[serde(flatten)]
pub remote: email::message::send_raw::config::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();
@ -86,11 +103,13 @@ impl MessageSendConfig {
}
}
#[cfg(feature = "message-peek")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessagePeekConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "message-peek")]
impl MessagePeekConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -103,6 +122,7 @@ impl MessagePeekConfig {
}
}
#[cfg(any(feature = "message-get", feature = "message-read"))]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageGetConfig {
pub backend: Option<BackendKind>,
@ -111,6 +131,7 @@ pub struct MessageGetConfig {
pub remote: email::message::get::config::MessageReadConfig,
}
#[cfg(any(feature = "message-get", feature = "message-read"))]
impl MessageGetConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -123,11 +144,13 @@ 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();
@ -140,11 +163,13 @@ impl MessageCopyConfig {
}
}
#[cfg(feature = "message-move")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct MessageMoveConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "message-move")]
impl MessageMoveConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();

View file

@ -1,15 +1,16 @@
use anyhow::{anyhow, Result};
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::{get::imap::GetMessagesImap, peek::imap::PeekMessagesImap};
use email::message::get::imap::GetMessagesImap;
#[cfg(feature = "maildir")]
use email::{flag::add::maildir::AddFlagsMaildir, message::peek::maildir::PeekMessagesMaildir};
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameOptionalFlag,
@ -36,6 +37,7 @@ pub struct TemplateForwardCommand {
#[command(flatten)]
pub body: MessageRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -51,6 +53,7 @@ impl TemplateForwardCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -61,6 +64,12 @@ impl TemplateForwardCommand {
&account_config,
get_messages_kind,
|builder| match get_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_peek_messages(|ctx| {
ctx.maildir.as_ref().and_then(PeekMessagesMaildir::new)
@ -68,6 +77,7 @@ impl TemplateForwardCommand {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_peek_messages(|ctx| {
ctx.maildir_for_sync
@ -78,13 +88,6 @@ impl TemplateForwardCommand {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_peek_messages(|ctx| ctx.imap.as_ref().and_then(PeekMessagesImap::new));
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
_ => (),
},
)

View file

@ -1,7 +1,12 @@
#[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;
use anyhow::Result;
@ -9,10 +14,16 @@ use clap::Subcommand;
use crate::{config::TomlConfig, printer::Printer};
use self::{
forward::TemplateForwardCommand, reply::TemplateReplyCommand, save::TemplateSaveCommand,
send::TemplateSendCommand, write::TemplateWriteCommand,
};
#[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;
/// Manage templates.
///
@ -25,30 +36,41 @@ use self::{
/// <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,15 +1,16 @@
use anyhow::{anyhow, Result};
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::{get::imap::GetMessagesImap, peek::imap::PeekMessagesImap};
use email::message::get::imap::GetMessagesImap;
#[cfg(feature = "maildir")]
use email::{flag::add::maildir::AddFlagsMaildir, message::peek::maildir::PeekMessagesMaildir};
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameOptionalFlag,
@ -40,6 +41,7 @@ pub struct TemplateReplyCommand {
#[command(flatten)]
pub body: MessageRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -56,6 +58,7 @@ impl TemplateReplyCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -66,6 +69,12 @@ impl TemplateReplyCommand {
&account_config,
get_messages_kind,
|builder| match get_messages_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_peek_messages(|ctx| {
ctx.maildir.as_ref().and_then(PeekMessagesMaildir::new)
@ -73,6 +82,7 @@ impl TemplateReplyCommand {
builder
.set_add_flags(|ctx| ctx.maildir.as_ref().and_then(AddFlagsMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_peek_messages(|ctx| {
ctx.maildir_for_sync
@ -83,13 +93,6 @@ impl TemplateReplyCommand {
ctx.maildir_for_sync.as_ref().and_then(AddFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_peek_messages(|ctx| ctx.imap.as_ref().and_then(PeekMessagesImap::new));
builder
.set_get_messages(|ctx| ctx.imap.as_ref().and_then(GetMessagesImap::new));
}
_ => (),
},
)

View file

@ -1,17 +1,18 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "imap")]
use email::message::add_raw::imap::AddRawMessageImap;
use email::message::add::imap::AddMessageImap;
#[cfg(feature = "maildir")]
use email::message::add_raw_with_flags::maildir::AddRawMessageWithFlagsMaildir;
use email::message::add_with_flags::maildir::AddMessageWithFlagsMaildir;
use log::info;
use mml::MmlCompilerBuilder;
use std::io::{self, BufRead, IsTerminal};
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
email::template::arg::TemplateRawArg,
folder::arg::name::FolderNameOptionalFlag,
@ -32,6 +33,7 @@ pub struct TemplateSaveCommand {
#[command(flatten)]
pub template: TemplateRawArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -47,34 +49,35 @@ impl TemplateSaveCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let add_message_kind = toml_account_config.add_raw_message_kind();
let add_message_kind = toml_account_config.add_message_kind();
let backend = Backend::new(
&toml_account_config,
&account_config,
add_message_kind,
|builder| match add_message_kind {
Some(BackendKind::Maildir) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
Some(BackendKind::MaildirForSync) => {
builder.set_add_raw_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddRawMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_raw_message(|ctx| {
ctx.imap.as_ref().and_then(AddRawMessageImap::new)
builder.set_add_message(|ctx| ctx.imap.as_ref().and_then(AddMessageImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_message_with_flags(|ctx| {
ctx.maildir_for_sync
.as_ref()
.and_then(AddMessageWithFlagsMaildir::new)
});
}
_ => (),
@ -102,7 +105,8 @@ impl TemplateSaveCommand {
compiler.set_some_pgp(account_config.pgp.clone());
let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend.add_raw_message(folder, &msg).await?;
backend.add_message(folder, &msg).await?;
printer.print(format!("Template successfully saved to {folder}!"))
}

View file

@ -1,17 +1,18 @@
use anyhow::Result;
use clap::Parser;
#[cfg(feature = "sendmail")]
use email::message::send_raw::sendmail::SendRawMessageSendmail;
use email::message::send::sendmail::SendMessageSendmail;
#[cfg(feature = "smtp")]
use email::message::send_raw::smtp::SendRawMessageSmtp;
use email::message::send::smtp::SendMessageSmtp;
use log::info;
use mml::MmlCompilerBuilder;
use std::io::{self, BufRead, IsTerminal};
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
email::template::arg::TemplateRawArg,
printer::Printer,
@ -28,6 +29,7 @@ pub struct TemplateSendCommand {
#[command(flatten)]
pub template: TemplateRawArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -41,10 +43,11 @@ impl TemplateSendCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
let send_message_kind = toml_account_config.send_raw_message_kind();
let send_message_kind = toml_account_config.send_message_kind();
let backend = Backend::new(
&toml_account_config,
@ -54,14 +57,14 @@ impl TemplateSendCommand {
match send_message_kind {
#[cfg(feature = "smtp")]
Some(BackendKind::Smtp) => {
builder.set_send_raw_message(|ctx| {
ctx.smtp.as_ref().and_then(SendRawMessageSmtp::new)
builder.set_send_message(|ctx| {
ctx.smtp.as_ref().and_then(SendMessageSmtp::new)
});
}
#[cfg(feature = "sendmail")]
Some(BackendKind::Sendmail) => {
builder.set_send_raw_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendRawMessageSendmail::new)
builder.set_send_message(|ctx| {
ctx.sendmail.as_ref().and_then(SendMessageSendmail::new)
});
}
_ => (),
@ -89,8 +92,8 @@ impl TemplateSendCommand {
let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend.send_raw_message(&msg).await?;
backend.send_message(&msg).await?;
printer.print("Template successfully sent!")
printer.print("Message successfully sent!")
}
}

View file

@ -3,8 +3,10 @@ use clap::Parser;
use email::message::Message;
use log::info;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag, cache::arg::disable::CacheDisableFlag, config::TomlConfig,
account::arg::name::AccountNameFlag, config::TomlConfig,
email::template::arg::body::TemplateRawBodyArg, message::arg::header::HeaderRawArgs,
printer::Printer,
};
@ -21,6 +23,7 @@ pub struct TemplateWriteCommand {
#[command(flatten)]
pub body: TemplateRawBodyArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -34,6 +37,7 @@ impl TemplateWriteCommand {
let (_, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;

View file

@ -6,13 +6,13 @@ use email::folder::add::imap::AddFolderImap;
use email::folder::add::maildir::AddFolderMaildir;
use log::info;
#[cfg(any(feature = "imap", feature = "maildir", feature = "sync"))]
use crate::backend::BackendKind;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameArg,
printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, config::TomlConfig,
folder::arg::name::FolderNameArg, printer::Printer,
};
/// Create a new folder.
@ -20,10 +20,11 @@ use crate::{
/// This command allows you to create a new folder using the given
/// name.
#[derive(Debug, Parser)]
pub struct FolderCreateCommand {
pub struct AddFolderCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -31,13 +32,14 @@ pub struct FolderCreateCommand {
pub account: AccountNameFlag,
}
impl FolderCreateCommand {
impl AddFolderCommand {
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
info!("executing create folder command");
let folder = &self.folder.name;
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -48,10 +50,16 @@ impl FolderCreateCommand {
&account_config,
add_folder_kind,
|builder| match add_folder_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_folder(|ctx| ctx.imap.as_ref().and_then(AddFolderImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder
.set_add_folder(|ctx| ctx.maildir.as_ref().and_then(AddFolderMaildir::new));
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_add_folder(|ctx| {
ctx.maildir_for_sync
@ -59,10 +67,6 @@ impl FolderCreateCommand {
.and_then(AddFolderMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_add_folder(|ctx| ctx.imap.as_ref().and_then(AddFolderImap::new));
}
_ => (),
},
)

View file

@ -8,13 +8,13 @@ use email::folder::delete::maildir::DeleteFolderMaildir;
use log::info;
use std::process;
#[cfg(any(feature = "imap", feature = "maildir", feature = "sync"))]
use crate::backend::BackendKind;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameArg,
printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, config::TomlConfig,
folder::arg::name::FolderNameArg, printer::Printer,
};
/// Delete a folder.
@ -26,6 +26,7 @@ pub struct FolderDeleteCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -51,6 +52,7 @@ impl FolderDeleteCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -61,11 +63,18 @@ impl FolderDeleteCommand {
&account_config,
delete_folder_kind,
|builder| match delete_folder_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_delete_folder(|ctx| ctx.imap.as_ref().and_then(DeleteFolderImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_delete_folder(|ctx| {
ctx.maildir.as_ref().and_then(DeleteFolderMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_delete_folder(|ctx| {
ctx.maildir_for_sync
@ -73,11 +82,6 @@ impl FolderDeleteCommand {
.and_then(DeleteFolderMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_delete_folder(|ctx| ctx.imap.as_ref().and_then(DeleteFolderImap::new));
}
_ => (),
},
)

View file

@ -6,13 +6,13 @@ use email::folder::expunge::imap::ExpungeFolderImap;
use email::folder::expunge::maildir::ExpungeFolderMaildir;
use log::info;
#[cfg(any(feature = "imap", feature = "maildir", feature = "sync"))]
use crate::backend::BackendKind;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameArg,
printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, config::TomlConfig,
folder::arg::name::FolderNameArg, printer::Printer,
};
/// Expunge a folder.
@ -25,6 +25,7 @@ pub struct FolderExpungeCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -39,6 +40,7 @@ impl FolderExpungeCommand {
let folder = &self.folder.name;
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -49,11 +51,19 @@ impl FolderExpungeCommand {
&account_config,
expunge_folder_kind,
|builder| match expunge_folder_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_expunge_folder(|ctx| {
ctx.imap.as_ref().and_then(ExpungeFolderImap::new)
});
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_expunge_folder(|ctx| {
ctx.maildir.as_ref().and_then(ExpungeFolderMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_expunge_folder(|ctx| {
ctx.maildir_for_sync
@ -61,12 +71,6 @@ impl FolderExpungeCommand {
.and_then(ExpungeFolderMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder.set_expunge_folder(|ctx| {
ctx.imap.as_ref().and_then(ExpungeFolderImap::new)
});
}
_ => (),
},
)

View file

@ -6,10 +6,13 @@ use email::folder::list::imap::ListFoldersImap;
use email::folder::list::maildir::ListFoldersMaildir;
use log::info;
#[cfg(any(feature = "imap", feature = "maildir", feature = "sync"))]
use crate::backend::BackendKind;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
backend::Backend,
config::TomlConfig,
folder::Folders,
printer::{PrintTableOpts, Printer},
@ -24,6 +27,7 @@ pub struct FolderListCommand {
#[command(flatten)]
pub table: TableMaxWidthFlag,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -37,6 +41,7 @@ impl FolderListCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -47,11 +52,18 @@ impl FolderListCommand {
&account_config,
list_folders_kind,
|builder| match list_folders_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_list_folders(|ctx| ctx.imap.as_ref().and_then(ListFoldersImap::new));
}
#[cfg(feature = "maildir")]
Some(BackendKind::Maildir) => {
builder.set_list_folders(|ctx| {
ctx.maildir.as_ref().and_then(ListFoldersMaildir::new)
});
}
#[cfg(feature = "sync")]
Some(BackendKind::MaildirForSync) => {
builder.set_list_folders(|ctx| {
ctx.maildir_for_sync
@ -59,11 +71,6 @@ impl FolderListCommand {
.and_then(ListFoldersMaildir::new)
});
}
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_list_folders(|ctx| ctx.imap.as_ref().and_then(ListFoldersImap::new));
}
_ => (),
},
)

View file

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

@ -6,13 +6,13 @@ use email::folder::purge::imap::PurgeFolderImap;
use log::info;
use std::process;
#[cfg(any(feature = "imap", feature = "maildir", feature = "sync"))]
use crate::backend::BackendKind;
#[cfg(feature = "sync")]
use crate::cache::arg::disable::CacheDisableFlag;
use crate::{
account::arg::name::AccountNameFlag,
backend::{Backend, BackendKind},
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameArg,
printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, config::TomlConfig,
folder::arg::name::FolderNameArg, printer::Printer,
};
/// Purge a folder.
@ -24,6 +24,7 @@ pub struct FolderPurgeCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[cfg(feature = "sync")]
#[command(flatten)]
pub cache: CacheDisableFlag,
@ -49,6 +50,7 @@ impl FolderPurgeCommand {
let (toml_account_config, account_config) = config.clone().into_account_configs(
self.account.name.as_ref().map(String::as_str),
#[cfg(feature = "sync")]
self.cache.disable,
)?;
@ -59,12 +61,19 @@ impl FolderPurgeCommand {
&account_config,
purge_folder_kind,
|builder| match purge_folder_kind {
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_purge_folder(|ctx| ctx.imap.as_ref().and_then(PurgeFolderImap::new));
}
// TODO
// #[cfg(feature = "maildir")]
// Some(BackendKind::Maildir) => {
// builder.set_purge_folder(|ctx| {
// ctx.maildir.as_ref().and_then(PurgeFolderMaildir::new)
// });
// }
// #[cfg(feature = "sync")]
// Some(BackendKind::MaildirForSync) => {
// builder.set_purge_folder(|ctx| {
// ctx.maildir_for_sync
@ -72,11 +81,6 @@ impl FolderPurgeCommand {
// .and_then(PurgeFolderMaildir::new)
// });
// }
#[cfg(feature = "imap")]
Some(BackendKind::Imap) => {
builder
.set_purge_folder(|ctx| ctx.imap.as_ref().and_then(PurgeFolderImap::new));
}
_ => (),
},
)

View file

@ -8,33 +8,44 @@ pub struct FolderConfig {
#[serde(alias = "aliases")]
pub alias: Option<HashMap<String, String>>,
#[cfg(feature = "folder-add")]
pub add: Option<FolderAddConfig>,
#[cfg(feature = "folder-list")]
pub list: Option<FolderListConfig>,
#[cfg(feature = "folder-expunge")]
pub expunge: Option<FolderExpungeConfig>,
#[cfg(feature = "folder-purge")]
pub purge: Option<FolderPurgeConfig>,
#[cfg(feature = "folder-delete")]
pub delete: Option<FolderDeleteConfig>,
}
impl FolderConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
#[allow(unused_mut)]
let mut kinds = HashSet::default();
#[cfg(feature = "folder-add")]
if let Some(add) = &self.add {
kinds.extend(add.get_used_backends());
}
#[cfg(feature = "folder-list")]
if let Some(list) = &self.list {
kinds.extend(list.get_used_backends());
}
#[cfg(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(feature = "folder-delete")]
if let Some(delete) = &self.delete {
kinds.extend(delete.get_used_backends());
}
@ -43,11 +54,13 @@ impl FolderConfig {
}
}
#[cfg(feature = "folder-add")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderAddConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "folder-add")]
impl FolderAddConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -60,6 +73,7 @@ impl FolderAddConfig {
}
}
#[cfg(feature = "folder-list")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderListConfig {
pub backend: Option<BackendKind>,
@ -68,6 +82,7 @@ pub struct FolderListConfig {
pub remote: email::folder::list::config::FolderListConfig,
}
#[cfg(feature = "folder-list")]
impl FolderListConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -80,11 +95,13 @@ impl FolderListConfig {
}
}
#[cfg(feature = "folder-expunge")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderExpungeConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "folder-expunge")]
impl FolderExpungeConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();
@ -97,11 +114,13 @@ 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();
@ -114,11 +133,13 @@ impl FolderPurgeConfig {
}
}
#[cfg(feature = "folder-delete")]
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct FolderDeleteConfig {
pub backend: Option<BackendKind>,
}
#[cfg(feature = "folder-delete")]
impl FolderDeleteConfig {
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
let mut kinds = HashSet::default();

View file

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

View file

@ -1,12 +1,14 @@
use anyhow::Result;
use clap::Parser;
use env_logger::{Builder as LoggerBuilder, Env, DEFAULT_FILTER_ENV};
use himalaya::{
cli::Cli, config::TomlConfig, envelope::command::list::ListEnvelopesCommand,
message::command::mailto::MessageMailtoCommand, printer::StdoutPrinter,
};
#[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 std::env;
#[tokio::main]
async fn main() -> Result<()> {
@ -21,9 +23,13 @@ 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) = env::args().nth(1).filter(|arg| arg.starts_with("mailto:")) {
if let Some(ref url) = std::env::args()
.nth(1)
.filter(|arg| arg.starts_with("mailto:"))
{
let mut printer = StdoutPrinter::default();
let config = TomlConfig::from_default_paths().await?;
@ -35,13 +41,20 @@ 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) => cmd.execute(&mut printer, cli.config_path.as_ref()).await,
Some(cmd) => return 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?;
ListEnvelopesCommand::default()
return 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,4 +1,4 @@
use anyhow::{anyhow, Context, Result};
use anyhow::{anyhow, bail, Context, Result};
use log::{debug, error};
use std::io::{self, Write};
@ -43,9 +43,11 @@ pub fn pre_edit() -> Result<PreEditChoice> {
}
pub enum PostEditChoice {
#[cfg(feature = "message-send")]
Send,
Edit,
LocalDraft,
#[cfg(feature = "message-add")]
RemoteDraft,
Discard,
}
@ -60,6 +62,7 @@ pub fn post_edit() -> Result<PostEditChoice> {
.context("cannot read stdin")?;
match buf.bytes().next().map(|bytes| bytes as char) {
#[cfg(feature = "message-send")]
Some('s') => {
debug!("send choice matched");
Ok(PostEditChoice::Send)
@ -68,6 +71,7 @@ pub fn post_edit() -> Result<PostEditChoice> {
debug!("save local draft choice matched");
Ok(PostEditChoice::LocalDraft)
}
#[cfg(feature = "message-add")]
Some('r') => {
debug!("save remote draft matched");
Ok(PostEditChoice::RemoteDraft)
@ -82,11 +86,11 @@ pub fn post_edit() -> Result<PostEditChoice> {
}
Some(choice) => {
error!(r#"invalid choice "{}""#, choice);
Err(anyhow!(r#"invalid choice "{}""#, choice))
bail!("invalid choice {choice}");
}
None => {
error!("empty choice");
Err(anyhow!("empty choice"))
bail!("empty choice");
}
}
}

View file

@ -2,10 +2,14 @@ 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,
};
use log::debug;
#[cfg(any(feature = "message-send", feature = "template-send"))]
use mml::MmlCompilerBuilder;
use process::SingleCmd;
use std::{env, fs};
@ -44,8 +48,9 @@ pub async fn open_with_local_draft() -> Result<String> {
open_with_tpl(content).await
}
#[allow(unused)]
pub async fn edit_tpl_with_editor<P: Printer>(
#[allow(unused)] config: &AccountConfig,
config: &AccountConfig,
printer: &mut P,
backend: &Backend,
mut tpl: String,
@ -77,6 +82,7 @@ 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…")?;
@ -88,7 +94,7 @@ pub async fn edit_tpl_with_editor<P: Printer>(
let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend.send_raw_message(&email).await?;
backend.send_message(&email).await?;
remove_local_draft()?;
printer.print("Done!")?;
@ -102,6 +108,7 @@ 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();
@ -112,7 +119,7 @@ pub async fn edit_tpl_with_editor<P: Printer>(
let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
backend
.add_raw_message_with_flags(
.add_message_with_flags(
DRAFTS,
&email,
&Flags::from_iter([Flag::Seen, Flag::Draft]),