CONDSTORE #71
4 changed files with 49 additions and 18 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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...
|
||||
|
|
Loading…
Reference in a new issue