mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
add basic support of xdg-email (#162)
This commit is contained in:
parent
a70631de1c
commit
2acd5d71d3
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
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]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -322,6 +332,7 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
"tree_magic",
|
"tree_magic",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -674,6 +685,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -1069,6 +1086,18 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
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]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|
|
@ -23,4 +23,5 @@ terminal_size = "0.1.15"
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
tree_magic = "0.2.3"
|
tree_magic = "0.2.3"
|
||||||
unicode-width = "0.1.7"
|
unicode-width = "0.1.7"
|
||||||
|
url = "2.2.2"
|
||||||
uuid = {version = "0.8", features = ["v4"]}
|
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 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};
|
||||||
|
use url::{self, Url};
|
||||||
|
|
||||||
use himalaya::{
|
use himalaya::{
|
||||||
ctx::Ctx,
|
|
||||||
comp::cli::{comp_matches, comp_subcmds},
|
comp::cli::{comp_matches, comp_subcmds},
|
||||||
config::{cli::config_args, model::Config},
|
config::{cli::config_args, model::Config},
|
||||||
|
ctx::Ctx,
|
||||||
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_matches_mailto, msg_subcmds},
|
||||||
output::{cli::output_args, model::Output},
|
output::{cli::output_args, model::Output},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +25,9 @@ error_chain! {
|
||||||
MboxCli(himalaya::mbox::cli::Error, himalaya::mbox::cli::ErrorKind);
|
MboxCli(himalaya::mbox::cli::Error, himalaya::mbox::cli::ErrorKind);
|
||||||
MsgCli(himalaya::msg::cli::Error, himalaya::msg::cli::ErrorKind);
|
MsgCli(himalaya::msg::cli::Error, himalaya::msg::cli::ErrorKind);
|
||||||
}
|
}
|
||||||
|
foreign_links {
|
||||||
|
Url(url::ParseError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args<'a>() -> clap::App<'a, 'a> {
|
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"),
|
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 args = parse_args();
|
||||||
let arg_matches = args.get_matches();
|
let arg_matches = args.get_matches();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
io::{self, BufRead},
|
io::{self, BufRead},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
};
|
};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ctx::Ctx,
|
ctx::Ctx,
|
||||||
|
@ -594,3 +595,47 @@ fn msg_matches_save(ctx: &Ctx, matches: &clap::ArgMatches) -> Result<bool> {
|
||||||
imap_conn.logout();
|
imap_conn.logout();
|
||||||
Ok(true)
|
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 error_chain::error_chain;
|
||||||
use mailparse::{self, MailHeaderMap};
|
use mailparse::{self, MailHeaderMap};
|
||||||
use serde::Serialize;
|
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};
|
use crate::{ctx::Ctx, msg::model::Msg};
|
||||||
|
|
||||||
|
@ -187,6 +188,51 @@ impl Tpl {
|
||||||
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 {
|
pub fn header<K: ToString, V: ToString>(&mut self, key: K, val: V) -> &Self {
|
||||||
self.headers.insert(key.to_string(), val.to_string());
|
self.headers.insert(key.to_string(), val.to_string());
|
||||||
self
|
self
|
||||||
|
|
Loading…
Reference in a new issue