From cd68008e670200ac6aa879bbc99a72149789adab Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 13 Oct 2020 13:57:04 +0300 Subject: [PATCH] melib: Implement delete_messages for IMAP, Maildir --- melib/src/backends.rs | 14 +++++------- melib/src/backends/imap.rs | 23 ++++++++++++++++++++ melib/src/backends/jmap.rs | 8 +++++++ melib/src/backends/maildir/backend.rs | 31 +++++++++++++++++++++++++++ melib/src/backends/mbox.rs | 8 +++++++ melib/src/backends/nntp.rs | 14 +++++++++--- melib/src/backends/notmuch.rs | 8 +++++++ src/conf/accounts.rs | 14 ------------ 8 files changed, 94 insertions(+), 26 deletions(-) diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 7d4dda40..d64a008d 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -335,15 +335,11 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync { ) -> ResultFuture<()>; fn delete_messages( - &self, - _env_hashes: EnvelopeHashBatch, - _mailbox_hash: MailboxHash, - ) -> ResultFuture<()> { - Err(MeliError::new("Unimplemented.")) - } - fn delete(&self, _env_hash: EnvelopeHash, _mailbox_hash: MailboxHash) -> ResultFuture<()> { - Err(MeliError::new("Unimplemented.")) - } + &mut self, + env_hashes: EnvelopeHashBatch, + mailbox_hash: MailboxHash, + ) -> ResultFuture<()>; + fn tags(&self) -> Option>>> { None } diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index 8ef7d940..07704f4d 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -807,6 +807,29 @@ impl MailBackend for ImapType { })) } + fn delete_messages( + &mut self, + env_hashes: EnvelopeHashBatch, + mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + let flag_future = self.set_flags( + env_hashes, + mailbox_hash, + smallvec::smallvec![(Ok(Flag::TRASHED), true)], + )?; + let connection = self.connection.clone(); + Ok(Box::pin(async move { + flag_future.await?; + let mut response = Vec::with_capacity(8 * 1024); + let mut conn = connection.lock().await; + conn.send_command("EXPUNGE".as_bytes()).await?; + conn.read_response(&mut response, RequiredResponses::empty()) + .await?; + debug!("EXPUNGE response: {}", &String::from_utf8_lossy(&response)); + Ok(()) + })) + } + fn tags(&self) -> Option>>> { Some(self.uid_store.tag_index.clone()) } diff --git a/melib/src/backends/jmap.rs b/melib/src/backends/jmap.rs index 2ee314a5..ab3e1dd1 100644 --- a/melib/src/backends/jmap.rs +++ b/melib/src/backends/jmap.rs @@ -788,6 +788,14 @@ impl MailBackend for JmapType { Ok(()) })) } + + fn delete_messages( + &mut self, + _env_hashes: EnvelopeHashBatch, + _mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + Err(MeliError::new("Unimplemented.")) + } } impl JmapType { diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index a0e759c5..422b1d75 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -913,6 +913,37 @@ impl MailBackend for MaildirType { })) } + fn delete_messages( + &mut self, + env_hashes: EnvelopeHashBatch, + mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + let hash_index = self.hash_indexes.clone(); + Ok(Box::pin(async move { + let mut hash_indexes_lck = hash_index.lock().unwrap(); + let hash_index = hash_indexes_lck.entry(mailbox_hash).or_default(); + + for env_hash in env_hashes.iter() { + let _path = { + if !hash_index.contains_key(&env_hash) { + continue; + } + if let Some(modif) = &hash_index[&env_hash].modified { + match modif { + PathMod::Path(ref path) => path.clone(), + PathMod::Hash(hash) => hash_index[&hash].to_path_buf(), + } + } else { + hash_index[&env_hash].to_path_buf() + } + }; + + fs::remove_file(&_path)?; + } + Ok(()) + })) + } + fn copy_messages( &mut self, env_hashes: EnvelopeHashBatch, diff --git a/melib/src/backends/mbox.rs b/melib/src/backends/mbox.rs index 378ba062..a00af89a 100644 --- a/melib/src/backends/mbox.rs +++ b/melib/src/backends/mbox.rs @@ -1012,6 +1012,14 @@ impl MailBackend for MboxType { Err(MeliError::new("Unimplemented.")) } + fn delete_messages( + &mut self, + _env_hashes: EnvelopeHashBatch, + _mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + Err(MeliError::new("Unimplemented.")) + } + fn save( &self, _bytes: Vec, diff --git a/melib/src/backends/nntp.rs b/melib/src/backends/nntp.rs index 413c2134..48e5c955 100644 --- a/melib/src/backends/nntp.rs +++ b/melib/src/backends/nntp.rs @@ -278,7 +278,7 @@ impl MailBackend for NntpType { _mailbox_hash: MailboxHash, _flags: Option, ) -> ResultFuture<()> { - Err(MeliError::new("Unimplemented.")) + Err(MeliError::new("NNTP doesn't support saving.")) } fn copy_messages( @@ -288,7 +288,7 @@ impl MailBackend for NntpType { _destination_mailbox_hash: MailboxHash, _move_: bool, ) -> ResultFuture<()> { - Err(MeliError::new("Unimplemented.")) + Err(MeliError::new("NNTP doesn't support copying/moving.")) } fn set_flags( @@ -297,7 +297,15 @@ impl MailBackend for NntpType { _mailbox_hash: MailboxHash, _flags: SmallVec<[(std::result::Result, bool); 8]>, ) -> ResultFuture<()> { - Err(MeliError::new("Unimplemented.")) + Err(MeliError::new("NNTP doesn't support flags.")) + } + + fn delete_messages( + &mut self, + _env_hashes: EnvelopeHashBatch, + _mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + Err(MeliError::new("NNTP doesn't support deletion.")) } fn tags(&self) -> Option>>> { diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs index 512fcf00..1d8c48f8 100644 --- a/melib/src/backends/notmuch.rs +++ b/melib/src/backends/notmuch.rs @@ -802,6 +802,14 @@ impl MailBackend for NotmuchDb { })) } + fn delete_messages( + &mut self, + _env_hashes: EnvelopeHashBatch, + _mailbox_hash: MailboxHash, + ) -> ResultFuture<()> { + Err(MeliError::new("Unimplemented.")) + } + fn search( &self, melib_query: crate::search::Query, diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index c93a5f2d..defa2652 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -1378,20 +1378,6 @@ impl Account { } } - pub fn delete( - &mut self, - env_hash: EnvelopeHash, - mailbox_hash: MailboxHash, - ) -> ResultFuture<()> { - 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, mailbox_hash) - } - pub fn contains_key(&self, h: EnvelopeHash) -> bool { self.collection.contains_key(&h) }