mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-03 07:55:13 +00:00
refactor template with clap derive api
This commit is contained in:
parent
b28f12c367
commit
fff11fbe20
11
src/cli.rs
11
src/cli.rs
|
@ -10,7 +10,10 @@ use crate::{
|
|||
flag::command::FlagSubcommand,
|
||||
folder::command::FolderSubcommand,
|
||||
manual::command::ManualGenerateCommand,
|
||||
message::{attachment::command::AttachmentSubcommand, command::MessageSubcommand},
|
||||
message::{
|
||||
attachment::command::AttachmentSubcommand, command::MessageSubcommand,
|
||||
template::command::TemplateSubcommand,
|
||||
},
|
||||
output::{ColorFmt, OutputFmt},
|
||||
printer::Printer,
|
||||
};
|
||||
|
@ -105,6 +108,11 @@ pub enum HimalayaCommand {
|
|||
#[command(alias = "messages", alias = "msgs", alias = "msg")]
|
||||
Message(MessageSubcommand),
|
||||
|
||||
/// Manage templates
|
||||
#[command(subcommand)]
|
||||
#[command(alias = "templates", alias = "tpls", alias = "tpl")]
|
||||
Template(TemplateSubcommand),
|
||||
|
||||
/// Manage attachments
|
||||
#[command(subcommand)]
|
||||
Attachment(AttachmentSubcommand),
|
||||
|
@ -128,6 +136,7 @@ impl HimalayaCommand {
|
|||
Self::Envelope(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Flag(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Message(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Template(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Attachment(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Manual(cmd) => cmd.execute(printer).await,
|
||||
Self::Completion(cmd) => cmd.execute(printer).await,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use clap::Parser;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// The raw message body argument parser
|
||||
#[derive(Debug, Parser)]
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod body;
|
||||
pub mod header;
|
||||
pub mod reply;
|
||||
|
|
9
src/email/message/arg/reply.rs
Normal file
9
src/email/message/arg/reply.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use clap::Parser;
|
||||
|
||||
/// The reply to all argument parser
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct MessageReplyAllArg {
|
||||
/// Reply to all recipients
|
||||
#[arg(long, short = 'A')]
|
||||
pub all: bool,
|
||||
}
|
|
@ -36,7 +36,7 @@ impl AttachmentDownloadCommand {
|
|||
|
||||
let (toml_account_config, account_config) =
|
||||
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(), false).await?;
|
||||
|
||||
let ids = &self.envelopes.ids;
|
||||
let emails = backend.get_messages(&folder, ids).await?;
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
config::TomlConfig,
|
||||
envelope::arg::ids::EnvelopeIdArg,
|
||||
folder::arg::name::FolderNameArg,
|
||||
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
|
||||
message::arg::{body::BodyRawArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
||||
printer::Printer,
|
||||
ui::editor,
|
||||
};
|
||||
|
@ -26,9 +26,8 @@ pub struct MessageReplyCommand {
|
|||
#[command(flatten)]
|
||||
pub envelope: EnvelopeIdArg,
|
||||
|
||||
/// Reply to all recipients
|
||||
#[arg(long, short = 'A')]
|
||||
pub all: bool,
|
||||
#[command(flatten)]
|
||||
pub reply: MessageReplyAllArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub headers: HeaderRawArgs,
|
||||
|
@ -73,11 +72,11 @@ impl MessageReplyCommand {
|
|||
.get_messages(folder, &[id])
|
||||
.await?
|
||||
.first()
|
||||
.ok_or(anyhow!("cannot find message"))?
|
||||
.ok_or(anyhow!("cannot find message {id}"))?
|
||||
.to_reply_tpl_builder(&account_config)
|
||||
.with_headers(self.headers.raw)
|
||||
.with_body(body)
|
||||
.with_reply_all(self.all)
|
||||
.with_reply_all(self.reply.all)
|
||||
.build()
|
||||
.await?;
|
||||
editor::edit_tpl_with_editor(&account_config, printer, &backend, tpl).await?;
|
||||
|
|
|
@ -2,4 +2,4 @@ pub mod arg;
|
|||
pub mod attachment;
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
// pub mod template;
|
||||
pub mod template;
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
//! Module related to email template CLI.
|
||||
//!
|
||||
//! This module provides subcommands, arguments and a command matcher
|
||||
//! related to email templating.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use log::warn;
|
||||
|
||||
use crate::message;
|
||||
|
||||
const ARG_BODY: &str = "body";
|
||||
const ARG_HEADERS: &str = "headers";
|
||||
const ARG_TPL: &str = "template";
|
||||
const CMD_FORWARD: &str = "forward";
|
||||
const CMD_REPLY: &str = "reply";
|
||||
const CMD_SAVE: &str = "save";
|
||||
const CMD_SEND: &str = "send";
|
||||
const CMD_WRITE: &str = "write";
|
||||
|
||||
pub const CMD_TPL: &str = "template";
|
||||
|
||||
pub type RawTpl = String;
|
||||
pub type Headers<'a> = Option<Vec<(&'a str, &'a str)>>;
|
||||
pub type Body<'a> = Option<&'a str>;
|
||||
|
||||
/// Represents the template commands.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Cmd<'a> {
|
||||
Forward(message::args::Id<'a>, Headers<'a>, Body<'a>),
|
||||
Write(Headers<'a>, Body<'a>),
|
||||
Reply(
|
||||
message::args::Id<'a>,
|
||||
message::args::All,
|
||||
Headers<'a>,
|
||||
Body<'a>,
|
||||
),
|
||||
Save(RawTpl),
|
||||
Send(RawTpl),
|
||||
}
|
||||
|
||||
/// Represents the template command matcher.
|
||||
pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Cmd<'a>>> {
|
||||
let cmd = if let Some(m) = m.subcommand_matches(CMD_FORWARD) {
|
||||
let id = message::args::parse_id_arg(m);
|
||||
let headers = parse_headers_arg(m);
|
||||
let body = parse_body_arg(m);
|
||||
Some(Cmd::Forward(id, headers, body))
|
||||
} else if let Some(m) = m.subcommand_matches(CMD_REPLY) {
|
||||
let id = message::args::parse_id_arg(m);
|
||||
let all = message::args::parse_reply_all_flag(m);
|
||||
let headers = parse_headers_arg(m);
|
||||
let body = parse_body_arg(m);
|
||||
Some(Cmd::Reply(id, all, headers, body))
|
||||
} else if let Some(m) = m.subcommand_matches(CMD_SAVE) {
|
||||
let raw_tpl = parse_raw_arg(m);
|
||||
Some(Cmd::Save(raw_tpl))
|
||||
} else if let Some(m) = m.subcommand_matches(CMD_SEND) {
|
||||
let raw_tpl = parse_raw_arg(m);
|
||||
Some(Cmd::Send(raw_tpl))
|
||||
} else if let Some(m) = m.subcommand_matches(CMD_WRITE) {
|
||||
let headers = parse_headers_arg(m);
|
||||
let body = parse_body_arg(m);
|
||||
Some(Cmd::Write(headers, body))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
/// Represents the template subcommands.
|
||||
pub fn subcmd() -> Command {
|
||||
Command::new(CMD_TPL)
|
||||
.alias("tpl")
|
||||
.about("Subcommand to manage templates")
|
||||
.long_about("Subcommand to manage templates like write, reply, send or save")
|
||||
.subcommand_required(true)
|
||||
.arg_required_else_help(true)
|
||||
.subcommand(
|
||||
Command::new(CMD_FORWARD)
|
||||
.alias("fwd")
|
||||
.about("Generate a template for forwarding an email")
|
||||
.arg(message::args::id_arg())
|
||||
.args(&args()),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new(CMD_REPLY)
|
||||
.about("Generate a template for replying to an email")
|
||||
.arg(message::args::id_arg())
|
||||
.arg(message::args::reply_all_flag())
|
||||
.args(&args()),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new(CMD_SAVE)
|
||||
.about("Compile the template into a valid email then saves it")
|
||||
.arg(Arg::new(ARG_TPL).raw(true)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new(CMD_SEND)
|
||||
.about("Compile the template into a valid email then sends it")
|
||||
.arg(Arg::new(ARG_TPL).raw(true)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new(CMD_WRITE)
|
||||
.aliases(["new", "n"])
|
||||
.about("Generate a template for writing a new email")
|
||||
.args(&args()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Represents the template arguments.
|
||||
pub fn args() -> Vec<Arg> {
|
||||
vec![
|
||||
Arg::new(ARG_HEADERS)
|
||||
.help("Override a specific header")
|
||||
.short('H')
|
||||
.long("header")
|
||||
.value_name("KEY:VAL")
|
||||
.action(ArgAction::Append),
|
||||
Arg::new(ARG_BODY)
|
||||
.help("Override the body")
|
||||
.short('B')
|
||||
.long("body")
|
||||
.value_name("STRING"),
|
||||
]
|
||||
}
|
||||
|
||||
/// Represents the template headers argument parser.
|
||||
pub fn parse_headers_arg(m: &ArgMatches) -> Headers<'_> {
|
||||
m.get_many::<String>(ARG_HEADERS).map(|h| {
|
||||
h.filter_map(|h| match h.split_once(':') {
|
||||
Some((key, val)) => Some((key, val.trim())),
|
||||
None => {
|
||||
warn!("invalid raw header {h:?}, skipping it");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Represents the template body argument parser.
|
||||
pub fn parse_body_arg(matches: &ArgMatches) -> Body<'_> {
|
||||
matches.get_one::<String>(ARG_BODY).map(String::as_str)
|
||||
}
|
||||
|
||||
/// Represents the raw template argument parser.
|
||||
pub fn parse_raw_arg(matches: &ArgMatches) -> RawTpl {
|
||||
matches
|
||||
.get_one::<String>(ARG_TPL)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
}
|
65
src/email/message/template/command/forward.rs
Normal file
65
src/email/message/template/command/forward.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
backend::Backend,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
envelope::arg::ids::EnvelopeIdArg,
|
||||
folder::arg::name::FolderNameArg,
|
||||
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Generate a forward message template
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct TemplateForwardCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub envelope: EnvelopeIdArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub headers: HeaderRawArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub body: BodyRawArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
}
|
||||
|
||||
impl TemplateForwardCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing template forward command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
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(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let id = self.envelope.id;
|
||||
let tpl: String = backend
|
||||
.get_messages(folder, &[id])
|
||||
.await?
|
||||
.first()
|
||||
.ok_or(anyhow!("cannot find message {id}"))?
|
||||
.to_forward_tpl_builder(&account_config)
|
||||
.with_headers(self.headers.raw)
|
||||
.with_body(self.body.raw())
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
}
|
52
src/email/message/template/command/mod.rs
Normal file
52
src/email/message/template/command/mod.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
pub mod forward;
|
||||
pub mod reply;
|
||||
pub mod save;
|
||||
pub mod send;
|
||||
pub mod write;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::{config::TomlConfig, printer::Printer};
|
||||
|
||||
use self::{
|
||||
forward::TemplateForwardCommand, reply::TemplateReplyCommand, save::TemplateSaveCommand,
|
||||
send::TemplateSendCommand, write::TemplateWriteCommand,
|
||||
};
|
||||
|
||||
/// Subcommand to manage templates
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum TemplateSubcommand {
|
||||
/// Write a new template
|
||||
#[command(alias = "new", alias = "compose")]
|
||||
Write(TemplateWriteCommand),
|
||||
|
||||
/// Reply to a template
|
||||
#[command()]
|
||||
Reply(TemplateReplyCommand),
|
||||
|
||||
/// Generate a template for forwarding an email
|
||||
#[command(alias = "fwd")]
|
||||
Forward(TemplateForwardCommand),
|
||||
|
||||
/// Save a template to a folder
|
||||
#[command(arg_required_else_help = true)]
|
||||
#[command(alias = "add", alias = "create")]
|
||||
Save(TemplateSaveCommand),
|
||||
|
||||
/// Send a template
|
||||
#[command(arg_required_else_help = true)]
|
||||
Send(TemplateSendCommand),
|
||||
}
|
||||
|
||||
impl TemplateSubcommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
match self {
|
||||
Self::Write(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Reply(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Forward(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Save(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Send(cmd) => cmd.execute(printer, config).await,
|
||||
}
|
||||
}
|
||||
}
|
69
src/email/message/template/command/reply.rs
Normal file
69
src/email/message/template/command/reply.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
backend::Backend,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
envelope::arg::ids::EnvelopeIdArg,
|
||||
folder::arg::name::FolderNameArg,
|
||||
message::arg::{body::BodyRawArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Generate a reply message template
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct TemplateReplyCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub envelope: EnvelopeIdArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub reply: MessageReplyAllArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub headers: HeaderRawArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub body: BodyRawArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
}
|
||||
|
||||
impl TemplateReplyCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing template reply command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
let id = self.envelope.id;
|
||||
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(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let tpl: String = backend
|
||||
.get_messages(folder, &[id])
|
||||
.await?
|
||||
.first()
|
||||
.ok_or(anyhow!("cannot find message {id}"))?
|
||||
.to_reply_tpl_builder(&account_config)
|
||||
.with_headers(self.headers.raw)
|
||||
.with_body(self.body.raw())
|
||||
.with_reply_all(self.reply.all)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
}
|
66
src/email/message/template/command/save.rs
Normal file
66
src/email/message/template/command/save.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use anyhow::Result;
|
||||
use atty::Stream;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use mml::MmlCompilerBuilder;
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
|
||||
};
|
||||
|
||||
/// Save a template to a folder
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct TemplateSaveCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
/// The raw template to save
|
||||
#[arg(raw = true, value_delimiter = ' ')]
|
||||
pub raw: Vec<String>,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
}
|
||||
|
||||
impl TemplateSaveCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing template save command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
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(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let is_tty = atty::is(Stream::Stdin);
|
||||
let is_json = printer.is_json();
|
||||
let tpl = if is_tty || is_json {
|
||||
self.raw.join(" ").replace("\r", "")
|
||||
} else {
|
||||
io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut compiler = MmlCompilerBuilder::new();
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
compiler.set_some_pgp(config.pgp.clone());
|
||||
|
||||
let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
|
||||
backend.add_raw_message(folder, &msg).await?;
|
||||
|
||||
printer.print(format!("Template successfully saved to {folder}!"))
|
||||
}
|
||||
}
|
73
src/email/message/template/command/send.rs
Normal file
73
src/email/message/template/command/send.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use anyhow::Result;
|
||||
use atty::Stream;
|
||||
use clap::Parser;
|
||||
use email::flag::Flag;
|
||||
use log::info;
|
||||
use mml::MmlCompilerBuilder;
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig, printer::Printer,
|
||||
};
|
||||
|
||||
/// Send a template
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct TemplateSendCommand {
|
||||
/// The raw template to save
|
||||
#[arg(raw = true, value_delimiter = ' ')]
|
||||
pub raw: Vec<String>,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
}
|
||||
|
||||
impl TemplateSendCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing template send 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(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
||||
let folder = account_config.sent_folder_alias()?;
|
||||
|
||||
let is_tty = atty::is(Stream::Stdin);
|
||||
let is_json = printer.is_json();
|
||||
let tpl = if is_tty || is_json {
|
||||
self.raw.join(" ").replace("\r", "")
|
||||
} else {
|
||||
io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\r\n")
|
||||
};
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut compiler = MmlCompilerBuilder::new();
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
compiler.set_some_pgp(config.pgp.clone());
|
||||
|
||||
let msg = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
|
||||
|
||||
backend.send_raw_message(&msg).await?;
|
||||
|
||||
if account_config.email_sending_save_copy.unwrap_or_default() {
|
||||
backend
|
||||
.add_raw_message_with_flag(&folder, &msg, Flag::Seen)
|
||||
.await?;
|
||||
|
||||
printer.print(format!("Template successfully sent and saved to {folder}!"))
|
||||
} else {
|
||||
printer.print("Template successfully sent!")
|
||||
}
|
||||
}
|
||||
}
|
48
src/email/message/template/command/write.rs
Normal file
48
src/email/message/template/command/write.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use email::message::Message;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Write a new template
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct TemplateWriteCommand {
|
||||
#[command(flatten)]
|
||||
pub headers: HeaderRawArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub body: BodyRawArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
}
|
||||
|
||||
impl TemplateWriteCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing template write command");
|
||||
|
||||
let account = self.account.name.as_ref().map(String::as_str);
|
||||
let cache = self.cache.disable;
|
||||
|
||||
let (_, account_config) = config.clone().into_account_configs(account, cache)?;
|
||||
|
||||
let tpl: String = Message::new_tpl_builder(&account_config)
|
||||
.with_headers(self.headers.raw)
|
||||
.with_body(self.body.raw())
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use atty::Stream;
|
||||
use email::{account::config::AccountConfig, flag::Flag, message::Message};
|
||||
use mml::MmlCompilerBuilder;
|
||||
use std::io::{stdin, BufRead};
|
||||
|
||||
use crate::{backend::Backend, printer::Printer};
|
||||
|
||||
pub async fn forward<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &Backend,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let tpl: String = backend
|
||||
.get_messages(folder, &[id])
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_forward_tpl_builder(config)
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
|
||||
pub async fn reply<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &Backend,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
all: bool,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let tpl: String = backend
|
||||
.get_messages(folder, &[id])
|
||||
.await?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_reply_tpl_builder(config)
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.with_reply_all(all)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
||||
|
||||
pub async fn save<P: Printer>(
|
||||
#[allow(unused_variables)] config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &Backend,
|
||||
folder: &str,
|
||||
tpl: String,
|
||||
) -> Result<()> {
|
||||
let tpl = if atty::is(Stream::Stdin) || printer.is_json() {
|
||||
tpl.replace("\r", "")
|
||||
} else {
|
||||
stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut compiler = MmlCompilerBuilder::new();
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
compiler.set_some_pgp(config.pgp.clone());
|
||||
|
||||
let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
|
||||
|
||||
backend.add_raw_message(folder, &email).await?;
|
||||
|
||||
printer.print("Template successfully saved!")
|
||||
}
|
||||
|
||||
pub async fn send<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &Backend,
|
||||
tpl: String,
|
||||
) -> Result<()> {
|
||||
let folder = config.sent_folder_alias()?;
|
||||
|
||||
let tpl = if atty::is(Stream::Stdin) || printer.is_json() {
|
||||
tpl.replace("\r", "")
|
||||
} else {
|
||||
stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut compiler = MmlCompilerBuilder::new();
|
||||
|
||||
#[cfg(feature = "pgp")]
|
||||
compiler.set_some_pgp(config.pgp.clone());
|
||||
|
||||
let email = compiler.build(tpl.as_str())?.compile().await?.into_vec()?;
|
||||
|
||||
backend.send_raw_message(&email).await?;
|
||||
|
||||
if config.email_sending_save_copy.unwrap_or_default() {
|
||||
backend
|
||||
.add_raw_message_with_flag(&folder, &email, Flag::Seen)
|
||||
.await?;
|
||||
}
|
||||
|
||||
printer.print("Template successfully sent!")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn write<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let tpl: String = Message::new_tpl_builder(config)
|
||||
.with_some_headers(headers)
|
||||
.with_some_body(body)
|
||||
.build()
|
||||
.await?
|
||||
.into();
|
||||
|
||||
printer.print(tpl)
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
pub mod args;
|
||||
pub mod handlers;
|
||||
pub mod command;
|
||||
|
|
|
@ -2,5 +2,7 @@ pub mod envelope;
|
|||
pub mod message;
|
||||
|
||||
#[doc(inline)]
|
||||
// pub use self::{envelope::flag, message::template};
|
||||
pub use self::envelope::flag;
|
||||
pub use self::{
|
||||
envelope::flag,
|
||||
message::{attachment, template},
|
||||
};
|
||||
|
|
93
src/main.rs
93
src/main.rs
|
@ -36,96 +36,3 @@ async fn main() -> Result<()> {
|
|||
|
||||
cli.command.execute(&mut printer, &config).await
|
||||
}
|
||||
|
||||
// fn create_app() -> clap::Command {
|
||||
// clap::Command::new(env!("CARGO_PKG_NAME"))
|
||||
// .subcommand(message::args::subcmd())
|
||||
// .subcommand(template::args::subcmd())
|
||||
// }
|
||||
|
||||
// #[tokio::main]
|
||||
// async fn main() -> Result<()> {
|
||||
// // check mailto command before app initialization
|
||||
// let raw_args: Vec<String> = env::args().collect();
|
||||
// if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
||||
// let url = Url::parse(&raw_args[1])?;
|
||||
// let (toml_account_config, account_config) = TomlConfig::from_default_paths()
|
||||
// .await?
|
||||
// .into_account_configs(None, false)?;
|
||||
// let backend_builder =
|
||||
// BackendBuilder::new(toml_account_config, account_config.clone(), true).await?;
|
||||
// let backend = backend_builder.build().await?;
|
||||
// let mut printer = StdoutPrinter::default();
|
||||
|
||||
// return message::handlers::mailto(&account_config, &backend, &mut printer, &url).await;
|
||||
// }
|
||||
|
||||
// match message::args::matches(&m)? {
|
||||
// Some(message::args::Cmd::Attachments(ids)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return message::handlers::attachments(
|
||||
// &account_config,
|
||||
// &mut printer,
|
||||
// &backend,
|
||||
// &folder,
|
||||
// ids,
|
||||
// )
|
||||
// .await;
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
|
||||
// match template::args::matches(&m)? {
|
||||
// Some(template::args::Cmd::Forward(id, headers, body)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return template::handlers::forward(
|
||||
// &account_config,
|
||||
// &mut printer,
|
||||
// &backend,
|
||||
// &folder,
|
||||
// id,
|
||||
// headers,
|
||||
// body,
|
||||
// )
|
||||
// .await;
|
||||
// }
|
||||
// Some(template::args::Cmd::Write(headers, body)) => {
|
||||
// return template::handlers::write(&account_config, &mut printer, headers, body).await;
|
||||
// }
|
||||
// Some(template::args::Cmd::Reply(id, all, headers, body)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return template::handlers::reply(
|
||||
// &account_config,
|
||||
// &mut printer,
|
||||
// &backend,
|
||||
// &folder,
|
||||
// id,
|
||||
// all,
|
||||
// headers,
|
||||
// body,
|
||||
// )
|
||||
// .await;
|
||||
// }
|
||||
// Some(template::args::Cmd::Save(template)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return template::handlers::save(
|
||||
// &account_config,
|
||||
// &mut printer,
|
||||
// &backend,
|
||||
// &folder,
|
||||
// template,
|
||||
// )
|
||||
// .await;
|
||||
// }
|
||||
// Some(template::args::Cmd::Send(template)) => {
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
|
||||
// return template::handlers::send(&account_config, &mut printer, &backend, template)
|
||||
// .await;
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue