summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2019-06-18 22:13:54 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-06-18 22:16:32 +0300
commit9026fb866e6e77221a5c248de431df144125407e (patch)
tree1385fb380c026f727152bf864ee241dd49f91464
parent07700ca00f1e5e78ea37173c40122761cdaf6d53 (diff)
ui: Add ability to call mailing list actions from Envelope view
-rw-r--r--ui/src/components/mail/compose.rs104
-rw-r--r--ui/src/components/mail/listing.rs2
-rw-r--r--ui/src/components/mail/view.rs175
-rw-r--r--ui/src/components/utilities.rs8
-rw-r--r--ui/src/execute/actions.rs4
5 files changed, 244 insertions, 49 deletions
diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs
index ef12e292..41742166 100644
--- a/ui/src/components/mail/compose.rs
+++ b/ui/src/components/mail/compose.rs
@@ -173,6 +173,11 @@ impl Composer {
ret
}
+ pub fn set_draft(&mut self, draft: Draft) {
+ self.draft = draft;
+ self.update_form();
+ }
+
fn update_draft(&mut self) {
let header_values = self.form.values_mut();
let draft_header_map = self.draft.headers_mut();
@@ -526,51 +531,12 @@ impl Component for Composer {
return true;
}
UIEvent::Input(Key::Char('s')) if self.mode.is_overview() => {
- use std::io::Write;
- use std::process::{Command, Stdio};
- let settings = &context.settings;
- let parts = split_command!(settings.mailer.mailer_cmd);
- let (cmd, args) = (parts[0], &parts[1..]);
- let mut msmtp = Command::new(cmd)
- .args(args)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .spawn()
- .expect("Failed to start mailer command");
- {
- let stdin = msmtp.stdin.as_mut().expect("failed to open stdin");
- self.update_draft();
- let draft = self.draft.clone().finalise().unwrap();
- stdin
- .write_all(draft.as_bytes())
- .expect("Failed to write to stdin");
- if let Err(e) = context.accounts[self.account_cursor].save(
- draft.as_bytes(),
- &context.accounts[self.account_cursor]
- .settings
- .conf()
- .sent_folder(),
- ) {
- debug!("{:?} could not save sent msg", e);
- context.replies.push_back(UIEvent::Notification(
- Some("Could not save in 'Sent' folder.".into()),
- e.into(),
- ));
- }
+ self.update_draft();
+ if send_draft(context, self.account_cursor, self.draft.clone()) {
+ context
+ .replies
+ .push_back(UIEvent::Action(Tab(Kill(self.id))));
}
- context.replies.push_back(UIEvent::Notification(
- Some("Sent.".into()),
- format!(
- "Mailer output: {:#?}",
- msmtp
- .wait_with_output()
- .expect("Failed to wait on filter")
- .stdout
- ),
- ));
- context
- .replies
- .push_back(UIEvent::Action(Tab(Kill(self.id))));
return true;
}
UIEvent::Input(Key::Char('e')) if self.cursor == Cursor::Body => {
@@ -685,3 +651,53 @@ fn get_display_name(context: &Context, idx: usize) -> String {
settings.identity.to_string()
}
}
+
+pub fn send_draft(context: &mut Context, account_cursor: usize, draft: Draft) -> bool {
+ use std::io::Write;
+ use std::process::{Command, Stdio};
+ let mut failure = true;
+ let settings = &context.settings;
+ let parts = split_command!(settings.mailer.mailer_cmd);
+ let (cmd, args) = (parts[0], &parts[1..]);
+ let mut msmtp = Command::new(cmd)
+ .args(args)
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()
+ .expect("Failed to start mailer command");
+ {
+ let stdin = msmtp.stdin.as_mut().expect("failed to open stdin");
+ let draft = draft.finalise().unwrap();
+ stdin
+ .write_all(draft.as_bytes())
+ .expect("Failed to write to stdin");
+ if let Err(e) = context.accounts[account_cursor].save(
+ draft.as_bytes(),
+ &context.accounts[account_cursor]
+ .settings
+ .conf()
+ .sent_folder(),
+ ) {
+ debug!("{:?} could not save sent msg", e);
+ context.replies.push_back(UIEvent::Notification(
+ Some("Could not save in 'Sent' folder.".into()),
+ e.into(),
+ ));
+ } else {
+ failure = false;
+ }
+ }
+ if !failure {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Sent.".into()),
+ format!(
+ "Mailer output: {:#?}",
+ msmtp
+ .wait_with_output()
+ .expect("Failed to wait on filter")
+ .stdout
+ ),
+ ));
+ }
+ return !failure;
+}
diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs
index a6510a04..94e73174 100644
--- a/ui/src/components/mail/listing.rs
+++ b/ui/src/components/mail/listing.rs
@@ -288,7 +288,7 @@ impl Component for Listing {
UIEvent::Input(ref k) if k == shortcuts["new_mail"] => {
context
.replies
- .push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0))));
+ .push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0, None))));
return true;
}
UIEvent::StartupCheck(_) => {
diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs
index c9f032d7..ab67aca1 100644
--- a/ui/src/components/mail/view.rs
+++ b/ui/src/components/mail/view.rs
@@ -22,6 +22,7 @@
use super::*;
use linkify::{Link, LinkFinder};
+use std::convert::TryFrom;
use std::process::{Command, Stdio};
mod list_management;
@@ -408,6 +409,91 @@ impl Component for MailView {
}
y = _y;
}
+ if let Some(list_management::ListActions {
+ ref id,
+ ref archive,
+ ref post,
+ ref unsubscribe,
+ }) = list_management::detect(envelope)
+ {
+ let mut x = get_x(upper_left);
+ y += 1;
+ if let Some(id) = id {
+ let (_x, _) = write_string_to_grid(
+ "List-ID: ",
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ (set_y(upper_left, y), bottom_right),
+ false,
+ );
+ let (_x, _) = write_string_to_grid(
+ id,
+ grid,
+ Color::Default,
+ Color::Default,
+ ((_x, y), bottom_right),
+ false,
+ );
+ x = _x;
+ }
+ if archive.is_some() || post.is_some() || unsubscribe.is_some() {
+ let (_x, _) = write_string_to_grid(
+ " Available actions: [ ",
+ grid,
+ Color::Byte(33),
+ Color::Default,
+ ((x, y), bottom_right),
+ false,
+ );
+ x = _x;
+ }
+ if archive.is_some() {
+ let (_x, _) = write_string_to_grid(
+ "list-archive, ",
+ grid,
+ Color::Default,
+ Color::Default,
+ ((x, y), bottom_right),
+ false,
+ );
+ x = _x;
+ }
+ if post.is_some() {
+ let (_x, _) = write_string_to_grid(
+ "list-post, ",
+ grid,
+ Color::Default,
+ Color::Default,
+ ((x, y), bottom_right),
+ false,
+ );
+ x = _x;
+ }
+ if unsubscribe.is_some() {
+ let (_x, _) = write_string_to_grid(
+ "list-unsubscribe, ",
+ grid,
+ Color::Default,
+ Color::Default,
+ ((x, y), bottom_right),
+ false,
+ );
+ x = _x;
+ }
+ if archive.is_some() || post.is_some() || unsubscribe.is_some() {
+ grid[(x - 2, y)].set_ch(' ');
+ grid[(x - 1, y)].set_fg(Color::Byte(33));
+ grid[(x - 1, y)].set_bg(Color::Default);
+ grid[(x - 1, y)].set_ch(']');
+ }
+ for x in x..=get_x(bottom_right) {
+ grid[(x, y)].set_ch(' ');
+ grid[(x, y)].set_bg(Color::Default);
+ grid[(x, y)].set_fg(Color::Default);
+ }
+ }
+
clear_area(grid, (set_y(upper_left, y + 1), set_y(bottom_right, y + 1)));
context
.dirty_areas
@@ -744,6 +830,95 @@ impl Component for MailView {
UIEvent::EnvelopeRename(old_hash, new_hash) if self.coordinates.2 == old_hash => {
self.coordinates.2 = new_hash;
}
+ UIEvent::Action(MailingListAction(ref e)) => {
+ let unsafe_context = context as *mut Context;
+ let account = &context.accounts[self.coordinates.0];
+ if !account.contains_key(self.coordinates.2) {
+ /* The envelope has been renamed or removed, so wait for the appropriate event to
+ * arrive */
+ return true;
+ }
+ let envelope: &Envelope = &account.get_env(&self.coordinates.2);
+ if let Some(actions) = list_management::detect(envelope) {
+ match e {
+ MailingListAction::ListPost if actions.post.is_some() => {
+ /* open composer */
+ let mut draft = Draft::default();
+ draft.set_header("To", actions.post.unwrap().to_string());
+ context.replies.push_back(UIEvent::Action(Tab(NewDraft(
+ self.coordinates.0,
+ Some(draft),
+ ))));
+ return true;
+ }
+ MailingListAction::ListUnsubscribe if actions.unsubscribe.is_some() => {
+ /* autosend or open unsubscribe option*/
+ let unsubscribe = actions.unsubscribe.unwrap();
+ for option in unsubscribe {
+ /* TODO: Ask for confirmation before proceding with an action */
+ match option {
+ list_management::UnsubscribeOption::Email(email) => {
+ if let Ok(mailto) = Mailto::try_from(email) {
+ let draft: Draft = mailto.into();
+ if super::compose::send_draft(
+ /* FIXME: refactor to avoid unsafe.
+ *
+ * actions contains byte slices from the envelope's
+ * headers send_draft only needs a mut ref for
+ * context to push back replies and save the sent
+ * message */
+ unsafe { &mut *(unsafe_context) },
+ self.coordinates.0,
+ draft,
+ ) {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Sent unsubscribe email.".into()),
+ "Sent unsubscribe email".to_string(),
+ ));
+ return true;
+ }
+ }
+ }
+ list_management::UnsubscribeOption::Url(url) => {
+ if let Err(e) = Command::new("xdg-open")
+ .arg(String::from_utf8_lossy(url).into_owned())
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()
+ {
+ context.replies.push_back(UIEvent::StatusEvent(
+ StatusEvent::DisplayMessage(format!(
+ "Couldn't launch xdg-open: {}",
+ e
+ )),
+ ));
+ }
+ return true;
+ }
+ }
+ }
+ }
+ MailingListAction::ListArchive if actions.archive.is_some() => {
+ /* open archive url with xdg-open */
+ if let Err(e) = Command::new("xdg-open")
+ .arg(actions.archive.unwrap())
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()
+ {
+ context.replies.push_back(UIEvent::StatusEvent(
+ StatusEvent::DisplayMessage(format!(
+ "Couldn't launch xdg-open: {}",
+ e
+ )),
+ ));
+ }
+ return true;
+ }
+ _ => { /* error print message to user */ }
+ }
+ }
+ }
_ => {
return false;
}
diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs
index 10cb56dd..5d22d4b3 100644
--- a/ui/src/components/utilities.rs
+++ b/ui/src/components/utilities.rs
@@ -1247,8 +1247,12 @@ impl Component for Tabbed {
self.set_dirty();
return true;
}
- UIEvent::Action(Tab(NewDraft(account_idx))) => {
- self.add_component(Box::new(Composer::new(account_idx)));
+ UIEvent::Action(Tab(NewDraft(account_idx, ref draft))) => {
+ let mut composer = Composer::new(account_idx);
+ if let Some(draft) = draft {
+ composer.set_draft(draft.clone());
+ }
+ self.add_component(Box::new(composer));
self.cursor_pos = self.children.len() - 1;
self.children[self.cursor_pos].set_dirty();
return true;
diff --git a/ui/src/execute/actions.rs b/ui/src/execute/actions.rs
index 7745576c..2a89ef24 100644
--- a/ui/src/execute/actions.rs
+++ b/ui/src/execute/actions.rs
@@ -26,7 +26,7 @@
use crate::components::Component;
pub use melib::mailbox::{SortField, SortOrder};
use melib::thread::ThreadHash;
-use melib::EnvelopeHash;
+use melib::{Draft, EnvelopeHash};
extern crate uuid;
use uuid::Uuid;
@@ -41,7 +41,7 @@ pub enum ListingAction {
#[derive(Debug)]
pub enum TabAction {
TabOpen(Option<Box<Component>>),
- NewDraft(usize),
+ NewDraft(usize, Option<Draft>),
Reply((usize, usize, usize), ThreadHash), // thread coordinates (account, mailbox, root_set idx) and thread hash
Close,
Edit(usize, EnvelopeHash), // account_position, envelope hash