aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-01-11 17:13:59 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-01-11 17:13:59 +0100
commitd24eb9918e3ab0c69af05c8cb92424ecaba903f3 (patch)
tree325fa925216778a12505774d4968176a389a1078
parent60a166185a034019d9e55136ee4417386ff57703 (diff)
downloadaerogramme-d24eb9918e3ab0c69af05c8cb92424ecaba903f3.tar.gz
aerogramme-d24eb9918e3ab0c69af05c8cb92424ecaba903f3.zip
Enable CONDSTORE on STORE/FETCH modifier
-rw-r--r--src/imap/capability.rs22
-rw-r--r--src/imap/command/examined.rs15
-rw-r--r--src/imap/command/selected.rs20
-rw-r--r--src/imap/mailbox_view.rs10
4 files changed, 49 insertions, 18 deletions
diff --git a/src/imap/capability.rs b/src/imap/capability.rs
index 53d7b7d..6533ccb 100644
--- a/src/imap/capability.rs
+++ b/src/imap/capability.rs
@@ -1,9 +1,11 @@
-use imap_codec::imap_types::command::SelectExamineModifier;
+use imap_codec::imap_types::command::{FetchModifier, StoreModifier, SelectExamineModifier};
use imap_codec::imap_types::core::NonEmptyVec;
use imap_codec::imap_types::extensions::enable::{CapabilityEnable, Utf8Kind};
use imap_codec::imap_types::response::Capability;
use std::collections::HashSet;
+use crate::imap::attributes::AttributesProxy;
+
fn capability_unselect() -> Capability<'static> {
Capability::try_from("UNSELECT").unwrap()
}
@@ -91,6 +93,24 @@ impl ClientCapability {
self.condstore = self.condstore.enable();
}
+ pub fn attributes_enable(&mut self, ap: &AttributesProxy) {
+ if ap.is_enabling_condstore() {
+ self.enable_condstore()
+ }
+ }
+
+ pub fn fetch_modifiers_enable(&mut self, mods: &[FetchModifier]) {
+ if mods.iter().any(|x| matches!(x, FetchModifier::ChangedSince(..))) {
+ self.enable_condstore()
+ }
+ }
+
+ pub fn store_modifiers_enable(&mut self, mods: &[StoreModifier]) {
+ if mods.iter().any(|x| matches!(x, StoreModifier::UnchangedSince(..))) {
+ self.enable_condstore()
+ }
+ }
+
pub fn select_enable(&mut self, mods: &[SelectExamineModifier]) {
for m in mods.iter() {
match m {
diff --git a/src/imap/command/examined.rs b/src/imap/command/examined.rs
index a8077e3..cdebc6d 100644
--- a/src/imap/command/examined.rs
+++ b/src/imap/command/examined.rs
@@ -7,6 +7,7 @@ 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;
@@ -92,11 +93,15 @@ impl<'a> ExaminedContext<'a> {
modifiers: &[FetchModifier],
uid: &bool,
) -> Result<(Response<'static>, flow::Transition)> {
- match self.mailbox.fetch(sequence_set, attributes, uid).await {
- Ok((resp, enable_condstore)) => {
- if enable_condstore {
- self.client_capabilities.enable_condstore();
- }
+ let ap = AttributesProxy::new(attributes, *uid);
+
+ match self.mailbox.fetch(sequence_set, &ap, 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)
diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs
index 862d4aa..d7aa94f 100644
--- a/src/imap/command/selected.rs
+++ b/src/imap/command/selected.rs
@@ -15,7 +15,7 @@ use crate::imap::command::{anystate, authenticated, MailboxName};
use crate::imap::flow;
use crate::imap::mailbox_view::MailboxView;
use crate::imap::response::Response;
-
+use crate::imap::attributes::AttributesProxy;
use crate::mail::user::User;
pub struct SelectedContext<'a> {
@@ -118,11 +118,16 @@ impl<'a> SelectedContext<'a> {
modifiers: &[FetchModifier],
uid: &bool,
) -> Result<(Response<'static>, flow::Transition)> {
- match self.mailbox.fetch(sequence_set, attributes, uid).await {
- Ok((resp, enable_condstore)) => {
- if enable_condstore {
- self.client_capabilities.enable_condstore();
- }
+ let ap = AttributesProxy::new(attributes, *uid);
+
+ match self.mailbox.fetch(sequence_set, &ap, 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);
+
+ // Response to the client
Ok((
Response::build()
.to_req(self.req)
@@ -199,12 +204,13 @@ impl<'a> SelectedContext<'a> {
modifiers: &[StoreModifier],
uid: &bool,
) -> Result<(Response<'static>, flow::Transition)> {
- tracing::info!(modifiers=?modifiers);
let data = self
.mailbox
.store(sequence_set, kind, response, flags, uid)
.await?;
+ self.client_capabilities.store_modifiers_enable(modifiers);
+
Ok((
Response::build()
.to_req(self.req)
diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs
index 9e9e785..c3900cf 100644
--- a/src/imap/mailbox_view.rs
+++ b/src/imap/mailbox_view.rs
@@ -6,7 +6,7 @@ use anyhow::{anyhow, Error, Result};
use futures::stream::{FuturesOrdered, StreamExt};
use imap_codec::imap_types::core::Charset;
-use imap_codec::imap_types::fetch::{MacroOrMessageDataItemNames, MessageDataItem};
+use imap_codec::imap_types::fetch::MessageDataItem;
use imap_codec::imap_types::flag::{Flag, FlagFetch, FlagPerm, StoreResponse, StoreType};
use imap_codec::imap_types::response::{Code, CodeOther, Data, Status};
use imap_codec::imap_types::search::SearchKey;
@@ -257,13 +257,13 @@ impl MailboxView {
pub async fn fetch<'b>(
&self,
sequence_set: &SequenceSet,
- attributes: &'b MacroOrMessageDataItemNames<'static>,
+ ap: &AttributesProxy,
is_uid_fetch: &bool,
- ) -> Result<(Vec<Body<'static>>, bool)> {
+ ) -> Result<Vec<Body<'static>>> {
// [1/6] Pre-compute data
// a. what are the uuids of the emails we want?
// b. do we need to fetch the full body?
- let ap = AttributesProxy::new(attributes, *is_uid_fetch);
+ //let ap = AttributesProxy::new(attributes, *is_uid_fetch);
let query_scope = match ap.need_body() {
true => QueryScope::Full,
_ => QueryScope::Partial,
@@ -316,7 +316,7 @@ impl MailboxView {
.collect::<Result<_, _>>()?;
// [6/6] Build the final result that will be sent to the client.
- Ok((imap_ret, ap.is_enabling_condstore()))
+ Ok(imap_ret)
}
/// A naive search implementation...