mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
fix new tpl sig
This commit is contained in:
parent
8e2a703e2b
commit
e065d8d905
|
@ -1,13 +1,13 @@
|
|||
//! 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 clap::{App, Shell};
|
||||
use std::{io, str::FromStr};
|
||||
|
||||
/// 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())
|
||||
.map_err(|err| anyhow!(err))
|
||||
.context("cannot parse shell")?;
|
||||
|
|
|
@ -183,60 +183,6 @@ impl Config {
|
|||
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<()> {
|
||||
let cmds = account
|
||||
.watch_cmds
|
||||
|
@ -551,10 +497,10 @@ impl<'a> TryFrom<(&'a Config, Option<&str>)> for Account {
|
|||
.or_else(|| config.signature.as_ref());
|
||||
let signature = signature
|
||||
.and_then(|sig| shellexpand::full(sig).ok())
|
||||
.map(|sig| sig.to_string())
|
||||
.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))
|
||||
.map(|sig| format!("\n{}{}", signature_delim, sig.trim_end()))
|
||||
.unwrap_or_default();
|
||||
|
||||
let account = Account {
|
||||
|
|
|
@ -7,16 +7,16 @@ use clap::{App, Arg, ArgMatches, SubCommand};
|
|||
use log::debug;
|
||||
|
||||
/// Mailbox commands.
|
||||
pub enum Commands {
|
||||
pub enum Command {
|
||||
/// List all available mailboxes.
|
||||
List,
|
||||
}
|
||||
|
||||
/// 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") {
|
||||
debug!("mailboxes command matched");
|
||||
return Ok(Some(Commands::List));
|
||||
return Ok(Some(Command::List));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
|
|
@ -34,8 +34,8 @@ pub enum Command<'a> {
|
|||
Send(RawMsg<'a>),
|
||||
Write(AttachmentsPaths<'a>),
|
||||
|
||||
Flag(msg::flag::arg::Command<'a>),
|
||||
Tpl(msg::tpl::arg::Command<'a>),
|
||||
Flag(Option<msg::flag::arg::Command<'a>>),
|
||||
Tpl(Option<msg::tpl::arg::Command<'a>>),
|
||||
}
|
||||
|
||||
/// Message command matcher.
|
||||
|
@ -63,10 +63,6 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Command<'a>>> {
|
|||
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") {
|
||||
debug!("forward command matched");
|
||||
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)));
|
||||
}
|
||||
|
||||
if let Some(m) = msg::tpl::arg::matches(&m)? {
|
||||
return Ok(Some(Command::Tpl(m)));
|
||||
}
|
||||
|
||||
if let Some(m) = m.subcommand_matches("write") {
|
||||
debug!("write command matched");
|
||||
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)));
|
||||
}
|
||||
|
||||
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");
|
||||
Ok(Some(Command::List(None, 0)))
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ use std::fmt;
|
|||
/// This part of the msg/msg would be stored in this struct.
|
||||
#[derive(Clone, Serialize, Debug, PartialEq, Eq)]
|
||||
pub struct Body {
|
||||
/// The text version of a body (if available)
|
||||
pub text: Option<String>,
|
||||
/// The plain version of a body (if available)
|
||||
pub plain: Option<String>,
|
||||
|
||||
/// The html version of a body (if available)
|
||||
pub html: Option<String>,
|
||||
|
@ -61,7 +61,7 @@ impl Body {
|
|||
/// ```
|
||||
pub fn new_with_text<S: ToString>(text: S) -> Self {
|
||||
Self {
|
||||
text: Some(text.to_string()),
|
||||
plain: Some(text.to_string()),
|
||||
html: None,
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ impl Body {
|
|||
/// ```
|
||||
pub fn new_with_html<S: ToString>(html: S) -> Self {
|
||||
Self {
|
||||
text: None,
|
||||
plain: None,
|
||||
html: Some(html.to_string()),
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ impl Body {
|
|||
/// ```
|
||||
pub fn new_with_both<S: ToString>(text: S, html: S) -> Self {
|
||||
Self {
|
||||
text: Some(text.to_string()),
|
||||
plain: Some(text.to_string()),
|
||||
html: Some(html.to_string()),
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl Body {
|
|||
impl Default for Body {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
text: None,
|
||||
plain: None,
|
||||
html: None,
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ impl Default for Body {
|
|||
|
||||
impl fmt::Display for Body {
|
||||
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
|
||||
} else if let Some(html) = self.html.clone() {
|
||||
html
|
||||
|
|
|
@ -16,8 +16,7 @@ use crate::ui::editor;
|
|||
use serde::Serialize;
|
||||
|
||||
use lettre::message::{
|
||||
header::ContentTransferEncoding, header::ContentType, Attachment as lettre_Attachment, Mailbox,
|
||||
Message, MultiPart, SinglePart,
|
||||
header::ContentType, Attachment as lettre_Attachment, Mailbox, Message, MultiPart, SinglePart,
|
||||
};
|
||||
|
||||
use std::{
|
||||
|
@ -64,7 +63,7 @@ impl fmt::Display for MsgSerialized {
|
|||
|
||||
/// This struct represents a whole msg with its attachments, body-content
|
||||
/// and its headers.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct Msg {
|
||||
/// All added attachments are listed in this vector.
|
||||
pub attachments: Vec<Attachment>,
|
||||
|
@ -80,6 +79,9 @@ pub struct Msg {
|
|||
/// This includes the general content text and the signature.
|
||||
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
|
||||
/// new message, then we're generating it.
|
||||
uid: Option<u32>,
|
||||
|
@ -167,11 +169,6 @@ impl Msg {
|
|||
if headers.from.is_empty() {
|
||||
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() {
|
||||
format!("\n{}", sig)
|
||||
} else {
|
||||
|
@ -181,6 +178,7 @@ impl Msg {
|
|||
Self {
|
||||
headers,
|
||||
body,
|
||||
sig: account.signature.to_owned(),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +278,7 @@ impl Msg {
|
|||
// each line which includes a string.
|
||||
let mut new_body = self
|
||||
.body
|
||||
.text
|
||||
.plain
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.lines()
|
||||
|
@ -354,7 +352,11 @@ impl Msg {
|
|||
// apply a line which should indicate where the forwarded message begins
|
||||
body.push_str(&format!(
|
||||
"\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);
|
||||
|
@ -685,16 +687,16 @@ impl Msg {
|
|||
let mut msg_parts = MultiPart::mixed().build();
|
||||
|
||||
// -- 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(
|
||||
self.body.text.clone().unwrap(),
|
||||
self.body.plain.clone().unwrap(),
|
||||
self.body.html.clone().unwrap(),
|
||||
));
|
||||
} else {
|
||||
let msg_body = SinglePart::builder()
|
||||
.header(ContentType::TEXT_PLAIN)
|
||||
.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);
|
||||
}
|
||||
|
@ -740,42 +742,16 @@ impl Msg {
|
|||
|
||||
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 {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
formatter,
|
||||
"{}\n{}",
|
||||
"{}\n{}{}",
|
||||
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
|
||||
// immediately fetch the body from the first part of the mail.
|
||||
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(),
|
||||
_ => (),
|
||||
};
|
||||
|
@ -889,8 +865,8 @@ impl TryFrom<&Fetch> for Msg {
|
|||
// now it might happen, that the body is *in* a multipart, if
|
||||
// that's the case, look, if we've already applied a body
|
||||
// (body.is_empty()) and set it, if needed
|
||||
if body.text.is_none() && subpart.ctype.mimetype == "text/plain" {
|
||||
body.text = subpart.get_body().ok();
|
||||
if body.plain.is_none() && subpart.ctype.mimetype == "text/plain" {
|
||||
body.plain = subpart.get_body().ok();
|
||||
} else if body.html.is_none() && subpart.ctype.mimetype == "text/html" {
|
||||
body.html = subpart.get_body().ok();
|
||||
}
|
||||
|
@ -918,6 +894,7 @@ impl TryFrom<&Fetch> for Msg {
|
|||
uid,
|
||||
date,
|
||||
raw,
|
||||
..Self::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,26 +3,61 @@
|
|||
//! This module provides subcommands, arguments and a command matcher related to message template.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
||||
use clap::{self, App, AppSettings, Arg, ArgMatches, SubCommand, Values};
|
||||
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;
|
||||
|
||||
/// Message template commands.
|
||||
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),
|
||||
Forward(Uid<'a>),
|
||||
}
|
||||
|
||||
/// Message template command matcher.
|
||||
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");
|
||||
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") {
|
||||
|
@ -100,6 +135,7 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
|||
vec![SubCommand::with_name("template")
|
||||
.aliases(&["tpl"])
|
||||
.about("Generates a message template")
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommand(
|
||||
SubCommand::with_name("new")
|
||||
.aliases(&["n"])
|
||||
|
|
|
@ -1,25 +1,42 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::TryFrom,
|
||||
io::{self, BufRead},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use log::trace;
|
||||
use atty::Stream;
|
||||
use clap::Values;
|
||||
use log::{debug, trace};
|
||||
|
||||
use crate::{
|
||||
config::entity::Account,
|
||||
domain::{
|
||||
imap::service::ImapServiceInterface,
|
||||
msg::entity::{Msg, MsgSerialized},
|
||||
msg::{
|
||||
body::Body,
|
||||
entity::{Msg, MsgSerialized},
|
||||
headers::Headers,
|
||||
},
|
||||
},
|
||||
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,
|
||||
output: &OutputService,
|
||||
imap: &mut ImapService,
|
||||
) -> Result<()> {
|
||||
let msg = Msg::new(&account);
|
||||
// FIXME
|
||||
// override_msg_with_args(&mut msg, &matches);
|
||||
let mut msg = Msg::new(&account);
|
||||
override_msg_with_args(&mut msg, subject, from, to, cc, bcc, headers, body, sig);
|
||||
trace!("message: {:#?}", msg);
|
||||
output.print(MsgSerialized::try_from(&msg)?)?;
|
||||
imap.logout()?;
|
||||
|
@ -62,89 +79,85 @@ 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(msg: &mut Msg) {
|
||||
// // -- Collecting credentials --
|
||||
// let from: Vec<String> = match matches.values_of("from") {
|
||||
// Some(from) => from.map(|arg| arg.to_string()).collect(),
|
||||
// None => msg.headers.from.clone(),
|
||||
// };
|
||||
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>,
|
||||
) {
|
||||
// -- 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") {
|
||||
// Some(to) => to.map(|arg| arg.to_string()).collect(),
|
||||
// None => Vec::new(),
|
||||
// };
|
||||
let to: Vec<String> = match to {
|
||||
Some(to) => to.map(|arg| arg.to_string()).collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
|
||||
// let subject = matches
|
||||
// .value_of("subject")
|
||||
// .and_then(|subject| Some(subject.to_string()));
|
||||
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 cc: Option<Vec<String>> = matches
|
||||
// .values_of("cc")
|
||||
// .and_then(|cc| Some(cc.map(|arg| arg.to_string()).collect()));
|
||||
let custom_headers: Option<HashMap<String, Vec<String>>> = {
|
||||
if let Some(matched_headers) = headers {
|
||||
let mut custom_headers: HashMap<String, Vec<String>> = HashMap::new();
|
||||
|
||||
// let bcc: Option<Vec<String>> = matches
|
||||
// .values_of("bcc")
|
||||
// .and_then(|bcc| Some(bcc.map(|arg| arg.to_string()).collect()));
|
||||
// collect the custom headers
|
||||
for header in matched_headers {
|
||||
let mut header = header.split(":");
|
||||
let key = header.next().unwrap_or_default();
|
||||
let val = header.next().unwrap_or_default().trim_start();
|
||||
|
||||
// let signature = matches
|
||||
// .value_of("signature")
|
||||
// .and_then(|signature| Some(signature.to_string()))
|
||||
// .or(msg.headers.signature.clone());
|
||||
custom_headers.insert(key.to_string(), vec![val.to_string()]);
|
||||
}
|
||||
|
||||
// let custom_headers: Option<HashMap<String, Vec<String>>> = {
|
||||
// if let Some(matched_headers) = matches.values_of("header") {
|
||||
// let mut custom_headers: HashMap<String, Vec<String>> = HashMap::new();
|
||||
Some(custom_headers)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// // collect the custom headers
|
||||
// for header in matched_headers {
|
||||
// let mut header = header.split(":");
|
||||
// let key = header.next().unwrap_or_default();
|
||||
// let val = header.next().unwrap_or_default().trim_start();
|
||||
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) = 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)
|
||||
// } else {
|
||||
// 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;
|
||||
// }
|
||||
msg.headers = headers;
|
||||
msg.body = body;
|
||||
}
|
||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use clap;
|
||||
use clap::{self, AppSettings};
|
||||
use env_logger;
|
||||
use std::{convert::TryFrom, env};
|
||||
use url::Url;
|
||||
|
@ -24,8 +24,10 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
|
|||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
.args(&output::arg::args())
|
||||
.setting(AppSettings::GlobalVersion)
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.args(&config::arg::args())
|
||||
.args(&output::arg::args())
|
||||
.arg(mbox::arg::source_arg())
|
||||
.subcommands(compl::arg::subcmds())
|
||||
.subcommands(imap::arg::subcmds())
|
||||
|
@ -59,7 +61,7 @@ fn main() -> Result<()> {
|
|||
// See https://github.com/soywod/himalaya/issues/115.
|
||||
match compl::arg::matches(&m)? {
|
||||
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.
|
||||
match mbox::arg::matches(&m)? {
|
||||
Some(mbox::arg::Commands::List) => {
|
||||
Some(mbox::arg::Command::List) => {
|
||||
return mbox::handler::list(&output, &mut imap);
|
||||
}
|
||||
_ => (),
|
||||
|
@ -130,26 +132,30 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
msg::flag::arg::Command::Add(uid, flags) => {
|
||||
Some(msg::flag::arg::Command::Add(uid, flags)) => {
|
||||
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);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Some(msg::arg::Command::Tpl(m)) => match m {
|
||||
msg::tpl::arg::Command::New => {
|
||||
return msg::tpl::handler::new(&account, &output, &mut imap);
|
||||
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,
|
||||
);
|
||||
}
|
||||
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);
|
||||
}
|
||||
msg::tpl::arg::Command::Forward(uid) => {
|
||||
Some(msg::tpl::arg::Command::Forward(uid)) => {
|
||||
return msg::tpl::handler::forward(uid, &account, &output, &mut imap);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue