diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 6af6b9dc9..97e969f42 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -287,6 +287,9 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync { fn operation(&self, hash: EnvelopeHash) -> Box; fn save(&self, bytes: &[u8], mailbox: &str, flags: Option) -> Result<()>; + fn delete(&self, env_hash: EnvelopeHash) -> Result<()> { + Err(MeliError::new("Unimplemented.")) + } fn tags(&self) -> Option>>> { None } diff --git a/src/components/mail/compose.rs b/src/components/mail/compose.rs index 7ad5a1832..089d5420e 100644 --- a/src/components/mail/compose.rs +++ b/src/components/mail/compose.rs @@ -954,6 +954,64 @@ impl Component for Composer { } UIEvent::Action(ref a) => { match a { + Action::Compose(ComposeAction::AddAttachmentPipe(ref cmd)) => { + let parts = split_command!(cmd); + if parts.is_empty() { + context.replies.push_back(UIEvent::Notification( + None, + format!("pipe cmd value is invalid: {}", cmd), + Some(NotificationType::ERROR), + )); + return false; + } + let (cmd, args) = (parts[0], &parts[1..]); + let f = create_temp_file(&[], None, None, true); + match std::process::Command::new(cmd) + .args(args) + .stdin(std::process::Stdio::null()) + .stdout(std::process::Stdio::from(f.file())) + .spawn() + { + Ok(child) => { + let out = child + .wait_with_output() + .expect("failed to launch cmd") + .stdout; + let mut attachment = + match melib::email::attachment_from_file(f.path()) { + Ok(a) => a, + Err(e) => { + context.replies.push_back(UIEvent::Notification( + Some("could not add attachment".to_string()), + e.to_string(), + Some(NotificationType::ERROR), + )); + self.dirty = true; + return true; + } + }; + if let Ok(mime_type) = query_mime_info(f.path()) { + match attachment.content_type { + ContentType::Other { ref mut tag, .. } => { + *tag = mime_type; + } + _ => {} + } + } + self.draft.attachments_mut().push(attachment); + self.dirty = true; + return true; + } + Err(err) => { + context.replies.push_back(UIEvent::Notification( + None, + format!("could not execute pipe cmd: {}", cmd), + Some(NotificationType::ERROR), + )); + return true; + } + } + } Action::Compose(ComposeAction::AddAttachment(ref path)) => { let mut attachment = match melib::email::attachment_from_file(path) { Ok(a) => a, diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 1e2c8474e..5b94271d0 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -146,7 +146,7 @@ pub trait MailListingTrait: ListingTrait { ); } for env_hash in envs_to_set { - let op = account.operation(env_hash); + let mut op = account.operation(env_hash); let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash); match a { ListingAction::SetSeen => { @@ -164,7 +164,30 @@ pub trait MailListingTrait: ListingTrait { } } ListingAction::Delete => { - /* do nothing */ + drop(envelope); + if let Err(err) = account.delete(env_hash) { + context.replies.push_back(UIEvent::Notification( + Some("Could not delete.".to_string()), + err.to_string(), + Some(NotificationType::ERROR), + )); + return; + } + continue; + } + ListingAction::CopyTo(ref mailbox_path) => { + drop(envelope); + if let Err(err) = op + .as_bytes() + .and_then(|bytes| account.save(bytes, mailbox_path, None)) + { + context.replies.push_back(UIEvent::Notification( + Some("Could not copy.".to_string()), + err.to_string(), + Some(NotificationType::ERROR), + )); + return; + } continue; } ListingAction::Tag(Remove(ref tag_str)) => { diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index e65b92930..b93a578e7 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -876,6 +876,16 @@ impl Account { self.backend.write().unwrap().save(bytes, mailbox, flags) } + pub fn delete(&self, env_hash: EnvelopeHash) -> Result<()> { + if self.settings.account.read_only() { + return Err(MeliError::new(format!( + "Account {} is read-only.", + self.name.as_str() + ))); + } + self.backend.write().unwrap().delete(env_hash) + } + pub fn contains_key(&self, h: EnvelopeHash) -> bool { self.collection.contains_key(&h) } diff --git a/src/execute.rs b/src/execute.rs index 80cda54b0..98ea9fb45 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -79,6 +79,10 @@ define_commands!([ | map!(ws!(tag!("unseen")), |_| Listing(SetUnseen)) ) ) | map!(preceded!(tag!("delete"), eof!()), |_| Listing(Delete)) + | do_parse!(tag!("copyto") + >> is_a!(" ") + >> path: quoted_argument + >> ({ Listing(CopyTo(path.to_string())) })) ) ); ) }, diff --git a/src/execute/actions.rs b/src/execute/actions.rs index d9bc9a567..53e7c5d0c 100644 --- a/src/execute/actions.rs +++ b/src/execute/actions.rs @@ -46,6 +46,7 @@ pub enum ListingAction { Search(String), SetSeen, SetUnseen, + CopyTo(MailboxPath), Delete, OpenInNewTab, Tag(TagAction),