mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 09:05:13 +00:00
fix tpl forward/reply, fix flag subcmd (#190)
This commit is contained in:
parent
e065d8d905
commit
cdce6c0bf2
|
@ -500,7 +500,7 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
|
|||
.map(String::from)
|
||||
.and_then(|sig| fs::read_to_string(sig).ok())
|
||||
.or_else(|| signature.map(|sig| sig.to_owned()))
|
||||
.map(|sig| format!("\n{}{}", signature_delim, sig.trim_end()))
|
||||
.map(|sig| format!("\n\n{}{}", signature_delim, sig.trim_end()))
|
||||
.unwrap_or_default();
|
||||
|
||||
let account = Account {
|
||||
|
|
|
@ -183,7 +183,7 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
|
|||
return Ok(Some(Command::Tpl(msg::tpl::arg::matches(&m)?)));
|
||||
}
|
||||
|
||||
if let Some(m) = m.subcommand_matches("flag") {
|
||||
if let Some(m) = m.subcommand_matches("flags") {
|
||||
return Ok(Some(Command::Flag(msg::flag::arg::matches(&m)?)));
|
||||
}
|
||||
|
||||
|
|
|
@ -169,15 +169,10 @@ impl Msg {
|
|||
if headers.from.is_empty() {
|
||||
headers.from = vec![account.address()];
|
||||
}
|
||||
let body = Body::new_with_text(if let Some(sig) = headers.signature.as_ref() {
|
||||
format!("\n{}", sig)
|
||||
} else {
|
||||
String::from("\n")
|
||||
});
|
||||
|
||||
Self {
|
||||
headers,
|
||||
body,
|
||||
body: Body::new_with_text(""),
|
||||
sig: account.signature.to_owned(),
|
||||
..Self::default()
|
||||
}
|
||||
|
@ -269,14 +264,13 @@ impl Msg {
|
|||
cc,
|
||||
subject: Some(subject),
|
||||
in_reply_to: self.headers.message_id.clone(),
|
||||
signature: Some(account.signature.to_owned()),
|
||||
// and clear the rest of the fields
|
||||
..Headers::default()
|
||||
};
|
||||
|
||||
// comment "out" the body of the msg, by adding the `>` characters to
|
||||
// each line which includes a string.
|
||||
let mut new_body = self
|
||||
let new_body = self
|
||||
.body
|
||||
.plain
|
||||
.clone()
|
||||
|
@ -289,15 +283,10 @@ impl Msg {
|
|||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
// also add the the signature in the end
|
||||
if let Some(sig) = new_headers.signature.as_ref() {
|
||||
new_body.push('\n');
|
||||
new_body.push_str(&sig)
|
||||
}
|
||||
|
||||
self.body = Body::new_with_text(new_body);
|
||||
self.headers = new_headers;
|
||||
self.attachments.clear();
|
||||
self.sig = account.signature.to_owned();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -358,10 +347,8 @@ impl Msg {
|
|||
.unwrap_or_default()
|
||||
.replace("\r", ""),
|
||||
));
|
||||
|
||||
body.push_str(&account.signature);
|
||||
|
||||
self.body = Body::new_with_text(body);
|
||||
self.sig = account.signature.to_owned();
|
||||
}
|
||||
|
||||
/// Returns the bytes of the *sendable message* of the struct!
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! This module provides subcommands, arguments and a command matcher related to message flag.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
||||
use clap::{self, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use log::debug;
|
||||
|
||||
use crate::domain::msg;
|
||||
|
@ -63,6 +63,7 @@ fn flags_arg<'a>() -> Arg<'a, 'a> {
|
|||
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||
vec![SubCommand::with_name("flags")
|
||||
.about("Handles flags")
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommand(
|
||||
SubCommand::with_name("set")
|
||||
.about("Replaces all message flags")
|
||||
|
|
|
@ -266,7 +266,6 @@ pub fn mailto<ImapService: ImapServiceInterface, SmtpService: SmtpServiceInterfa
|
|||
encoding: ContentTransferEncoding::Base64,
|
||||
bcc: Some(bcc),
|
||||
cc: Some(cc),
|
||||
signature: Some(account.signature.to_owned()),
|
||||
subject: Some(subject.into()),
|
||||
..Headers::default()
|
||||
};
|
||||
|
|
|
@ -48,7 +48,6 @@ pub struct Headers {
|
|||
pub message_id: Option<String>,
|
||||
pub reply_to: Option<Vec<String>>,
|
||||
pub sender: Option<String>,
|
||||
pub signature: Option<String>,
|
||||
pub subject: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -202,7 +201,6 @@ impl Default for Headers {
|
|||
message_id: None,
|
||||
reply_to: None,
|
||||
sender: None,
|
||||
signature: None,
|
||||
subject: None,
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +259,6 @@ impl TryFrom<Option<&imap_proto::types::Envelope<'_>>> for Headers {
|
|||
bcc,
|
||||
in_reply_to,
|
||||
custom_headers: None,
|
||||
signature: None,
|
||||
encoding: ContentTransferEncoding::Base64,
|
||||
})
|
||||
} else {
|
||||
|
@ -414,15 +411,7 @@ impl<'from> From<&mailparse::ParsedMail<'from>> for Headers {
|
|||
/// [get_header_as_string]: struct.Headers.html#method.get_header_as_string
|
||||
impl fmt::Display for Headers {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut header = self.get_header_as_string();
|
||||
|
||||
// now add some space between the header and the signature
|
||||
header.push_str("\n\n\n");
|
||||
|
||||
// and add the signature in the end
|
||||
header.push_str(&self.signature.clone().unwrap_or(String::new()));
|
||||
|
||||
write!(formatter, "{}", header)
|
||||
write!(formatter, "{}", self.get_header_as_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,56 +8,44 @@ use log::debug;
|
|||
|
||||
use crate::domain::msg::{self, arg::uid_arg};
|
||||
|
||||
type Subject<'a> = Option<&'a str>;
|
||||
type From<'a> = Option<Values<'a>>;
|
||||
type To<'a> = Option<Values<'a>>;
|
||||
type Cc<'a> = Option<Values<'a>>;
|
||||
type Bcc<'a> = Option<Values<'a>>;
|
||||
type Headers<'a> = Option<Values<'a>>;
|
||||
type Body<'a> = Option<&'a str>;
|
||||
type Signature<'a> = Option<&'a str>;
|
||||
type Uid<'a> = &'a str;
|
||||
type All = bool;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tpl<'a> {
|
||||
pub subject: Option<&'a str>,
|
||||
pub from: Option<Values<'a>>,
|
||||
pub to: Option<Values<'a>>,
|
||||
pub cc: Option<Values<'a>>,
|
||||
pub bcc: Option<Values<'a>>,
|
||||
pub headers: Option<Values<'a>>,
|
||||
pub body: Option<&'a str>,
|
||||
pub sig: Option<&'a str>,
|
||||
}
|
||||
|
||||
/// Message template commands.
|
||||
pub enum Command<'a> {
|
||||
New(
|
||||
Subject<'a>,
|
||||
From<'a>,
|
||||
To<'a>,
|
||||
Cc<'a>,
|
||||
Bcc<'a>,
|
||||
Headers<'a>,
|
||||
Body<'a>,
|
||||
Signature<'a>,
|
||||
),
|
||||
Reply(Uid<'a>, All),
|
||||
Forward(Uid<'a>),
|
||||
New(Tpl<'a>),
|
||||
Reply(Uid<'a>, All, Tpl<'a>),
|
||||
Forward(Uid<'a>, Tpl<'a>),
|
||||
}
|
||||
|
||||
/// Message template command matcher.
|
||||
pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
|
||||
if let Some(m) = m.subcommand_matches("new") {
|
||||
debug!("new command matched");
|
||||
let subject = m.value_of("subject");
|
||||
debug!("subject: `{:?}`", subject);
|
||||
let from = m.values_of("from");
|
||||
debug!("from: `{:?}`", from);
|
||||
let to = m.values_of("to");
|
||||
debug!("to: `{:?}`", to);
|
||||
let cc = m.values_of("cc");
|
||||
debug!("cc: `{:?}`", cc);
|
||||
let bcc = m.values_of("bcc");
|
||||
debug!("bcc: `{:?}`", bcc);
|
||||
let headers = m.values_of("header");
|
||||
debug!("headers: `{:?}`", headers);
|
||||
let body = m.value_of("body");
|
||||
debug!("body: `{:?}`", body);
|
||||
let sig = m.value_of("signature");
|
||||
debug!("signature: `{:?}`", sig);
|
||||
return Ok(Some(Command::New(
|
||||
subject, from, to, cc, bcc, headers, body, sig,
|
||||
)));
|
||||
let tpl = Tpl {
|
||||
subject: m.value_of("subject"),
|
||||
from: m.values_of("from"),
|
||||
to: m.values_of("to"),
|
||||
cc: m.values_of("cc"),
|
||||
bcc: m.values_of("bcc"),
|
||||
headers: m.values_of("headers"),
|
||||
body: m.value_of("body"),
|
||||
sig: m.value_of("signature"),
|
||||
};
|
||||
debug!("template: `{:?}`", tpl);
|
||||
return Ok(Some(Command::New(tpl)));
|
||||
}
|
||||
|
||||
if let Some(m) = m.subcommand_matches("reply") {
|
||||
|
@ -66,14 +54,36 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
|
|||
debug!("uid: {}", uid);
|
||||
let all = m.is_present("reply-all");
|
||||
debug!("reply all: {}", all);
|
||||
return Ok(Some(Command::Reply(uid, all)));
|
||||
let tpl = Tpl {
|
||||
subject: m.value_of("subject"),
|
||||
from: m.values_of("from"),
|
||||
to: m.values_of("to"),
|
||||
cc: m.values_of("cc"),
|
||||
bcc: m.values_of("bcc"),
|
||||
headers: m.values_of("headers"),
|
||||
body: m.value_of("body"),
|
||||
sig: m.value_of("signature"),
|
||||
};
|
||||
debug!("template: `{:?}`", tpl);
|
||||
return Ok(Some(Command::Reply(uid, all, tpl)));
|
||||
}
|
||||
|
||||
if let Some(m) = m.subcommand_matches("forward") {
|
||||
debug!("forward command matched");
|
||||
let uid = m.value_of("uid").unwrap();
|
||||
debug!("uid: {}", uid);
|
||||
return Ok(Some(Command::Forward(uid)));
|
||||
let tpl = Tpl {
|
||||
subject: m.value_of("subject"),
|
||||
from: m.values_of("from"),
|
||||
to: m.values_of("to"),
|
||||
cc: m.values_of("cc"),
|
||||
bcc: m.values_of("bcc"),
|
||||
headers: m.values_of("headers"),
|
||||
body: m.value_of("body"),
|
||||
sig: m.value_of("signature"),
|
||||
};
|
||||
debug!("template: `{:?}`", tpl);
|
||||
return Ok(Some(Command::Forward(uid, tpl)));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
|
|
@ -6,7 +6,6 @@ use std::{
|
|||
|
||||
use anyhow::Result;
|
||||
use atty::Stream;
|
||||
use clap::Values;
|
||||
use log::{debug, trace};
|
||||
|
||||
use crate::{
|
||||
|
@ -17,59 +16,54 @@ use crate::{
|
|||
body::Body,
|
||||
entity::{Msg, MsgSerialized},
|
||||
headers::Headers,
|
||||
tpl::arg::Tpl,
|
||||
},
|
||||
},
|
||||
output::service::OutputServiceInterface,
|
||||
};
|
||||
|
||||
pub fn new<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
|
||||
subject: Option<&'a str>,
|
||||
from: Option<Values<'a>>,
|
||||
to: Option<Values<'a>>,
|
||||
cc: Option<Values<'a>>,
|
||||
bcc: Option<Values<'a>>,
|
||||
headers: Option<Values<'a>>,
|
||||
body: Option<&'a str>,
|
||||
sig: Option<&'a str>,
|
||||
account: &Account,
|
||||
output: &OutputService,
|
||||
imap: &mut ImapService,
|
||||
tpl: Tpl<'a>,
|
||||
account: &'a Account,
|
||||
output: &'a OutputService,
|
||||
imap: &'a mut ImapService,
|
||||
) -> Result<()> {
|
||||
let mut msg = Msg::new(&account);
|
||||
override_msg_with_args(&mut msg, subject, from, to, cc, bcc, headers, body, sig);
|
||||
override_msg_with_args(&mut msg, tpl);
|
||||
trace!("message: {:#?}", msg);
|
||||
output.print(MsgSerialized::try_from(&msg)?)?;
|
||||
imap.logout()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reply<OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
|
||||
pub fn reply<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
|
||||
uid: &str,
|
||||
all: bool,
|
||||
account: &Account,
|
||||
output: &OutputService,
|
||||
imap: &mut ImapService,
|
||||
tpl: Tpl<'a>,
|
||||
account: &'a Account,
|
||||
output: &'a OutputService,
|
||||
imap: &'a mut ImapService,
|
||||
) -> Result<()> {
|
||||
let mut msg = imap.get_msg(&uid)?;
|
||||
msg.change_to_reply(&account, all)?;
|
||||
// FIXME
|
||||
// override_msg_with_args(&mut msg, &matches);
|
||||
let mut msg = imap.get_msg(uid)?;
|
||||
msg.change_to_reply(account, all)?;
|
||||
override_msg_with_args(&mut msg, tpl);
|
||||
trace!("Message: {:?}", msg);
|
||||
output.print(MsgSerialized::try_from(&msg)?)?;
|
||||
imap.logout()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn forward<OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
|
||||
pub fn forward<'a, OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>(
|
||||
uid: &str,
|
||||
account: &Account,
|
||||
output: &OutputService,
|
||||
imap: &mut ImapService,
|
||||
tpl: Tpl<'a>,
|
||||
account: &'a Account,
|
||||
output: &'a OutputService,
|
||||
imap: &'a mut ImapService,
|
||||
) -> Result<()> {
|
||||
let mut msg = imap.get_msg(&uid)?;
|
||||
msg.sig = account.signature.to_owned();
|
||||
msg.change_to_forwarding(&account);
|
||||
// FIXME
|
||||
// override_msg_with_args(&mut msg, &matches);
|
||||
override_msg_with_args(&mut msg, tpl);
|
||||
trace!("Message: {:?}", msg);
|
||||
output.print(MsgSerialized::try_from(&msg)?)?;
|
||||
imap.logout()?;
|
||||
|
@ -79,35 +73,24 @@ pub fn forward<OutputService: OutputServiceInterface, ImapService: ImapServiceIn
|
|||
// == Helper functions ==
|
||||
// -- Template Subcommands --
|
||||
// These functions are more used for the "template" subcommand
|
||||
fn override_msg_with_args<'a>(
|
||||
msg: &mut Msg,
|
||||
subject: Option<&'a str>,
|
||||
from: Option<Values<'a>>,
|
||||
to: Option<Values<'a>>,
|
||||
cc: Option<Values<'a>>,
|
||||
bcc: Option<Values<'a>>,
|
||||
headers: Option<Values<'a>>,
|
||||
body: Option<&'a str>,
|
||||
sig: Option<&'a str>,
|
||||
) {
|
||||
fn override_msg_with_args<'a>(msg: &mut Msg, tpl: Tpl<'a>) {
|
||||
// -- Collecting credentials --
|
||||
let from: Vec<String> = match from {
|
||||
let from: Vec<String> = match tpl.from {
|
||||
Some(from) => from.map(|arg| arg.to_string()).collect(),
|
||||
None => msg.headers.from.clone(),
|
||||
};
|
||||
|
||||
let to: Vec<String> = match to {
|
||||
let to: Vec<String> = match tpl.to {
|
||||
Some(to) => to.map(|arg| arg.to_string()).collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
|
||||
let subject = subject.map(String::from);
|
||||
let cc: Option<Vec<String>> = cc.map(|cc| cc.map(|arg| arg.to_string()).collect());
|
||||
let bcc: Option<Vec<String>> = bcc.map(|bcc| bcc.map(|arg| arg.to_string()).collect());
|
||||
let signature = sig.map(String::from).or(msg.headers.signature.to_owned());
|
||||
let subject = tpl.subject.map(String::from);
|
||||
let cc: Option<Vec<String>> = tpl.cc.map(|cc| cc.map(|arg| arg.to_string()).collect());
|
||||
let bcc: Option<Vec<String>> = tpl.bcc.map(|bcc| bcc.map(|arg| arg.to_string()).collect());
|
||||
|
||||
let custom_headers: Option<HashMap<String, Vec<String>>> = {
|
||||
if let Some(matched_headers) = headers {
|
||||
if let Some(matched_headers) = tpl.headers {
|
||||
let mut custom_headers: HashMap<String, Vec<String>> = HashMap::new();
|
||||
|
||||
// collect the custom headers
|
||||
|
@ -136,11 +119,15 @@ fn override_msg_with_args<'a>(
|
|||
.join("\n");
|
||||
debug!("overriden body from stdin: {:?}", body);
|
||||
body
|
||||
} else if let Some(body) = body {
|
||||
} else if let Some(body) = tpl.body {
|
||||
debug!("overriden body: {:?}", body);
|
||||
body.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
msg.body
|
||||
.plain
|
||||
.as_ref()
|
||||
.map(String::from)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -153,11 +140,11 @@ fn override_msg_with_args<'a>(
|
|||
to,
|
||||
cc,
|
||||
bcc,
|
||||
signature,
|
||||
custom_headers,
|
||||
..msg.headers.clone()
|
||||
};
|
||||
|
||||
msg.headers = headers;
|
||||
msg.body = body;
|
||||
msg.sig = tpl.sig.map(String::from).unwrap_or(msg.sig.to_owned());
|
||||
}
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -25,7 +25,6 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
|
|||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
.setting(AppSettings::GlobalVersion)
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.args(&config::arg::args())
|
||||
.args(&output::arg::args())
|
||||
.arg(mbox::arg::source_arg())
|
||||
|
@ -144,16 +143,14 @@ fn main() -> Result<()> {
|
|||
_ => (),
|
||||
},
|
||||
Some(msg::arg::Command::Tpl(m)) => match m {
|
||||
Some(msg::tpl::arg::Command::New(sub, from, to, cc, bcc, h, body, sig)) => {
|
||||
return msg::tpl::handler::new(
|
||||
sub, from, to, cc, bcc, h, body, sig, &account, &output, &mut imap,
|
||||
);
|
||||
Some(msg::tpl::arg::Command::New(tpl)) => {
|
||||
return msg::tpl::handler::new(tpl, &account, &output, &mut imap);
|
||||
}
|
||||
Some(msg::tpl::arg::Command::Reply(uid, all)) => {
|
||||
return msg::tpl::handler::reply(uid, all, &account, &output, &mut imap);
|
||||
Some(msg::tpl::arg::Command::Reply(uid, all, tpl)) => {
|
||||
return msg::tpl::handler::reply(uid, all, tpl, &account, &output, &mut imap);
|
||||
}
|
||||
Some(msg::tpl::arg::Command::Forward(uid)) => {
|
||||
return msg::tpl::handler::forward(uid, &account, &output, &mut imap);
|
||||
Some(msg::tpl::arg::Command::Forward(uid, tpl)) => {
|
||||
return msg::tpl::handler::forward(uid, tpl, &account, &output, &mut imap);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue