From 96c527dd1ab8c7914e47f2f5b22b7fd5a88dfe28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Tue, 23 Mar 2021 22:06:42 +0100 Subject: [PATCH] clean msg/mbox cli files --- src/app.rs | 355 +------------------- src/flag/cli.rs | 6 +- src/imap.rs | 6 +- src/mbox/cli.rs | 10 +- src/msg/cli.rs | 837 ++++++++++++++++++++---------------------------- 5 files changed, 380 insertions(+), 834 deletions(-) diff --git a/src/app.rs b/src/app.rs index 0cc3352..8faa774 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,21 +1,15 @@ use clap::{self, Arg, SubCommand}; use error_chain::error_chain; -use std::{env, fs}; +use std::env; use crate::{ - config::Config, flag::cli::{flag_matches, flag_subcmds}, - imap::ImapConnector, - input, mbox::cli::{mbox_arg, mbox_matches, mbox_subcmds}, - msg::cli::{msg_args, msg_matches, msg_subcmds}, - output::{self, print}, - smtp, + msg::cli::{msg_matches, msg_subcmds}, }; error_chain! { links { - Config(crate::config::Error, crate::config::ErrorKind); MboxCli(crate::mbox::cli::Error, crate::mbox::cli::ErrorKind); MsgCli(crate::msg::cli::Error, crate::msg::cli::ErrorKind); FlagCli(crate::flag::cli::Error, crate::flag::cli::ErrorKind); @@ -25,47 +19,6 @@ error_chain! { pub struct App<'a>(pub clap::App<'a, 'a>); impl<'a> App<'a> { - // fn mailbox_arg() -> Arg<'a, 'a> { - // Arg::with_name("mailbox") - // .short("m") - // .long("mailbox") - // .help("Mailbox name") - // .value_name("STRING") - // .default_value("INBOX") - // } - - // fn uid_arg() -> Arg<'a, 'a> { - // Arg::with_name("uid") - // .help("Message UID") - // .value_name("UID") - // .required(true) - // } - - // fn reply_all_arg() -> Arg<'a, 'a> { - // Arg::with_name("reply-all") - // .help("Includes all recipients") - // .short("a") - // .long("all") - // } - - // fn page_size_arg() -> Arg<'a, 'a> { - // Arg::with_name("size") - // .help("Page size") - // .short("s") - // .long("size") - // .value_name("INT") - // .default_value("10") - // } - - // fn page_arg() -> Arg<'a, 'a> { - // Arg::with_name("page") - // .help("Page number") - // .short("p") - // .long("page") - // .value_name("INT") - // .default_value("0") - // } - pub fn new() -> Self { let app = clap::App::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) @@ -87,12 +40,12 @@ impl<'a> App<'a> { .help("Selects a specific account") .value_name("STRING"), ) - .arg(mbox_arg()); + .arg(mbox_arg()) + .subcommand(SubCommand::with_name("idle").about("Spawns a blocking idle daemon")); let app = app.subcommands(mbox_subcmds()); - let app = app.subcommands(msg_subcmds()); let app = app.subcommands(flag_subcmds()); - let app = app.args(&msg_args()); + let app = app.subcommands(msg_subcmds()); Self(app) } @@ -100,296 +53,18 @@ impl<'a> App<'a> { pub fn run(self) -> Result<()> { let matches = self.0.get_matches(); - let matched = mbox_matches(&matches)?; - let matched = flag_matches(matched, &matches)?; - let matched = msg_matches(matched, &matches)?; + loop { + if mbox_matches(&matches)? { + break; + } - // if let Some(matches) = matches.subcommand_matches("search") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - // let mbox = matches.value_of("mailbox").unwrap(); - // let page_size: usize = matches.value_of("size").unwrap().parse().unwrap(); - // let page: usize = matches.value_of("page").unwrap().parse().unwrap(); - // let query = matches - // .values_of("query") - // .unwrap_or_default() - // .fold((false, vec![]), |(escape, mut cmds), cmd| { - // match (cmd, escape) { - // // Next command is an arg and needs to be escaped - // ("subject", _) | ("body", _) | ("text", _) => { - // cmds.push(cmd.to_string()); - // (true, cmds) - // } - // // Escaped arg commands - // (_, true) => { - // cmds.push(format!("\"{}\"", cmd)); - // (false, cmds) - // } - // // Regular commands - // (_, false) => { - // cmds.push(cmd.to_string()); - // (false, cmds) - // } - // } - // }) - // .1 - // .join(" "); + if flag_matches(&matches)? { + break; + } - // let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?; - // let msgs = Msgs::from(&msgs); - - // print(&output_type, msgs)?; - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("read") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - // let mime = format!("text/{}", matches.value_of("mime-type").unwrap()); - - // let msg = imap_conn.read_msg(&mbox, &uid)?; - // let msg = ReadableMsg::from_bytes(&mime, &msg)?; - - // print(&output_type, msg)?; - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("attachments") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // let msg = imap_conn.read_msg(&mbox, &uid)?; - // let attachments = Attachments::from_bytes(&msg)?; - - // match output_type.as_str() { - // "text" => { - // println!( - // "{} attachment(s) found for message {}", - // attachments.0.len(), - // uid - // ); - - // attachments.0.iter().for_each(|attachment| { - // let filepath = config.downloads_filepath(&account, &attachment.filename); - // println!("Downloading {}…", &attachment.filename); - // fs::write(filepath, &attachment.raw).unwrap() - // }); - - // println!("Done!"); - // } - // "json" => { - // attachments.0.iter().for_each(|attachment| { - // let filepath = config.downloads_filepath(&account, &attachment.filename); - // fs::write(filepath, &attachment.raw).unwrap() - // }); - - // print!("{{}}"); - // } - // _ => (), - // } - - // imap_conn.logout(); - // } - - // if let Some(_) = matches.subcommand_matches("write") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - // let tpl = Msg::build_new_tpl(&config, &account)?; - // let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // let msg = msg.to_sendable_msg()?; - // smtp::send(&account, &msg)?; - // imap_conn.append_msg("Sent", &msg.formatted())?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("template") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // if let Some(_) = matches.subcommand_matches("new") { - // let tpl = Msg::build_new_tpl(&config, &account)?; - // print(&output_type, &tpl)?; - // } - - // if let Some(matches) = matches.subcommand_matches("reply") { - // let uid = matches.value_of("uid").unwrap(); - // let mbox = matches.value_of("mailbox").unwrap(); - - // 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)? - // }; - - // print(&output_type, &tpl)?; - // } - - // if let Some(matches) = matches.subcommand_matches("forward") { - // let uid = matches.value_of("uid").unwrap(); - // let mbox = matches.value_of("mailbox").unwrap(); - - // let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - // let tpl = msg.build_forward_tpl(&config, &account)?; - - // print(&output_type, &tpl)?; - // } - // } - - // if let Some(matches) = matches.subcommand_matches("reply") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // 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)? - // }; - - // let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // smtp::send(&account, &msg.to_sendable_msg()?)?; - // imap_conn.append_msg("Sent", &msg.to_vec()?)?; - // imap_conn.add_flags(mbox, uid, "\\Answered")?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("forward") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - // let tpl = msg.build_forward_tpl(&config, &account)?; - // let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // smtp::send(&account, &msg.to_sendable_msg()?)?; - // imap_conn.append_msg("Sent", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("send") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let msg = matches.value_of("message").unwrap(); - // let msg = Msg::from(msg.to_string()); - // let msg = msg.to_sendable_msg()?; - - // smtp::send(&account, &msg)?; - // imap_conn.append_msg("Sent", &msg.formatted())?; - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("save") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let msg = matches.value_of("message").unwrap(); - // let msg = Msg::from(msg.to_string()); - - // imap_conn.append_msg(mbox, &msg.to_vec()?)?; - // imap_conn.logout(); - // } + msg_matches(&matches)?; + break; + } // if let Some(matches) = matches.subcommand_matches("idle") { // let config = Config::new_from_file()?; diff --git a/src/flag/cli.rs b/src/flag/cli.rs index 24ffa67..125ded8 100644 --- a/src/flag/cli.rs +++ b/src/flag/cli.rs @@ -55,11 +55,7 @@ pub fn flag_subcmds<'a>() -> Vec> { )] } -pub fn flag_matches(matched: bool, matches: &ArgMatches) -> Result { - if matched { - return Ok(true); - } - +pub fn flag_matches(matches: &ArgMatches) -> Result { let config = Config::new_from_file()?; let account = config.find_account_by_name(matches.value_of("account"))?; let output_fmt = matches.value_of("output").unwrap(); diff --git a/src/imap.rs b/src/imap.rs index a7ff851..54c2f2f 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -136,8 +136,8 @@ impl<'ic> ImapConnector<'ic> { pub fn list_msgs( &mut self, mbox: &str, - page_size: &u32, - page: &u32, + page_size: &usize, + page: &usize, ) -> Result>> { let last_seq = self .sess @@ -146,7 +146,7 @@ impl<'ic> ImapConnector<'ic> { .exists as i64; if last_seq == 0 { - return Err(format!("Cannot select empty mailbox `{}`", mbox).into()); + return Err(format!("The `{}` mailbox is empty", mbox).into()); } // TODO: add tests, improve error management when empty page diff --git a/src/mbox/cli.rs b/src/mbox/cli.rs index 8b73417..418b15d 100644 --- a/src/mbox/cli.rs +++ b/src/mbox/cli.rs @@ -28,15 +28,15 @@ pub fn mbox_subcmds<'a>() -> Vec> { } pub fn mbox_matches(matches: &ArgMatches) -> Result { + let config = Config::new_from_file()?; + let account = config.find_account_by_name(matches.value_of("account"))?; + let output_fmt = matches.value_of("output").unwrap(); + let mut imap_conn = ImapConnector::new(&account)?; + if let Some(_) = matches.subcommand_matches("mailboxes") { - let config = Config::new_from_file()?; - let account = config.find_account_by_name(matches.value_of("account"))?; - let output_fmt = matches.value_of("output").unwrap(); - let mut imap_conn = ImapConnector::new(&account)?; let mboxes = imap_conn.list_mboxes()?; print(&output_fmt, mboxes)?; imap_conn.logout(); - return Ok(true); } diff --git a/src/msg/cli.rs b/src/msg/cli.rs index 42eb0dc..58ad02f 100644 --- a/src/msg/cli.rs +++ b/src/msg/cli.rs @@ -1,51 +1,42 @@ use clap::{self, App, Arg, ArgMatches, SubCommand}; use error_chain::error_chain; -use std::{env, fs}; +use std::fs; use crate::{ - config::{self, Account, Config}, - imap::{self, ImapConnector}, + config::Config, + imap::ImapConnector, input, - // msg::{self, Attachments, Msg, Msgs, ReadableMsg}, - msg::model::Msgs, - output::{self, print}, + msg::model::{Attachments, Msg, Msgs, ReadableMsg}, + output::print, smtp, }; error_chain! { links { - Config(config::Error, config::ErrorKind); - Imap(imap::Error, imap::ErrorKind); - Input(input::Error, input::ErrorKind); - Output(output::Error, output::ErrorKind); - Smtp(smtp::Error, smtp::ErrorKind); + Config(crate::config::Error, crate::config::ErrorKind); + Imap(crate::imap::Error, crate::imap::ErrorKind); + Input(crate::input::Error, crate::input::ErrorKind); + MsgModel(crate::msg::model::Error, crate::msg::model::ErrorKind); + Output(crate::output::Error, crate::output::ErrorKind); + Smtp(crate::smtp::Error, crate::smtp::ErrorKind); } } -fn mailbox_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("mailbox") - .short("m") - .long("mailbox") - .help("Mailbox name") - .value_name("STRING") - .default_value("INBOX") -} - -fn uid_arg<'a, 'b>() -> Arg<'a, 'b> { +fn uid_arg<'a>() -> Arg<'a, 'a> { Arg::with_name("uid") .help("Message UID") .value_name("UID") .required(true) } -fn reply_all_arg<'a, 'b>() -> Arg<'a, 'b> { +fn reply_all_arg<'a>() -> Arg<'a, 'a> { Arg::with_name("reply-all") .help("Includes all recipients") .short("a") .long("all") } -fn page_size_arg<'a, 'b>() -> Arg<'a, 'b> { +fn page_size_arg<'a>() -> Arg<'a, 'a> { Arg::with_name("size") .help("Page size") .short("s") @@ -54,7 +45,7 @@ fn page_size_arg<'a, 'b>() -> Arg<'a, 'b> { .default_value("10") } -fn page_arg<'a, 'b>() -> Arg<'a, 'b> { +fn page_arg<'a>() -> Arg<'a, 'a> { Arg::with_name("page") .help("Page number") .short("p") @@ -63,474 +54,358 @@ fn page_arg<'a, 'b>() -> Arg<'a, 'b> { .default_value("0") } -pub fn msg_args<'a>() -> Vec> { +pub fn msg_subcmds<'a>() -> Vec> { vec![ - Arg::with_name("page") - .help("Page number") - .short("p") - .long("page") - .value_name("INT") - .default_value("0"), - Arg::with_name("size") - .help("Page size") - .short("s") - .long("size") - .value_name("INT") - .default_value("10"), + SubCommand::with_name("messages") + .aliases(&["message", "msgs", "msg", "m"]) + .about("Lists all messages") + .arg(page_size_arg()) + .arg(page_arg()), + SubCommand::with_name("search") + .aliases(&["query", "q", "s"]) + .about("Lists messages matching the given IMAP query") + .arg(page_size_arg()) + .arg(page_arg()) + .arg( + Arg::with_name("query") + .help("IMAP query (see https://tools.ietf.org/html/rfc3501#section-6.4.4)") + .value_name("QUERY") + .multiple(true) + .required(true), + ), + SubCommand::with_name("write").about("Writes a new message"), + SubCommand::with_name("send") + .about("Sends a raw message") + .arg(Arg::with_name("message").raw(true)), + SubCommand::with_name("save") + .about("Saves a raw message") + .arg(Arg::with_name("message").raw(true)), + SubCommand::with_name("read") + .aliases(&["r"]) + .about("Reads text bodies of a message") + .arg(uid_arg()) + .arg( + Arg::with_name("mime-type") + .help("MIME type to use") + .short("t") + .long("mime-type") + .value_name("STRING") + .possible_values(&["plain", "html"]) + .default_value("plain"), + ), + SubCommand::with_name("attachments") + .aliases(&["attach", "att", "a"]) + .about("Downloads all attachments from an email") + .arg(uid_arg()), + SubCommand::with_name("reply") + .aliases(&["rep", "re"]) + .about("Answers to an email") + .arg(uid_arg()) + .arg(reply_all_arg()), + SubCommand::with_name("forward") + .aliases(&["fwd", "f"]) + .about("Forwards an email") + .arg(uid_arg()), + SubCommand::with_name("template") + .aliases(&["tpl", "t"]) + .about("Generates a message template") + .subcommand( + SubCommand::with_name("new") + .aliases(&["n"]) + .about("Generates a new message template"), + ) + .subcommand( + SubCommand::with_name("reply") + .aliases(&["rep", "r"]) + .about("Generates a reply message template") + .arg(uid_arg()) + .arg(reply_all_arg()), + ) + .subcommand( + SubCommand::with_name("forward") + .aliases(&["fwd", "fw", "f"]) + .about("Generates a forward message template") + .arg(uid_arg()), + ), ] } -pub fn msg_subcmds<'a>() -> Vec> { - vec![SubCommand::with_name("list") - .aliases(&["lst", "l"]) - .about("Lists messages sorted by UID") - .arg(page_size_arg()) - .arg(page_arg())] - // SubCommand::with_name("messages") - // .aliases(&["messages", "message", "msgs", "msg"]) - // .about("Handles message actions") - // .arg(mailbox_arg()) - // .subcommand( - // SubCommand::with_name("list") - // .aliases(&["lst", "l"]) - // .about("Lists messages sorted by UID") - // .arg(page_size_arg()) - // .arg(page_arg()), - // ) - // .subcommand( - // SubCommand::with_name("search") - // .aliases(&["query", "q", "s"]) - // .about("Lists messages matching the given IMAP query") - // .arg(page_size_arg()) - // .arg(page_arg()) - // .arg( - // Arg::with_name("query") - // .help("IMAP query (see https://tools.ietf.org/html/rfc3501#section-6.4.4)") - // .value_name("QUERY") - // .multiple(true) - // .required(true), - // ), - // ) - // .subcommand(SubCommand::with_name("write").about("Writes a new message")) - // .subcommand( - // SubCommand::with_name("send") - // .about("Sends a raw message") - // .arg(Arg::with_name("message").raw(true)), - // ) - // .subcommand( - // SubCommand::with_name("save") - // .about("Saves a raw message") - // .arg(Arg::with_name("message").raw(true)), - // ) - // .subcommand( - // SubCommand::with_name("read") - // .aliases(&["r"]) - // .about("Reads text bodies of a message") - // .arg(uid_arg()) - // .arg( - // Arg::with_name("mime-type") - // .help("MIME type to use") - // .short("t") - // .long("mime-type") - // .value_name("STRING") - // .possible_values(&["plain", "html"]) - // .default_value("plain"), - // ), - // ) - // .subcommand( - // SubCommand::with_name("attachments") - // .aliases(&["attach", "att", "a"]) - // .about("Downloads all attachments from an email") - // .arg(uid_arg()), - // ) - // .subcommand( - // SubCommand::with_name("reply") - // .aliases(&["rep", "re"]) - // .about("Answers to an email") - // .arg(uid_arg()) - // .arg(reply_all_arg()), - // ) - // .subcommand( - // SubCommand::with_name("forward") - // .aliases(&["fwd", "f"]) - // .about("Forwards an email") - // .arg(uid_arg()), - // ) - // .subcommand( - // SubCommand::with_name("template") - // .aliases(&["tpl", "t"]) - // .about("Generates a message template") - // .subcommand( - // SubCommand::with_name("new") - // .aliases(&["n"]) - // .about("Generates a new message template"), - // ) - // .subcommand( - // SubCommand::with_name("reply") - // .aliases(&["rep", "r"]) - // .about("Generates a reply message template") - // .arg(uid_arg()) - // .arg(reply_all_arg()), - // ) - // .subcommand( - // SubCommand::with_name("forward") - // .aliases(&["fwd", "fw", "f"]) - // .about("Generates a forward message template") - // .arg(uid_arg()), - // ), - // ) -} - -pub fn msg_matches(matched: bool, matches: &ArgMatches) -> Result { - if matched { - return Ok(true); - } - +pub fn msg_matches(matches: &ArgMatches) -> Result<()> { let config = Config::new_from_file()?; let account = config.find_account_by_name(matches.value_of("account"))?; let output_fmt = matches.value_of("output").unwrap(); let mbox = matches.value_of("mailbox").unwrap(); let mut imap_conn = ImapConnector::new(&account)?; - let page_size: u32 = matches.value_of("size").unwrap().parse().unwrap(); - let page: u32 = matches.value_of("page").unwrap().parse().unwrap(); + loop { + if let Some(matches) = matches.subcommand_matches("messages") { + let page_size: usize = matches.value_of("size").unwrap().parse().unwrap(); + let page: usize = matches.value_of("page").unwrap().parse().unwrap(); - let msgs = imap_conn.list_msgs(&mbox, &page_size, &page)?; - let msgs = Msgs::from(&msgs); + let msgs = imap_conn.list_msgs(&mbox, &page_size, &page)?; + let msgs = Msgs::from(&msgs); + + print(&output_fmt, msgs)?; + break; + } + + if let Some(matches) = matches.subcommand_matches("search") { + let page_size: usize = matches.value_of("size").unwrap().parse().unwrap(); + let page: usize = matches.value_of("page").unwrap().parse().unwrap(); + let query = matches + .values_of("query") + .unwrap_or_default() + .fold((false, vec![]), |(escape, mut cmds), cmd| { + match (cmd, escape) { + // Next command is an arg and needs to be escaped + ("subject", _) | ("body", _) | ("text", _) => { + cmds.push(cmd.to_string()); + (true, cmds) + } + // Escaped arg commands + (_, true) => { + cmds.push(format!("\"{}\"", cmd)); + (false, cmds) + } + // Regular commands + (_, false) => { + cmds.push(cmd.to_string()); + (false, cmds) + } + } + }) + .1 + .join(" "); + + let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?; + let msgs = Msgs::from(&msgs); + + print(&output_fmt, msgs)?; + break; + } + + if let Some(matches) = matches.subcommand_matches("read") { + let uid = matches.value_of("uid").unwrap(); + let mime = format!("text/{}", matches.value_of("mime-type").unwrap()); + + let msg = imap_conn.read_msg(&mbox, &uid)?; + let msg = ReadableMsg::from_bytes(&mime, &msg)?; + + print(&output_fmt, msg)?; + break; + } + + if let Some(matches) = matches.subcommand_matches("attachments") { + let uid = matches.value_of("uid").unwrap(); + + let msg = imap_conn.read_msg(&mbox, &uid)?; + let attachments = Attachments::from_bytes(&msg)?; + + match output_fmt { + "text" => { + println!( + "{} attachment(s) found for message {}", + attachments.0.len(), + uid + ); + + attachments.0.iter().for_each(|attachment| { + let filepath = config.downloads_filepath(&account, &attachment.filename); + println!("Downloading {}…", &attachment.filename); + fs::write(filepath, &attachment.raw).unwrap() + }); + + println!("Done!"); + } + "json" => { + attachments.0.iter().for_each(|attachment| { + let filepath = config.downloads_filepath(&account, &attachment.filename); + fs::write(filepath, &attachment.raw).unwrap() + }); + + print!("{{}}"); + } + _ => (), + } + + break; + } + + if let Some(_) = matches.subcommand_matches("write") { + let tpl = Msg::build_new_tpl(&config, &account)?; + let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?; + let mut msg = Msg::from(content); + + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + let msg = msg.to_sendable_msg()?; + smtp::send(&account, &msg)?; + imap_conn.append_msg("Sent", &msg.formatted())?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } + + break; + } + + if let Some(matches) = matches.subcommand_matches("template") { + if let Some(_) = matches.subcommand_matches("new") { + let tpl = Msg::build_new_tpl(&config, &account)?; + print(&output_fmt, &tpl)?; + } + + if let Some(matches) = matches.subcommand_matches("reply") { + let uid = matches.value_of("uid").unwrap(); + let mbox = matches.value_of("mailbox").unwrap(); + + 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)? + }; + + print(&output_fmt, &tpl)?; + } + + if let Some(matches) = matches.subcommand_matches("forward") { + let uid = matches.value_of("uid").unwrap(); + let mbox = matches.value_of("mailbox").unwrap(); + + let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); + let tpl = msg.build_forward_tpl(&config, &account)?; + + print(&output_fmt, &tpl)?; + } + + break; + } + + if let Some(matches) = matches.subcommand_matches("reply") { + let uid = matches.value_of("uid").unwrap(); + + 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)? + }; + + let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; + let mut msg = Msg::from(content); + + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + smtp::send(&account, &msg.to_sendable_msg()?)?; + imap_conn.append_msg("Sent", &msg.to_vec()?)?; + imap_conn.add_flags(mbox, uid, "\\Answered")?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } + + break; + } + + if let Some(matches) = matches.subcommand_matches("forward") { + let uid = matches.value_of("uid").unwrap(); + + let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); + let tpl = msg.build_forward_tpl(&config, &account)?; + let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; + let mut msg = Msg::from(content); + + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + smtp::send(&account, &msg.to_sendable_msg()?)?; + imap_conn.append_msg("Sent", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } + + break; + } + + if let Some(matches) = matches.subcommand_matches("send") { + let msg = matches.value_of("message").unwrap(); + let msg = Msg::from(msg.to_string()); + let msg = msg.to_sendable_msg()?; + + smtp::send(&account, &msg)?; + imap_conn.append_msg("Sent", &msg.formatted())?; + break; + } + + if let Some(matches) = matches.subcommand_matches("save") { + let msg = matches.value_of("message").unwrap(); + let msg = Msg::from(msg.to_string()); + + imap_conn.append_msg(mbox, &msg.to_vec()?)?; + break; + } + + // Default case: list all messages + + let msgs = imap_conn.list_msgs(&mbox, &10, &0)?; + let msgs = Msgs::from(&msgs); + + print(&output_fmt, msgs)?; + break; + } - print(&output_fmt, msgs)?; imap_conn.logout(); - - Ok(false) - // let output_type = matches.value_of("output").unwrap().to_owned(); - // let account = matches.value_of("account"); - // let mbox = matches.value_of("mailbox").unwrap(); - - // if let Some(_) = matches.subcommand_matches("mailboxes") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mboxes = imap_conn.list_mboxes()?; - // print(&output_type, mboxes)?; - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("flags") { - // flags_matches(account, &mbox, &matches) - // .chain_err(|| "Could not handle flags arg matches")?; - // } - - // if let Some(matches) = matches.subcommand_matches("list") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let page_size: u32 = matches.value_of("size").unwrap().parse().unwrap(); - // let page: u32 = matches.value_of("page").unwrap().parse().unwrap(); - - // let msgs = imap_conn.list_msgs(&mbox, &page_size, &page)?; - // let msgs = Msgs::from(&msgs); - - // print(&output_type, msgs)?; - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("search") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - // let mbox = matches.value_of("mailbox").unwrap(); - // let page_size: usize = matches.value_of("size").unwrap().parse().unwrap(); - // let page: usize = matches.value_of("page").unwrap().parse().unwrap(); - // let query = matches - // .values_of("query") - // .unwrap_or_default() - // .fold((false, vec![]), |(escape, mut cmds), cmd| { - // match (cmd, escape) { - // // Next command is an arg and needs to be escaped - // ("subject", _) | ("body", _) | ("text", _) => { - // cmds.push(cmd.to_string()); - // (true, cmds) - // } - // // Escaped arg commands - // (_, true) => { - // cmds.push(format!("\"{}\"", cmd)); - // (false, cmds) - // } - // // Regular commands - // (_, false) => { - // cmds.push(cmd.to_string()); - // (false, cmds) - // } - // } - // }) - // .1 - // .join(" "); - - // let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?; - // let msgs = Msgs::from(&msgs); - - // print(&output_type, msgs)?; - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("read") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - // let mime = format!("text/{}", matches.value_of("mime-type").unwrap()); - - // let msg = imap_conn.read_msg(&mbox, &uid)?; - // let msg = ReadableMsg::from_bytes(&mime, &msg)?; - - // print(&output_type, msg)?; - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("attachments") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // let msg = imap_conn.read_msg(&mbox, &uid)?; - // let attachments = Attachments::from_bytes(&msg)?; - - // match output_type.as_str() { - // "text" => { - // println!( - // "{} attachment(s) found for message {}", - // attachments.0.len(), - // uid - // ); - - // attachments.0.iter().for_each(|attachment| { - // let filepath = config.downloads_filepath(&account, &attachment.filename); - // println!("Downloading {}…", &attachment.filename); - // fs::write(filepath, &attachment.raw).unwrap() - // }); - - // println!("Done!"); - // } - // "json" => { - // attachments.0.iter().for_each(|attachment| { - // let filepath = config.downloads_filepath(&account, &attachment.filename); - // fs::write(filepath, &attachment.raw).unwrap() - // }); - - // print!("{{}}"); - // } - // _ => (), - // } - - // imap_conn.logout(); - // } - - // if let Some(_) = matches.subcommand_matches("write") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - // let tpl = Msg::build_new_tpl(&config, &account)?; - // let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // let msg = msg.to_sendable_msg()?; - // smtp::send(&account, &msg)?; - // imap_conn.append_msg("Sent", &msg.formatted())?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("template") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // if let Some(_) = matches.subcommand_matches("new") { - // let tpl = Msg::build_new_tpl(&config, &account)?; - // print(&output_type, &tpl)?; - // } - - // if let Some(matches) = matches.subcommand_matches("reply") { - // let uid = matches.value_of("uid").unwrap(); - // let mbox = matches.value_of("mailbox").unwrap(); - - // 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)? - // }; - - // print(&output_type, &tpl)?; - // } - - // if let Some(matches) = matches.subcommand_matches("forward") { - // let uid = matches.value_of("uid").unwrap(); - // let mbox = matches.value_of("mailbox").unwrap(); - - // let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - // let tpl = msg.build_forward_tpl(&config, &account)?; - - // print(&output_type, &tpl)?; - // } - // } - - // if let Some(matches) = matches.subcommand_matches("reply") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // 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)? - // }; - - // let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // smtp::send(&account, &msg.to_sendable_msg()?)?; - // imap_conn.append_msg("Sent", &msg.to_vec()?)?; - // imap_conn.add_flags(mbox, uid, "\\Answered")?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("forward") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let uid = matches.value_of("uid").unwrap(); - - // let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - // let tpl = msg.build_forward_tpl(&config, &account)?; - // let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - // let mut msg = Msg::from(content); - - // loop { - // match input::post_edit_choice() { - // Ok(choice) => match choice { - // input::Choice::Send => { - // println!("Sending…"); - // smtp::send(&account, &msg.to_sendable_msg()?)?; - // imap_conn.append_msg("Sent", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Draft => { - // println!("Saving to draft…"); - // imap_conn.append_msg("Drafts", &msg.to_vec()?)?; - // println!("Done!"); - // break; - // } - // input::Choice::Edit => { - // let content = input::open_editor_with_draft()?; - // msg = Msg::from(content); - // } - // input::Choice::Quit => break, - // }, - // Err(err) => eprintln!("{}", err), - // } - // } - - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("send") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let msg = matches.value_of("message").unwrap(); - // let msg = Msg::from(msg.to_string()); - // let msg = msg.to_sendable_msg()?; - - // smtp::send(&account, &msg)?; - // imap_conn.append_msg("Sent", &msg.formatted())?; - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("save") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - - // let mbox = matches.value_of("mailbox").unwrap(); - // let msg = matches.value_of("message").unwrap(); - // let msg = Msg::from(msg.to_string()); - - // imap_conn.append_msg(mbox, &msg.to_vec()?)?; - // imap_conn.logout(); - // } - - // if let Some(matches) = matches.subcommand_matches("idle") { - // let config = Config::new_from_file()?; - // let account = config.find_account_by_name(account)?; - // let mut imap_conn = ImapConnector::new(&account)?; - // let mbox = matches.value_of("mailbox").unwrap(); - // imap_conn.idle(&config, &mbox)?; - // } + Ok(()) }