mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 11:00:19 +00:00
improve logging, replace log-level by RUST_LOG
This commit is contained in:
parent
950e57acdb
commit
fa2f93185f
16 changed files with 340 additions and 361 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Replace `log-level` arg by default `RUST_LOG` env var [#130]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- IDLE mode after network interruption [#123]
|
||||||
|
- Output redirected to `stderr` [#130]
|
||||||
|
- Refactor table system [#132]
|
||||||
|
- Editon file format on Linux [#133]
|
||||||
|
- Show email address when name not available [#131]
|
||||||
|
|
||||||
## [0.2.7] - 2021-04-24
|
## [0.2.7] - 2021-04-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -24,11 +36,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- Improve config compatibility on Windows [#111](https://github.com/soywod/himalaya/pull/111)
|
- Improve config compatibility on Windows [#111](https://github.com/soywod/himalaya/pull/111)
|
||||||
- Vim table containing emoji [#122]
|
- Vim table containing emoji [#122]
|
||||||
- IDLE mode after network interruption [#123]
|
|
||||||
- Output redirected to `stderr` [#130]
|
|
||||||
- Refactor table system [#132]
|
|
||||||
- Editon file format on Linux [#133]
|
|
||||||
- Show email address when name not available [#131]
|
|
||||||
|
|
||||||
## [0.2.6] - 2021-04-17
|
## [0.2.6] - 2021-04-17
|
||||||
|
|
||||||
|
|
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -24,6 +24,15 @@ dependencies = [
|
||||||
"memchr 2.3.4",
|
"memchr 2.3.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -165,6 +174,8 @@ version = "2.33.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"strsim",
|
"strsim",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
|
|
|
@ -7,7 +7,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
clap = {version = "2.33.3", default-features = false, features = ["suggestions"]}
|
clap = {version = "2.33.3", default-features = false, features = ["suggestions", "color"]}
|
||||||
env_logger = "0.8.3"
|
env_logger = "0.8.3"
|
||||||
error-chain = "0.12.4"
|
error-chain = "0.12.4"
|
||||||
imap = "2.4.0"
|
imap = "2.4.0"
|
||||||
|
|
32
src/app.rs
Normal file
32
src/app.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use clap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::model::{Account, Config},
|
||||||
|
output::model::Output,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct App<'a> {
|
||||||
|
pub config: &'a Config,
|
||||||
|
pub account: &'a Account,
|
||||||
|
pub output: &'a Output,
|
||||||
|
pub mbox: &'a str,
|
||||||
|
pub arg_matches: &'a clap::ArgMatches<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> App<'a> {
|
||||||
|
pub fn new(
|
||||||
|
config: &'a Config,
|
||||||
|
account: &'a Account,
|
||||||
|
output: &'a Output,
|
||||||
|
mbox: &'a str,
|
||||||
|
arg_matches: &'a clap::ArgMatches<'a>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
account,
|
||||||
|
output,
|
||||||
|
mbox,
|
||||||
|
arg_matches,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ pub fn comp_subcmds<'s>() -> Vec<App<'s, 's>> {
|
||||||
.required(true)])]
|
.required(true)])]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn comp_matches(mut app: App, matches: &ArgMatches) -> Result<bool> {
|
pub fn comp_matches<'a>(app: fn() -> App<'a, 'a>, matches: &ArgMatches) -> Result<bool> {
|
||||||
if let Some(matches) = matches.subcommand_matches("completion") {
|
if let Some(matches) = matches.subcommand_matches("completion") {
|
||||||
debug!("completion command matched");
|
debug!("completion command matched");
|
||||||
let shell = match matches.value_of("shell").unwrap() {
|
let shell = match matches.value_of("shell").unwrap() {
|
||||||
|
@ -22,7 +22,7 @@ pub fn comp_matches(mut app: App, matches: &ArgMatches) -> Result<bool> {
|
||||||
"bash" | _ => Shell::Bash,
|
"bash" | _ => Shell::Bash,
|
||||||
};
|
};
|
||||||
debug!("shell: {}", shell);
|
debug!("shell: {}", shell);
|
||||||
app.gen_completions_to("himalaya", shell, &mut io::stdout());
|
app().gen_completions_to("himalaya", shell, &mut io::stdout());
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,43 @@
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap;
|
||||||
use error_chain::error_chain;
|
use error_chain::error_chain;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::{config::model::Account, imap::model::ImapConnector, msg::cli::uid_arg};
|
use crate::{app::App, imap::model::ImapConnector, msg::cli::uid_arg};
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
links {
|
||||||
Config(crate::config::model::Error, crate::config::model::ErrorKind);
|
|
||||||
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flags_arg<'a>() -> Arg<'a, 'a> {
|
fn flags_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("flags")
|
clap::Arg::with_name("flags")
|
||||||
.help("IMAP flags (see https://tools.ietf.org/html/rfc3501#page-11)")
|
.help("IMAP flags (see https://tools.ietf.org/html/rfc3501#page-11)")
|
||||||
.value_name("FLAGS…")
|
.value_name("FLAGS…")
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flag_subcmds<'s>() -> Vec<App<'s, 's>> {
|
pub fn flag_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
vec![SubCommand::with_name("flags")
|
vec![clap::SubCommand::with_name("flags")
|
||||||
.aliases(&["flag"])
|
.aliases(&["flag"])
|
||||||
.about("Handles flags")
|
.about("Handles flags")
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("set")
|
clap::SubCommand::with_name("set")
|
||||||
.aliases(&["s"])
|
.aliases(&["s"])
|
||||||
.about("Replaces all message flags")
|
.about("Replaces all message flags")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(flags_arg()),
|
.arg(flags_arg()),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add")
|
clap::SubCommand::with_name("add")
|
||||||
.aliases(&["a"])
|
.aliases(&["a"])
|
||||||
.about("Appends flags to a message")
|
.about("Appends flags to a message")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(flags_arg()),
|
.arg(flags_arg()),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("remove")
|
clap::SubCommand::with_name("remove")
|
||||||
.aliases(&["rm", "r"])
|
.aliases(&["rm", "r"])
|
||||||
.about("Removes flags from a message")
|
.about("Removes flags from a message")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
|
@ -46,8 +45,8 @@ pub fn flag_subcmds<'s>() -> Vec<App<'s, 's>> {
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Result<bool> {
|
pub fn flag_matches(app: &App) -> Result<bool> {
|
||||||
if let Some(matches) = matches.subcommand_matches("set") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("set") {
|
||||||
debug!("set command matched");
|
debug!("set command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -56,14 +55,14 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
||||||
let flags = matches.value_of("flags").unwrap();
|
let flags = matches.value_of("flags").unwrap();
|
||||||
debug!("flags: {}", flags);
|
debug!("flags: {}", flags);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
imap_conn.set_flags(mbox, uid, flags)?;
|
imap_conn.set_flags(app.mbox, uid, flags)?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("add") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("add") {
|
||||||
debug!("add command matched");
|
debug!("add command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -72,14 +71,14 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
||||||
let flags = matches.value_of("flags").unwrap();
|
let flags = matches.value_of("flags").unwrap();
|
||||||
debug!("flags: {}", flags);
|
debug!("flags: {}", flags);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
imap_conn.add_flags(mbox, uid, flags)?;
|
imap_conn.add_flags(app.mbox, uid, flags)?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("remove") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("remove") {
|
||||||
debug!("remove command matched");
|
debug!("remove command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -88,8 +87,8 @@ pub fn flag_matches(account: &Account, mbox: &str, matches: &ArgMatches) -> Resu
|
||||||
let flags = matches.value_of("flags").unwrap();
|
let flags = matches.value_of("flags").unwrap();
|
||||||
debug!("flags: {}", flags);
|
debug!("flags: {}", flags);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
imap_conn.remove_flags(mbox, uid, flags)?;
|
imap_conn.remove_flags(app.mbox, uid, flags)?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use clap::{self, App, ArgMatches, SubCommand};
|
use clap;
|
||||||
use error_chain::error_chain;
|
use error_chain::error_chain;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{app::App, imap::model::ImapConnector};
|
||||||
config::model::{Account, Config},
|
|
||||||
imap::model::ImapConnector,
|
|
||||||
};
|
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
links {
|
||||||
|
@ -14,20 +11,17 @@ error_chain! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imap_subcmds<'s>() -> Vec<App<'s, 's>> {
|
pub fn imap_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
vec![SubCommand::with_name("idle").about("Spawns a blocking idle daemon")]
|
vec![clap::SubCommand::with_name("idle").about("Spawns a blocking idle daemon")]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imap_matches(
|
pub fn imap_matches(app: &App) -> Result<bool> {
|
||||||
config: &Config,
|
if let Some(_) = app.arg_matches.subcommand_matches("idle") {
|
||||||
account: &Account,
|
|
||||||
mbox: &str,
|
|
||||||
matches: &ArgMatches,
|
|
||||||
) -> Result<bool> {
|
|
||||||
if let Some(_) = matches.subcommand_matches("idle") {
|
|
||||||
debug!("idle command matched");
|
debug!("idle command matched");
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
|
||||||
imap_conn.idle(&config, &mbox)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
|
imap_conn.idle(&app.config, &app.mbox)?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
52
src/main.rs
52
src/main.rs
|
@ -1,8 +1,10 @@
|
||||||
use clap;
|
use clap;
|
||||||
|
use env_logger;
|
||||||
use error_chain::error_chain;
|
use error_chain::error_chain;
|
||||||
use log::{debug, error, trace};
|
use log::{debug, error, trace};
|
||||||
use std::{env, path::PathBuf, process::exit};
|
use std::{env, path::PathBuf, process::exit};
|
||||||
|
|
||||||
|
mod app;
|
||||||
mod comp;
|
mod comp;
|
||||||
mod config;
|
mod config;
|
||||||
mod flag;
|
mod flag;
|
||||||
|
@ -15,17 +17,14 @@ mod smtp;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
app::App,
|
||||||
comp::cli::{comp_matches, comp_subcmds},
|
comp::cli::{comp_matches, comp_subcmds},
|
||||||
config::{cli::config_args, model::Config},
|
config::{cli::config_args, model::Config},
|
||||||
flag::cli::{flag_matches, flag_subcmds},
|
flag::cli::{flag_matches, flag_subcmds},
|
||||||
imap::cli::{imap_matches, imap_subcmds},
|
imap::cli::{imap_matches, imap_subcmds},
|
||||||
mbox::cli::{mbox_matches, mbox_source_arg, mbox_subcmds},
|
mbox::cli::{mbox_matches, mbox_source_arg, mbox_subcmds},
|
||||||
msg::cli::{msg_matches, msg_subcmds},
|
msg::cli::{msg_matches, msg_subcmds},
|
||||||
output::{
|
output::{cli::output_args, model::Output},
|
||||||
cli::output_args,
|
|
||||||
fmt::OutputFmt,
|
|
||||||
log::{init as init_logger, LogLevel},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
|
@ -36,11 +35,10 @@ error_chain! {
|
||||||
ImapCli(crate::imap::cli::Error, crate::imap::cli::ErrorKind);
|
ImapCli(crate::imap::cli::Error, crate::imap::cli::ErrorKind);
|
||||||
MboxCli(crate::mbox::cli::Error, crate::mbox::cli::ErrorKind);
|
MboxCli(crate::mbox::cli::Error, crate::mbox::cli::ErrorKind);
|
||||||
MsgCli(crate::msg::cli::Error, crate::msg::cli::ErrorKind);
|
MsgCli(crate::msg::cli::Error, crate::msg::cli::ErrorKind);
|
||||||
OutputLog(crate::output::log::Error, crate::output::log::ErrorKind);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_app<'a>() -> clap::App<'a, 'a> {
|
fn parse_args<'a>() -> clap::App<'a, 'a> {
|
||||||
clap::App::new(env!("CARGO_PKG_NAME"))
|
clap::App::new(env!("CARGO_PKG_NAME"))
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||||
|
@ -56,38 +54,39 @@ fn build_app<'a>() -> clap::App<'a, 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> Result<()> {
|
fn run() -> Result<()> {
|
||||||
let app = build_app();
|
env_logger::init_from_env(
|
||||||
let matches = app.get_matches();
|
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "off"),
|
||||||
|
);
|
||||||
|
|
||||||
let output_fmt: OutputFmt = matches.value_of("output").unwrap().into();
|
let args = parse_args();
|
||||||
let log_level: LogLevel = matches.value_of("log-level").unwrap().into();
|
let arg_matches = args.get_matches();
|
||||||
init_logger(output_fmt, log_level)?;
|
|
||||||
|
|
||||||
// Check completion matches before the config init
|
// Check completion before init config
|
||||||
if comp_matches(build_app(), &matches)? {
|
if comp_matches(parse_args, &arg_matches)? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let custom_config: Option<PathBuf> = matches.value_of("config").map(|s| s.into());
|
let output = Output::new(arg_matches.value_of("output").unwrap());
|
||||||
debug!("custom config path: {:?}", custom_config);
|
debug!("output: {:?}", output);
|
||||||
|
|
||||||
debug!("init config");
|
debug!("init config");
|
||||||
|
let custom_config: Option<PathBuf> = arg_matches.value_of("config").map(|s| s.into());
|
||||||
|
debug!("custom config path: {:?}", custom_config);
|
||||||
let config = Config::new(custom_config)?;
|
let config = Config::new(custom_config)?;
|
||||||
trace!("config: {:?}", config);
|
trace!("config: {:?}", config);
|
||||||
|
|
||||||
let account_name = matches.value_of("account");
|
let account_name = arg_matches.value_of("account");
|
||||||
debug!("init account: {}", account_name.unwrap_or("default"));
|
debug!("init account: {}", account_name.unwrap_or("default"));
|
||||||
let account = config.find_account_by_name(account_name)?;
|
let account = config.find_account_by_name(account_name)?;
|
||||||
trace!("account: {:?}", account);
|
trace!("account: {:?}", account);
|
||||||
|
|
||||||
let mbox = matches.value_of("mailbox").unwrap();
|
let mbox = arg_matches.value_of("mailbox").unwrap();
|
||||||
debug!("mailbox: {}", mbox);
|
debug!("mailbox: {}", mbox);
|
||||||
|
|
||||||
debug!("begin matching");
|
debug!("begin matching");
|
||||||
let _matched = mbox_matches(&account, &matches)?
|
let app = App::new(&config, &account, &output, &mbox, &arg_matches);
|
||||||
|| flag_matches(&account, &mbox, &matches)?
|
let _matched =
|
||||||
|| imap_matches(&config, &account, &mbox, &matches)?
|
mbox_matches(&app)? || flag_matches(&app)? || imap_matches(&app)? || msg_matches(&app)?;
|
||||||
|| msg_matches(&config, &account, &mbox, &matches)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,13 +94,20 @@ fn run() -> Result<()> {
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Err(ref errs) = run() {
|
if let Err(ref errs) = run() {
|
||||||
let mut errs = errs.iter();
|
let mut errs = errs.iter();
|
||||||
|
|
||||||
match errs.next() {
|
match errs.next() {
|
||||||
None => (),
|
None => (),
|
||||||
Some(err) => {
|
Some(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
errs.for_each(|err| error!(" ↳ {}", err));
|
eprintln!("{}", err);
|
||||||
|
|
||||||
|
errs.for_each(|err| {
|
||||||
|
error!("{}", err);
|
||||||
|
eprintln!(" ↳ {}", err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
use clap;
|
||||||
use error_chain::error_chain;
|
use error_chain::error_chain;
|
||||||
use log::{debug, info, trace};
|
use log::{debug, trace};
|
||||||
|
|
||||||
use crate::{config::model::Account, imap::model::ImapConnector};
|
use crate::{app::App, imap::model::ImapConnector};
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
links {
|
||||||
Config(crate::config::model::Error, crate::config::model::ErrorKind);
|
|
||||||
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
||||||
MsgCli(crate::msg::cli::Error, crate::msg::cli::ErrorKind);
|
|
||||||
OutputUtils(crate::output::utils::Error, crate::output::utils::ErrorKind);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mbox_source_arg<'a>() -> Arg<'a, 'a> {
|
pub fn mbox_source_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("mailbox")
|
clap::Arg::with_name("mailbox")
|
||||||
.short("m")
|
.short("m")
|
||||||
.long("mailbox")
|
.long("mailbox")
|
||||||
.help("Selects a specific mailbox")
|
.help("Selects a specific mailbox")
|
||||||
|
@ -22,26 +19,27 @@ pub fn mbox_source_arg<'a>() -> Arg<'a, 'a> {
|
||||||
.default_value("INBOX")
|
.default_value("INBOX")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mbox_target_arg<'a>() -> Arg<'a, 'a> {
|
pub fn mbox_target_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("target")
|
clap::Arg::with_name("target")
|
||||||
.help("Specifies the targetted mailbox")
|
.help("Specifies the targetted mailbox")
|
||||||
.value_name("TARGET")
|
.value_name("TARGET")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mbox_subcmds<'s>() -> Vec<App<'s, 's>> {
|
pub fn mbox_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
vec![SubCommand::with_name("mailboxes")
|
vec![clap::SubCommand::with_name("mailboxes")
|
||||||
.aliases(&["mailbox", "mboxes", "mbox", "m"])
|
.aliases(&["mailbox", "mboxes", "mbox", "m"])
|
||||||
.about("Lists all mailboxes")]
|
.about("Lists all mailboxes")]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mbox_matches(account: &Account, matches: &ArgMatches) -> Result<bool> {
|
pub fn mbox_matches(app: &App) -> Result<bool> {
|
||||||
if let Some(_) = matches.subcommand_matches("mailboxes") {
|
if let Some(_) = app.arg_matches.subcommand_matches("mailboxes") {
|
||||||
debug!("mailboxes command matched");
|
debug!("mailboxes command matched");
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let mboxes = imap_conn.list_mboxes()?;
|
let mboxes = imap_conn.list_mboxes()?;
|
||||||
info!("{}", mboxes);
|
debug!("found {} mailboxes", mboxes.0.len());
|
||||||
trace!("mailboxes: {:?}", mboxes);
|
trace!("mailboxes: {:?}", mboxes);
|
||||||
|
app.output.print(mboxes);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|
|
@ -2,10 +2,7 @@ use imap;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::table::{Cell, Row, Table};
|
||||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
|
||||||
table::{Cell, Row, Table},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mbox
|
// Mbox
|
||||||
|
|
||||||
|
@ -42,7 +39,7 @@ impl Table for Mbox {
|
||||||
|
|
||||||
fn row(&self) -> Row {
|
fn row(&self) -> Row {
|
||||||
Row::new()
|
Row::new()
|
||||||
.cell(Cell::new(&self.delim).red())
|
.cell(Cell::new(&self.delim).white())
|
||||||
.cell(Cell::new(&self.name).green())
|
.cell(Cell::new(&self.name).green())
|
||||||
.cell(Cell::new(&self.attributes.join(", ")).shrinkable().yellow())
|
.cell(Cell::new(&self.attributes.join(", ")).shrinkable().yellow())
|
||||||
}
|
}
|
||||||
|
@ -55,16 +52,6 @@ pub struct Mboxes(pub Vec<Mbox>);
|
||||||
|
|
||||||
impl fmt::Display for Mboxes {
|
impl fmt::Display for Mboxes {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
|
||||||
match get_output_fmt() {
|
|
||||||
&OutputFmt::Plain => {
|
|
||||||
writeln!(f, "\n{}", Table::render(&self.0))
|
writeln!(f, "\n{}", Table::render(&self.0))
|
||||||
}
|
}
|
||||||
&OutputFmt::Json => {
|
|
||||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
|
||||||
write!(f, "{}", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
252
src/msg/cli.rs
252
src/msg/cli.rs
|
@ -1,10 +1,10 @@
|
||||||
use clap::{self, App, Arg, ArgMatches, SubCommand};
|
use clap;
|
||||||
use error_chain::error_chain;
|
use error_chain::error_chain;
|
||||||
use log::{debug, error, info, trace};
|
use log::{debug, error, trace};
|
||||||
use std::{fs, ops::Deref};
|
use std::{fs, ops::Deref};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::model::{Account, Config},
|
app::App,
|
||||||
flag::model::Flag,
|
flag::model::Flag,
|
||||||
imap::model::ImapConnector,
|
imap::model::ImapConnector,
|
||||||
input,
|
input,
|
||||||
|
@ -15,7 +15,6 @@ use crate::{
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
links {
|
||||||
Config(crate::config::model::Error, crate::config::model::ErrorKind);
|
|
||||||
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
Imap(crate::imap::model::Error, crate::imap::model::ErrorKind);
|
||||||
Input(crate::input::Error, crate::input::ErrorKind);
|
Input(crate::input::Error, crate::input::ErrorKind);
|
||||||
MsgModel(crate::msg::model::Error, crate::msg::model::ErrorKind);
|
MsgModel(crate::msg::model::Error, crate::msg::model::ErrorKind);
|
||||||
|
@ -26,30 +25,30 @@ error_chain! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uid_arg<'a>() -> Arg<'a, 'a> {
|
pub fn uid_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("uid")
|
clap::Arg::with_name("uid")
|
||||||
.help("Specifies the targetted message")
|
.help("Specifies the targetted message")
|
||||||
.value_name("UID")
|
.value_name("UID")
|
||||||
.required(true)
|
.required(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reply_all_arg<'a>() -> Arg<'a, 'a> {
|
fn reply_all_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("reply-all")
|
clap::Arg::with_name("reply-all")
|
||||||
.help("Includes all recipients")
|
.help("Includes all recipients")
|
||||||
.short("a")
|
.short("a")
|
||||||
.long("all")
|
.long("all")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_size_arg<'a>() -> Arg<'a, 'a> {
|
fn page_size_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("page-size")
|
clap::Arg::with_name("page-size")
|
||||||
.help("Page size")
|
.help("Page size")
|
||||||
.short("s")
|
.short("s")
|
||||||
.long("size")
|
.long("size")
|
||||||
.value_name("INT")
|
.value_name("INT")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_arg<'a>() -> Arg<'a, 'a> {
|
fn page_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("page")
|
clap::Arg::with_name("page")
|
||||||
.help("Page number")
|
.help("Page number")
|
||||||
.short("p")
|
.short("p")
|
||||||
.long("page")
|
.long("page")
|
||||||
|
@ -57,8 +56,8 @@ fn page_arg<'a>() -> Arg<'a, 'a> {
|
||||||
.default_value("0")
|
.default_value("0")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attachment_arg<'a>() -> Arg<'a, 'a> {
|
fn attachment_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||||
Arg::with_name("attachments")
|
clap::Arg::with_name("attachments")
|
||||||
.help("Adds attachment to the message")
|
.help("Adds attachment to the message")
|
||||||
.short("a")
|
.short("a")
|
||||||
.long("attachment")
|
.long("attachment")
|
||||||
|
@ -67,41 +66,41 @@ fn attachment_arg<'a>() -> Arg<'a, 'a> {
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn msg_subcmds<'s>() -> Vec<App<'s, 's>> {
|
pub fn msg_subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
vec![
|
vec![
|
||||||
SubCommand::with_name("list")
|
clap::SubCommand::with_name("list")
|
||||||
.aliases(&["lst", "l"])
|
.aliases(&["lst", "l"])
|
||||||
.about("Lists all messages")
|
.about("Lists all messages")
|
||||||
.arg(page_size_arg())
|
.arg(page_size_arg())
|
||||||
.arg(page_arg()),
|
.arg(page_arg()),
|
||||||
SubCommand::with_name("search")
|
clap::SubCommand::with_name("search")
|
||||||
.aliases(&["query", "q", "s"])
|
.aliases(&["query", "q", "s"])
|
||||||
.about("Lists messages matching the given IMAP query")
|
.about("Lists messages matching the given IMAP query")
|
||||||
.arg(page_size_arg())
|
.arg(page_size_arg())
|
||||||
.arg(page_arg())
|
.arg(page_arg())
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("query")
|
clap::Arg::with_name("query")
|
||||||
.help("IMAP query (see https://tools.ietf.org/html/rfc3501#section-6.4.4)")
|
.help("IMAP query (see https://tools.ietf.org/html/rfc3501#section-6.4.4)")
|
||||||
.value_name("QUERY")
|
.value_name("QUERY")
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.required(true),
|
.required(true),
|
||||||
),
|
),
|
||||||
SubCommand::with_name("write")
|
clap::SubCommand::with_name("write")
|
||||||
.aliases(&["w"])
|
.aliases(&["w"])
|
||||||
.about("Writes a new message")
|
.about("Writes a new message")
|
||||||
.arg(attachment_arg()),
|
.arg(attachment_arg()),
|
||||||
SubCommand::with_name("send")
|
clap::SubCommand::with_name("send")
|
||||||
.about("Sends a raw message")
|
.about("Sends a raw message")
|
||||||
.arg(Arg::with_name("message").raw(true)),
|
.arg(clap::Arg::with_name("message").raw(true)),
|
||||||
SubCommand::with_name("save")
|
clap::SubCommand::with_name("save")
|
||||||
.about("Saves a raw message")
|
.about("Saves a raw message")
|
||||||
.arg(Arg::with_name("message").raw(true)),
|
.arg(clap::Arg::with_name("message").raw(true)),
|
||||||
SubCommand::with_name("read")
|
clap::SubCommand::with_name("read")
|
||||||
.aliases(&["r"])
|
.aliases(&["r"])
|
||||||
.about("Reads text bodies of a message")
|
.about("Reads text bodies of a message")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("mime-type")
|
clap::Arg::with_name("mime-type")
|
||||||
.help("MIME type to use")
|
.help("MIME type to use")
|
||||||
.short("t")
|
.short("t")
|
||||||
.long("mime-type")
|
.long("mime-type")
|
||||||
|
@ -110,55 +109,55 @@ pub fn msg_subcmds<'s>() -> Vec<App<'s, 's>> {
|
||||||
.default_value("plain"),
|
.default_value("plain"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("raw")
|
clap::Arg::with_name("raw")
|
||||||
.help("Reads raw message")
|
.help("Reads raw message")
|
||||||
.long("raw")
|
.long("raw")
|
||||||
.short("r"),
|
.short("r"),
|
||||||
),
|
),
|
||||||
SubCommand::with_name("attachments")
|
clap::SubCommand::with_name("attachments")
|
||||||
.aliases(&["attach", "att", "a"])
|
.aliases(&["attach", "att", "a"])
|
||||||
.about("Downloads all message attachments")
|
.about("Downloads all message attachments")
|
||||||
.arg(uid_arg()),
|
.arg(uid_arg()),
|
||||||
SubCommand::with_name("reply")
|
clap::SubCommand::with_name("reply")
|
||||||
.aliases(&["rep", "re"])
|
.aliases(&["rep", "re"])
|
||||||
.about("Answers to a message")
|
.about("Answers to a message")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(reply_all_arg()),
|
.arg(reply_all_arg()),
|
||||||
SubCommand::with_name("forward")
|
clap::SubCommand::with_name("forward")
|
||||||
.aliases(&["fwd", "f"])
|
.aliases(&["fwd", "f"])
|
||||||
.about("Forwards a message")
|
.about("Forwards a message")
|
||||||
.arg(uid_arg()),
|
.arg(uid_arg()),
|
||||||
SubCommand::with_name("copy")
|
clap::SubCommand::with_name("copy")
|
||||||
.aliases(&["cp", "c"])
|
.aliases(&["cp", "c"])
|
||||||
.about("Copies a message to the targetted mailbox")
|
.about("Copies a message to the targetted mailbox")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(mbox_target_arg()),
|
.arg(mbox_target_arg()),
|
||||||
SubCommand::with_name("move")
|
clap::SubCommand::with_name("move")
|
||||||
.aliases(&["mv", "m"])
|
.aliases(&["mv", "m"])
|
||||||
.about("Moves a message to the targetted mailbox")
|
.about("Moves a message to the targetted mailbox")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(mbox_target_arg()),
|
.arg(mbox_target_arg()),
|
||||||
SubCommand::with_name("delete")
|
clap::SubCommand::with_name("delete")
|
||||||
.aliases(&["remove", "rm", "del", "d"])
|
.aliases(&["remove", "rm", "del", "d"])
|
||||||
.about("Deletes a message")
|
.about("Deletes a message")
|
||||||
.arg(uid_arg()),
|
.arg(uid_arg()),
|
||||||
SubCommand::with_name("template")
|
clap::SubCommand::with_name("template")
|
||||||
.aliases(&["tpl", "t"])
|
.aliases(&["tpl", "t"])
|
||||||
.about("Generates a message template")
|
.about("Generates a message template")
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("new")
|
clap::SubCommand::with_name("new")
|
||||||
.aliases(&["n"])
|
.aliases(&["n"])
|
||||||
.about("Generates a new message template"),
|
.about("Generates a new message template"),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("reply")
|
clap::SubCommand::with_name("reply")
|
||||||
.aliases(&["rep", "r"])
|
.aliases(&["rep", "r"])
|
||||||
.about("Generates a reply message template")
|
.about("Generates a reply message template")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(reply_all_arg()),
|
.arg(reply_all_arg()),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("forward")
|
clap::SubCommand::with_name("forward")
|
||||||
.aliases(&["fwd", "fw", "f"])
|
.aliases(&["fwd", "fw", "f"])
|
||||||
.about("Generates a forward message template")
|
.about("Generates a forward message template")
|
||||||
.arg(uid_arg()),
|
.arg(uid_arg()),
|
||||||
|
@ -166,19 +165,14 @@ pub fn msg_subcmds<'s>() -> Vec<App<'s, 's>> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn msg_matches(
|
pub fn msg_matches(app: &App) -> Result<bool> {
|
||||||
config: &Config,
|
if let Some(matches) = app.arg_matches.subcommand_matches("list") {
|
||||||
account: &Account,
|
|
||||||
mbox: &str,
|
|
||||||
matches: &ArgMatches,
|
|
||||||
) -> Result<bool> {
|
|
||||||
if let Some(matches) = matches.subcommand_matches("list") {
|
|
||||||
debug!("list command matched");
|
debug!("list command matched");
|
||||||
|
|
||||||
let page_size: usize = matches
|
let page_size: usize = matches
|
||||||
.value_of("page-size")
|
.value_of("page-size")
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(config.default_page_size(&account));
|
.unwrap_or(app.config.default_page_size(&app.account));
|
||||||
debug!("page size: {}", &page_size);
|
debug!("page size: {}", &page_size);
|
||||||
let page: usize = matches
|
let page: usize = matches
|
||||||
.value_of("page")
|
.value_of("page")
|
||||||
|
@ -187,23 +181,23 @@ pub fn msg_matches(
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
debug!("page: {}", &page);
|
debug!("page: {}", &page);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs = imap_conn.list_msgs(&mbox, &page_size, &page)?;
|
let msgs = imap_conn.list_msgs(&app.mbox, &page_size, &page)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = Msgs::from(&msgs);
|
||||||
info!("{}", msgs);
|
|
||||||
trace!("messages: {:?}", msgs);
|
trace!("messages: {:?}", msgs);
|
||||||
|
app.output.print(msgs);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("search") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("search") {
|
||||||
debug!("search command matched");
|
debug!("search command matched");
|
||||||
|
|
||||||
let page_size: usize = matches
|
let page_size: usize = matches
|
||||||
.value_of("page-size")
|
.value_of("page-size")
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(config.default_page_size(&account));
|
.unwrap_or(app.config.default_page_size(&app.account));
|
||||||
debug!("page size: {}", &page_size);
|
debug!("page size: {}", &page_size);
|
||||||
let page: usize = matches
|
let page: usize = matches
|
||||||
.value_of("page")
|
.value_of("page")
|
||||||
|
@ -238,17 +232,17 @@ pub fn msg_matches(
|
||||||
.join(" ");
|
.join(" ");
|
||||||
debug!("query: {}", &page);
|
debug!("query: {}", &page);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?;
|
let msgs = imap_conn.search_msgs(&app.mbox, &query, &page_size, &page)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = Msgs::from(&msgs);
|
||||||
info!("{}", msgs);
|
|
||||||
trace!("messages: {:?}", msgs);
|
trace!("messages: {:?}", msgs);
|
||||||
|
app.output.print(msgs);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("read") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("read") {
|
||||||
debug!("read command matched");
|
debug!("read command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -258,30 +252,30 @@ pub fn msg_matches(
|
||||||
let raw = matches.is_present("raw");
|
let raw = matches.is_present("raw");
|
||||||
debug!("raw: {}", raw);
|
debug!("raw: {}", raw);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = imap_conn.read_msg(&mbox, &uid)?;
|
let msg = imap_conn.read_msg(&app.mbox, &uid)?;
|
||||||
if raw {
|
if raw {
|
||||||
let msg = String::from_utf8(msg)
|
let msg = String::from_utf8(msg)
|
||||||
.chain_err(|| "Could not decode raw message as utf8 string")?;
|
.chain_err(|| "Could not decode raw message as utf8 string")?;
|
||||||
let msg = msg.trim_end_matches("\n");
|
let msg = msg.trim_end_matches("\n");
|
||||||
info!("{}", msg);
|
app.output.print(msg);
|
||||||
} else {
|
} else {
|
||||||
let msg = ReadableMsg::from_bytes(&mime, &msg)?;
|
let msg = ReadableMsg::from_bytes(&mime, &msg)?;
|
||||||
info!("{}", msg);
|
app.output.print(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("attachments") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("attachments") {
|
||||||
debug!("attachments command matched");
|
debug!("attachments command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", &uid);
|
debug!("uid: {}", &uid);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = imap_conn.read_msg(&mbox, &uid)?;
|
let msg = imap_conn.read_msg(&app.mbox, &uid)?;
|
||||||
let attachments = Attachments::from_bytes(&msg)?;
|
let attachments = Attachments::from_bytes(&msg)?;
|
||||||
debug!(
|
debug!(
|
||||||
"{} attachment(s) found for message {}",
|
"{} attachment(s) found for message {}",
|
||||||
|
@ -289,30 +283,37 @@ pub fn msg_matches(
|
||||||
&uid
|
&uid
|
||||||
);
|
);
|
||||||
for attachment in attachments.0.iter() {
|
for attachment in attachments.0.iter() {
|
||||||
let filepath = config.downloads_filepath(&account, &attachment.filename);
|
let filepath = app
|
||||||
|
.config
|
||||||
|
.downloads_filepath(&app.account, &attachment.filename);
|
||||||
debug!("downloading {}…", &attachment.filename);
|
debug!("downloading {}…", &attachment.filename);
|
||||||
fs::write(&filepath, &attachment.raw)
|
fs::write(&filepath, &attachment.raw)
|
||||||
.chain_err(|| format!("Could not save attachment {:?}", filepath))?;
|
.chain_err(|| format!("Could not save attachment {:?}", filepath))?;
|
||||||
}
|
}
|
||||||
info!(
|
|
||||||
|
debug!(
|
||||||
"{} attachment(s) successfully downloaded",
|
"{} attachment(s) successfully downloaded",
|
||||||
&attachments.0.len()
|
&attachments.0.len()
|
||||||
);
|
);
|
||||||
|
app.output.print(format!(
|
||||||
|
"{} attachment(s) successfully downloaded",
|
||||||
|
&attachments.0.len()
|
||||||
|
));
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("write") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("write") {
|
||||||
debug!("write command matched");
|
debug!("write command matched");
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let attachments = matches
|
let attachments = matches
|
||||||
.values_of("attachments")
|
.values_of("attachments")
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
let tpl = Msg::build_new_tpl(&app.config, &app.account)?;
|
||||||
let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?;
|
let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?;
|
||||||
let mut msg = Msg::from(content);
|
let mut msg = Msg::from(content);
|
||||||
msg.attachments = attachments;
|
msg.attachments = attachments;
|
||||||
|
@ -323,10 +324,10 @@ pub fn msg_matches(
|
||||||
input::PostEditChoice::Send => {
|
input::PostEditChoice::Send => {
|
||||||
debug!("sending message…");
|
debug!("sending message…");
|
||||||
let msg = msg.to_sendable_msg()?;
|
let msg = msg.to_sendable_msg()?;
|
||||||
smtp::send(&account, &msg)?;
|
smtp::send(&app.account, &msg)?;
|
||||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully sent");
|
app.output.print("Message successfully sent");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Edit => {
|
input::PostEditChoice::Edit => {
|
||||||
|
@ -338,7 +339,7 @@ pub fn msg_matches(
|
||||||
debug!("saving to draft…");
|
debug!("saving to draft…");
|
||||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully saved to Drafts");
|
app.output.print("Message successfully saved to Drafts");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Discard => {
|
input::PostEditChoice::Discard => {
|
||||||
|
@ -353,7 +354,7 @@ pub fn msg_matches(
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("reply") {
|
||||||
debug!("reply command matched");
|
debug!("reply command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -366,12 +367,12 @@ pub fn msg_matches(
|
||||||
debug!("found {} attachments", attachments.len());
|
debug!("found {} attachments", attachments.len());
|
||||||
trace!("attachments: {:?}", attachments);
|
trace!("attachments: {:?}", attachments);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let tpl = if matches.is_present("reply-all") {
|
let tpl = if matches.is_present("reply-all") {
|
||||||
msg.build_reply_all_tpl(&config, &account)?
|
msg.build_reply_all_tpl(&app.config, &app.account)?
|
||||||
} else {
|
} else {
|
||||||
msg.build_reply_tpl(&config, &account)?
|
msg.build_reply_tpl(&app.config, &app.account)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||||
|
@ -384,11 +385,11 @@ pub fn msg_matches(
|
||||||
input::PostEditChoice::Send => {
|
input::PostEditChoice::Send => {
|
||||||
debug!("sending message…");
|
debug!("sending message…");
|
||||||
let msg = msg.to_sendable_msg()?;
|
let msg = msg.to_sendable_msg()?;
|
||||||
smtp::send(&account, &msg)?;
|
smtp::send(&app.account, &msg)?;
|
||||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||||
imap_conn.add_flags(&mbox, uid, "\\Answered")?;
|
imap_conn.add_flags(&app.mbox, uid, "\\Answered")?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully sent");
|
app.output.print("Message successfully sent");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Edit => {
|
input::PostEditChoice::Edit => {
|
||||||
|
@ -400,7 +401,7 @@ pub fn msg_matches(
|
||||||
debug!("saving to draft…");
|
debug!("saving to draft…");
|
||||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully saved to Drafts");
|
app.output.print("Message successfully saved to Drafts");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Discard => {
|
input::PostEditChoice::Discard => {
|
||||||
|
@ -416,7 +417,7 @@ pub fn msg_matches(
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("forward") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("forward") {
|
||||||
debug!("forward command matched");
|
debug!("forward command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -429,9 +430,9 @@ pub fn msg_matches(
|
||||||
debug!("found {} attachments", attachments.len());
|
debug!("found {} attachments", attachments.len());
|
||||||
trace!("attachments: {:?}", attachments);
|
trace!("attachments: {:?}", attachments);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
let tpl = msg.build_forward_tpl(&app.config, &app.account)?;
|
||||||
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?;
|
||||||
let mut msg = Msg::from(content);
|
let mut msg = Msg::from(content);
|
||||||
msg.attachments = attachments;
|
msg.attachments = attachments;
|
||||||
|
@ -442,10 +443,10 @@ pub fn msg_matches(
|
||||||
input::PostEditChoice::Send => {
|
input::PostEditChoice::Send => {
|
||||||
debug!("sending message…");
|
debug!("sending message…");
|
||||||
let msg = msg.to_sendable_msg()?;
|
let msg = msg.to_sendable_msg()?;
|
||||||
smtp::send(&account, &msg)?;
|
smtp::send(&app.account, &msg)?;
|
||||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully sent");
|
app.output.print("Message successfully sent");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Edit => {
|
input::PostEditChoice::Edit => {
|
||||||
|
@ -457,7 +458,7 @@ pub fn msg_matches(
|
||||||
debug!("saving to draft…");
|
debug!("saving to draft…");
|
||||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?;
|
||||||
input::remove_draft()?;
|
input::remove_draft()?;
|
||||||
info!("Message successfully saved to Drafts");
|
app.output.print("Message successfully saved to Drafts");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input::PostEditChoice::Discard => {
|
input::PostEditChoice::Discard => {
|
||||||
|
@ -473,14 +474,14 @@ pub fn msg_matches(
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("template") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("template") {
|
||||||
debug!("template command matched");
|
debug!("template command matched");
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("new") {
|
if let Some(_) = matches.subcommand_matches("new") {
|
||||||
debug!("new command matched");
|
debug!("new command matched");
|
||||||
let tpl = Msg::build_new_tpl(&config, &account)?;
|
let tpl = Msg::build_new_tpl(&app.config, &app.account)?;
|
||||||
info!("{}", tpl);
|
|
||||||
trace!("tpl: {:?}", tpl);
|
trace!("tpl: {:?}", tpl);
|
||||||
|
app.output.print(tpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("reply") {
|
if let Some(matches) = matches.subcommand_matches("reply") {
|
||||||
|
@ -489,15 +490,15 @@ pub fn msg_matches(
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", uid);
|
debug!("uid: {}", uid);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let tpl = if matches.is_present("reply-all") {
|
let tpl = if matches.is_present("reply-all") {
|
||||||
msg.build_reply_all_tpl(&config, &account)?
|
msg.build_reply_all_tpl(&app.config, &app.account)?
|
||||||
} else {
|
} else {
|
||||||
msg.build_reply_tpl(&config, &account)?
|
msg.build_reply_tpl(&app.config, &app.account)?
|
||||||
};
|
};
|
||||||
info!("{}", tpl);
|
|
||||||
trace!("tpl: {:?}", tpl);
|
trace!("tpl: {:?}", tpl);
|
||||||
|
app.output.print(tpl);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
}
|
}
|
||||||
|
@ -508,11 +509,11 @@ pub fn msg_matches(
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", uid);
|
debug!("uid: {}", uid);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let tpl = msg.build_forward_tpl(&config, &account)?;
|
let tpl = msg.build_forward_tpl(&app.config, &app.account)?;
|
||||||
info!("{}", tpl);
|
|
||||||
trace!("tpl: {:?}", tpl);
|
trace!("tpl: {:?}", tpl);
|
||||||
|
app.output.print(tpl);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
}
|
}
|
||||||
|
@ -520,7 +521,7 @@ pub fn msg_matches(
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("copy") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("copy") {
|
||||||
debug!("copy command matched");
|
debug!("copy command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -528,18 +529,22 @@ pub fn msg_matches(
|
||||||
let target = matches.value_of("target").unwrap();
|
let target = matches.value_of("target").unwrap();
|
||||||
debug!("target: {}", &target);
|
debug!("target: {}", &target);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let mut flags = msg.flags.deref().to_vec();
|
let mut flags = msg.flags.deref().to_vec();
|
||||||
flags.push(Flag::Seen);
|
flags.push(Flag::Seen);
|
||||||
imap_conn.append_msg(target, &msg.raw, &flags)?;
|
imap_conn.append_msg(target, &msg.raw, &flags)?;
|
||||||
info!("Message {} successfully copied to folder `{}`", uid, target);
|
debug!("message {} successfully copied to folder `{}`", uid, target);
|
||||||
|
app.output.print(format!(
|
||||||
|
"Message {} successfully copied to folder `{}`",
|
||||||
|
uid, target
|
||||||
|
));
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("move") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("move") {
|
||||||
debug!("move command matched");
|
debug!("move command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
|
@ -547,55 +552,61 @@ pub fn msg_matches(
|
||||||
let target = matches.value_of("target").unwrap();
|
let target = matches.value_of("target").unwrap();
|
||||||
debug!("target: {}", &target);
|
debug!("target: {}", &target);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?);
|
let msg = Msg::from(imap_conn.read_msg(&app.mbox, &uid)?);
|
||||||
let mut flags = msg.flags.deref().to_vec();
|
let mut flags = msg.flags.deref().to_vec();
|
||||||
flags.push(Flag::Seen);
|
flags.push(Flag::Seen);
|
||||||
imap_conn.append_msg(target, &msg.raw, msg.flags.deref())?;
|
imap_conn.append_msg(target, &msg.raw, msg.flags.deref())?;
|
||||||
imap_conn.add_flags(&mbox, uid, "\\Seen \\Deleted")?;
|
imap_conn.add_flags(&app.mbox, uid, "\\Seen \\Deleted")?;
|
||||||
info!("Message {} successfully moved to folder `{}`", uid, target);
|
debug!("message {} successfully moved to folder `{}`", uid, target);
|
||||||
|
app.output.print(format!(
|
||||||
|
"Message {} successfully moved to folder `{}`",
|
||||||
|
uid, target
|
||||||
|
));
|
||||||
|
|
||||||
imap_conn.expunge(&mbox)?;
|
imap_conn.expunge(&app.mbox)?;
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("delete") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("delete") {
|
||||||
debug!("delete command matched");
|
debug!("delete command matched");
|
||||||
|
|
||||||
let uid = matches.value_of("uid").unwrap();
|
let uid = matches.value_of("uid").unwrap();
|
||||||
debug!("uid: {}", &uid);
|
debug!("uid: {}", &uid);
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
imap_conn.add_flags(&mbox, uid, "\\Seen \\Deleted")?;
|
imap_conn.add_flags(&app.mbox, uid, "\\Seen \\Deleted")?;
|
||||||
info!("Message {} successfully deleted", uid);
|
debug!("message {} successfully deleted", uid);
|
||||||
|
app.output
|
||||||
|
.print(format!("Message {} successfully deleted", uid));
|
||||||
|
|
||||||
imap_conn.expunge(&mbox)?;
|
imap_conn.expunge(&app.mbox)?;
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("send") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("send") {
|
||||||
debug!("send command matched");
|
debug!("send command matched");
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = matches.value_of("message").unwrap();
|
let msg = matches.value_of("message").unwrap();
|
||||||
let msg = Msg::from(msg.to_string());
|
let msg = Msg::from(msg.to_string());
|
||||||
let msg = msg.to_sendable_msg()?;
|
let msg = msg.to_sendable_msg()?;
|
||||||
smtp::send(&account, &msg)?;
|
smtp::send(&app.account, &msg)?;
|
||||||
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
imap_conn.append_msg("Sent", &msg.formatted(), &[Flag::Seen])?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("save") {
|
if let Some(matches) = app.arg_matches.subcommand_matches("save") {
|
||||||
debug!("save command matched");
|
debug!("save command matched");
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msg = matches.value_of("message").unwrap();
|
let msg = matches.value_of("message").unwrap();
|
||||||
let msg = Msg::from(msg.to_string());
|
let msg = Msg::from(msg.to_string());
|
||||||
imap_conn.append_msg(&mbox, &msg.to_vec()?, &[Flag::Seen])?;
|
imap_conn.append_msg(&app.mbox, &msg.to_vec()?, &[Flag::Seen])?;
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
@ -604,10 +615,11 @@ pub fn msg_matches(
|
||||||
{
|
{
|
||||||
debug!("default list command matched");
|
debug!("default list command matched");
|
||||||
|
|
||||||
let mut imap_conn = ImapConnector::new(&account)?;
|
let mut imap_conn = ImapConnector::new(&app.account)?;
|
||||||
let msgs = imap_conn.list_msgs(&mbox, &config.default_page_size(&account), &0)?;
|
let msgs =
|
||||||
|
imap_conn.list_msgs(&app.mbox, &app.config.default_page_size(&app.account), &0)?;
|
||||||
let msgs = Msgs::from(&msgs);
|
let msgs = Msgs::from(&msgs);
|
||||||
info!("{}", msgs);
|
app.output.print(msgs);
|
||||||
|
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
|
@ -15,7 +15,6 @@ use uuid::Uuid;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::model::{Account, Config},
|
config::model::{Account, Config},
|
||||||
flag::model::{Flag, Flags},
|
flag::model::{Flag, Flags},
|
||||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
|
||||||
table::{Cell, Row, Table},
|
table::{Cell, Row, Table},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,18 +32,8 @@ pub struct Tpl(String);
|
||||||
|
|
||||||
impl fmt::Display for Tpl {
|
impl fmt::Display for Tpl {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
|
||||||
match get_output_fmt() {
|
|
||||||
&OutputFmt::Plain => {
|
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
&OutputFmt::Json => {
|
|
||||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
|
||||||
write!(f, "{}", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Tpl {
|
impl Serialize for Tpl {
|
||||||
|
@ -132,18 +121,8 @@ impl Serialize for ReadableMsg {
|
||||||
|
|
||||||
impl fmt::Display for ReadableMsg {
|
impl fmt::Display for ReadableMsg {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
|
||||||
match get_output_fmt() {
|
|
||||||
&OutputFmt::Plain => {
|
|
||||||
writeln!(f, "{}", self.content)
|
writeln!(f, "{}", self.content)
|
||||||
}
|
}
|
||||||
&OutputFmt::Json => {
|
|
||||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
|
||||||
write!(f, "{}", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ReadableMsg {
|
impl<'a> ReadableMsg {
|
||||||
|
@ -677,16 +656,6 @@ impl<'m> From<&'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>> for Msgs<'m> {
|
||||||
|
|
||||||
impl<'m> fmt::Display for Msgs<'m> {
|
impl<'m> fmt::Display for Msgs<'m> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
|
||||||
match get_output_fmt() {
|
|
||||||
&OutputFmt::Plain => {
|
|
||||||
writeln!(f, "\n{}", Table::render(&self.0))
|
writeln!(f, "\n{}", Table::render(&self.0))
|
||||||
}
|
}
|
||||||
&OutputFmt::Json => {
|
|
||||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
|
||||||
write!(f, "{}", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,7 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub static mut OUTPUT_FMT: &'static OutputFmt = &OutputFmt::Plain;
|
// Output format
|
||||||
|
|
||||||
pub fn set_output_fmt(output_fmt: &'static OutputFmt) {
|
|
||||||
unsafe { OUTPUT_FMT = output_fmt }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_output_fmt() -> &'static OutputFmt {
|
|
||||||
OUTPUT_FMT
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum OutputFmt {
|
pub enum OutputFmt {
|
||||||
Plain,
|
Plain,
|
||||||
|
@ -38,6 +30,8 @@ impl fmt::Display for OutputFmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Response helper
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Response<T: Serialize + fmt::Display> {
|
pub struct Response<T: Serialize + fmt::Display> {
|
||||||
response: T,
|
response: T,
|
||||||
|
@ -49,17 +43,4 @@ impl<T: Serialize + fmt::Display> Response<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize + fmt::Display> fmt::Display for Response<T> {
|
// Print helper
|
||||||
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,83 +0,0 @@
|
||||||
use chrono::Local;
|
|
||||||
use env_logger;
|
|
||||||
use error_chain::error_chain;
|
|
||||||
use log::{self, debug, Level, LevelFilter};
|
|
||||||
use std::{fmt, io, io::Write, ops::Deref};
|
|
||||||
|
|
||||||
use super::fmt::{set_output_fmt, OutputFmt};
|
|
||||||
|
|
||||||
error_chain! {}
|
|
||||||
|
|
||||||
// Log level wrapper
|
|
||||||
|
|
||||||
pub struct LogLevel(pub LevelFilter);
|
|
||||||
|
|
||||||
impl From<&str> for LogLevel {
|
|
||||||
fn from(s: &str) -> Self {
|
|
||||||
match s {
|
|
||||||
"error" => Self(LevelFilter::Error),
|
|
||||||
"warn" => Self(LevelFilter::Warn),
|
|
||||||
"debug" => Self(LevelFilter::Debug),
|
|
||||||
"trace" => Self(LevelFilter::Trace),
|
|
||||||
"info" | _ => Self(LevelFilter::Info),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for LogLevel {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.deref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for LogLevel {
|
|
||||||
type Target = LevelFilter;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init
|
|
||||||
|
|
||||||
pub fn init(fmt: OutputFmt, filter: LogLevel) -> Result<()> {
|
|
||||||
let level_filter = filter.deref();
|
|
||||||
let level = level_filter.to_level();
|
|
||||||
|
|
||||||
match fmt {
|
|
||||||
OutputFmt::Plain => {
|
|
||||||
set_output_fmt(&OutputFmt::Plain);
|
|
||||||
}
|
|
||||||
OutputFmt::Json => {
|
|
||||||
set_output_fmt(&OutputFmt::Json);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
env_logger::Builder::new()
|
|
||||||
.target(env_logger::Target::Stdout)
|
|
||||||
.format(move |buf, record| match level {
|
|
||||||
None => Ok(()),
|
|
||||||
Some(Level::Info) => match record.metadata().level() {
|
|
||||||
Level::Info => write!(buf, "{}", record.args()),
|
|
||||||
Level::Error => writeln!(&mut io::stderr(), "{}", record.args()),
|
|
||||||
_ => writeln!(buf, "{}", record.args()),
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
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_filter)
|
|
||||||
.init();
|
|
||||||
|
|
||||||
debug!("output format: {}", fmt);
|
|
||||||
debug!("log level: {}", filter);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,4 +1,3 @@
|
||||||
pub(crate) mod cli;
|
pub(crate) mod cli;
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod model;
|
||||||
pub(crate) mod log;
|
|
||||||
pub(crate) mod utils;
|
pub(crate) mod utils;
|
||||||
|
|
67
src/output/model.rs
Normal file
67
src/output/model.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// Output format
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OutputFmt {
|
||||||
|
Plain,
|
||||||
|
Json,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for OutputFmt {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"json" => Self::Json,
|
||||||
|
"plain" | _ => Self::Plain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for OutputFmt {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let fmt = match *self {
|
||||||
|
OutputFmt::Json => "JSON",
|
||||||
|
OutputFmt::Plain => "PLAIN",
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{}", fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON output helper
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct OutputJson<T: Serialize> {
|
||||||
|
response: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Serialize> OutputJson<T> {
|
||||||
|
pub fn new(response: T) -> Self {
|
||||||
|
Self { response }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Output {
|
||||||
|
fmt: OutputFmt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
pub fn new(fmt: &str) -> Self {
|
||||||
|
Self { fmt: fmt.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print<T: Serialize + fmt::Display>(&self, item: T) {
|
||||||
|
match self.fmt {
|
||||||
|
OutputFmt::Plain => {
|
||||||
|
println!("{}", item)
|
||||||
|
}
|
||||||
|
OutputFmt::Json => {
|
||||||
|
print!("{}", serde_json::to_string(&OutputJson::new(item)).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue