mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 02:50:19 +00:00
use env_logger for plain output fmt (#126)
This commit is contained in:
parent
477b7748de
commit
15c635eb1d
16 changed files with 318 additions and 228 deletions
|
@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Custom config path [#86]
|
||||
- Setting idle-hook-cmds
|
||||
|
||||
### Changed
|
||||
|
||||
- Plain logger with `env_logger` [#126]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Improve config compatibility on Windows [#111](https://github.com/soywod/himalaya/pull/111)
|
||||
|
@ -193,3 +197,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#89]: https://github.com/soywod/himalaya/issues/89
|
||||
[#96]: https://github.com/soywod/himalaya/issues/96
|
||||
[#100]: https://github.com/soywod/himalaya/issues/100
|
||||
[#126]: https://github.com/soywod/himalaya/issues/126
|
||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -308,6 +308,7 @@ dependencies = [
|
|||
name = "himalaya"
|
||||
version = "0.2.6"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"error-chain",
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
[package]
|
||||
name = "himalaya"
|
||||
description = "📫 Minimalist CLI email client"
|
||||
description = "📫 The CLI email client."
|
||||
version = "0.2.6"
|
||||
authors = ["soywod <clement.douin@posteo.net>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.19"
|
||||
clap = {version = "2.33.3", default-features = false, features = ["suggestions"]}
|
||||
env_logger = "0.8.3"
|
||||
error-chain = "0.12.4"
|
||||
|
|
|
@ -15,17 +15,17 @@ pub fn comp_subcmds<'s>() -> Vec<App<'s, 's>> {
|
|||
|
||||
pub fn comp_matches(mut app: App, matches: &ArgMatches) -> Result<bool> {
|
||||
if let Some(matches) = matches.subcommand_matches("completion") {
|
||||
debug!("[comp::cli::matches] completion command matched");
|
||||
debug!("completion command matched");
|
||||
let shell = match matches.value_of("shell").unwrap() {
|
||||
"fish" => Shell::Fish,
|
||||
"zsh" => Shell::Zsh,
|
||||
"bash" | _ => Shell::Bash,
|
||||
};
|
||||
debug!("[comp::cli::matches] shell: {}", shell);
|
||||
debug!("shell: {}", shell);
|
||||
app.gen_completions_to("himalaya", shell, &mut io::stdout());
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
debug!("[comp::cli::matches] nothing matched");
|
||||
debug!("nothing matched");
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ pub struct Account {
|
|||
|
||||
impl Account {
|
||||
pub fn imap_addr(&self) -> (&str, u16) {
|
||||
debug!("host: {}", self.imap_host);
|
||||
debug!("port: {}", self.imap_port);
|
||||
(&self.imap_host, self.imap_port)
|
||||
}
|
||||
|
||||
|
@ -56,17 +58,23 @@ impl Account {
|
|||
}
|
||||
|
||||
pub fn imap_starttls(&self) -> bool {
|
||||
match self.imap_starttls {
|
||||
let starttls = match self.imap_starttls {
|
||||
Some(true) => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
debug!("STARTTLS: {}", starttls);
|
||||
starttls
|
||||
}
|
||||
|
||||
pub fn imap_insecure(&self) -> bool {
|
||||
match self.imap_insecure {
|
||||
let insecure = match self.imap_insecure {
|
||||
Some(true) => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
debug!("insecure: {}", insecure);
|
||||
insecure
|
||||
}
|
||||
|
||||
pub fn smtp_creds(&self) -> Result<SmtpCredentials> {
|
||||
|
|
|
@ -48,13 +48,13 @@ pub fn flag_subcmds<'s>() -> Vec<App<'s, 's>> {
|
|||
|
||||
pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Result<bool> {
|
||||
if let Some(matches) = matches.subcommand_matches("set") {
|
||||
debug!("[flag::cli::matches] set command matched");
|
||||
debug!("set command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[flag::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
|
||||
let flags = matches.value_of("flags").unwrap();
|
||||
debug!("[flag::cli::matches] flags: {}", flags);
|
||||
debug!("flags: {}", flags);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
imap_conn.set_flags(mbox, uid, flags)?;
|
||||
|
@ -64,13 +64,13 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("add") {
|
||||
debug!("[flag::cli::matches] add command matched");
|
||||
debug!("add command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[flag::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
|
||||
let flags = matches.value_of("flags").unwrap();
|
||||
debug!("[flag::cli::matches] flags: {}", flags);
|
||||
debug!("flags: {}", flags);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
imap_conn.add_flags(mbox, uid, flags)?;
|
||||
|
@ -80,13 +80,13 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("remove") {
|
||||
debug!("[flag::cli::matches] remove command matched");
|
||||
debug!("remove command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[flag::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
|
||||
let flags = matches.value_of("flags").unwrap();
|
||||
debug!("[flag::cli::matches] flags: {}", flags);
|
||||
debug!("flags: {}", flags);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
imap_conn.remove_flags(mbox, uid, flags)?;
|
||||
|
@ -95,6 +95,6 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
|||
return Ok(true);
|
||||
}
|
||||
|
||||
debug!("[flag::cli::matches] nothing matched");
|
||||
debug!("nothing matched");
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@ pub fn imap_matches(
|
|||
matches: &ArgMatches,
|
||||
) -> Result<bool> {
|
||||
if let Some(_) = matches.subcommand_matches("idle") {
|
||||
debug!("[imap::cli::matches] idle command matched");
|
||||
debug!("idle command matched");
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
imap_conn.idle(&config, &mbox)?;
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
debug!("[imap::cli::matches] nothing matched");
|
||||
debug!("nothing matched");
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -25,12 +25,15 @@ pub struct ImapConnector<'a> {
|
|||
|
||||
impl<'ic> ImapConnector<'ic> {
|
||||
pub fn new(account: &'ic Account) -> Result<Self> {
|
||||
debug!("create TLS builder");
|
||||
let insecure = account.imap_insecure();
|
||||
let tls = TlsConnector::builder()
|
||||
.danger_accept_invalid_certs(account.imap_insecure())
|
||||
.danger_accept_invalid_hostnames(account.imap_insecure())
|
||||
.danger_accept_invalid_certs(insecure)
|
||||
.danger_accept_invalid_hostnames(insecure)
|
||||
.build()
|
||||
.chain_err(|| "Cannot create TLS connector")?;
|
||||
|
||||
debug!("create client");
|
||||
let client = if account.imap_starttls() {
|
||||
imap::connect_starttls(account.imap_addr(), &account.imap_host, &tls)
|
||||
.chain_err(|| "Cannot connect using STARTTLS")
|
||||
|
@ -39,6 +42,7 @@ impl<'ic> ImapConnector<'ic> {
|
|||
.chain_err(|| "Cannot connect using TLS")
|
||||
}?;
|
||||
|
||||
debug!("create session");
|
||||
let sess = client
|
||||
.login(&account.imap_login, &account.imap_passwd()?)
|
||||
.map_err(|res| res.0)
|
||||
|
@ -48,6 +52,7 @@ impl<'ic> ImapConnector<'ic> {
|
|||
}
|
||||
|
||||
pub fn logout(&mut self) {
|
||||
debug!("logout");
|
||||
match self.sess.logout() {
|
||||
_ => (),
|
||||
}
|
||||
|
@ -108,19 +113,19 @@ impl<'ic> ImapConnector<'ic> {
|
|||
}
|
||||
|
||||
pub fn idle(&mut self, config: &Config, mbox: &str) -> Result<()> {
|
||||
debug!("[imap::model::idle] begin");
|
||||
debug!("begin");
|
||||
|
||||
debug!("[imap::model::idle] examine mailbox {}", mbox);
|
||||
debug!("examine mailbox {}", mbox);
|
||||
self.sess
|
||||
.examine(mbox)
|
||||
.chain_err(|| format!("Could not examine mailbox `{}`", mbox))?;
|
||||
|
||||
debug!("[imap::model::idle] init message hashset");
|
||||
debug!("init message hashset");
|
||||
let mut msg_set: HashSet<u32> = HashSet::from_iter(self.search_new_msgs()?.iter().cloned());
|
||||
trace!("[imap::model::idle] {:?}", msg_set);
|
||||
trace!("{:?}", msg_set);
|
||||
|
||||
loop {
|
||||
debug!("[imap::model::idle] begin loop");
|
||||
debug!("begin loop");
|
||||
|
||||
self.sess
|
||||
.idle()
|
||||
|
@ -132,11 +137,8 @@ impl<'ic> ImapConnector<'ic> {
|
|||
.into_iter()
|
||||
.filter(|seq| msg_set.get(&seq).is_none())
|
||||
.collect();
|
||||
debug!(
|
||||
"[imap::model::idle] found {} new messages not in hashset",
|
||||
new_msgs.len()
|
||||
);
|
||||
trace!("[imap::model::idle] {:?}", new_msgs);
|
||||
debug!("found {} new messages not in hashset", new_msgs.len());
|
||||
trace!("messages: {:?}", new_msgs);
|
||||
|
||||
if !new_msgs.is_empty() {
|
||||
let new_msgs = new_msgs
|
||||
|
@ -152,20 +154,17 @@ impl<'ic> ImapConnector<'ic> {
|
|||
for fetch in fetches.iter() {
|
||||
let msg = Msg::from(fetch);
|
||||
config.run_notify_cmd(&msg.subject, &msg.sender)?;
|
||||
debug!("[imap::model::idle] notify message {}", fetch.message);
|
||||
trace!("[imap::model::idle] {:?}", msg);
|
||||
debug!("notify message {}", fetch.message);
|
||||
trace!("message: {:?}", msg);
|
||||
|
||||
debug!(
|
||||
"[imap::model::idle] insert msg {} to hashset",
|
||||
fetch.message
|
||||
);
|
||||
debug!("insert msg {} to hashset", fetch.message);
|
||||
msg_set.insert(fetch.message);
|
||||
trace!("[imap::model::idle] {:?}", msg_set);
|
||||
trace!("messages: {:?}", msg_set);
|
||||
}
|
||||
}
|
||||
|
||||
config.exec_idle_hooks()?;
|
||||
debug!("[imap::model::idle] end loop");
|
||||
debug!("end loop");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
src/main.rs
24
src/main.rs
|
@ -60,30 +60,32 @@ fn run() -> Result<()> {
|
|||
let matches = app.get_matches();
|
||||
|
||||
let output_fmt: OutputFmt = matches.value_of("output").unwrap().into();
|
||||
let log_level: LogLevel = matches.value_of("log").unwrap().into();
|
||||
let custom_config: Option<PathBuf> = matches.value_of("config").map(|s| s.into());
|
||||
let log_level: LogLevel = matches.value_of("log-level").unwrap().into();
|
||||
init_logger(&output_fmt, &log_level)?;
|
||||
debug!("[main] output format: {}", output_fmt);
|
||||
debug!("[main] log level: {}", log_level);
|
||||
debug!("[main] custom config path: {:?}", custom_config);
|
||||
debug!("output format: {}", output_fmt);
|
||||
debug!("log level: {}", log_level);
|
||||
|
||||
// Check completion matches before the config init
|
||||
if comp_matches(build_app(), &matches)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
debug!("[main] init config");
|
||||
let custom_config: Option<PathBuf> = matches.value_of("config").map(|s| s.into());
|
||||
debug!("custom config path: {:?}", custom_config);
|
||||
|
||||
debug!("init config");
|
||||
let config = Config::new(custom_config)?;
|
||||
trace!("[main] {:#?}", config);
|
||||
trace!("config: {:?}", config);
|
||||
|
||||
let account_name = matches.value_of("account");
|
||||
debug!("[main] find {} account", account_name.unwrap_or("default"));
|
||||
debug!("init account: {}", account_name.unwrap_or("default"));
|
||||
let account = config.find_account_by_name(account_name)?;
|
||||
trace!("[main] {:#?}", account);
|
||||
trace!("account: {:?}", account);
|
||||
|
||||
let mbox = matches.value_of("mailbox").unwrap();
|
||||
debug!("[main] mailbox: {}", mbox);
|
||||
debug!("mailbox: {}", mbox);
|
||||
|
||||
debug!("[main] begin matching");
|
||||
debug!("begin matching");
|
||||
let _matched = mbox_matches(&account, &matches)?
|
||||
|| flag_matches(&account, &mbox, &matches)?
|
||||
|| imap_matches(&config, &account, &mbox, &matches)?
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
||||
use error_chain::error_chain;
|
||||
use log::{debug, trace};
|
||||
use log::{debug, info, trace};
|
||||
|
||||
use crate::{config::model::Account, imap::model::ImapConnector, info};
|
||||
use crate::{config::model::Account, imap::model::ImapConnector};
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
|
@ -36,17 +36,17 @@ pub fn mbox_subcmds<'s>() -> Vec<App<'s, 's>> {
|
|||
|
||||
pub fn mbox_matches(account: &Account, matches: &ArgMatches) -> Result<bool> {
|
||||
if let Some(_) = matches.subcommand_matches("mailboxes") {
|
||||
debug!("[mbox::cli::matches] mailboxes command matched");
|
||||
debug!("mailboxes command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let mboxes = imap_conn.list_mboxes()?;
|
||||
info!(&mboxes);
|
||||
trace!("[mbox::cli::matches] {:#?}", mboxes);
|
||||
info!("{}", mboxes);
|
||||
trace!("mailboxes: {:?}", mboxes);
|
||||
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
debug!("[mbox::cli::matches] nothing matched");
|
||||
debug!("nothing matched");
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ use imap;
|
|||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
use crate::table::{self, DisplayRow, DisplayTable};
|
||||
use crate::{
|
||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
||||
table::{self, DisplayRow, DisplayTable},
|
||||
};
|
||||
|
||||
// Mbox
|
||||
|
||||
|
@ -58,6 +61,16 @@ impl<'a> DisplayTable<'a, Mbox> for Mboxes {
|
|||
|
||||
impl fmt::Display for Mboxes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\n{}", self.to_table())
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "\n{}", self.to_table())
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
216
src/msg/cli.rs
216
src/msg/cli.rs
|
@ -1,13 +1,13 @@
|
|||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
||||
use error_chain::error_chain;
|
||||
use log::{debug, error, trace};
|
||||
use log::{debug, error, info, trace};
|
||||
use std::{fs, ops::Deref};
|
||||
|
||||
use crate::{
|
||||
config::model::{Account, Config},
|
||||
flag::model::Flag,
|
||||
imap::model::ImapConnector,
|
||||
info, input,
|
||||
input,
|
||||
mbox::cli::mbox_target_arg,
|
||||
msg::model::{Attachments, Msg, Msgs, ReadableMsg},
|
||||
smtp,
|
||||
|
@ -173,44 +173,44 @@ pub fn msg_matches(
|
|||
matches: &ArgMatches,
|
||||
) -> Result<bool> {
|
||||
if let Some(matches) = matches.subcommand_matches("list") {
|
||||
debug!("[msg::cli::matches] list command matched");
|
||||
debug!("list command matched");
|
||||
|
||||
let page_size: usize = matches
|
||||
.value_of("page-size")
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(config.default_page_size(&account));
|
||||
debug!("[msg::cli::matches] page size: {}", &page_size);
|
||||
debug!("page size: {}", &page_size);
|
||||
let page: usize = matches
|
||||
.value_of("page")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap_or_default();
|
||||
debug!("[msg::cli::matches] page: {}", &page);
|
||||
debug!("page: {}", &page);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msgs = imap_conn.list_msgs(&mbox, &page_size, &page)?;
|
||||
let msgs = Msgs::from(&msgs);
|
||||
info!(&msgs);
|
||||
trace!("[msg::cli::matches] {:#?}", msgs);
|
||||
info!("{}", msgs);
|
||||
trace!("messages: {:?}", msgs);
|
||||
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("search") {
|
||||
debug!("[msg::cli::matches] search command matched");
|
||||
debug!("search command matched");
|
||||
|
||||
let page_size: usize = matches
|
||||
.value_of("page-size")
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(config.default_page_size(&account));
|
||||
debug!("[msg::cli::matches] page size: {}", &page_size);
|
||||
debug!("page size: {}", &page_size);
|
||||
let page: usize = matches
|
||||
.value_of("page")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap_or_default();
|
||||
debug!("[msg::cli::matches] page: {}", &page);
|
||||
debug!("page: {}", &page);
|
||||
|
||||
let query = matches
|
||||
.values_of("query")
|
||||
|
@ -236,27 +236,27 @@ pub fn msg_matches(
|
|||
})
|
||||
.1
|
||||
.join(" ");
|
||||
debug!("[msg::cli::matches] query: {}", &page);
|
||||
debug!("query: {}", &page);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?;
|
||||
let msgs = Msgs::from(&msgs);
|
||||
info!(&msgs);
|
||||
trace!("[msg::cli::matches] {:#?}", msgs);
|
||||
info!("{}", msgs);
|
||||
trace!("messages: {:?}", msgs);
|
||||
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("read") {
|
||||
debug!("[msg::cli::matches] read command matched");
|
||||
debug!("read command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
let mime = format!("text/{}", matches.value_of("mime-type").unwrap());
|
||||
debug!("[msg::cli::matches] mime: {}", mime);
|
||||
debug!("mime: {}", mime);
|
||||
let raw = matches.is_present("raw");
|
||||
debug!("[msg::cli::matches] raw: {}", raw);
|
||||
debug!("raw: {}", raw);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = imap_conn.read_msg(&mbox, &uid)?;
|
||||
|
@ -264,10 +264,10 @@ pub fn msg_matches(
|
|||
let msg = String::from_utf8(msg)
|
||||
.chain_err(|| "Could not decode raw message as utf8 string")?;
|
||||
let msg = msg.trim_end_matches("\n");
|
||||
info!(&msg);
|
||||
info!("{}", msg);
|
||||
} else {
|
||||
let msg = ReadableMsg::from_bytes(&mime, &msg)?;
|
||||
info!(&msg);
|
||||
info!("{}", msg);
|
||||
}
|
||||
|
||||
imap_conn.logout();
|
||||
|
@ -275,36 +275,36 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("attachments") {
|
||||
debug!("[msg::cli::matches] attachments command matched");
|
||||
debug!("attachments command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", &uid);
|
||||
debug!("uid: {}", &uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = imap_conn.read_msg(&mbox, &uid)?;
|
||||
let attachments = Attachments::from_bytes(&msg)?;
|
||||
debug!(
|
||||
"[msg::cli::matches] {} attachment(s) found for message {}",
|
||||
"{} attachment(s) found for message {}",
|
||||
&attachments.0.len(),
|
||||
&uid
|
||||
);
|
||||
for attachment in attachments.0.iter() {
|
||||
let filepath = config.downloads_filepath(&account, &attachment.filename);
|
||||
debug!("[msg::cli::matches] downloading {}…", &attachment.filename);
|
||||
debug!("downloading {}…", &attachment.filename);
|
||||
fs::write(&filepath, &attachment.raw)
|
||||
.chain_err(|| format!("Could not save attachment {:?}", filepath))?;
|
||||
}
|
||||
info!(&format!(
|
||||
info!(
|
||||
"{} attachment(s) successfully downloaded",
|
||||
&attachments.0.len()
|
||||
));
|
||||
);
|
||||
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("write") {
|
||||
debug!("[msg::cli::matches] write command matched");
|
||||
debug!("write command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let attachments = matches
|
||||
|
@ -321,7 +321,7 @@ pub fn msg_matches(
|
|||
match input::post_edit_choice() {
|
||||
Ok(choice) => match choice {
|
||||
input::PostEditChoice::Send => {
|
||||
debug!("[msg::cli::matches] sending message…");
|
||||
debug!("sending message…");
|
||||
let msg = msg.to_sendable_msg()?;
|
||||
smtp::send(&account, &msg)?;
|
||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||
|
@ -335,7 +335,7 @@ pub fn msg_matches(
|
|||
}
|
||||
input::PostEditChoice::LocalDraft => break,
|
||||
input::PostEditChoice::RemoteDraft => {
|
||||
debug!("[msg::cli::matches] saving to draft…");
|
||||
debug!("saving to draft…");
|
||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||
input::remove_draft()?;
|
||||
info!("Message successfully saved to Drafts");
|
||||
|
@ -353,68 +353,18 @@ pub fn msg_matches(
|
|||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("template") {
|
||||
debug!("[msg::cli::matches] template command matched");
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("new") {
|
||||
debug!("[msg::cli::matches] new command matched");
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
info!(&tpl);
|
||||
trace!("[msg::cli::matches] tpl: {:#?}", tpl);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
debug!("[msg::cli::matches] reply command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
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)?
|
||||
};
|
||||
info!(&tpl);
|
||||
trace!("[msg::cli::matches] tpl: {:#?}", tpl);
|
||||
|
||||
imap_conn.logout();
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||
debug!("[msg::cli::matches] forward command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
info!(&tpl);
|
||||
trace!("[msg::cli::matches] tpl: {:#?}", tpl);
|
||||
|
||||
imap_conn.logout();
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
debug!("[msg::cli::matches] reply command matched");
|
||||
debug!("reply command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
let attachments = matches
|
||||
.values_of("attachments")
|
||||
.unwrap_or_default()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
debug!(
|
||||
"[msg::cli::matches] found {} attachments",
|
||||
attachments.len()
|
||||
);
|
||||
trace!("[msg::cli::matches] {:#?}", attachments);
|
||||
debug!("found {} attachments", attachments.len());
|
||||
trace!("attachments: {:?}", attachments);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
|
@ -432,7 +382,7 @@ pub fn msg_matches(
|
|||
match input::post_edit_choice() {
|
||||
Ok(choice) => match choice {
|
||||
input::PostEditChoice::Send => {
|
||||
debug!("[msg::cli::matches] sending message…");
|
||||
debug!("sending message…");
|
||||
let msg = msg.to_sendable_msg()?;
|
||||
smtp::send(&account, &msg)?;
|
||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||
|
@ -447,7 +397,7 @@ pub fn msg_matches(
|
|||
}
|
||||
input::PostEditChoice::LocalDraft => break,
|
||||
input::PostEditChoice::RemoteDraft => {
|
||||
debug!("[msg::cli::matches] saving to draft…");
|
||||
debug!("saving to draft…");
|
||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||
input::remove_draft()?;
|
||||
info!("Message successfully saved to Drafts");
|
||||
|
@ -467,20 +417,17 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||
debug!("[msg::cli::matches] forward command matched");
|
||||
debug!("forward command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", uid);
|
||||
debug!("uid: {}", uid);
|
||||
let attachments = matches
|
||||
.values_of("attachments")
|
||||
.unwrap_or_default()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
debug!(
|
||||
"[msg::cli::matches] found {} attachments",
|
||||
attachments.len()
|
||||
);
|
||||
trace!("[msg::cli::matches] {:#?}", attachments);
|
||||
debug!("found {} attachments", attachments.len());
|
||||
trace!("attachments: {:?}", attachments);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
|
@ -493,7 +440,7 @@ pub fn msg_matches(
|
|||
match input::post_edit_choice() {
|
||||
Ok(choice) => match choice {
|
||||
input::PostEditChoice::Send => {
|
||||
debug!("[msg::cli::matches] sending message…");
|
||||
debug!("sending message…");
|
||||
let msg = msg.to_sendable_msg()?;
|
||||
smtp::send(&account, &msg)?;
|
||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||
|
@ -507,7 +454,7 @@ pub fn msg_matches(
|
|||
}
|
||||
input::PostEditChoice::LocalDraft => break,
|
||||
input::PostEditChoice::RemoteDraft => {
|
||||
debug!("[msg::cli::matches] saving to draft…");
|
||||
debug!("saving to draft…");
|
||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||
input::remove_draft()?;
|
||||
info!("Message successfully saved to Drafts");
|
||||
|
@ -526,35 +473,79 @@ pub fn msg_matches(
|
|||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("template") {
|
||||
debug!("template command matched");
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("new") {
|
||||
debug!("new command matched");
|
||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
||||
info!("{}", tpl);
|
||||
trace!("tpl: {:?}", tpl);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||
debug!("reply command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("uid: {}", uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
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)?
|
||||
};
|
||||
info!("{}", tpl);
|
||||
trace!("tpl: {:?}", tpl);
|
||||
|
||||
imap_conn.logout();
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
||||
debug!("forward command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("uid: {}", uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
||||
info!("{}", tpl);
|
||||
trace!("tpl: {:?}", tpl);
|
||||
|
||||
imap_conn.logout();
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("copy") {
|
||||
debug!("[msg::cli::matches] copy command matched");
|
||||
debug!("copy command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", &uid);
|
||||
debug!("uid: {}", &uid);
|
||||
let target = matches.value_of("target").unwrap();
|
||||
debug!("[msg::cli::matches] target: {}", &target);
|
||||
debug!("target: {}", &target);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
let mut flags = msg.flags.deref().to_vec();
|
||||
flags.push(Flag::Seen);
|
||||
imap_conn.append_msg(target, &msg.raw, &flags)?;
|
||||
info!(&format!(
|
||||
"Message {} successfully copied to folder `{}`",
|
||||
&uid, &target
|
||||
));
|
||||
info!("Message {} successfully copied to folder `{}`", uid, target);
|
||||
|
||||
imap_conn.logout();
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("move") {
|
||||
debug!("[msg::cli::matches] move command matched");
|
||||
debug!("move command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", &uid);
|
||||
debug!("uid: {}", &uid);
|
||||
let target = matches.value_of("target").unwrap();
|
||||
debug!("[msg::cli::matches] target: {}", &target);
|
||||
debug!("target: {}", &target);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
||||
|
@ -562,10 +553,7 @@ pub fn msg_matches(
|
|||
flags.push(Flag::Seen);
|
||||
imap_conn.append_msg(target, &msg.raw, msg.flags.deref())?;
|
||||
imap_conn.add_flags(&mbox, uid, "\\Seen \\Deleted")?;
|
||||
info!(&format!(
|
||||
"Message {} successfully moved to folder `{}`",
|
||||
&uid, &target
|
||||
));
|
||||
info!("Message {} successfully moved to folder `{}`", uid, target);
|
||||
|
||||
imap_conn.expunge(&mbox)?;
|
||||
imap_conn.logout();
|
||||
|
@ -573,14 +561,14 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("delete") {
|
||||
debug!("[msg::cli::matches] delete command matched");
|
||||
debug!("delete command matched");
|
||||
|
||||
let uid = matches.value_of("uid").unwrap();
|
||||
debug!("[msg::cli::matches] uid: {}", &uid);
|
||||
debug!("uid: {}", &uid);
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
imap_conn.add_flags(&mbox, uid, "\\Seen \\Deleted")?;
|
||||
info!(&format!("Message {} successfully deleted", &uid));
|
||||
info!("Message {} successfully deleted", uid);
|
||||
|
||||
imap_conn.expunge(&mbox)?;
|
||||
imap_conn.logout();
|
||||
|
@ -588,7 +576,7 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("send") {
|
||||
debug!("[msg::cli::matches] send command matched");
|
||||
debug!("send command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = matches.value_of("message").unwrap();
|
||||
|
@ -602,7 +590,7 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("save") {
|
||||
debug!("[msg::cli::matches] save command matched");
|
||||
debug!("save command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msg = matches.value_of("message").unwrap();
|
||||
|
@ -614,12 +602,12 @@ pub fn msg_matches(
|
|||
}
|
||||
|
||||
{
|
||||
debug!("[msg::cli::matches] default list command matched");
|
||||
debug!("default list command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&account)?;
|
||||
let msgs = imap_conn.list_msgs(&mbox, &config.default_page_size(&account), &0)?;
|
||||
let msgs = Msgs::from(&msgs);
|
||||
info!(&msgs);
|
||||
info!("{}", msgs);
|
||||
|
||||
imap_conn.logout();
|
||||
Ok(true)
|
||||
|
|
|
@ -11,9 +11,12 @@ use std::{borrow::Cow, fmt, fs, path::PathBuf, result};
|
|||
use tree_magic;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config::model::{Account, Config};
|
||||
use crate::flag::model::{Flag, Flags};
|
||||
use crate::table::{self, DisplayRow, DisplayTable};
|
||||
use crate::{
|
||||
config::model::{Account, Config},
|
||||
flag::model::{Flag, Flags},
|
||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
||||
table::{self, DisplayRow, DisplayTable},
|
||||
};
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
|
@ -29,7 +32,17 @@ pub struct Tpl(String);
|
|||
|
||||
impl fmt::Display for Tpl {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "{}", self.0)
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +131,17 @@ impl Serialize for ReadableMsg {
|
|||
|
||||
impl fmt::Display for ReadableMsg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.content)
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "{}", self.content)
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +398,7 @@ impl<'m> Msg<'m> {
|
|||
}
|
||||
|
||||
pub fn build_new_tpl(config: &Config, account: &Account) -> Result<Tpl> {
|
||||
let msg_spec = MsgSpec{
|
||||
let msg_spec = MsgSpec {
|
||||
in_reply_to: None,
|
||||
to: None,
|
||||
cc: None,
|
||||
|
@ -389,11 +412,11 @@ impl<'m> Msg<'m> {
|
|||
let msg = &self.parse()?;
|
||||
let headers = msg.get_headers();
|
||||
let to = headers
|
||||
.get_first_value("reply-to")
|
||||
.or(headers.get_first_value("from"));
|
||||
.get_first_value("reply-to")
|
||||
.or(headers.get_first_value("from"));
|
||||
let to = match to {
|
||||
Some(t) => {Some(vec![t])},
|
||||
None => {None},
|
||||
Some(t) => Some(vec![t]),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let thread = self // Original msg prepend with ">"
|
||||
|
@ -403,7 +426,7 @@ impl<'m> Msg<'m> {
|
|||
.map(|line| format!(">{}", line))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let msg_spec = MsgSpec{
|
||||
let msg_spec = MsgSpec {
|
||||
in_reply_to: headers.get_first_value("message-id"),
|
||||
to,
|
||||
cc: None,
|
||||
|
@ -455,12 +478,14 @@ impl<'m> Msg<'m> {
|
|||
};
|
||||
|
||||
// "Cc" header
|
||||
let cc = Some(headers
|
||||
.get_all_values("cc")
|
||||
.iter()
|
||||
.flat_map(|addrs| addrs.split(","))
|
||||
.map(|addr| addr.trim().to_string())
|
||||
.collect::<Vec<String>>());
|
||||
let cc = Some(
|
||||
headers
|
||||
.get_all_values("cc")
|
||||
.iter()
|
||||
.flat_map(|addrs| addrs.split(","))
|
||||
.map(|addr| addr.trim().to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
);
|
||||
|
||||
// Original msg prepend with ">"
|
||||
let thread = self
|
||||
|
@ -469,7 +494,7 @@ impl<'m> Msg<'m> {
|
|||
.map(|line| format!(">{}", line))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let msg_spec = MsgSpec{
|
||||
let msg_spec = MsgSpec {
|
||||
in_reply_to: headers.get_first_value("message-id"),
|
||||
cc,
|
||||
to: Some(vec![reply_to, to].concat()),
|
||||
|
@ -483,13 +508,18 @@ impl<'m> Msg<'m> {
|
|||
let msg = &self.parse()?;
|
||||
let headers = msg.get_headers();
|
||||
|
||||
let subject = format!("Fwd: {}", headers.get_first_value("subject").unwrap_or_else(String::new));
|
||||
let subject = format!(
|
||||
"Fwd: {}",
|
||||
headers
|
||||
.get_first_value("subject")
|
||||
.unwrap_or_else(String::new)
|
||||
);
|
||||
let original_msg = vec![
|
||||
"-------- Forwarded Message --------".to_string(),
|
||||
self.text_bodies("text/plain")?,
|
||||
];
|
||||
|
||||
let msg_spec = MsgSpec{
|
||||
let msg_spec = MsgSpec {
|
||||
in_reply_to: None,
|
||||
cc: None,
|
||||
to: None,
|
||||
|
@ -520,10 +550,17 @@ impl<'m> Msg<'m> {
|
|||
}
|
||||
|
||||
fn add_to_header(tpl: &mut Vec<String>, to: Option<Vec<String>>) {
|
||||
tpl.push(format!("To: {}", match to {
|
||||
Some(t) => {t.join(", ")}
|
||||
None => {String::new()}
|
||||
}));
|
||||
tpl.push(format!(
|
||||
"To: {}",
|
||||
match to {
|
||||
Some(t) => {
|
||||
t.join(", ")
|
||||
}
|
||||
None => {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
fn add_subject_header(tpl: &mut Vec<String>, subject: Option<String>) {
|
||||
|
@ -619,6 +656,16 @@ impl<'m> From<&'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>> for Msgs<'m> {
|
|||
|
||||
impl<'m> fmt::Display for Msgs<'m> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\n{}", self.to_table())
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "\n{}", self.to_table())
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
write!(f, "{}", res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,9 @@ pub fn output_args<'a>() -> Vec<Arg<'a, 'a>> {
|
|||
.value_name("FMT")
|
||||
.possible_values(&["plain", "json"])
|
||||
.default_value("plain"),
|
||||
Arg::with_name("log")
|
||||
.long("log")
|
||||
Arg::with_name("log-level")
|
||||
.long("log-level")
|
||||
.alias("log")
|
||||
.short("l")
|
||||
.help("Defines the logs level")
|
||||
.value_name("LEVEL")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
static mut OUTPUT_FMT: &'static OutputFmt = &OutputFmt::Plain;
|
||||
pub static mut OUTPUT_FMT: &'static OutputFmt = &OutputFmt::Plain;
|
||||
|
||||
pub fn set_output_fmt(output_fmt: &'static OutputFmt) {
|
||||
unsafe { OUTPUT_FMT = output_fmt }
|
||||
|
@ -36,3 +37,29 @@ impl fmt::Display for OutputFmt {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Response<T: Serialize + fmt::Display> {
|
||||
response: T,
|
||||
}
|
||||
|
||||
impl<T: Serialize + fmt::Display> Response<T> {
|
||||
pub fn new(response: T) -> Self {
|
||||
Self { response }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize + fmt::Display> fmt::Display for Response<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "{}", self.response)
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
write!(f, "{}", serde_json::to_string(self).unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,13 @@
|
|||
use chrono::Local;
|
||||
use env_logger;
|
||||
use error_chain::error_chain;
|
||||
use log::{self, Level, LevelFilter, Metadata, Record};
|
||||
use std::fmt;
|
||||
use std::{fmt, io::Write};
|
||||
|
||||
use super::fmt::{set_output_fmt, OutputFmt};
|
||||
|
||||
error_chain! {}
|
||||
|
||||
// Macros
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! info {
|
||||
($t:expr) => {
|
||||
use crate::output::fmt::{get_output_fmt, OutputFmt};
|
||||
use log::info as log_info;
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
OutputFmt::Plain => log_info!("{}", $t.to_string()),
|
||||
OutputFmt::Json => {
|
||||
// Should be safe enough to `.unwrap()` since it's
|
||||
// formatted by Himalaya itself
|
||||
log_info!("{{\"response\":{}}}", serde_json::to_string($t).unwrap())
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Log level struct
|
||||
|
||||
pub struct LogLevel(pub LevelFilter);
|
||||
|
@ -95,16 +77,32 @@ impl log::Log for JsonLogger {
|
|||
// Init
|
||||
|
||||
pub fn init(fmt: &OutputFmt, level: &LogLevel) -> Result<()> {
|
||||
log::set_logger(match fmt {
|
||||
match fmt {
|
||||
&OutputFmt::Plain => {
|
||||
set_output_fmt(&OutputFmt::Plain);
|
||||
&PlainLogger
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
set_output_fmt(&OutputFmt::Json);
|
||||
&JsonLogger
|
||||
}
|
||||
})
|
||||
.map(|()| log::set_max_level(level.0))
|
||||
.chain_err(|| "Could not init logger")
|
||||
};
|
||||
|
||||
env_logger::Builder::new()
|
||||
.format(|buf, record| {
|
||||
if let log::Level::Info = record.metadata().level() {
|
||||
write!(buf, "{}", record.args())
|
||||
} else {
|
||||
writeln!(
|
||||
buf,
|
||||
"[{} {:5} {}] {}",
|
||||
Local::now().format("%Y-%m-%dT%H:%M:%S"),
|
||||
record.metadata().level(),
|
||||
record.module_path().unwrap_or_default(),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
})
|
||||
.filter_level(level.0)
|
||||
.init();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue