mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 12:00:22 +00:00
add basic support of xdg-email (#162)
This commit is contained in:
parent
a70631de1c
commit
2acd5d71d3
5 changed files with 141 additions and 4 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -263,6 +263,16 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
|
@ -322,6 +332,7 @@ dependencies = [
|
|||
"toml",
|
||||
"tree_magic",
|
||||
"unicode-width",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -674,6 +685,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
|
@ -1069,6 +1086,18 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
|
|
|
@ -23,4 +23,5 @@ terminal_size = "0.1.15"
|
|||
toml = "0.5.8"
|
||||
tree_magic = "0.2.3"
|
||||
unicode-width = "0.1.7"
|
||||
url = "2.2.2"
|
||||
uuid = {version = "0.8", features = ["v4"]}
|
||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -1,17 +1,18 @@
|
|||
use clap;
|
||||
use clap::{self, ArgMatches};
|
||||
use env_logger;
|
||||
use error_chain::error_chain;
|
||||
use log::{debug, error, trace};
|
||||
use std::{env, path::PathBuf, process::exit};
|
||||
use url::{self, Url};
|
||||
|
||||
use himalaya::{
|
||||
ctx::Ctx,
|
||||
comp::cli::{comp_matches, comp_subcmds},
|
||||
config::{cli::config_args, model::Config},
|
||||
ctx::Ctx,
|
||||
flag::cli::{flag_matches, flag_subcmds},
|
||||
imap::cli::{imap_matches, imap_subcmds},
|
||||
mbox::cli::{mbox_matches, mbox_source_arg, mbox_subcmds},
|
||||
msg::cli::{msg_matches, msg_subcmds},
|
||||
msg::cli::{msg_matches, msg_matches_mailto, msg_subcmds},
|
||||
output::{cli::output_args, model::Output},
|
||||
};
|
||||
|
||||
|
@ -24,6 +25,9 @@ error_chain! {
|
|||
MboxCli(himalaya::mbox::cli::Error, himalaya::mbox::cli::ErrorKind);
|
||||
MsgCli(himalaya::msg::cli::Error, himalaya::msg::cli::ErrorKind);
|
||||
}
|
||||
foreign_links {
|
||||
Url(url::ParseError);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_args<'a>() -> clap::App<'a, 'a> {
|
||||
|
@ -47,6 +51,18 @@ fn run() -> Result<()> {
|
|||
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "off"),
|
||||
);
|
||||
|
||||
let raw_args: Vec<String> = env::args().collect();
|
||||
if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
||||
let config = Config::new(None)?;
|
||||
let account = config.find_account_by_name(None)?;
|
||||
let output = Output::new("plain");
|
||||
let mbox = "INBOX";
|
||||
let arg_matches = ArgMatches::default();
|
||||
let app = Ctx::new(&config, &account, &output, &mbox, &arg_matches);
|
||||
let url = Url::parse(&raw_args[1])?;
|
||||
return Ok(msg_matches_mailto(&app, &url)?);
|
||||
}
|
||||
|
||||
let args = parse_args();
|
||||
let arg_matches = args.get_matches();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
|||
io::{self, BufRead},
|
||||
ops::Deref,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
ctx::Ctx,
|
||||
|
@ -594,3 +595,47 @@ fn msg_matches_save(ctx: &Ctx, matches: &clap::ArgMatches) -> Result<bool> {
|
|||
imap_conn.logout();
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn msg_matches_mailto(ctx: &Ctx, url: &Url) -> Result<()> {
|
||||
debug!("mailto command matched");
|
||||
|
||||
let mut imap_conn = ImapConnector::new(&ctx.account)?;
|
||||
let tpl = Tpl::mailto(&ctx, &url);
|
||||
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::PostEditChoice::Send => {
|
||||
debug!("sending message…");
|
||||
let msg = msg.to_sendable_msg()?;
|
||||
smtp::send(&ctx.account, &msg)?;
|
||||
imap_conn.append_msg("Sent", &msg.formatted(), vec![Flag::Seen])?;
|
||||
input::remove_draft()?;
|
||||
ctx.output.print("Message successfully sent");
|
||||
break;
|
||||
}
|
||||
input::PostEditChoice::Edit => {
|
||||
let content = input::open_editor_with_draft()?;
|
||||
msg = Msg::from(content);
|
||||
}
|
||||
input::PostEditChoice::LocalDraft => break,
|
||||
input::PostEditChoice::RemoteDraft => {
|
||||
debug!("saving to draft…");
|
||||
imap_conn.append_msg("Drafts", &msg.to_vec()?, vec![Flag::Seen])?;
|
||||
input::remove_draft()?;
|
||||
ctx.output.print("Message successfully saved to Drafts");
|
||||
break;
|
||||
}
|
||||
input::PostEditChoice::Discard => {
|
||||
input::remove_draft()?;
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(err) => error!("{}", err),
|
||||
}
|
||||
}
|
||||
imap_conn.logout();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use error_chain::error_chain;
|
||||
use mailparse::{self, MailHeaderMap};
|
||||
use serde::Serialize;
|
||||
use std::{collections::HashMap, fmt};
|
||||
use std::{borrow::Cow, collections::HashMap, fmt};
|
||||
use url::Url;
|
||||
|
||||
use crate::{ctx::Ctx, msg::model::Msg};
|
||||
|
||||
|
@ -187,6 +188,51 @@ impl Tpl {
|
|||
tpl
|
||||
}
|
||||
|
||||
pub fn mailto(ctx: &Ctx, url: &Url) -> Self {
|
||||
let mut headers = HashMap::new();
|
||||
|
||||
let mut cc = Vec::new();
|
||||
let mut bcc = Vec::new();
|
||||
let mut subject = Cow::default();
|
||||
let mut body = Cow::default();
|
||||
|
||||
for (key, val) in url.query_pairs() {
|
||||
match key.as_bytes() {
|
||||
b"cc" => {
|
||||
cc.push(val);
|
||||
}
|
||||
b"bcc" => {
|
||||
bcc.push(val);
|
||||
}
|
||||
b"subject" => {
|
||||
subject = val;
|
||||
}
|
||||
b"body" => {
|
||||
body = val;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
headers.insert(String::from("To"), url.path().to_string());
|
||||
headers.insert(String::from("Subject"), subject.into());
|
||||
if !cc.is_empty() {
|
||||
headers.insert(String::from("Cc"), cc.join(", "));
|
||||
}
|
||||
if !bcc.is_empty() {
|
||||
headers.insert(String::from("Bcc"), cc.join(", "));
|
||||
}
|
||||
|
||||
let mut tpl = Self {
|
||||
headers,
|
||||
body: Some(body.into()),
|
||||
signature: ctx.config.signature(&ctx.account),
|
||||
raw: String::new(),
|
||||
};
|
||||
tpl.raw = tpl.to_string();
|
||||
tpl
|
||||
}
|
||||
|
||||
pub fn header<K: ToString, V: ToString>(&mut self, key: K, val: V) -> &Self {
|
||||
self.headers.insert(key.to_string(), val.to_string());
|
||||
self
|
||||
|
|
Loading…
Reference in a new issue