prepare condstore

This commit is contained in:
Quentin 2024-01-09 17:40:23 +01:00
parent 5dfa02e381
commit 6e798b90f5
Signed by: quentin
GPG key ID: E9602264D639FF68
5 changed files with 58 additions and 35 deletions

View file

@ -48,15 +48,21 @@ impl ServerCapability {
}
}
enum ClientStatus {
pub enum ClientStatus {
NotSupportedByServer,
Disabled,
Enabled,
}
impl ClientStatus {
pub fn is_enabled(&self) -> bool {
matches!(self, Self::Enabled)
}
}
pub struct ClientCapability {
condstore: ClientStatus,
utf8kind: Option<Utf8Kind>,
pub condstore: ClientStatus,
pub utf8kind: Option<Utf8Kind>,
}
impl ClientCapability {

View file

@ -292,7 +292,7 @@ impl<'a> AuthenticatedContext<'a> {
}
};
let view = MailboxView::new(mb).await;
let view = MailboxView::new(mb, self.client_capabilities.condstore.is_enabled()).await;
let mut ret_attrs = vec![];
for attr in attributes.iter() {
@ -439,7 +439,7 @@ impl<'a> AuthenticatedContext<'a> {
};
tracing::info!(username=%self.user.username, mailbox=%name, "mailbox.selected");
let mb = MailboxView::new(mb).await;
let mb = MailboxView::new(mb, self.client_capabilities.condstore.is_enabled()).await;
let data = mb.summary()?;
Ok((
@ -474,7 +474,7 @@ impl<'a> AuthenticatedContext<'a> {
};
tracing::info!(username=%self.user.username, mailbox=%name, "mailbox.examined");
let mb = MailboxView::new(mb).await;
let mb = MailboxView::new(mb, self.client_capabilities.condstore.is_enabled()).await;
let data = mb.summary()?;
Ok((

View file

@ -127,7 +127,7 @@ impl<'a> ExaminedContext<'a> {
}
pub async fn noop(self) -> Result<(Response<'static>, flow::Transition)> {
self.mailbox.0.mailbox.force_sync().await?;
self.mailbox.internal.mailbox.force_sync().await?;
let updates = self.mailbox.update().await?;
Ok((

View file

@ -152,7 +152,7 @@ impl<'a> SelectedContext<'a> {
}
pub async fn noop(self) -> Result<(Response<'static>, flow::Transition)> {
self.mailbox.0.mailbox.force_sync().await?;
self.mailbox.internal.mailbox.force_sync().await?;
let updates = self.mailbox.update().await?;
Ok((

View file

@ -8,7 +8,7 @@ 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::flag::{Flag, FlagFetch, FlagPerm, StoreResponse, StoreType};
use imap_codec::imap_types::response::{Code, Data, Status};
use imap_codec::imap_types::response::{Code, CodeOther, Data, Status};
use imap_codec::imap_types::search::SearchKey;
use imap_codec::imap_types::sequence::SequenceSet;
@ -39,12 +39,18 @@ const DEFAULT_FLAGS: [Flag; 5] = [
/// To do this, it keeps a variable `known_state` that corresponds to
/// what the client knows, and produces IMAP messages to be sent to the
/// client that go along updates to `known_state`.
pub struct MailboxView(pub FrozenMailbox);
pub struct MailboxView {
pub internal: FrozenMailbox,
pub is_condstore: bool,
}
impl MailboxView {
/// Creates a new IMAP view into a mailbox.
pub async fn new(mailbox: Arc<Mailbox>) -> Self {
Self(mailbox.frozen().await)
pub async fn new(mailbox: Arc<Mailbox>, is_cond: bool) -> Self {
Self {
internal: mailbox.frozen().await,
is_condstore: is_cond,
}
}
/// Create an updated view, useful to make a diff
@ -54,8 +60,8 @@ impl MailboxView {
/// This does NOT trigger a sync, it bases itself on what is currently
/// loaded in RAM by Bayou.
pub async fn update(&mut self) -> Result<Vec<Body<'static>>> {
let old_snapshot = self.0.update().await;
let new_snapshot = &self.0.snapshot;
let old_snapshot = self.internal.update().await;
let new_snapshot = &self.internal.snapshot;
let mut data = Vec::<Body>::new();
@ -130,6 +136,9 @@ impl MailboxView {
data.extend(self.flags_status()?.into_iter());
data.push(self.uidvalidity_status()?);
data.push(self.uidnext_status()?);
if self.is_condstore {
data.push(self.highestmodseq_status()?);
}
/*self.unseen_first_status()?
.map(|unseen_status| data.push(unseen_status));*/
@ -144,7 +153,7 @@ impl MailboxView {
flags: &[Flag<'a>],
is_uid_store: &bool,
) -> Result<Vec<Body<'static>>> {
self.0.sync().await?;
self.internal.sync().await?;
let flags = flags.iter().map(|x| x.to_string()).collect::<Vec<_>>();
@ -153,13 +162,13 @@ impl MailboxView {
for mi in mails.iter() {
match kind {
StoreType::Add => {
self.0.mailbox.add_flags(mi.uuid, &flags[..]).await?;
self.internal.mailbox.add_flags(mi.uuid, &flags[..]).await?;
}
StoreType::Remove => {
self.0.mailbox.del_flags(mi.uuid, &flags[..]).await?;
self.internal.mailbox.del_flags(mi.uuid, &flags[..]).await?;
}
StoreType::Replace => {
self.0.mailbox.set_flags(mi.uuid, &flags[..]).await?;
self.internal.mailbox.set_flags(mi.uuid, &flags[..]).await?;
}
}
}
@ -169,8 +178,8 @@ impl MailboxView {
}
pub async fn expunge(&mut self) -> Result<Vec<Body<'static>>> {
self.0.sync().await?;
let state = self.0.peek().await;
self.internal.sync().await?;
let state = self.internal.peek().await;
let deleted_flag = Flag::Deleted.to_string();
let msgs = state
@ -180,7 +189,7 @@ impl MailboxView {
.map(|(uuid, _)| *uuid);
for msg in msgs {
self.0.mailbox.delete(msg).await?;
self.internal.mailbox.delete(msg).await?;
}
self.update().await
@ -197,7 +206,7 @@ impl MailboxView {
let mut new_uuids = vec![];
for mi in mails.iter() {
new_uuids.push(to.copy_from(&self.0.mailbox, mi.uuid).await?);
new_uuids.push(to.copy_from(&self.internal.mailbox, mi.uuid).await?);
}
let mut ret = vec![];
@ -224,7 +233,7 @@ impl MailboxView {
let mails = idx.fetch(sequence_set, *is_uid_copy)?;
for mi in mails.iter() {
to.move_from(&self.0.mailbox, mi.uuid).await?;
to.move_from(&self.internal.mailbox, mi.uuid).await?;
}
let mut ret = vec![];
@ -268,7 +277,7 @@ impl MailboxView {
.iter()
.map(|midx| midx.uuid)
.collect::<Vec<_>>();
let query_result = self.0.query(&uuids, query_scope).fetch().await?;
let query_result = self.internal.query(&uuids, query_scope).fetch().await?;
// [3/6] Derive an IMAP-specific view from the results, apply the filters
let views = query_result
@ -294,7 +303,7 @@ impl MailboxView {
.filter(|(_mv, seen)| matches!(seen, SeenFlag::MustAdd))
.map(|(mv, _seen)| async move {
let seen_flag = Flag::Seen.to_string();
self.0
self.internal
.mailbox
.add_flags(*mv.query_result.uuid(), &[seen_flag])
.await?;
@ -332,7 +341,7 @@ impl MailboxView {
// 4. Fetch additional info about the emails
let query_scope = crit.query_scope();
let uuids = to_fetch.iter().map(|midx| midx.uuid).collect::<Vec<_>>();
let query_result = self.0.query(&uuids, query_scope).fetch().await?;
let query_result = self.internal.query(&uuids, query_scope).fetch().await?;
// 5. If needed, filter the selection based on the body
let kept_query = crit.filter_on_query(&to_fetch, &query_result)?;
@ -354,7 +363,7 @@ impl MailboxView {
/// It's not trivial to refactor the code to do that, so we are doing
/// some useless computation for now...
fn index<'a>(&'a self) -> Result<Index<'a>> {
Index::new(&self.0.snapshot)
Index::new(&self.internal.snapshot)
}
/// Produce an OK [UIDVALIDITY _] message corresponding to `known_state`
@ -369,7 +378,7 @@ impl MailboxView {
}
pub(crate) fn uidvalidity(&self) -> ImapUidvalidity {
self.0.snapshot.uidvalidity
self.internal.snapshot.uidvalidity
}
/// Produce an OK [UIDNEXT _] message corresponding to `known_state`
@ -384,7 +393,15 @@ impl MailboxView {
}
pub(crate) fn uidnext(&self) -> ImapUid {
self.0.snapshot.uidnext
self.internal.snapshot.uidnext
}
pub(crate) fn highestmodseq_status(&self) -> Result<Body<'static>> {
Ok(Body::Status(Status::ok(
None,
Some(Code::Other(CodeOther::unvalidated(format!("HIGHESTMODSEQ {}", 0).into_bytes()))),
"Highest",
)?))
}
/// Produce an EXISTS message corresponding to the number of mails
@ -394,7 +411,7 @@ impl MailboxView {
}
pub(crate) fn exists(&self) -> Result<u32> {
Ok(u32::try_from(self.0.snapshot.idx_by_uid.len())?)
Ok(u32::try_from(self.internal.snapshot.idx_by_uid.len())?)
}
/// Produce a RECENT message corresponding to the number of
@ -416,7 +433,7 @@ impl MailboxView {
#[allow(dead_code)]
fn unseen_first(&self) -> Result<Option<NonZeroU32>> {
Ok(self
.0
.internal
.snapshot
.table
.values()
@ -428,7 +445,7 @@ impl MailboxView {
pub(crate) fn recent(&self) -> Result<u32> {
let recent = self
.0
.internal
.snapshot
.idx_by_flag
.get(&"\\Recent".to_string())
@ -445,7 +462,7 @@ impl MailboxView {
// 1. Collecting all the possible flags in the mailbox
// 1.a Fetch them from our index
let mut known_flags: Vec<Flag> = self
.0
.internal
.snapshot
.idx_by_flag
.flags()
@ -485,9 +502,9 @@ impl MailboxView {
}
pub(crate) fn unseen_count(&self) -> usize {
let total = self.0.snapshot.table.len();
let total = self.internal.snapshot.table.len();
let seen = self
.0
.internal
.snapshot
.idx_by_flag
.get(&Flag::Seen.to_string())