mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
adjust api, test commands with a greenmail instance
This commit is contained in:
parent
ef3214f36f
commit
04e721d591
|
@ -7,7 +7,7 @@ display-name = "My example account"
|
||||||
email = "example@localhost"
|
email = "example@localhost"
|
||||||
|
|
||||||
sync = true
|
sync = true
|
||||||
sync-dir = "./.sync"
|
sync-dir = "/tmp/himalaya-sync-example"
|
||||||
|
|
||||||
# The default backend used for all the features like adding folders,
|
# The default backend used for all the features like adding folders,
|
||||||
# listing envelopes or copying messages.
|
# listing envelopes or copying messages.
|
||||||
|
@ -21,7 +21,7 @@ imap.ssl = false
|
||||||
imap.starttls = false
|
imap.starttls = false
|
||||||
imap.insecure = true
|
imap.insecure = true
|
||||||
imap.auth = "passwd"
|
imap.auth = "passwd"
|
||||||
imap.passwd.raw = "example"
|
imap.passwd.keyring = "example-passwd"
|
||||||
|
|
||||||
# Override the backend used for sending messages.
|
# Override the backend used for sending messages.
|
||||||
message.send.backend = "smtp"
|
message.send.backend = "smtp"
|
||||||
|
@ -35,3 +35,22 @@ smtp.starttls = false
|
||||||
smtp.insecure = true
|
smtp.insecure = true
|
||||||
smtp.auth = "passwd"
|
smtp.auth = "passwd"
|
||||||
smtp.passwd.raw = "example"
|
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"
|
||||||
|
|
|
@ -12,13 +12,13 @@ pub struct AccountNameArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The account name flag parser.
|
/// The account name flag parser.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Default, Parser)]
|
||||||
pub struct AccountNameFlag {
|
pub struct AccountNameFlag {
|
||||||
/// Override the default account.
|
/// Override the default account.
|
||||||
///
|
///
|
||||||
/// An account name corresponds to an entry in the table at the
|
/// An account name corresponds to an entry in the table at the
|
||||||
/// root level of your TOML configuration file.
|
/// 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")]
|
#[arg(name = "account_name", value_name = "NAME")]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use self::{
|
||||||
///
|
///
|
||||||
/// An account is a set of settings, identified by an account
|
/// An account is a set of settings, identified by an account
|
||||||
/// name. Settings are directly taken from your TOML configuration
|
/// name. Settings are directly taken from your TOML configuration
|
||||||
/// file.
|
/// file. This subcommand allows you to manage them.
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum AccountSubcommand {
|
pub enum AccountSubcommand {
|
||||||
#[command(alias = "cfg")]
|
#[command(alias = "cfg")]
|
||||||
|
@ -24,7 +24,7 @@ pub enum AccountSubcommand {
|
||||||
#[command(alias = "lst")]
|
#[command(alias = "lst")]
|
||||||
List(AccountListCommand),
|
List(AccountListCommand),
|
||||||
|
|
||||||
#[command()]
|
#[command(alias = "synchronize", alias = "synchronise")]
|
||||||
Sync(AccountSyncCommand),
|
Sync(AccountSyncCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ const SUB_PROGRESS_DONE_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
|
||||||
/// Synchronize an account.
|
/// Synchronize an account.
|
||||||
///
|
///
|
||||||
/// This command allows you to synchronize all folders and emails
|
/// 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.
|
/// Maildir folder.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct AccountSyncCommand {
|
pub struct AccountSyncCommand {
|
||||||
|
|
|
@ -123,7 +123,10 @@ impl From<Iter<'_, String, TomlAccountConfig>> for Accounts {
|
||||||
Account::new(name, &backends, account.default.unwrap_or_default())
|
Account::new(name, &backends, account.default.unwrap_or_default())
|
||||||
})
|
})
|
||||||
.collect();
|
.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)
|
Self(accounts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
src/cache/arg/disable.rs
vendored
2
src/cache/arg/disable.rs
vendored
|
@ -1,7 +1,7 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
/// The disable cache flag parser.
|
/// The disable cache flag parser.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Default, Parser)]
|
||||||
pub struct CacheDisableFlag {
|
pub struct CacheDisableFlag {
|
||||||
/// Disable any sort of cache.
|
/// Disable any sort of cache.
|
||||||
///
|
///
|
||||||
|
|
|
@ -82,6 +82,7 @@ pub enum HimalayaCommand {
|
||||||
Account(AccountSubcommand),
|
Account(AccountSubcommand),
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
#[command(visible_alias = "mailbox", aliases = ["mailboxes", "mboxes", "mbox"])]
|
||||||
#[command(alias = "folders")]
|
#[command(alias = "folders")]
|
||||||
Folder(FolderSubcommand),
|
Folder(FolderSubcommand),
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct FlagAddCommand {
|
pub struct FlagAddCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub args: IdsAndFlagsArgs,
|
pub args: IdsAndFlagsArgs,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct FlagRemoveCommand {
|
pub struct FlagRemoveCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub args: IdsAndFlagsArgs,
|
pub args: IdsAndFlagsArgs,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct FlagSetCommand {
|
pub struct FlagSetCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub args: IdsAndFlagsArgs,
|
pub args: IdsAndFlagsArgs,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::ops::Deref;
|
||||||
pub struct MessageRawBodyArg {
|
pub struct MessageRawBodyArg {
|
||||||
/// Prefill the template with a custom body.
|
/// Prefill the template with a custom body.
|
||||||
#[arg(trailing_var_arg = true)]
|
#[arg(trailing_var_arg = true)]
|
||||||
#[arg(name = "body-raw")]
|
#[arg(name = "body_raw", value_name = "BODY")]
|
||||||
pub raw: Vec<String>,
|
pub raw: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
pub mod body;
|
pub mod body;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod reply;
|
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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageRawArg {
|
||||||
|
pub fn raw(self) -> String {
|
||||||
|
self.raw.join(" ").replace("\r", "").replace("\n", "\r\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
|
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs,
|
||||||
printer::Printer,
|
folder::arg::name::FolderNameOptionalFlag, printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Download all attachments for the given message.
|
/// Download all attachments for the given message.
|
||||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct AttachmentDownloadCommand {
|
pub struct AttachmentDownloadCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelopes: EnvelopeIdsArgs,
|
pub envelopes: EnvelopeIdsArgs,
|
||||||
|
|
|
@ -4,8 +4,8 @@ use log::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
|
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs,
|
||||||
printer::Printer,
|
folder::arg::name::FolderNameOptionalFlag, printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Mark as deleted a message from a folder.
|
/// Mark as deleted a message from a folder.
|
||||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageDeleteCommand {
|
pub struct MessageDeleteCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelopes: EnvelopeIdsArgs,
|
pub envelopes: EnvelopeIdsArgs,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use atty::Stream;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::io::{self, BufRead};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag,
|
account::arg::name::AccountNameFlag,
|
||||||
|
@ -10,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
envelope::arg::ids::EnvelopeIdArg,
|
envelope::arg::ids::EnvelopeIdArg,
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
|
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
ui::editor,
|
ui::editor,
|
||||||
|
@ -25,7 +23,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageForwardCommand {
|
pub struct MessageForwardCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelope: EnvelopeIdArg,
|
pub envelope: EnvelopeIdArg,
|
||||||
|
@ -55,19 +53,6 @@ impl MessageForwardCommand {
|
||||||
config.clone().into_account_configs(account, cache)?;
|
config.clone().into_account_configs(account, cache)?;
|
||||||
let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
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::<Vec<String>>()
|
|
||||||
.join("\r\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = self.envelope.id;
|
let id = self.envelope.id;
|
||||||
let tpl = backend
|
let tpl = backend
|
||||||
.get_messages(folder, &[id])
|
.get_messages(folder, &[id])
|
||||||
|
@ -76,7 +61,7 @@ impl MessageForwardCommand {
|
||||||
.ok_or(anyhow!("cannot find message"))?
|
.ok_or(anyhow!("cannot find message"))?
|
||||||
.to_forward_tpl_builder(&account_config)
|
.to_forward_tpl_builder(&account_config)
|
||||||
.with_headers(self.headers.raw)
|
.with_headers(self.headers.raw)
|
||||||
.with_body(body)
|
.with_body(self.body.raw())
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
editor::edit_tpl_with_editor(&account_config, printer, &backend, tpl).await
|
editor::edit_tpl_with_editor(&account_config, printer, &backend, tpl).await
|
||||||
|
|
|
@ -4,7 +4,10 @@ use log::{debug, info};
|
||||||
use mail_builder::MessageBuilder;
|
use mail_builder::MessageBuilder;
|
||||||
use url::Url;
|
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.
|
/// Parse and edit a message from a mailto URL string.
|
||||||
///
|
///
|
||||||
|
@ -17,19 +20,31 @@ pub struct MessageMailtoCommand {
|
||||||
/// The mailto url.
|
/// The mailto url.
|
||||||
#[arg()]
|
#[arg()]
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
|
|
||||||
|
#[command(flatten)]
|
||||||
|
pub cache: CacheDisableFlag,
|
||||||
|
|
||||||
|
#[command(flatten)]
|
||||||
|
pub account: AccountNameFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageMailtoCommand {
|
impl MessageMailtoCommand {
|
||||||
pub fn new(url: &str) -> Result<Self> {
|
pub fn new(url: &str) -> Result<Self> {
|
||||||
let url = Url::parse(url)?;
|
Ok(Self {
|
||||||
Ok(Self { url })
|
url: Url::parse(url)?,
|
||||||
|
cache: Default::default(),
|
||||||
|
account: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||||
info!("executing message mailto command");
|
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) =
|
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 backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
||||||
|
|
||||||
let mut builder = MessageBuilder::new().to(self.url.path());
|
let mut builder = MessageBuilder::new().to(self.url.path());
|
||||||
|
|
|
@ -32,32 +32,34 @@ pub enum MessageSubcommand {
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
Read(MessageReadCommand),
|
Read(MessageReadCommand),
|
||||||
|
|
||||||
#[command(alias = "add", alias = "create", alias = "new", alias = "compose")]
|
#[command(aliases = ["add", "create", "new", "compose"])]
|
||||||
Write(MessageWriteCommand),
|
Write(MessageWriteCommand),
|
||||||
|
|
||||||
#[command()]
|
#[command()]
|
||||||
Reply(MessageReplyCommand),
|
Reply(MessageReplyCommand),
|
||||||
|
|
||||||
#[command(alias = "fwd")]
|
#[command(aliases = ["fwd", "fd"])]
|
||||||
Forward(MessageForwardCommand),
|
Forward(MessageForwardCommand),
|
||||||
|
|
||||||
#[command()]
|
#[command()]
|
||||||
Mailto(MessageMailtoCommand),
|
Mailto(MessageMailtoCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
#[command(alias = "add", alias = "create")]
|
|
||||||
Save(MessageSaveCommand),
|
Save(MessageSaveCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
Send(MessageSendCommand),
|
Send(MessageSendCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
|
#[command(aliases = ["cpy", "cp"])]
|
||||||
Copy(MessageCopyCommand),
|
Copy(MessageCopyCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
|
#[command(alias = "mv")]
|
||||||
Move(MessageMoveCommand),
|
Move(MessageMoveCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
|
#[command(aliases = ["remove", "rm"])]
|
||||||
Delete(MessageDeleteCommand),
|
Delete(MessageDeleteCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ use mml::message::FilterParts;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
|
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs,
|
||||||
printer::Printer,
|
folder::arg::name::FolderNameOptionalFlag, printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Read a message.
|
/// Read a message.
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageReadCommand {
|
pub struct MessageReadCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelopes: EnvelopeIdsArgs,
|
pub envelopes: EnvelopeIdsArgs,
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use atty::Stream;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use email::flag::Flag;
|
use email::flag::Flag;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::io::{self, BufRead};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag,
|
account::arg::name::AccountNameFlag,
|
||||||
|
@ -11,7 +9,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
envelope::arg::ids::EnvelopeIdArg,
|
envelope::arg::ids::EnvelopeIdArg,
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
ui::editor,
|
ui::editor,
|
||||||
|
@ -26,7 +24,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageReplyCommand {
|
pub struct MessageReplyCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelope: EnvelopeIdArg,
|
pub envelope: EnvelopeIdArg,
|
||||||
|
@ -59,19 +57,6 @@ impl MessageReplyCommand {
|
||||||
config.clone().into_account_configs(account, cache)?;
|
config.clone().into_account_configs(account, cache)?;
|
||||||
let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
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::<Vec<String>>()
|
|
||||||
.join("\r\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = self.envelope.id;
|
let id = self.envelope.id;
|
||||||
let tpl = backend
|
let tpl = backend
|
||||||
.get_messages(folder, &[id])
|
.get_messages(folder, &[id])
|
||||||
|
@ -80,7 +65,7 @@ impl MessageReplyCommand {
|
||||||
.ok_or(anyhow!("cannot find message {id}"))?
|
.ok_or(anyhow!("cannot find message {id}"))?
|
||||||
.to_reply_tpl_builder(&account_config)
|
.to_reply_tpl_builder(&account_config)
|
||||||
.with_headers(self.headers.raw)
|
.with_headers(self.headers.raw)
|
||||||
.with_body(body)
|
.with_body(self.body.raw())
|
||||||
.with_reply_all(self.reply.all)
|
.with_reply_all(self.reply.all)
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::io::{self, BufRead};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
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,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,10 +16,10 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageSaveCommand {
|
pub struct MessageSaveCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub body: MessageRawBodyArg,
|
pub message: MessageRawArg,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub cache: CacheDisableFlag,
|
pub cache: CacheDisableFlag,
|
||||||
|
@ -43,7 +43,7 @@ impl MessageSaveCommand {
|
||||||
let is_tty = atty::is(Stream::Stdin);
|
let is_tty = atty::is(Stream::Stdin);
|
||||||
let is_json = printer.is_json();
|
let is_json = printer.is_json();
|
||||||
let msg = if is_tty || is_json {
|
let msg = if is_tty || is_json {
|
||||||
self.body.raw()
|
self.message.raw()
|
||||||
} else {
|
} else {
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::io::{self, BufRead};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
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.
|
/// Send a message.
|
||||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct MessageSendCommand {
|
pub struct MessageSendCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub body: MessageRawBodyArg,
|
pub message: MessageRawArg,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub cache: CacheDisableFlag,
|
pub cache: CacheDisableFlag,
|
||||||
|
@ -41,7 +41,7 @@ impl MessageSendCommand {
|
||||||
let is_tty = atty::is(Stream::Stdin);
|
let is_tty = atty::is(Stream::Stdin);
|
||||||
let is_json = printer.is_json();
|
let is_json = printer.is_json();
|
||||||
let msg = if is_tty || is_json {
|
let msg = if is_tty || is_json {
|
||||||
self.body.raw()
|
self.message.raw()
|
||||||
} else {
|
} else {
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use atty::Stream;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use email::message::Message;
|
use email::message::Message;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::io::{self, BufRead};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag,
|
account::arg::name::AccountNameFlag,
|
||||||
|
@ -47,22 +45,9 @@ impl MessageWriteCommand {
|
||||||
config.clone().into_account_configs(account, cache)?;
|
config.clone().into_account_configs(account, cache)?;
|
||||||
let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
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::<Vec<String>>()
|
|
||||||
.join("\r\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
let tpl = Message::new_tpl_builder(&account_config)
|
let tpl = Message::new_tpl_builder(&account_config)
|
||||||
.with_headers(self.headers.raw)
|
.with_headers(self.headers.raw)
|
||||||
.with_body(body)
|
.with_body(self.body.raw())
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ use std::ops::Deref;
|
||||||
/// The raw template body argument parser.
|
/// The raw template body argument parser.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct TemplateRawBodyArg {
|
pub struct TemplateRawBodyArg {
|
||||||
/// Prefill the template with a custom body.
|
/// Prefill the template with a custom MML body.
|
||||||
#[arg(trailing_var_arg = true)]
|
#[arg(trailing_var_arg = true)]
|
||||||
#[arg(name = "body-raw")]
|
#[arg(name = "body_raw", value_name = "BODY")]
|
||||||
pub raw: Vec<String>,
|
pub raw: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1,18 @@
|
||||||
pub mod body;
|
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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TemplateRawArg {
|
||||||
|
pub fn raw(self) -> String {
|
||||||
|
self.raw.join(" ").replace("\r", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
envelope::arg::ids::EnvelopeIdArg,
|
envelope::arg::ids::EnvelopeIdArg,
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
|
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct TemplateForwardCommand {
|
pub struct TemplateForwardCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelope: EnvelopeIdArg,
|
pub envelope: EnvelopeIdArg,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use self::{
|
||||||
/// <https://crates.io/crates/mml-lib>.
|
/// <https://crates.io/crates/mml-lib>.
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum TemplateSubcommand {
|
pub enum TemplateSubcommand {
|
||||||
#[command(alias = "create", alias = "new", alias = "compose")]
|
#[command(aliases = ["add", "create", "new", "compose"])]
|
||||||
Write(TemplateWriteCommand),
|
Write(TemplateWriteCommand),
|
||||||
|
|
||||||
#[command(arg_required_else_help = true)]
|
#[command(arg_required_else_help = true)]
|
||||||
|
@ -35,7 +35,7 @@ pub enum TemplateSubcommand {
|
||||||
#[command(alias = "fwd")]
|
#[command(alias = "fwd")]
|
||||||
Forward(TemplateForwardCommand),
|
Forward(TemplateForwardCommand),
|
||||||
|
|
||||||
#[command(alias = "add")]
|
#[command()]
|
||||||
Save(TemplateSaveCommand),
|
Save(TemplateSaveCommand),
|
||||||
|
|
||||||
#[command()]
|
#[command()]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
cache::arg::disable::CacheDisableFlag,
|
cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig,
|
config::TomlConfig,
|
||||||
envelope::arg::ids::EnvelopeIdArg,
|
envelope::arg::ids::EnvelopeIdArg,
|
||||||
folder::arg::name::FolderNameArg,
|
folder::arg::name::FolderNameOptionalFlag,
|
||||||
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
||||||
printer::Printer,
|
printer::Printer,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct TemplateReplyCommand {
|
pub struct TemplateReplyCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub envelope: EnvelopeIdArg,
|
pub envelope: EnvelopeIdArg,
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::io::{self, BufRead};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig, email::template::arg::body::TemplateRawBodyArg,
|
config::TomlConfig, email::template::arg::TemplateRawArg,
|
||||||
folder::arg::name::FolderNameArg, printer::Printer,
|
folder::arg::name::FolderNameOptionalFlag, printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Save a template to a folder.
|
/// Save a template to a folder.
|
||||||
|
@ -20,10 +20,10 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct TemplateSaveCommand {
|
pub struct TemplateSaveCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalFlag,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub body: TemplateRawBodyArg,
|
pub template: TemplateRawArg,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub cache: CacheDisableFlag,
|
pub cache: CacheDisableFlag,
|
||||||
|
@ -47,7 +47,7 @@ impl TemplateSaveCommand {
|
||||||
let is_tty = atty::is(Stream::Stdin);
|
let is_tty = atty::is(Stream::Stdin);
|
||||||
let is_json = printer.is_json();
|
let is_json = printer.is_json();
|
||||||
let tpl = if is_tty || is_json {
|
let tpl = if is_tty || is_json {
|
||||||
self.body.raw()
|
self.template.raw()
|
||||||
} else {
|
} else {
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::io::{self, BufRead};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
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.
|
/// Send a template.
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct TemplateSendCommand {
|
pub struct TemplateSendCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub body: TemplateRawBodyArg,
|
pub template: TemplateRawArg,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub cache: CacheDisableFlag,
|
pub cache: CacheDisableFlag,
|
||||||
|
@ -44,7 +44,7 @@ impl TemplateSendCommand {
|
||||||
let is_tty = atty::is(Stream::Stdin);
|
let is_tty = atty::is(Stream::Stdin);
|
||||||
let is_json = printer.is_json();
|
let is_json = printer.is_json();
|
||||||
let tpl = if is_tty || is_json {
|
let tpl = if is_tty || is_json {
|
||||||
self.body.raw()
|
self.template.raw()
|
||||||
} else {
|
} else {
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use email::account::config::DEFAULT_INBOX_FOLDER;
|
use email::account::config::DEFAULT_INBOX_FOLDER;
|
||||||
|
|
||||||
/// The folder name argument parser.
|
/// The optional folder name flag parser.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct FolderNameArg {
|
pub struct FolderNameOptionalFlag {
|
||||||
/// The name of the folder.
|
/// 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,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +18,14 @@ pub struct FolderNameOptionalArg {
|
||||||
pub name: String,
|
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.
|
/// The source folder name argument parser.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct SourceFolderNameArg {
|
pub struct SourceFolderNameArg {
|
||||||
|
|
|
@ -16,8 +16,8 @@ use self::{
|
||||||
|
|
||||||
/// Manage folders.
|
/// Manage folders.
|
||||||
///
|
///
|
||||||
/// A folder (AKA mailbox, or directory) contains envelopes and
|
/// A folder (as known as mailbox, or directory) contains one or more
|
||||||
/// messages. This subcommand allows you to manage them.
|
/// emails. This subcommand allows you to manage them.
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum FolderSubcommand {
|
pub enum FolderSubcommand {
|
||||||
#[command(alias = "add", alias = "new")]
|
#[command(alias = "add", alias = "new")]
|
||||||
|
|
Loading…
Reference in a new issue