From 0eb8156cde27c54734cbe3d269ab05a876ef53ac Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Wed, 17 Jan 2024 08:33:08 +0100 Subject: [PATCH] Delete EXAMINE that has been merged in SELECTED --- src/imap/command/examined.rs | 164 ----------------------------------- src/imap/command/mod.rs | 1 - src/imap/session.rs | 2 +- 3 files changed, 1 insertion(+), 166 deletions(-) delete mode 100644 src/imap/command/examined.rs diff --git a/src/imap/command/examined.rs b/src/imap/command/examined.rs deleted file mode 100644 index 9fc0990..0000000 --- a/src/imap/command/examined.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::sync::Arc; -use std::num::NonZeroU64; - -use anyhow::Result; -use imap_codec::imap_types::command::{Command, CommandBody, FetchModifier}; -use imap_codec::imap_types::core::Charset; -use imap_codec::imap_types::fetch::MacroOrMessageDataItemNames; -use imap_codec::imap_types::search::SearchKey; -use imap_codec::imap_types::sequence::SequenceSet; - -use crate::imap::attributes::AttributesProxy; -use crate::imap::capability::{ClientCapability, ServerCapability}; -use crate::imap::command::{anystate, authenticated}; -use crate::imap::flow; -use crate::imap::mailbox_view::{MailboxView, UpdateParameters}; -use crate::imap::response::Response; -use crate::mail::user::User; - -pub struct ExaminedContext<'a> { - pub req: &'a Command<'static>, - pub user: &'a Arc, - pub mailbox: &'a mut MailboxView, - pub server_capabilities: &'a ServerCapability, - pub client_capabilities: &'a mut ClientCapability, -} - -pub async fn dispatch(ctx: ExaminedContext<'_>) -> Result<(Response<'static>, flow::Transition)> { - match &ctx.req.body { - // Any State - // noop is specific to this state - CommandBody::Capability => { - anystate::capability(ctx.req.tag.clone(), ctx.server_capabilities) - } - CommandBody::Logout => anystate::logout(), - - // Specific to the EXAMINE state (specialization of the SELECTED state) - // ~3 commands -> close, fetch, search + NOOP - CommandBody::Close => ctx.close("CLOSE").await, - CommandBody::Fetch { - sequence_set, - macro_or_item_names, - modifiers, - uid, - } => ctx.fetch(sequence_set, macro_or_item_names, modifiers, uid).await, - CommandBody::Search { - charset, - criteria, - uid, - } => ctx.search(charset, criteria, uid).await, - CommandBody::Noop | CommandBody::Check => ctx.noop().await, - CommandBody::Expunge { .. } | CommandBody::Store { .. } => Ok(( - Response::build() - .to_req(ctx.req) - .message("Forbidden command: can't write in read-only mode (EXAMINE)") - .no()?, - flow::Transition::None, - )), - - // UNSELECT extension (rfc3691) - CommandBody::Unselect => ctx.close("UNSELECT").await, - - // In examined mode, we fallback to authenticated when needed - _ => { - authenticated::dispatch(authenticated::AuthenticatedContext { - req: ctx.req, - server_capabilities: ctx.server_capabilities, - client_capabilities: ctx.client_capabilities, - user: ctx.user, - }) - .await - } - } -} - -// --- PRIVATE --- - -impl<'a> ExaminedContext<'a> { - /// CLOSE in examined state is not the same as in selected state - /// (in selected state it also does an EXPUNGE, here it doesn't) - async fn close(self, kind: &str) -> Result<(Response<'static>, flow::Transition)> { - Ok(( - Response::build() - .to_req(self.req) - .message(format!("{} completed", kind)) - .ok()?, - flow::Transition::Unselect, - )) - } - - pub async fn fetch( - self, - sequence_set: &SequenceSet, - attributes: &'a MacroOrMessageDataItemNames<'static>, - modifiers: &[FetchModifier], - uid: &bool, - ) -> Result<(Response<'static>, flow::Transition)> { - let ap = AttributesProxy::new(attributes, modifiers, *uid); - let mut changed_since: Option = None; - modifiers.iter().for_each(|m| match m { - FetchModifier::ChangedSince(val) => { - changed_since = Some(*val); - }, - }); - - match self.mailbox.fetch(sequence_set, &ap, changed_since, uid).await { - Ok(resp) => { - // Capabilities enabling logic only on successful command - // (according to my understanding of the spec) - self.client_capabilities.attributes_enable(&ap); - self.client_capabilities.fetch_modifiers_enable(modifiers); - - Ok(( - Response::build() - .to_req(self.req) - .message("FETCH completed") - .set_body(resp) - .ok()?, - flow::Transition::None, - )) - }, - Err(e) => Ok(( - Response::build() - .to_req(self.req) - .message(e.to_string()) - .no()?, - flow::Transition::None, - )), - } - } - - pub async fn search( - self, - charset: &Option>, - criteria: &SearchKey<'a>, - uid: &bool, - ) -> Result<(Response<'static>, flow::Transition)> { - let (found, enable_condstore) = self.mailbox.search(charset, criteria, *uid).await?; - if enable_condstore { - self.client_capabilities.enable_condstore(); - } - Ok(( - Response::build() - .to_req(self.req) - .set_body(found) - .message("SEARCH completed") - .ok()?, - flow::Transition::None, - )) - } - - pub async fn noop(self) -> Result<(Response<'static>, flow::Transition)> { - self.mailbox.internal.mailbox.force_sync().await?; - - let updates = self.mailbox.update(UpdateParameters::default()).await?; - Ok(( - Response::build() - .to_req(self.req) - .message("NOOP completed.") - .set_body(updates) - .ok()?, - flow::Transition::None, - )) - } -} diff --git a/src/imap/command/mod.rs b/src/imap/command/mod.rs index dc95746..073040e 100644 --- a/src/imap/command/mod.rs +++ b/src/imap/command/mod.rs @@ -1,7 +1,6 @@ pub mod anonymous; pub mod anystate; pub mod authenticated; -pub mod examined; pub mod selected; use crate::mail::user::INBOX; diff --git a/src/imap/session.rs b/src/imap/session.rs index d86e6ff..11c2764 100644 --- a/src/imap/session.rs +++ b/src/imap/session.rs @@ -1,6 +1,6 @@ use anyhow::anyhow; use crate::imap::capability::{ClientCapability, ServerCapability}; -use crate::imap::command::{anonymous, authenticated, examined, selected}; +use crate::imap::command::{anonymous, authenticated, selected}; use crate::imap::flow; use crate::imap::request::Request; use crate::imap::response::{Response, ResponseOrIdle};