From c2a518a997fa12f6e82b2a9eb1ba8cd6059fdf41 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Fri, 19 Jan 2024 17:39:55 +0100 Subject: [PATCH] filter expunge --- Cargo.lock | 4 ++-- src/imap/command/selected.rs | 11 +++++++---- src/imap/mailbox_view.rs | 22 ++++++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b49312..afa6980 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1807,7 +1807,7 @@ dependencies = [ [[package]] name = "imap-codec" version = "2.0.0" -source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#b0a80c4826f3d8bf2d2e69f68443c261e62bb40f" +source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#0f27fe2f10d16c96e0be18914fdbeda9df545beb" dependencies = [ "abnf-core", "base64 0.21.5", @@ -1834,7 +1834,7 @@ dependencies = [ [[package]] name = "imap-types" version = "2.0.0" -source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#b0a80c4826f3d8bf2d2e69f68443c261e62bb40f" +source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#0f27fe2f10d16c96e0be18914fdbeda9df545beb" dependencies = [ "base64 0.21.5", "bounded-static", diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs index 98b3b00..154e28c 100644 --- a/src/imap/command/selected.rs +++ b/src/imap/command/selected.rs @@ -59,7 +59,10 @@ pub async fn dispatch<'a>( criteria, uid, } => ctx.search(charset, criteria, uid).await, - CommandBody::Expunge => ctx.expunge().await, + CommandBody::Expunge { + // UIDPLUS (rfc4315) + uid_sequence_set, + } => ctx.expunge(uid_sequence_set).await, CommandBody::Store { sequence_set, kind, @@ -114,7 +117,7 @@ impl<'a> SelectedContext<'a> { // We expunge messages, // but we don't send the untagged EXPUNGE responses let tag = self.req.tag.clone(); - self.expunge().await?; + self.expunge(&None).await?; Ok(( Response::build().tag(tag).message("CLOSE completed").ok()?, flow::Transition::Unselect, @@ -223,13 +226,13 @@ impl<'a> SelectedContext<'a> { )) } - async fn expunge(self) -> Result<(Response<'static>, flow::Transition)> { + async fn expunge(self, uid_sequence_set: &Option) -> Result<(Response<'static>, flow::Transition)> { if let Some(failed) = self.fail_read_only() { return Ok((failed, flow::Transition::None)); } let tag = self.req.tag.clone(); - let data = self.mailbox.expunge().await?; + let data = self.mailbox.expunge(uid_sequence_set).await?; Ok(( Response::build() diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs index 0efa987..f632df1 100644 --- a/src/imap/mailbox_view.rs +++ b/src/imap/mailbox_view.rs @@ -237,16 +237,26 @@ impl MailboxView { self.update(UpdateParameters::default()).await } - pub async fn expunge(&mut self) -> Result>> { + pub async fn expunge(&mut self, maybe_seq_set: &Option) -> Result>> { + // Get a recent view to apply our change self.internal.sync().await?; let state = self.internal.peek().await; + let idx = Index::new(&state)?; + + // Build a default sequence set for the default case + use imap_codec::imap_types::sequence::{Sequence, SeqOrUid}; + let seq = match maybe_seq_set { + Some(s) => s.clone(), + None => SequenceSet(vec![Sequence::Range(SeqOrUid::Value(NonZeroU32::MIN), SeqOrUid::Asterisk)].try_into().unwrap()), + }; + let deleted_flag = Flag::Deleted.to_string(); - let msgs = state - .table - .iter() - .filter(|(_uuid, (_uid, _modseq, flags))| flags.iter().any(|x| *x == deleted_flag)) - .map(|(uuid, _)| *uuid); + let msgs = idx + .fetch_on_uid(&seq) + .into_iter() + .filter(|midx| midx.flags.iter().any(|x| *x == deleted_flag)) + .map(|midx| midx.uuid); for msg in msgs { self.internal.mailbox.delete(msg).await?;