From 660bacb9262dac7457bd8c421cc70343a0db3cd5 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Fri, 30 Dec 2022 17:02:10 +0200 Subject: [PATCH] Add `mailto` command to open composer with initial values from mailto template --- docs/meli.1 | 4 ++++ melib/src/email/mailto.rs | 10 ++++++++-- melib/src/email/parser.rs | 8 +++++++- src/command.rs | 15 +++++++++++++++ src/command/actions.rs | 1 + src/components/mail/listing.rs | 9 +++++++++ 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/meli.1 b/docs/meli.1 index e248538a..8a721d7e 100644 --- a/docs/meli.1 +++ b/docs/meli.1 @@ -472,6 +472,10 @@ open list archive with .El .Ss composing mail commands .Bl -tag -width 36n +.It Cm mailto Ar MAILTO_ADDRESS +Opens a composer tab with initial values parsed from the +.Li mailto: +address. .It Cm add-attachment Ar PATH in composer, add .Ar PATH diff --git a/melib/src/email/mailto.rs b/melib/src/email/mailto.rs index a5ecaa15..efec1bb7 100644 --- a/melib/src/email/mailto.rs +++ b/melib/src/email/mailto.rs @@ -23,7 +23,7 @@ use super::*; use std::convert::TryFrom; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Mailto { pub address: Address, pub subject: Option, @@ -47,7 +47,13 @@ impl From for Draft { ret.set_header("Bcc", bcc.unwrap_or_default()); ret.set_body(body.unwrap_or_default()); ret.set_header("To", address.to_string()); - debug!(ret) + ret + } +} + +impl From<&Mailto> for Draft { + fn from(val: &Mailto) -> Self { + Draft::from(val.clone()) } } diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 72f64885..efb66fa8 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -184,6 +184,12 @@ impl From>> for Error { } } +impl<'i> From> for nom::error::Error<&'i [u8]> { + fn from(val: ParsingError<&'i [u8]>) -> nom::error::Error<&'i [u8]> { + nom::error::Error::new(val.input, ErrorKind::Satisfy) + } +} + macro_rules! is_ctl_or_space { ($var:ident) => { /* */ @@ -952,7 +958,7 @@ pub mod generic { let value = String::from_utf8_lossy(&input[..value_end]).to_string(); match tag { b"subject" if subject.is_none() => { - subject = Some(value); + subject = Some(value.replace("%20", " ")); } b"cc" if cc.is_none() => { cc = Some(value); diff --git a/src/command.rs b/src/command.rs index c83008bf..562b1a5d 100644 --- a/src/command.rs +++ b/src/command.rs @@ -500,6 +500,20 @@ define_commands!([ } ) }, + { tags: ["mailto "], + desc: "mailto MAILTO_ADDRESS", + tokens: &[One(Literal("mailto")), One(QuotedStringValue)], + parser:( + fn mailto(input: &[u8]) -> IResult<&[u8], Action> { + let (input, _) = tag("mailto")(input.ltrim())?; + let (input, _) = is_a(" ")(input)?; + let (input, val) = map_res(not_line_ending, std::str::from_utf8)(input.trim())?; + let (_empty, _) = eof(input)?; + let (input, val) = melib::email::parser::generic::mailto(val.as_bytes()).map_err(|err| err.map(Into::into))?; + Ok((input, Compose(Mailto(val)))) + } + ) + }, /* Pipe pager contents to binary */ { tags: ["pipe "], desc: "pipe EXECUTABLE ARGS", @@ -931,6 +945,7 @@ fn listing_action(input: &[u8]) -> IResult<&[u8], Action> { fn compose_action(input: &[u8]) -> IResult<&[u8], Action> { alt(( add_attachment, + mailto, remove_attachment, toggle_sign, toggle_encrypt, diff --git a/src/command/actions.rs b/src/command/actions.rs index 8cc89aea..7152471e 100644 --- a/src/command/actions.rs +++ b/src/command/actions.rs @@ -89,6 +89,7 @@ pub enum ComposeAction { SaveDraft, ToggleSign, ToggleEncrypt, + Mailto(melib::Mailto), } #[derive(Debug)] diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 849d2370..5a0e9d06 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -1889,6 +1889,15 @@ impl Component for Listing { .push_back(UIEvent::Action(Tab(New(Some(Box::new(mgr)))))); return true; } + UIEvent::Action(Action::Compose(ComposeAction::Mailto(ref mailto))) => { + let account_hash = context.accounts[self.cursor_pos.0].hash(); + let mut composer = Composer::with_account(account_hash, context); + composer.set_draft(mailto.into()); + context + .replies + .push_back(UIEvent::Action(Tab(New(Some(Box::new(composer)))))); + return true; + } UIEvent::StartupCheck(_) | UIEvent::MailboxUpdate(_) | UIEvent::EnvelopeUpdate(_)