diff --git a/src/msg/cli.rs b/src/msg/cli.rs index 75718f3..466e2c4 100644 --- a/src/msg/cli.rs +++ b/src/msg/cli.rs @@ -39,7 +39,7 @@ fn reply_all_arg<'a>() -> Arg<'a, 'a> { } fn page_size_arg<'a>() -> Arg<'a, 'a> { - Arg::with_name("size") + Arg::with_name("page-size") .help("Page size") .short("s") .long("size") @@ -164,330 +164,327 @@ pub fn msg_matches(matches: &ArgMatches) -> Result<()> { let output_fmt = matches.value_of("output").unwrap(); let mbox = matches.value_of("mailbox").unwrap(); - loop { - if let Some(matches) = matches.subcommand_matches("messages") { - let mut imap_conn = ImapConnector::new(&account)?; - 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); - print(&output_fmt, msgs)?; - imap_conn.logout(); - break; - } + if let Some(matches) = matches.subcommand_matches("list") { + let mut imap_conn = ImapConnector::new(&account)?; + let page_size: usize = matches.value_of("page-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); + print(&output_fmt, msgs)?; + imap_conn.logout(); + return Ok(()); + } - if let Some(matches) = matches.subcommand_matches("search") { - let mut imap_conn = ImapConnector::new(&account)?; - 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) - } + if let Some(matches) = matches.subcommand_matches("search") { + let mut imap_conn = ImapConnector::new(&account)?; + 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)?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("read") { - let mut imap_conn = ImapConnector::new(&account)?; - 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)?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("attachments") { - let mut imap_conn = ImapConnector::new(&account)?; - 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() - }); + }) + .1 + .join(" "); + let msgs = imap_conn.search_msgs(&mbox, &query, &page_size, &page)?; + let msgs = Msgs::from(&msgs); + print(&output_fmt, msgs)?; + imap_conn.logout(); + return Ok(()); + } - print!("{{}}"); - } - _ => (), + if let Some(matches) = matches.subcommand_matches("read") { + let mut imap_conn = ImapConnector::new(&account)?; + 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)?; + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("attachments") { + let mut imap_conn = ImapConnector::new(&account)?; + 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!"); } - imap_conn.logout(); - break; - } + "json" => { + attachments.0.iter().for_each(|attachment| { + let filepath = config.downloads_filepath(&account, &attachment.filename); + fs::write(filepath, &attachment.raw).unwrap() + }); - if let Some(matches) = matches.subcommand_matches("write") { - let mut imap_conn = ImapConnector::new(&account)?; - let attachments = matches - .values_of("attachments") - .unwrap_or_default() - .map(String::from) - .collect::>(); + print!("{{}}"); + } + _ => (), + } + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("write") { + let mut imap_conn = ImapConnector::new(&account)?; + let attachments = matches + .values_of("attachments") + .unwrap_or_default() + .map(String::from) + .collect::>(); + 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); + msg.attachments = attachments; + + 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(), &[Flag::Seen])?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?; + 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(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("template") { + if let Some(_) = matches.subcommand_matches("new") { 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); - msg.attachments = attachments; - - 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(), &[Flag::Seen])?; - println!("Done!"); - break; - } - input::Choice::Draft => { - println!("Saving to draft…"); - imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?; - 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(); - 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 mut imap_conn = ImapConnector::new(&account)?; - 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)? - }; - print(&output_fmt, &tpl)?; - imap_conn.logout(); - } - - if let Some(matches) = matches.subcommand_matches("forward") { - let mut imap_conn = ImapConnector::new(&account)?; - 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)?; - print(&output_fmt, &tpl)?; - imap_conn.logout(); - } - - break; + print(&output_fmt, &tpl)?; } if let Some(matches) = matches.subcommand_matches("reply") { let mut imap_conn = ImapConnector::new(&account)?; - let attachments = matches - .values_of("attachments") - .unwrap_or_default() - .map(String::from) - .collect::>(); 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); - msg.attachments = attachments; - - 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()?, &[Flag::Seen])?; - 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()?, &[Flag::Seen])?; - 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), - } - } + print(&output_fmt, &tpl)?; imap_conn.logout(); - break; } if let Some(matches) = matches.subcommand_matches("forward") { let mut imap_conn = ImapConnector::new(&account)?; - let attachments = matches - .values_of("attachments") - .unwrap_or_default() - .map(String::from) - .collect::>(); 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); - msg.attachments = attachments; - - 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()?, &[Flag::Seen])?; - println!("Done!"); - break; - } - input::Choice::Draft => { - println!("Saving to draft…"); - imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?; - 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), - } - } + print(&output_fmt, &tpl)?; imap_conn.logout(); - break; } - if let Some(matches) = matches.subcommand_matches("copy") { - let mut imap_conn = ImapConnector::new(&account)?; - let uid = matches.value_of("uid").unwrap(); - let target = matches.value_of("target").unwrap(); - let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - let mut flags = msg.flags.deref().to_vec(); - flags.push(Flag::Seen); - imap_conn.append_msg(target, &msg.to_vec()?, &flags)?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("move") { - let mut imap_conn = ImapConnector::new(&account)?; - let uid = matches.value_of("uid").unwrap(); - let target = matches.value_of("target").unwrap(); - let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); - let mut flags = msg.flags.deref().to_vec(); - flags.push(Flag::Seen); - imap_conn.append_msg(target, &msg.to_vec()?, msg.flags.deref())?; - imap_conn.add_flags(mbox, uid, "\\Seen \\Deleted")?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("delete") { - let mut imap_conn = ImapConnector::new(&account)?; - let uid = matches.value_of("uid").unwrap(); - imap_conn.add_flags(mbox, uid, "\\Seen \\Deleted")?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("send") { - 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(), &[Flag::Seen])?; - imap_conn.logout(); - break; - } - - if let Some(matches) = matches.subcommand_matches("save") { - let mut imap_conn = ImapConnector::new(&account)?; - let msg = matches.value_of("message").unwrap(); - let msg = Msg::from(msg.to_string()); - imap_conn.append_msg(mbox, &msg.to_vec()?, &[Flag::Seen])?; - imap_conn.logout(); - break; - } - - // Default case: list all messages - - let mut imap_conn = ImapConnector::new(&account)?; - let msgs = imap_conn.list_msgs(&mbox, &10, &0)?; - let msgs = Msgs::from(&msgs); - print(&output_fmt, msgs)?; - imap_conn.logout(); - break; + return Ok(()); } + if let Some(matches) = matches.subcommand_matches("reply") { + let mut imap_conn = ImapConnector::new(&account)?; + let attachments = matches + .values_of("attachments") + .unwrap_or_default() + .map(String::from) + .collect::>(); + 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); + msg.attachments = attachments; + + 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()?, &[Flag::Seen])?; + 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()?, &[Flag::Seen])?; + 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(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("forward") { + let mut imap_conn = ImapConnector::new(&account)?; + let attachments = matches + .values_of("attachments") + .unwrap_or_default() + .map(String::from) + .collect::>(); + 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); + msg.attachments = attachments; + + 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()?, &[Flag::Seen])?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?, &[Flag::Seen])?; + 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(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("copy") { + let mut imap_conn = ImapConnector::new(&account)?; + let uid = matches.value_of("uid").unwrap(); + let target = matches.value_of("target").unwrap(); + let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); + let mut flags = msg.flags.deref().to_vec(); + flags.push(Flag::Seen); + imap_conn.append_msg(target, &msg.to_vec()?, &flags)?; + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("move") { + let mut imap_conn = ImapConnector::new(&account)?; + let uid = matches.value_of("uid").unwrap(); + let target = matches.value_of("target").unwrap(); + let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); + let mut flags = msg.flags.deref().to_vec(); + flags.push(Flag::Seen); + imap_conn.append_msg(target, &msg.to_vec()?, msg.flags.deref())?; + imap_conn.add_flags(mbox, uid, "\\Seen \\Deleted")?; + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("delete") { + let mut imap_conn = ImapConnector::new(&account)?; + let uid = matches.value_of("uid").unwrap(); + imap_conn.add_flags(mbox, uid, "\\Seen \\Deleted")?; + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("send") { + 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(), &[Flag::Seen])?; + imap_conn.logout(); + return Ok(()); + } + + if let Some(matches) = matches.subcommand_matches("save") { + let mut imap_conn = ImapConnector::new(&account)?; + let msg = matches.value_of("message").unwrap(); + let msg = Msg::from(msg.to_string()); + imap_conn.append_msg(mbox, &msg.to_vec()?, &[Flag::Seen])?; + imap_conn.logout(); + return Ok(()); + } + + // Default case: list first page messages + let mut imap_conn = ImapConnector::new(&account)?; + let msgs = imap_conn.list_msgs(&mbox, &10, &0)?; + let msgs = Msgs::from(&msgs); + print(&output_fmt, msgs)?; + imap_conn.logout(); Ok(()) } diff --git a/vim/autoload/himalaya/msg.vim b/vim/autoload/himalaya/msg.vim index 5a06ef2..b418eda 100644 --- a/vim/autoload/himalaya/msg.vim +++ b/vim/autoload/himalaya/msg.vim @@ -27,9 +27,9 @@ function! himalaya#msg#list() let buftype = stridx(bufname("%"), "Himalaya messages") == 0 ? "file" : "edit" execute printf("silent! %s Himalaya messages [%s] [page %d]", buftype, mbox, page + 1) setlocal modifiable - execute "%d" + silent execute "%d" call append(0, s:render("list", msgs)) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-list let &modified = 0 execute 0 @@ -48,9 +48,9 @@ function! himalaya#msg#read() let attachment = msg.hasAttachment ? " []" : "" execute printf("silent! edit Himalaya read message [%d]%s", s:msg_id, attachment) setlocal modifiable - execute "%d" + silent execute "%d" call append(0, split(substitute(msg.content, "\r", "", "g"), "\n")) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-read let &modified = 0 execute 0 @@ -66,7 +66,7 @@ function! himalaya#msg#write() let msg = s:cli("template new", [], "Fetching new template") silent! edit Himalaya write call append(0, split(substitute(msg.template, "\r", "", "g"), "\n")) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-write let &modified = 0 execute 0 @@ -84,7 +84,7 @@ function! himalaya#msg#reply() let msg = s:cli("--mailbox %s template reply %d", [shellescape(mbox), msg_id], "Fetching reply template") execute printf("silent! edit Himalaya reply [%d]", msg_id) call append(0, split(substitute(msg.template, "\r", "", "g"), "\n")) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-write let &modified = 0 execute 0 @@ -102,7 +102,7 @@ function! himalaya#msg#reply_all() let msg = s:cli("--mailbox %s template reply %d --all", [shellescape(mbox), msg_id], "Fetching reply all template") execute printf("silent! edit Himalaya reply all [%d]", msg_id) call append(0, split(substitute(msg.template, "\r", "", "g"), "\n")) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-write let &modified = 0 execute 0 @@ -120,7 +120,7 @@ function! himalaya#msg#forward() let msg = s:cli("--mailbox %s template forward %d", [shellescape(mbox), msg_id], "Fetching forward template") execute printf("silent! edit Himalaya forward [%d]", msg_id) call append(0, split(substitute(msg.template, "\r", "", "g"), "\n")) - execute "$d" + silent execute "$d" setlocal filetype=himalaya-msg-write let &modified = 0 execute 0