fix new tpl sig

This commit is contained in:
Clément DOUIN 2021-09-18 21:45:26 +02:00
parent 8e2a703e2b
commit e065d8d905
No known key found for this signature in database
GPG key ID: 69C9B9CFFDEE2DEF
9 changed files with 199 additions and 221 deletions

View file

@ -1,13 +1,13 @@
//! Module related to completion handling. //! Module related to completion handling.
//! //!
//! This module gathers all completion actions triggered by the CLI. //! This module gathers all completion commands.
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use clap::{App, Shell}; use clap::{App, Shell};
use std::{io, str::FromStr}; use std::{io, str::FromStr};
/// Generate completion script from the given [`clap::App`] for the given shell slice. /// Generate completion script from the given [`clap::App`] for the given shell slice.
pub fn generate<'a>(shell: Option<&'a str>, mut app: App<'a, 'a>) -> Result<()> { pub fn generate<'a>(mut app: App<'a, 'a>, shell: Option<&'a str>) -> Result<()> {
let shell = Shell::from_str(shell.unwrap_or_default()) let shell = Shell::from_str(shell.unwrap_or_default())
.map_err(|err| anyhow!(err)) .map_err(|err| anyhow!(err))
.context("cannot parse shell")?; .context("cannot parse shell")?;

View file

@ -183,60 +183,6 @@ impl Config {
Ok(()) Ok(())
} }
/// Returns the signature of the given acccount in combination witht the sigantion delimiter.
/// If the account doesn't have a signature, then the global signature is used.
///
/// # Example
/// ```
/// use himalaya::config::model::{Config, Account};
///
/// fn main() {
/// let config = Config {
/// signature: Some("Global signature".to_string()),
/// .. Config::default()
/// };
///
/// // a config without a global signature
/// let config_no_global = Config::default();
///
/// let account1 = Account::new_with_signature(Some("Account Name"), "mail@address.com", Some("Cya"));
/// let account2 = Account::new(Some("Bruh"), "mail@address.com");
///
/// // Hint: Don't forget the default signature delimiter: '\n-- \n'
/// assert_eq!(config.signature(&account1), Some("\n-- \nCya".to_string()));
/// assert_eq!(config.signature(&account2), Some("\n-- \nGlobal signature".to_string()));
///
/// assert_eq!(config_no_global.signature(&account2), None);
/// }
/// ```
pub fn signature(&self, account: &ConfigAccountEntry) -> Option<String> {
let default_sig_delim = String::from("-- \n");
let sig_delim = account
.signature_delimiter
.as_ref()
.or_else(|| self.signature_delimiter.as_ref())
.unwrap_or(&default_sig_delim);
let sig = account
.signature
.as_ref()
.or_else(|| self.signature.as_ref());
sig.and_then(|sig| shellexpand::full(sig).ok())
.map(|sig| sig.to_string())
.and_then(|sig| fs::read_to_string(sig).ok())
.or_else(|| sig.map(|sig| sig.to_owned()))
.map(|sig| format!("\n{}{}", sig_delim, sig))
}
pub fn default_page_size(&self, account: &ConfigAccountEntry) -> usize {
account
.default_page_size
.as_ref()
.or_else(|| self.default_page_size.as_ref())
.or(Some(&DEFAULT_PAGE_SIZE))
.unwrap()
.to_owned()
}
pub fn exec_watch_cmds(&self, account: &ConfigAccountEntry) -> Result<()> { pub fn exec_watch_cmds(&self, account: &ConfigAccountEntry) -> Result<()> {
let cmds = account let cmds = account
.watch_cmds .watch_cmds
@ -551,10 +497,10 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
.or_else(|| config.signature.as_ref()); .or_else(|| config.signature.as_ref());
let signature = signature let signature = signature
.and_then(|sig| shellexpand::full(sig).ok()) .and_then(|sig| shellexpand::full(sig).ok())
.map(|sig| sig.to_string()) .map(String::from)
.and_then(|sig| fs::read_to_string(sig).ok()) .and_then(|sig| fs::read_to_string(sig).ok())
.or_else(|| signature.map(|sig| sig.to_owned())) .or_else(|| signature.map(|sig| sig.to_owned()))
.map(|sig| format!("\n{}{}", signature_delim, sig)) .map(|sig| format!("\n{}{}", signature_delim, sig.trim_end()))
.unwrap_or_default(); .unwrap_or_default();
let account = Account { let account = Account {

View file

@ -7,16 +7,16 @@ use clap::{App, Arg, ArgMatches, SubCommand};
use log::debug; use log::debug;
/// Mailbox commands. /// Mailbox commands.
pub enum Commands { pub enum Command {
/// List all available mailboxes. /// List all available mailboxes.
List, List,
} }
/// Mailbox command matcher. /// Mailbox command matcher.
pub fn matches(m: &ArgMatches) -> Result<Option<Commands>> { pub fn matches(m: &ArgMatches) -> Result<Option<Command>> {
if let Some(_) = m.subcommand_matches("mailboxes") { if let Some(_) = m.subcommand_matches("mailboxes") {
debug!("mailboxes command matched"); debug!("mailboxes command matched");
return Ok(Some(Commands::List)); return Ok(Some(Command::List));
} }
Ok(None) Ok(None)

View file

@ -34,8 +34,8 @@ pub enum Command<'a> {
Send(RawMsg<'a>), Send(RawMsg<'a>),
Write(AttachmentsPaths<'a>), Write(AttachmentsPaths<'a>),
Flag(msg::flag::arg::Command<'a>), Flag(Option<msg::flag::arg::Command<'a>>),
Tpl(msg::tpl::arg::Command<'a>), Tpl(Option<msg::tpl::arg::Command<'a>>),
} }
/// Message command matcher. /// Message command matcher.
@ -63,10 +63,6 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
return Ok(Some(Command::Delete(uid))); return Ok(Some(Command::Delete(uid)));
} }
if let Some(m) = msg::flag::arg::matches(&m)? {
return Ok(Some(Command::Flag(m)));
}
if let Some(m) = m.subcommand_matches("forward") { if let Some(m) = m.subcommand_matches("forward") {
debug!("forward command matched"); debug!("forward command matched");
let uid = m.value_of("uid").unwrap(); let uid = m.value_of("uid").unwrap();
@ -176,10 +172,6 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
return Ok(Some(Command::Send(msg))); return Ok(Some(Command::Send(msg)));
} }
if let Some(m) = msg::tpl::arg::matches(&m)? {
return Ok(Some(Command::Tpl(m)));
}
if let Some(m) = m.subcommand_matches("write") { if let Some(m) = m.subcommand_matches("write") {
debug!("write command matched"); debug!("write command matched");
let attachment_paths: Vec<&str> = m.values_of("attachments").unwrap_or_default().collect(); let attachment_paths: Vec<&str> = m.values_of("attachments").unwrap_or_default().collect();
@ -187,6 +179,14 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
return Ok(Some(Command::Write(attachment_paths))); return Ok(Some(Command::Write(attachment_paths)));
} }
if let Some(m) = m.subcommand_matches("template") {
return Ok(Some(Command::Tpl(msg::tpl::arg::matches(&m)?)));
}
if let Some(m) = m.subcommand_matches("flag") {
return Ok(Some(Command::Flag(msg::flag::arg::matches(&m)?)));
}
debug!("default list command matched"); debug!("default list command matched");
Ok(Some(Command::List(None, 0))) Ok(Some(Command::List(None, 0)))
} }

View file

@ -13,8 +13,8 @@ use std::fmt;
/// This part of the msg/msg would be stored in this struct. /// This part of the msg/msg would be stored in this struct.
#[derive(Clone, Serialize, Debug, PartialEq, Eq)] #[derive(Clone, Serialize, Debug, PartialEq, Eq)]
pub struct Body { pub struct Body {
/// The text version of a body (if available) /// The plain version of a body (if available)
pub text: Option<String>, pub plain: Option<String>,
/// The html version of a body (if available) /// The html version of a body (if available)
pub html: Option<String>, pub html: Option<String>,
@ -61,7 +61,7 @@ impl Body {
/// ``` /// ```
pub fn new_with_text<S: ToString>(text: S) -> Self { pub fn new_with_text<S: ToString>(text: S) -> Self {
Self { Self {
text: Some(text.to_string()), plain: Some(text.to_string()),
html: None, html: None,
} }
} }
@ -85,7 +85,7 @@ impl Body {
/// ``` /// ```
pub fn new_with_html<S: ToString>(html: S) -> Self { pub fn new_with_html<S: ToString>(html: S) -> Self {
Self { Self {
text: None, plain: None,
html: Some(html.to_string()), html: Some(html.to_string()),
} }
} }
@ -109,7 +109,7 @@ impl Body {
/// ``` /// ```
pub fn new_with_both<S: ToString>(text: S, html: S) -> Self { pub fn new_with_both<S: ToString>(text: S, html: S) -> Self {
Self { Self {
text: Some(text.to_string()), plain: Some(text.to_string()),
html: Some(html.to_string()), html: Some(html.to_string()),
} }
} }
@ -119,7 +119,7 @@ impl Body {
impl Default for Body { impl Default for Body {
fn default() -> Self { fn default() -> Self {
Self { Self {
text: None, plain: None,
html: None, html: None,
} }
} }
@ -127,7 +127,7 @@ impl Default for Body {
impl fmt::Display for Body { impl fmt::Display for Body {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let content = if let Some(text) = self.text.clone() { let content = if let Some(text) = self.plain.clone() {
text text
} else if let Some(html) = self.html.clone() { } else if let Some(html) = self.html.clone() {
html html

View file

@ -16,8 +16,7 @@ use crate::ui::editor;
use serde::Serialize; use serde::Serialize;
use lettre::message::{ use lettre::message::{
header::ContentTransferEncoding, header::ContentType, Attachment as lettre_Attachment, Mailbox, header::ContentType, Attachment as lettre_Attachment, Mailbox, Message, MultiPart, SinglePart,
Message, MultiPart, SinglePart,
}; };
use std::{ use std::{
@ -64,7 +63,7 @@ impl fmt::Display for MsgSerialized {
/// This struct represents a whole msg with its attachments, body-content /// This struct represents a whole msg with its attachments, body-content
/// and its headers. /// and its headers.
#[derive(Debug, PartialEq, Eq, Clone, Serialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
pub struct Msg { pub struct Msg {
/// All added attachments are listed in this vector. /// All added attachments are listed in this vector.
pub attachments: Vec<Attachment>, pub attachments: Vec<Attachment>,
@ -80,6 +79,9 @@ pub struct Msg {
/// This includes the general content text and the signature. /// This includes the general content text and the signature.
pub body: Body, pub body: Body,
/// The signature of the message.
pub sig: String,
/// The UID of the msg. In general, a message should already have one, unless you're writing a /// The UID of the msg. In general, a message should already have one, unless you're writing a
/// new message, then we're generating it. /// new message, then we're generating it.
uid: Option<u32>, uid: Option<u32>,
@ -167,11 +169,6 @@ impl Msg {
if headers.from.is_empty() { if headers.from.is_empty() {
headers.from = vec![account.address()]; headers.from = vec![account.address()];
} }
if let None = headers.signature {
headers.signature = Some(account.signature.to_owned());
}
let body = Body::new_with_text(if let Some(sig) = headers.signature.as_ref() { let body = Body::new_with_text(if let Some(sig) = headers.signature.as_ref() {
format!("\n{}", sig) format!("\n{}", sig)
} else { } else {
@ -181,6 +178,7 @@ impl Msg {
Self { Self {
headers, headers,
body, body,
sig: account.signature.to_owned(),
..Self::default() ..Self::default()
} }
} }
@ -280,7 +278,7 @@ impl Msg {
// each line which includes a string. // each line which includes a string.
let mut new_body = self let mut new_body = self
.body .body
.text .plain
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.lines() .lines()
@ -354,7 +352,11 @@ impl Msg {
// apply a line which should indicate where the forwarded message begins // apply a line which should indicate where the forwarded message begins
body.push_str(&format!( body.push_str(&format!(
"\n---------- Forwarded Message ----------\n{}", "\n---------- Forwarded Message ----------\n{}",
self.body.text.clone().unwrap_or_default().replace("\r", ""), self.body
.plain
.clone()
.unwrap_or_default()
.replace("\r", ""),
)); ));
body.push_str(&account.signature); body.push_str(&account.signature);
@ -685,16 +687,16 @@ impl Msg {
let mut msg_parts = MultiPart::mixed().build(); let mut msg_parts = MultiPart::mixed().build();
// -- Body -- // -- Body --
if self.body.text.is_some() && self.body.html.is_some() { if self.body.plain.is_some() && self.body.html.is_some() {
msg_parts = msg_parts.multipart(MultiPart::alternative_plain_html( msg_parts = msg_parts.multipart(MultiPart::alternative_plain_html(
self.body.text.clone().unwrap(), self.body.plain.clone().unwrap(),
self.body.html.clone().unwrap(), self.body.html.clone().unwrap(),
)); ));
} else { } else {
let msg_body = SinglePart::builder() let msg_body = SinglePart::builder()
.header(ContentType::TEXT_PLAIN) .header(ContentType::TEXT_PLAIN)
.header(self.headers.encoding) .header(self.headers.encoding)
.body(self.body.text.clone().unwrap_or_default()); .body(self.body.plain.clone().unwrap_or_default());
msg_parts = msg_parts.singlepart(msg_body); msg_parts = msg_parts.singlepart(msg_body);
} }
@ -740,42 +742,16 @@ impl Msg {
Ok(raw_message) Ok(raw_message)
} }
/// Returns the [`ContentTransferEncoding`] of the body.
pub fn get_encoding(&self) -> ContentTransferEncoding {
self.headers.encoding
}
/// Returns the whole message: Header + Body as a String
pub fn get_full_message(&self) -> String {
format!("{}\n{}", self.headers.get_header_as_string(), self.body)
}
}
// -- Traits --
impl Default for Msg {
fn default() -> Self {
Self {
attachments: Vec::new(),
flags: Flags::default(),
headers: Headers::default(),
body: Body::default(),
// the uid is generated in the "to_sendable_msg" function if the server didn't apply a
// message id to it.
uid: None,
date: None,
raw: Vec::new(),
}
}
} }
impl fmt::Display for Msg { impl fmt::Display for Msg {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
formatter, formatter,
"{}\n{}", "{}\n{}{}",
self.headers.get_header_as_string(), self.headers.get_header_as_string(),
self.body self.body,
self.sig
) )
} }
} }
@ -880,7 +856,7 @@ impl TryFrom<&Fetch> for Msg {
// don't. This condition hits, if the body isn't in a multipart, so we can // don't. This condition hits, if the body isn't in a multipart, so we can
// immediately fetch the body from the first part of the mail. // immediately fetch the body from the first part of the mail.
match parsed.ctype.mimetype.as_ref() { match parsed.ctype.mimetype.as_ref() {
"text/plain" => body.text = parsed.get_body().ok(), "text/plain" => body.plain = parsed.get_body().ok(),
"text/html" => body.html = parsed.get_body().ok(), "text/html" => body.html = parsed.get_body().ok(),
_ => (), _ => (),
}; };
@ -889,8 +865,8 @@ impl TryFrom<&Fetch> for Msg {
// now it might happen, that the body is *in* a multipart, if // now it might happen, that the body is *in* a multipart, if
// that's the case, look, if we've already applied a body // that's the case, look, if we've already applied a body
// (body.is_empty()) and set it, if needed // (body.is_empty()) and set it, if needed
if body.text.is_none() && subpart.ctype.mimetype == "text/plain" { if body.plain.is_none() && subpart.ctype.mimetype == "text/plain" {
body.text = subpart.get_body().ok(); body.plain = subpart.get_body().ok();
} else if body.html.is_none() && subpart.ctype.mimetype == "text/html" { } else if body.html.is_none() && subpart.ctype.mimetype == "text/html" {
body.html = subpart.get_body().ok(); body.html = subpart.get_body().ok();
} }
@ -918,6 +894,7 @@ impl TryFrom<&Fetch> for Msg {
uid, uid,
date, date,
raw, raw,
..Self::default()
}) })
} }
} }

View file

@ -3,26 +3,61 @@
//! This module provides subcommands, arguments and a command matcher related to message template. //! This module provides subcommands, arguments and a command matcher related to message template.
use anyhow::Result; use anyhow::Result;
use clap::{self, App, Arg, ArgMatches, SubCommand}; use clap::{self, App, AppSettings, Arg, ArgMatches, SubCommand, Values};
use log::debug; use log::debug;
use crate::domain::msg::{self, arg::uid_arg}; 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 Uid<'a> = &'a str;
type All = bool; type All = bool;
/// Message template commands. /// Message template commands.
pub enum Command<'a> { pub enum Command<'a> {
New, New(
Subject<'a>,
From<'a>,
To<'a>,
Cc<'a>,
Bcc<'a>,
Headers<'a>,
Body<'a>,
Signature<'a>,
),
Reply(Uid<'a>, All), Reply(Uid<'a>, All),
Forward(Uid<'a>), Forward(Uid<'a>),
} }
/// Message template command matcher. /// Message template command matcher.
pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> { pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
if let Some(_) = m.subcommand_matches("new") { if let Some(m) = m.subcommand_matches("new") {
debug!("new command matched"); debug!("new command matched");
return Ok(Some(Command::New)); 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,
)));
} }
if let Some(m) = m.subcommand_matches("reply") { if let Some(m) = m.subcommand_matches("reply") {
@ -100,6 +135,7 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
vec![SubCommand::with_name("template") vec![SubCommand::with_name("template")
.aliases(&["tpl"]) .aliases(&["tpl"])
.about("Generates a message template") .about("Generates a message template")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand( .subcommand(
SubCommand::with_name("new") SubCommand::with_name("new")
.aliases(&["n"]) .aliases(&["n"])

View file

@ -1,25 +1,42 @@
use std::convert::TryFrom; use std::{
collections::HashMap,
convert::TryFrom,
io::{self, BufRead},
};
use anyhow::Result; use anyhow::Result;
use log::trace; use atty::Stream;
use clap::Values;
use log::{debug, trace};
use crate::{ use crate::{
config::entity::Account, config::entity::Account,
domain::{ domain::{
imap::service::ImapServiceInterface, imap::service::ImapServiceInterface,
msg::entity::{Msg, MsgSerialized}, msg::{
body::Body,
entity::{Msg, MsgSerialized},
headers::Headers,
},
}, },
output::service::OutputServiceInterface, output::service::OutputServiceInterface,
}; };
pub fn new<OutputService: OutputServiceInterface, ImapService: ImapServiceInterface>( 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, account: &Account,
output: &OutputService, output: &OutputService,
imap: &mut ImapService, imap: &mut ImapService,
) -> Result<()> { ) -> Result<()> {
let msg = Msg::new(&account); let mut msg = Msg::new(&account);
// FIXME override_msg_with_args(&mut msg, subject, from, to, cc, bcc, headers, body, sig);
// override_msg_with_args(&mut msg, &matches);
trace!("message: {:#?}", msg); trace!("message: {:#?}", msg);
output.print(MsgSerialized::try_from(&msg)?)?; output.print(MsgSerialized::try_from(&msg)?)?;
imap.logout()?; imap.logout()?;
@ -62,89 +79,85 @@ pub fn forward<OutputService: OutputServiceInterface, ImapService: ImapServiceIn
// == Helper functions == // == Helper functions ==
// -- Template Subcommands -- // -- Template Subcommands --
// These functions are more used for the "template" subcommand // These functions are more used for the "template" subcommand
// fn override_msg_with_args(msg: &mut Msg) { fn override_msg_with_args<'a>(
// // -- Collecting credentials -- msg: &mut Msg,
// let from: Vec<String> = match matches.values_of("from") { subject: Option<&'a str>,
// Some(from) => from.map(|arg| arg.to_string()).collect(), from: Option<Values<'a>>,
// None => msg.headers.from.clone(), to: Option<Values<'a>>,
// }; cc: Option<Values<'a>>,
bcc: Option<Values<'a>>,
headers: Option<Values<'a>>,
body: Option<&'a str>,
sig: Option<&'a str>,
) {
// -- Collecting credentials --
let from: Vec<String> = match from {
Some(from) => from.map(|arg| arg.to_string()).collect(),
None => msg.headers.from.clone(),
};
// let to: Vec<String> = match matches.values_of("to") { let to: Vec<String> = match to {
// Some(to) => to.map(|arg| arg.to_string()).collect(), Some(to) => to.map(|arg| arg.to_string()).collect(),
// None => Vec::new(), None => Vec::new(),
// }; };
// let subject = matches let subject = subject.map(String::from);
// .value_of("subject") let cc: Option<Vec<String>> = cc.map(|cc| cc.map(|arg| arg.to_string()).collect());
// .and_then(|subject| Some(subject.to_string())); 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 cc: Option<Vec<String>> = matches let custom_headers: Option<HashMap<String, Vec<String>>> = {
// .values_of("cc") if let Some(matched_headers) = headers {
// .and_then(|cc| Some(cc.map(|arg| arg.to_string()).collect())); let mut custom_headers: HashMap<String, Vec<String>> = HashMap::new();
// let bcc: Option<Vec<String>> = matches // collect the custom headers
// .values_of("bcc") for header in matched_headers {
// .and_then(|bcc| Some(bcc.map(|arg| arg.to_string()).collect())); let mut header = header.split(":");
let key = header.next().unwrap_or_default();
let val = header.next().unwrap_or_default().trim_start();
// let signature = matches custom_headers.insert(key.to_string(), vec![val.to_string()]);
// .value_of("signature") }
// .and_then(|signature| Some(signature.to_string()))
// .or(msg.headers.signature.clone());
// let custom_headers: Option<HashMap<String, Vec<String>>> = { Some(custom_headers)
// if let Some(matched_headers) = matches.values_of("header") { } else {
// let mut custom_headers: HashMap<String, Vec<String>> = HashMap::new(); None
}
};
// // collect the custom headers let body = {
// for header in matched_headers { if atty::isnt(Stream::Stdin) {
// let mut header = header.split(":"); let body = io::stdin()
// let key = header.next().unwrap_or_default(); .lock()
// let val = header.next().unwrap_or_default().trim_start(); .lines()
.filter_map(|line| line.ok())
.map(|line| line.to_string())
.collect::<Vec<String>>()
.join("\n");
debug!("overriden body from stdin: {:?}", body);
body
} else if let Some(body) = body {
debug!("overriden body: {:?}", body);
body.to_string()
} else {
String::new()
}
};
// debug!("overriden header: {}={}", key, val); let body = Body::new_with_text(body);
// custom_headers.insert(key.to_string(), vec![val.to_string()]); // -- Creating and printing --
// } let headers = Headers {
from,
subject,
to,
cc,
bcc,
signature,
custom_headers,
..msg.headers.clone()
};
// Some(custom_headers) msg.headers = headers;
// } else { msg.body = body;
// None }
// }
// };
// let body = {
// if atty::isnt(Stream::Stdin) {
// let body = io::stdin()
// .lock()
// .lines()
// .filter_map(|line| line.ok())
// .map(|line| line.to_string())
// .collect::<Vec<String>>()
// .join("\n");
// debug!("overriden body from stdin: {:?}", body);
// body
// } else if let Some(body) = matches.value_of("body") {
// debug!("overriden body: {:?}", body);
// body.to_string()
// } else {
// String::new()
// }
// };
// let body = Body::new_with_text(body);
// // -- Creating and printing --
// let headers = Headers {
// from,
// subject,
// to,
// cc,
// bcc,
// signature,
// custom_headers,
// ..msg.headers.clone()
// };
// msg.headers = headers;
// msg.body = body;
// }

View file

@ -1,5 +1,5 @@
use anyhow::Result; use anyhow::Result;
use clap; use clap::{self, AppSettings};
use env_logger; use env_logger;
use std::{convert::TryFrom, env}; use std::{convert::TryFrom, env};
use url::Url; use url::Url;
@ -24,8 +24,10 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.about(env!("CARGO_PKG_DESCRIPTION")) .about(env!("CARGO_PKG_DESCRIPTION"))
.author(env!("CARGO_PKG_AUTHORS")) .author(env!("CARGO_PKG_AUTHORS"))
.args(&output::arg::args()) .setting(AppSettings::GlobalVersion)
.setting(AppSettings::SubcommandRequiredElseHelp)
.args(&config::arg::args()) .args(&config::arg::args())
.args(&output::arg::args())
.arg(mbox::arg::source_arg()) .arg(mbox::arg::source_arg())
.subcommands(compl::arg::subcmds()) .subcommands(compl::arg::subcmds())
.subcommands(imap::arg::subcmds()) .subcommands(imap::arg::subcmds())
@ -59,7 +61,7 @@ fn main() -> Result<()> {
// See https://github.com/soywod/himalaya/issues/115. // See https://github.com/soywod/himalaya/issues/115.
match compl::arg::matches(&m)? { match compl::arg::matches(&m)? {
Some(compl::arg::Command::Generate(shell)) => { Some(compl::arg::Command::Generate(shell)) => {
return compl::handler::generate(shell, create_app()); return compl::handler::generate(create_app(), shell);
} }
_ => (), _ => (),
} }
@ -84,7 +86,7 @@ fn main() -> Result<()> {
// Check mailbox matches. // Check mailbox matches.
match mbox::arg::matches(&m)? { match mbox::arg::matches(&m)? {
Some(mbox::arg::Commands::List) => { Some(mbox::arg::Command::List) => {
return mbox::handler::list(&output, &mut imap); return mbox::handler::list(&output, &mut imap);
} }
_ => (), _ => (),
@ -130,26 +132,30 @@ fn main() -> Result<()> {
} }
Some(msg::arg::Command::Flag(m)) => match m { Some(msg::arg::Command::Flag(m)) => match m {
msg::flag::arg::Command::Set(uid, flags) => { Some(msg::flag::arg::Command::Set(uid, flags)) => {
return msg::flag::handler::set(uid, flags, &mut imap); return msg::flag::handler::set(uid, flags, &mut imap);
} }
msg::flag::arg::Command::Add(uid, flags) => { Some(msg::flag::arg::Command::Add(uid, flags)) => {
return msg::flag::handler::add(uid, flags, &mut imap); return msg::flag::handler::add(uid, flags, &mut imap);
} }
msg::flag::arg::Command::Remove(uid, flags) => { Some(msg::flag::arg::Command::Remove(uid, flags)) => {
return msg::flag::handler::remove(uid, flags, &mut imap); return msg::flag::handler::remove(uid, flags, &mut imap);
} }
_ => (),
}, },
Some(msg::arg::Command::Tpl(m)) => match m { Some(msg::arg::Command::Tpl(m)) => match m {
msg::tpl::arg::Command::New => { Some(msg::tpl::arg::Command::New(sub, from, to, cc, bcc, h, body, sig)) => {
return msg::tpl::handler::new(&account, &output, &mut imap); return msg::tpl::handler::new(
sub, from, to, cc, bcc, h, body, sig, &account, &output, &mut imap,
);
} }
msg::tpl::arg::Command::Reply(uid, all) => { Some(msg::tpl::arg::Command::Reply(uid, all)) => {
return msg::tpl::handler::reply(uid, all, &account, &output, &mut imap); return msg::tpl::handler::reply(uid, all, &account, &output, &mut imap);
} }
msg::tpl::arg::Command::Forward(uid) => { Some(msg::tpl::arg::Command::Forward(uid)) => {
return msg::tpl::handler::forward(uid, &account, &output, &mut imap); return msg::tpl::handler::forward(uid, &account, &output, &mut imap);
} }
_ => (),
}, },
_ => (), _ => (),
} }