mirror of
https://github.com/soywod/himalaya.git
synced 2025-04-22 17:23:27 +00:00
add template commands
This commit is contained in:
parent
3281c27d57
commit
2b5be91af9
2 changed files with 119 additions and 31 deletions
90
src/main.rs
90
src/main.rs
|
@ -8,6 +8,7 @@ mod smtp;
|
|||
mod table;
|
||||
|
||||
use clap::{App, AppSettings, Arg, SubCommand};
|
||||
use serde_json::json;
|
||||
use std::{fmt, fs, process::exit, result};
|
||||
|
||||
use crate::config::Config;
|
||||
|
@ -99,6 +100,13 @@ fn uid_arg() -> Arg<'static, 'static> {
|
|||
.required(true)
|
||||
}
|
||||
|
||||
fn reply_all_arg() -> Arg<'static, 'static> {
|
||||
Arg::with_name("reply-all")
|
||||
.help("Includes all recipients")
|
||||
.short("a")
|
||||
.long("all")
|
||||
}
|
||||
|
||||
fn page_size_arg<'a>(default: &'a str) -> Arg<'a, 'a> {
|
||||
Arg::with_name("size")
|
||||
.help("Page size")
|
||||
|
@ -139,12 +147,12 @@ fn run() -> Result<()> {
|
|||
Arg::with_name("account")
|
||||
.long("account")
|
||||
.short("a")
|
||||
.help("Name of the config file to use")
|
||||
.help("Name of the account to use")
|
||||
.value_name("STRING"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("mailboxes")
|
||||
.aliases(&["mboxes", "mb", "m"])
|
||||
.aliases(&["mboxes", "mbox", "mb", "m"])
|
||||
.about("Lists all available mailboxes"),
|
||||
)
|
||||
.subcommand(
|
||||
|
@ -188,7 +196,7 @@ fn run() -> Result<()> {
|
|||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("attachments")
|
||||
.aliases(&["attach", "a"])
|
||||
.aliases(&["attach", "att", "a"])
|
||||
.about("Downloads all attachments from an email")
|
||||
.arg(uid_arg())
|
||||
.arg(mailbox_arg()),
|
||||
|
@ -200,12 +208,7 @@ fn run() -> Result<()> {
|
|||
.about("Answers to an email")
|
||||
.arg(uid_arg())
|
||||
.arg(mailbox_arg())
|
||||
.arg(
|
||||
Arg::with_name("reply-all")
|
||||
.help("Includs all recipients")
|
||||
.short("a")
|
||||
.long("all"),
|
||||
),
|
||||
.arg(reply_all_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("forward")
|
||||
|
@ -214,6 +217,32 @@ fn run() -> Result<()> {
|
|||
.arg(uid_arg())
|
||||
.arg(mailbox_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("template")
|
||||
.aliases(&["tpl", "t"])
|
||||
.about("Generates a message template")
|
||||
.subcommand(
|
||||
SubCommand::with_name("new")
|
||||
.aliases(&["n"])
|
||||
.about("Generates a new message template")
|
||||
.arg(mailbox_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("reply")
|
||||
.aliases(&["rep", "r"])
|
||||
.about("Generates a reply message template")
|
||||
.arg(uid_arg())
|
||||
.arg(mailbox_arg())
|
||||
.arg(reply_all_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("forward")
|
||||
.aliases(&["fwd", "fw", "f"])
|
||||
.about("Generates a forward message template")
|
||||
.arg(uid_arg())
|
||||
.arg(mailbox_arg()),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let account_name = matches.value_of("account");
|
||||
|
@ -309,7 +338,7 @@ fn run() -> Result<()> {
|
|||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
|
||||
let text_bodies = msg.text_bodies(&mime)?;
|
||||
println!("{}", text_bodies);
|
||||
print(&output_type, json!({ "content": text_bodies }))?;
|
||||
|
||||
imap_conn.logout();
|
||||
}
|
||||
|
@ -343,7 +372,7 @@ fn run() -> Result<()> {
|
|||
let account = config.find_account_by_name(account_name)?;
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
|
@ -356,6 +385,41 @@ fn run() -> Result<()> {
|
|||
imap_conn.logout();
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("template") {
|
||||
let config = Config::new_from_file()?;
|
||||
let account = config.find_account_by_name(account_name)?;
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("new") {
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
print(&output_type, &tpl)?;
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
let mbox = matches.value_of("mailbox").unwrap();
|
||||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = if matches.is_present("reply-all") {
|
||||
msg.build_reply_all_tpl(&config, &account)?
|
||||
} else {
|
||||
msg.build_reply_tpl(&config, &account)?
|
||||
};
|
||||
|
||||
print(&output_type, &tpl)?;
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
let mbox = matches.value_of("mailbox").unwrap();
|
||||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
|
||||
print(&output_type, &tpl)?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
let config = Config::new_from_file()?;
|
||||
let account = config.find_account_by_name(account_name)?;
|
||||
|
@ -371,7 +435,7 @@ fn run() -> Result<()> {
|
|||
msg.build_reply_tpl(&config, &account)?
|
||||
};
|
||||
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
|
@ -394,7 +458,7 @@ fn run() -> Result<()> {
|
|||
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
let content = input::open_editor_with_tpl(&tpl.as_bytes())?;
|
||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||
let msg = Msg::from(content);
|
||||
|
||||
input::ask_for_confirmation("Send the message?")?;
|
||||
|
|
60
src/msg.rs
60
src/msg.rs
|
@ -1,7 +1,10 @@
|
|||
use lettre;
|
||||
use mailparse::{self, MailHeaderMap};
|
||||
use rfc2047_decoder;
|
||||
use serde::Serialize;
|
||||
use serde::{
|
||||
ser::{self, SerializeStruct},
|
||||
Serialize,
|
||||
};
|
||||
use std::{fmt, result};
|
||||
|
||||
use crate::config::{Account, Config};
|
||||
|
@ -41,7 +44,29 @@ impl From<lettre::error::Error> for Error {
|
|||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
// Msg
|
||||
// Template
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tpl(String);
|
||||
|
||||
impl fmt::Display for Tpl {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Tpl {
|
||||
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ser::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Tpl", 1)?;
|
||||
state.serialize_field("template", &self.0)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
// Message
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Msg {
|
||||
|
@ -228,7 +253,7 @@ impl<'a> Msg {
|
|||
Ok(parts)
|
||||
}
|
||||
|
||||
pub fn build_new_tpl(config: &Config, account: &Account) -> Result<String> {
|
||||
pub fn build_new_tpl(config: &Config, account: &Account) -> Result<Tpl> {
|
||||
let mut tpl = vec![];
|
||||
|
||||
// "From" header
|
||||
|
@ -240,10 +265,10 @@ impl<'a> Msg {
|
|||
// "Subject" header
|
||||
tpl.push("Subject: ".to_string());
|
||||
|
||||
Ok(tpl.join("\r\n"))
|
||||
Ok(Tpl(tpl.join("\r\n")))
|
||||
}
|
||||
|
||||
pub fn build_reply_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||
pub fn build_reply_tpl(&self, config: &Config, account: &Account) -> Result<Tpl> {
|
||||
let msg = &self.parse()?;
|
||||
let headers = msg.get_headers();
|
||||
let mut tpl = vec![];
|
||||
|
@ -271,19 +296,19 @@ impl<'a> Msg {
|
|||
tpl.push(String::new());
|
||||
|
||||
// Original msg prepend with ">"
|
||||
let thread = msg
|
||||
.get_body()
|
||||
.unwrap()
|
||||
.split("\r\n")
|
||||
let thread = self
|
||||
.text_bodies("text/plain")?
|
||||
.replace("\r", "")
|
||||
.split("\n")
|
||||
.map(|line| format!(">{}", line))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\r\n");
|
||||
tpl.push(thread);
|
||||
|
||||
Ok(tpl.join("\r\n"))
|
||||
Ok(Tpl(tpl.join("\r\n")))
|
||||
}
|
||||
|
||||
pub fn build_reply_all_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||
pub fn build_reply_all_tpl(&self, config: &Config, account: &Account) -> Result<Tpl> {
|
||||
let msg = &self.parse()?;
|
||||
let headers = msg.get_headers();
|
||||
let mut tpl = vec![];
|
||||
|
@ -353,19 +378,18 @@ impl<'a> Msg {
|
|||
tpl.push(String::new());
|
||||
|
||||
// Original msg prepend with ">"
|
||||
let thread = msg
|
||||
.get_body()
|
||||
.unwrap()
|
||||
let thread = self
|
||||
.text_bodies("text/plain")?
|
||||
.split("\r\n")
|
||||
.map(|line| format!(">{}", line))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\r\n");
|
||||
tpl.push(thread);
|
||||
|
||||
Ok(tpl.join("\r\n"))
|
||||
Ok(Tpl(tpl.join("\r\n")))
|
||||
}
|
||||
|
||||
pub fn build_forward_tpl(&self, config: &Config, account: &Account) -> Result<String> {
|
||||
pub fn build_forward_tpl(&self, config: &Config, account: &Account) -> Result<Tpl> {
|
||||
let msg = &self.parse()?;
|
||||
let headers = msg.get_headers();
|
||||
let mut tpl = vec![];
|
||||
|
@ -385,9 +409,9 @@ impl<'a> Msg {
|
|||
|
||||
// Original msg
|
||||
tpl.push("-------- Forwarded Message --------".to_string());
|
||||
tpl.push(msg.get_body().unwrap_or(String::new()));
|
||||
tpl.push(self.text_bodies("text/plain")?);
|
||||
|
||||
Ok(tpl.join("\r\n"))
|
||||
Ok(Tpl(tpl.join("\r\n")))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue