From 04e721d591ed0c5fe91e60eeb9b18ab76d087a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Sat, 9 Dec 2023 09:36:26 +0100 Subject: [PATCH] adjust api, test commands with a greenmail instance --- config.sample.toml | 23 +++++++++++++++++-- src/account/arg/name.rs | 4 ++-- src/account/command/mod.rs | 4 ++-- src/account/command/sync.rs | 2 +- src/account/mod.rs | 5 +++- src/cache/arg/disable.rs | 2 +- src/cli.rs | 1 + src/email/envelope/flag/command/add.rs | 4 ++-- src/email/envelope/flag/command/remove.rs | 4 ++-- src/email/envelope/flag/command/set.rs | 4 ++-- src/email/message/arg/body.rs | 2 +- src/email/message/arg/mod.rs | 17 ++++++++++++++ .../message/attachment/command/download.rs | 6 ++--- src/email/message/command/delete.rs | 6 ++--- src/email/message/command/forward.rs | 21 +++-------------- src/email/message/command/mailto.rs | 23 +++++++++++++++---- src/email/message/command/mod.rs | 8 ++++--- src/email/message/command/read.rs | 6 ++--- src/email/message/command/reply.rs | 21 +++-------------- src/email/message/command/save.rs | 8 +++---- src/email/message/command/send.rs | 6 ++--- src/email/message/command/write.rs | 17 +------------- src/email/message/template/arg/body.rs | 4 ++-- src/email/message/template/arg/mod.rs | 17 ++++++++++++++ src/email/message/template/command/forward.rs | 4 ++-- src/email/message/template/command/mod.rs | 4 ++-- src/email/message/template/command/reply.rs | 4 ++-- src/email/message/template/command/save.rs | 10 ++++---- src/email/message/template/command/send.rs | 6 ++--- src/folder/arg/name.rs | 15 +++++++++--- src/folder/command/mod.rs | 4 ++-- 31 files changed, 150 insertions(+), 112 deletions(-) diff --git a/config.sample.toml b/config.sample.toml index b59b07e..ca17825 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -7,7 +7,7 @@ display-name = "My example account" email = "example@localhost" sync = true -sync-dir = "./.sync" +sync-dir = "/tmp/himalaya-sync-example" # The default backend used for all the features like adding folders, # listing envelopes or copying messages. @@ -21,7 +21,7 @@ imap.ssl = false imap.starttls = false imap.insecure = true imap.auth = "passwd" -imap.passwd.raw = "example" +imap.passwd.keyring = "example-passwd" # Override the backend used for sending messages. message.send.backend = "smtp" @@ -35,3 +35,22 @@ smtp.starttls = false smtp.insecure = true smtp.auth = "passwd" smtp.passwd.raw = "example" + +[example-2] +display-name = "My example account 2" +email = "example2@localhost" + +backend = "imap" + +imap.host = "localhost" +imap.port = 3143 +imap.login = "example2@localhost" +imap.ssl = false +imap.starttls = false +imap.insecure = true +imap.auth = "passwd" +imap.passwd.raw = "example" + +message.send.backend = "sendmail" + +sendmail.cmd = "sendmail" diff --git a/src/account/arg/name.rs b/src/account/arg/name.rs index 189d5ba..b1fe3a2 100644 --- a/src/account/arg/name.rs +++ b/src/account/arg/name.rs @@ -12,13 +12,13 @@ pub struct AccountNameArg { } /// The account name flag parser. -#[derive(Debug, Parser)] +#[derive(Debug, Default, Parser)] pub struct AccountNameFlag { /// Override the default account. /// /// An account name corresponds to an entry in the table at the /// root level of your TOML configuration file. - #[arg(long = "account", short = 'a', global = true)] + #[arg(long = "account", short = 'a')] #[arg(name = "account_name", value_name = "NAME")] pub name: Option, } diff --git a/src/account/command/mod.rs b/src/account/command/mod.rs index 76c8147..0161821 100644 --- a/src/account/command/mod.rs +++ b/src/account/command/mod.rs @@ -15,7 +15,7 @@ use self::{ /// /// An account is a set of settings, identified by an account /// name. Settings are directly taken from your TOML configuration -/// file. +/// file. This subcommand allows you to manage them. #[derive(Debug, Subcommand)] pub enum AccountSubcommand { #[command(alias = "cfg")] @@ -24,7 +24,7 @@ pub enum AccountSubcommand { #[command(alias = "lst")] List(AccountListCommand), - #[command()] + #[command(alias = "synchronize", alias = "synchronise")] Sync(AccountSyncCommand), } diff --git a/src/account/command/sync.rs b/src/account/command/sync.rs index 7db35bc..cf136ac 100644 --- a/src/account/command/sync.rs +++ b/src/account/command/sync.rs @@ -35,7 +35,7 @@ const SUB_PROGRESS_DONE_STYLE: Lazy = Lazy::new(|| { /// Synchronize an account. /// /// This command allows you to synchronize all folders and emails -/// (including envelopes and messages) of an account into a local +/// (including envelopes and messages) of a given account into a local /// Maildir folder. #[derive(Debug, Parser)] pub struct AccountSyncCommand { diff --git a/src/account/mod.rs b/src/account/mod.rs index 1910174..683cdd9 100644 --- a/src/account/mod.rs +++ b/src/account/mod.rs @@ -123,7 +123,10 @@ impl From> for Accounts { Account::new(name, &backends, account.default.unwrap_or_default()) }) .collect(); - accounts.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap()); + + // sort accounts by name + accounts.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap()); + Self(accounts) } } diff --git a/src/cache/arg/disable.rs b/src/cache/arg/disable.rs index b1049f2..04f32a1 100644 --- a/src/cache/arg/disable.rs +++ b/src/cache/arg/disable.rs @@ -1,7 +1,7 @@ use clap::Parser; /// The disable cache flag parser. -#[derive(Debug, Parser)] +#[derive(Debug, Default, Parser)] pub struct CacheDisableFlag { /// Disable any sort of cache. /// diff --git a/src/cli.rs b/src/cli.rs index d8f9025..06a04ec 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -82,6 +82,7 @@ pub enum HimalayaCommand { Account(AccountSubcommand), #[command(subcommand)] + #[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])] #[command(alias = "folders")] Folder(FolderSubcommand), diff --git a/src/email/envelope/flag/command/add.rs b/src/email/envelope/flag/command/add.rs index c979993..5150516 100644 --- a/src/email/envelope/flag/command/add.rs +++ b/src/email/envelope/flag/command/add.rs @@ -8,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs}, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; @@ -19,7 +19,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct FlagAddCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub args: IdsAndFlagsArgs, diff --git a/src/email/envelope/flag/command/remove.rs b/src/email/envelope/flag/command/remove.rs index 807811d..e2d3a14 100644 --- a/src/email/envelope/flag/command/remove.rs +++ b/src/email/envelope/flag/command/remove.rs @@ -8,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs}, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; @@ -19,7 +19,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct FlagRemoveCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub args: IdsAndFlagsArgs, diff --git a/src/email/envelope/flag/command/set.rs b/src/email/envelope/flag/command/set.rs index 8c7343a..5cbe7f1 100644 --- a/src/email/envelope/flag/command/set.rs +++ b/src/email/envelope/flag/command/set.rs @@ -8,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs}, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; @@ -19,7 +19,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct FlagSetCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub args: IdsAndFlagsArgs, diff --git a/src/email/message/arg/body.rs b/src/email/message/arg/body.rs index f7ec4a1..e5eabd7 100644 --- a/src/email/message/arg/body.rs +++ b/src/email/message/arg/body.rs @@ -6,7 +6,7 @@ use std::ops::Deref; pub struct MessageRawBodyArg { /// Prefill the template with a custom body. #[arg(trailing_var_arg = true)] - #[arg(name = "body-raw")] + #[arg(name = "body_raw", value_name = "BODY")] pub raw: Vec, } diff --git a/src/email/message/arg/mod.rs b/src/email/message/arg/mod.rs index 509753e..216276b 100644 --- a/src/email/message/arg/mod.rs +++ b/src/email/message/arg/mod.rs @@ -1,3 +1,20 @@ +use clap::Parser; + pub mod body; pub mod header; pub mod reply; + +/// The raw message argument parser. +#[derive(Debug, Parser)] +pub struct MessageRawArg { + /// The raw message, including headers and body. + #[arg(trailing_var_arg = true)] + #[arg(name = "message_raw", value_name = "MESSAGE")] + pub raw: Vec, +} + +impl MessageRawArg { + pub fn raw(self) -> String { + self.raw.join(" ").replace("\r", "").replace("\n", "\r\n") + } +} diff --git a/src/email/message/attachment/command/download.rs b/src/email/message/attachment/command/download.rs index c2dad39..13be174 100644 --- a/src/email/message/attachment/command/download.rs +++ b/src/email/message/attachment/command/download.rs @@ -6,8 +6,8 @@ use uuid::Uuid; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg, - printer::Printer, + config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; /// Download all attachments for the given message. @@ -17,7 +17,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct AttachmentDownloadCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelopes: EnvelopeIdsArgs, diff --git a/src/email/message/command/delete.rs b/src/email/message/command/delete.rs index 8b67b91..a5145e7 100644 --- a/src/email/message/command/delete.rs +++ b/src/email/message/command/delete.rs @@ -4,8 +4,8 @@ use log::info; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg, - printer::Printer, + config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; /// Mark as deleted a message from a folder. @@ -17,7 +17,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageDeleteCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelopes: EnvelopeIdsArgs, diff --git a/src/email/message/command/forward.rs b/src/email/message/command/forward.rs index 4dbf61f..506e396 100644 --- a/src/email/message/command/forward.rs +++ b/src/email/message/command/forward.rs @@ -1,8 +1,6 @@ use anyhow::{anyhow, Result}; -use atty::Stream; use clap::Parser; use log::info; -use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, @@ -10,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, envelope::arg::ids::EnvelopeIdArg, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs}, printer::Printer, ui::editor, @@ -25,7 +23,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageForwardCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelope: EnvelopeIdArg, @@ -55,19 +53,6 @@ impl MessageForwardCommand { config.clone().into_account_configs(account, cache)?; let backend = Backend::new(toml_account_config, account_config.clone(), true).await?; - let is_tty = atty::is(Stream::Stdin); - let is_json = printer.is_json(); - let body = if !self.body.is_empty() && (is_tty || is_json) { - self.body.raw() - } else { - io::stdin() - .lock() - .lines() - .filter_map(Result::ok) - .collect::>() - .join("\r\n") - }; - let id = self.envelope.id; let tpl = backend .get_messages(folder, &[id]) @@ -76,7 +61,7 @@ impl MessageForwardCommand { .ok_or(anyhow!("cannot find message"))? .to_forward_tpl_builder(&account_config) .with_headers(self.headers.raw) - .with_body(body) + .with_body(self.body.raw()) .build() .await?; editor::edit_tpl_with_editor(&account_config, printer, &backend, tpl).await diff --git a/src/email/message/command/mailto.rs b/src/email/message/command/mailto.rs index c2daed4..a58f0ca 100644 --- a/src/email/message/command/mailto.rs +++ b/src/email/message/command/mailto.rs @@ -4,7 +4,10 @@ use log::{debug, info}; use mail_builder::MessageBuilder; use url::Url; -use crate::{backend::Backend, config::TomlConfig, printer::Printer, ui::editor}; +use crate::{ + account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, + config::TomlConfig, printer::Printer, ui::editor, +}; /// Parse and edit a message from a mailto URL string. /// @@ -17,19 +20,31 @@ pub struct MessageMailtoCommand { /// The mailto url. #[arg()] pub url: Url, + + #[command(flatten)] + pub cache: CacheDisableFlag, + + #[command(flatten)] + pub account: AccountNameFlag, } impl MessageMailtoCommand { pub fn new(url: &str) -> Result { - let url = Url::parse(url)?; - Ok(Self { url }) + Ok(Self { + url: Url::parse(url)?, + cache: Default::default(), + account: Default::default(), + }) } pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { info!("executing message mailto command"); + let account = self.account.name.as_ref().map(String::as_str); + let cache = self.cache.disable; + let (toml_account_config, account_config) = - config.clone().into_account_configs(None, false)?; + config.clone().into_account_configs(account, cache)?; let backend = Backend::new(toml_account_config, account_config.clone(), true).await?; let mut builder = MessageBuilder::new().to(self.url.path()); diff --git a/src/email/message/command/mod.rs b/src/email/message/command/mod.rs index 53606b2..9036b46 100644 --- a/src/email/message/command/mod.rs +++ b/src/email/message/command/mod.rs @@ -32,32 +32,34 @@ pub enum MessageSubcommand { #[command(arg_required_else_help = true)] Read(MessageReadCommand), - #[command(alias = "add", alias = "create", alias = "new", alias = "compose")] + #[command(aliases = ["add", "create", "new", "compose"])] Write(MessageWriteCommand), #[command()] Reply(MessageReplyCommand), - #[command(alias = "fwd")] + #[command(aliases = ["fwd", "fd"])] Forward(MessageForwardCommand), #[command()] Mailto(MessageMailtoCommand), #[command(arg_required_else_help = true)] - #[command(alias = "add", alias = "create")] Save(MessageSaveCommand), #[command(arg_required_else_help = true)] Send(MessageSendCommand), #[command(arg_required_else_help = true)] + #[command(aliases = ["cpy", "cp"])] Copy(MessageCopyCommand), #[command(arg_required_else_help = true)] + #[command(alias = "mv")] Move(MessageMoveCommand), #[command(arg_required_else_help = true)] + #[command(aliases = ["remove", "rm"])] Delete(MessageDeleteCommand), } diff --git a/src/email/message/command/read.rs b/src/email/message/command/read.rs index 53d1515..8acb3c1 100644 --- a/src/email/message/command/read.rs +++ b/src/email/message/command/read.rs @@ -5,8 +5,8 @@ use mml::message::FilterParts; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg, - printer::Printer, + config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; /// Read a message. @@ -15,7 +15,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageReadCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelopes: EnvelopeIdsArgs, diff --git a/src/email/message/command/reply.rs b/src/email/message/command/reply.rs index dfcbbbe..03437cc 100644 --- a/src/email/message/command/reply.rs +++ b/src/email/message/command/reply.rs @@ -1,9 +1,7 @@ use anyhow::{anyhow, Result}; -use atty::Stream; use clap::Parser; use email::flag::Flag; use log::info; -use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, @@ -11,7 +9,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, envelope::arg::ids::EnvelopeIdArg, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg}, printer::Printer, ui::editor, @@ -26,7 +24,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageReplyCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelope: EnvelopeIdArg, @@ -59,19 +57,6 @@ impl MessageReplyCommand { config.clone().into_account_configs(account, cache)?; let backend = Backend::new(toml_account_config, account_config.clone(), true).await?; - let is_tty = atty::is(Stream::Stdin); - let is_json = printer.is_json(); - let body = if !self.body.is_empty() && (is_tty || is_json) { - self.body.raw() - } else { - io::stdin() - .lock() - .lines() - .filter_map(Result::ok) - .collect::>() - .join("\r\n") - }; - let id = self.envelope.id; let tpl = backend .get_messages(folder, &[id]) @@ -80,7 +65,7 @@ impl MessageReplyCommand { .ok_or(anyhow!("cannot find message {id}"))? .to_reply_tpl_builder(&account_config) .with_headers(self.headers.raw) - .with_body(body) + .with_body(self.body.raw()) .with_reply_all(self.reply.all) .build() .await?; diff --git a/src/email/message/command/save.rs b/src/email/message/command/save.rs index 637ddeb..b20f919 100644 --- a/src/email/message/command/save.rs +++ b/src/email/message/command/save.rs @@ -6,7 +6,7 @@ use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, folder::arg::name::FolderNameArg, message::arg::body::MessageRawBodyArg, + config::TomlConfig, folder::arg::name::FolderNameOptionalFlag, message::arg::MessageRawArg, printer::Printer, }; @@ -16,10 +16,10 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageSaveCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] - pub body: MessageRawBodyArg, + pub message: MessageRawArg, #[command(flatten)] pub cache: CacheDisableFlag, @@ -43,7 +43,7 @@ impl MessageSaveCommand { let is_tty = atty::is(Stream::Stdin); let is_json = printer.is_json(); let msg = if is_tty || is_json { - self.body.raw() + self.message.raw() } else { io::stdin() .lock() diff --git a/src/email/message/command/send.rs b/src/email/message/command/send.rs index 9f176b1..d8e1930 100644 --- a/src/email/message/command/send.rs +++ b/src/email/message/command/send.rs @@ -7,7 +7,7 @@ use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, message::arg::body::MessageRawBodyArg, printer::Printer, + config::TomlConfig, message::arg::MessageRawArg, printer::Printer, }; /// Send a message. @@ -17,7 +17,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct MessageSendCommand { #[command(flatten)] - pub body: MessageRawBodyArg, + pub message: MessageRawArg, #[command(flatten)] pub cache: CacheDisableFlag, @@ -41,7 +41,7 @@ impl MessageSendCommand { let is_tty = atty::is(Stream::Stdin); let is_json = printer.is_json(); let msg = if is_tty || is_json { - self.body.raw() + self.message.raw() } else { io::stdin() .lock() diff --git a/src/email/message/command/write.rs b/src/email/message/command/write.rs index 38b1c28..16eb455 100644 --- a/src/email/message/command/write.rs +++ b/src/email/message/command/write.rs @@ -1,9 +1,7 @@ use anyhow::Result; -use atty::Stream; use clap::Parser; use email::message::Message; use log::info; -use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, @@ -47,22 +45,9 @@ impl MessageWriteCommand { config.clone().into_account_configs(account, cache)?; let backend = Backend::new(toml_account_config, account_config.clone(), true).await?; - let is_tty = atty::is(Stream::Stdin); - let is_json = printer.is_json(); - let body = if !self.body.is_empty() && (is_tty || is_json) { - self.body.raw() - } else { - io::stdin() - .lock() - .lines() - .filter_map(Result::ok) - .collect::>() - .join("\r\n") - }; - let tpl = Message::new_tpl_builder(&account_config) .with_headers(self.headers.raw) - .with_body(body) + .with_body(self.body.raw()) .build() .await?; diff --git a/src/email/message/template/arg/body.rs b/src/email/message/template/arg/body.rs index fafd455..f577d19 100644 --- a/src/email/message/template/arg/body.rs +++ b/src/email/message/template/arg/body.rs @@ -4,9 +4,9 @@ use std::ops::Deref; /// The raw template body argument parser. #[derive(Debug, Parser)] pub struct TemplateRawBodyArg { - /// Prefill the template with a custom body. + /// Prefill the template with a custom MML body. #[arg(trailing_var_arg = true)] - #[arg(name = "body-raw")] + #[arg(name = "body_raw", value_name = "BODY")] pub raw: Vec, } diff --git a/src/email/message/template/arg/mod.rs b/src/email/message/template/arg/mod.rs index 81f6efd..8798e08 100644 --- a/src/email/message/template/arg/mod.rs +++ b/src/email/message/template/arg/mod.rs @@ -1 +1,18 @@ pub mod body; + +use clap::Parser; + +/// The raw template argument parser. +#[derive(Debug, Parser)] +pub struct TemplateRawArg { + /// The raw template, including headers and MML body. + #[arg(trailing_var_arg = true)] + #[arg(name = "template_raw", value_name = "TEMPLATE")] + pub raw: Vec, +} + +impl TemplateRawArg { + pub fn raw(self) -> String { + self.raw.join(" ").replace("\r", "") + } +} diff --git a/src/email/message/template/command/forward.rs b/src/email/message/template/command/forward.rs index c09529d..f1b510c 100644 --- a/src/email/message/template/command/forward.rs +++ b/src/email/message/template/command/forward.rs @@ -8,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, envelope::arg::ids::EnvelopeIdArg, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs}, printer::Printer, }; @@ -21,7 +21,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct TemplateForwardCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelope: EnvelopeIdArg, diff --git a/src/email/message/template/command/mod.rs b/src/email/message/template/command/mod.rs index eed6ca7..fa4bab7 100644 --- a/src/email/message/template/command/mod.rs +++ b/src/email/message/template/command/mod.rs @@ -25,7 +25,7 @@ use self::{ /// . #[derive(Debug, Subcommand)] pub enum TemplateSubcommand { - #[command(alias = "create", alias = "new", alias = "compose")] + #[command(aliases = ["add", "create", "new", "compose"])] Write(TemplateWriteCommand), #[command(arg_required_else_help = true)] @@ -35,7 +35,7 @@ pub enum TemplateSubcommand { #[command(alias = "fwd")] Forward(TemplateForwardCommand), - #[command(alias = "add")] + #[command()] Save(TemplateSaveCommand), #[command()] diff --git a/src/email/message/template/command/reply.rs b/src/email/message/template/command/reply.rs index fe42af5..4d5cd6a 100644 --- a/src/email/message/template/command/reply.rs +++ b/src/email/message/template/command/reply.rs @@ -8,7 +8,7 @@ use crate::{ cache::arg::disable::CacheDisableFlag, config::TomlConfig, envelope::arg::ids::EnvelopeIdArg, - folder::arg::name::FolderNameArg, + folder::arg::name::FolderNameOptionalFlag, message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg}, printer::Printer, }; @@ -22,7 +22,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct TemplateReplyCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] pub envelope: EnvelopeIdArg, diff --git a/src/email/message/template/command/save.rs b/src/email/message/template/command/save.rs index 4253468..5e1b1c6 100644 --- a/src/email/message/template/command/save.rs +++ b/src/email/message/template/command/save.rs @@ -7,8 +7,8 @@ use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, email::template::arg::body::TemplateRawBodyArg, - folder::arg::name::FolderNameArg, printer::Printer, + config::TomlConfig, email::template::arg::TemplateRawArg, + folder::arg::name::FolderNameOptionalFlag, printer::Printer, }; /// Save a template to a folder. @@ -20,10 +20,10 @@ use crate::{ #[derive(Debug, Parser)] pub struct TemplateSaveCommand { #[command(flatten)] - pub folder: FolderNameArg, + pub folder: FolderNameOptionalFlag, #[command(flatten)] - pub body: TemplateRawBodyArg, + pub template: TemplateRawArg, #[command(flatten)] pub cache: CacheDisableFlag, @@ -47,7 +47,7 @@ impl TemplateSaveCommand { let is_tty = atty::is(Stream::Stdin); let is_json = printer.is_json(); let tpl = if is_tty || is_json { - self.body.raw() + self.template.raw() } else { io::stdin() .lock() diff --git a/src/email/message/template/command/send.rs b/src/email/message/template/command/send.rs index 4b74b95..c62d642 100644 --- a/src/email/message/template/command/send.rs +++ b/src/email/message/template/command/send.rs @@ -8,7 +8,7 @@ use std::io::{self, BufRead}; use crate::{ account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag, - config::TomlConfig, email::template::arg::body::TemplateRawBodyArg, printer::Printer, + config::TomlConfig, email::template::arg::TemplateRawArg, printer::Printer, }; /// Send a template. @@ -20,7 +20,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct TemplateSendCommand { #[command(flatten)] - pub body: TemplateRawBodyArg, + pub template: TemplateRawArg, #[command(flatten)] pub cache: CacheDisableFlag, @@ -44,7 +44,7 @@ impl TemplateSendCommand { let is_tty = atty::is(Stream::Stdin); let is_json = printer.is_json(); let tpl = if is_tty || is_json { - self.body.raw() + self.template.raw() } else { io::stdin() .lock() diff --git a/src/folder/arg/name.rs b/src/folder/arg/name.rs index 15307b8..8b6c515 100644 --- a/src/folder/arg/name.rs +++ b/src/folder/arg/name.rs @@ -1,11 +1,12 @@ use clap::Parser; use email::account::config::DEFAULT_INBOX_FOLDER; -/// The folder name argument parser. +/// The optional folder name flag parser. #[derive(Debug, Parser)] -pub struct FolderNameArg { +pub struct FolderNameOptionalFlag { /// The name of the folder. - #[arg(name = "folder_name", value_name = "FOLDER")] + #[arg(long = "folder", short = 'f')] + #[arg(name = "folder_name", value_name = "NAME", default_value = DEFAULT_INBOX_FOLDER)] pub name: String, } @@ -17,6 +18,14 @@ pub struct FolderNameOptionalArg { pub name: String, } +/// The required folder name argument parser. +#[derive(Debug, Parser)] +pub struct FolderNameArg { + /// The name of the folder. + #[arg(name = "folder_name", value_name = "FOLDER")] + pub name: String, +} + /// The source folder name argument parser. #[derive(Debug, Parser)] pub struct SourceFolderNameArg { diff --git a/src/folder/command/mod.rs b/src/folder/command/mod.rs index 29959aa..5de0450 100644 --- a/src/folder/command/mod.rs +++ b/src/folder/command/mod.rs @@ -16,8 +16,8 @@ use self::{ /// Manage folders. /// -/// A folder (AKA mailbox, or directory) contains envelopes and -/// messages. This subcommand allows you to manage them. +/// A folder (as known as mailbox, or directory) contains one or more +/// emails. This subcommand allows you to manage them. #[derive(Debug, Subcommand)] pub enum FolderSubcommand { #[command(alias = "add", alias = "new")]