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::core::NonEmptyVec;
|
||||||
use imap_codec::imap_types::extensions::enable::{CapabilityEnable, Utf8Kind};
|
use imap_codec::imap_types::extensions::enable::{CapabilityEnable, Utf8Kind};
|
||||||
use imap_codec::imap_types::response::Capability;
|
use imap_codec::imap_types::response::Capability;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::imap::attributes::AttributesProxy;
|
||||||
|
|
||||||
fn capability_unselect() -> Capability<'static> {
|
fn capability_unselect() -> Capability<'static> {
|
||||||
Capability::try_from("UNSELECT").unwrap()
|
Capability::try_from("UNSELECT").unwrap()
|
||||||
}
|
}
|
||||||
|
@ -91,6 +93,24 @@ impl ClientCapability {
|
||||||
self.condstore = self.condstore.enable();
|
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]) {
|
pub fn select_enable(&mut self, mods: &[SelectExamineModifier]) {
|
||||||
for m in mods.iter() {
|
for m in mods.iter() {
|
||||||
match m {
|
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::search::SearchKey;
|
||||||
use imap_codec::imap_types::sequence::SequenceSet;
|
use imap_codec::imap_types::sequence::SequenceSet;
|
||||||
|
|
||||||
|
use crate::imap::attributes::AttributesProxy;
|
||||||
use crate::imap::capability::{ClientCapability, ServerCapability};
|
use crate::imap::capability::{ClientCapability, ServerCapability};
|
||||||
use crate::imap::command::{anystate, authenticated};
|
use crate::imap::command::{anystate, authenticated};
|
||||||
use crate::imap::flow;
|
use crate::imap::flow;
|
||||||
|
@ -92,11 +93,15 @@ impl<'a> ExaminedContext<'a> {
|
||||||
modifiers: &[FetchModifier],
|
modifiers: &[FetchModifier],
|
||||||
uid: &bool,
|
uid: &bool,
|
||||||
) -> Result<(Response<'static>, flow::Transition)> {
|
) -> Result<(Response<'static>, flow::Transition)> {
|
||||||
match self.mailbox.fetch(sequence_set, attributes, uid).await {
|
let ap = AttributesProxy::new(attributes, *uid);
|
||||||
Ok((resp, enable_condstore)) => {
|
|
||||||
if enable_condstore {
|
match self.mailbox.fetch(sequence_set, &ap, uid).await {
|
||||||
self.client_capabilities.enable_condstore();
|
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((
|
Ok((
|
||||||
Response::build()
|
Response::build()
|
||||||
.to_req(self.req)
|
.to_req(self.req)
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::imap::command::{anystate, authenticated, MailboxName};
|
||||||
use crate::imap::flow;
|
use crate::imap::flow;
|
||||||
use crate::imap::mailbox_view::MailboxView;
|
use crate::imap::mailbox_view::MailboxView;
|
||||||
use crate::imap::response::Response;
|
use crate::imap::response::Response;
|
||||||
|
use crate::imap::attributes::AttributesProxy;
|
||||||
use crate::mail::user::User;
|
use crate::mail::user::User;
|
||||||
|
|
||||||
pub struct SelectedContext<'a> {
|
pub struct SelectedContext<'a> {
|
||||||
|
@ -118,11 +118,16 @@ impl<'a> SelectedContext<'a> {
|
||||||
modifiers: &[FetchModifier],
|
modifiers: &[FetchModifier],
|
||||||
uid: &bool,
|
uid: &bool,
|
||||||
) -> Result<(Response<'static>, flow::Transition)> {
|
) -> Result<(Response<'static>, flow::Transition)> {
|
||||||
match self.mailbox.fetch(sequence_set, attributes, uid).await {
|
let ap = AttributesProxy::new(attributes, *uid);
|
||||||
Ok((resp, enable_condstore)) => {
|
|
||||||
if enable_condstore {
|
match self.mailbox.fetch(sequence_set, &ap, uid).await {
|
||||||
self.client_capabilities.enable_condstore();
|
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((
|
Ok((
|
||||||
Response::build()
|
Response::build()
|
||||||
.to_req(self.req)
|
.to_req(self.req)
|
||||||
|
@ -199,12 +204,13 @@ impl<'a> SelectedContext<'a> {
|
||||||
modifiers: &[StoreModifier],
|
modifiers: &[StoreModifier],
|
||||||
uid: &bool,
|
uid: &bool,
|
||||||
) -> Result<(Response<'static>, flow::Transition)> {
|
) -> Result<(Response<'static>, flow::Transition)> {
|
||||||
tracing::info!(modifiers=?modifiers);
|
|
||||||
let data = self
|
let data = self
|
||||||
.mailbox
|
.mailbox
|
||||||
.store(sequence_set, kind, response, flags, uid)
|
.store(sequence_set, kind, response, flags, uid)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
self.client_capabilities.store_modifiers_enable(modifiers);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Response::build()
|
Response::build()
|
||||||
.to_req(self.req)
|
.to_req(self.req)
|
||||||
|
|
|
@ -6,7 +6,7 @@ use anyhow::{anyhow, Error, Result};
|
||||||
use futures::stream::{FuturesOrdered, StreamExt};
|
use futures::stream::{FuturesOrdered, StreamExt};
|
||||||
|
|
||||||
use imap_codec::imap_types::core::Charset;
|
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::flag::{Flag, FlagFetch, FlagPerm, StoreResponse, StoreType};
|
||||||
use imap_codec::imap_types::response::{Code, CodeOther, Data, Status};
|
use imap_codec::imap_types::response::{Code, CodeOther, Data, Status};
|
||||||
use imap_codec::imap_types::search::SearchKey;
|
use imap_codec::imap_types::search::SearchKey;
|
||||||
|
@ -257,13 +257,13 @@ impl MailboxView {
|
||||||
pub async fn fetch<'b>(
|
pub async fn fetch<'b>(
|
||||||
&self,
|
&self,
|
||||||
sequence_set: &SequenceSet,
|
sequence_set: &SequenceSet,
|
||||||
attributes: &'b MacroOrMessageDataItemNames<'static>,
|
ap: &AttributesProxy,
|
||||||
is_uid_fetch: &bool,
|
is_uid_fetch: &bool,
|
||||||
) -> Result<(Vec<Body<'static>>, bool)> {
|
) -> Result<Vec<Body<'static>>> {
|
||||||
// [1/6] Pre-compute data
|
// [1/6] Pre-compute data
|
||||||
// a. what are the uuids of the emails we want?
|
// a. what are the uuids of the emails we want?
|
||||||
// b. do we need to fetch the full body?
|
// 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() {
|
let query_scope = match ap.need_body() {
|
||||||
true => QueryScope::Full,
|
true => QueryScope::Full,
|
||||||
_ => QueryScope::Partial,
|
_ => QueryScope::Partial,
|
||||||
|
@ -316,7 +316,7 @@ impl MailboxView {
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
// [6/6] Build the final result that will be sent to the client.
|
// [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...
|
/// A naive search implementation...
|
||||||
|
|
Loading…
Reference in a new issue