Implement HIGHESTMODSEQ for STATUS

This commit is contained in:
Quentin 2024-01-10 17:07:07 +01:00
parent 96332c9bfe
commit 9cec7803d2
Signed by: quentin
GPG key ID: E9602264D639FF68
7 changed files with 33 additions and 26 deletions

4
Cargo.lock generated
View file

@ -1807,7 +1807,7 @@ dependencies = [
[[package]] [[package]]
name = "imap-codec" name = "imap-codec"
version = "2.0.0" version = "2.0.0"
source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#88bdca2b571f02bccb52257bee7355daebe7d123" source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#eb37f06a0e8d2543f60063ec80cde9e9dcb150f1"
dependencies = [ dependencies = [
"abnf-core", "abnf-core",
"base64 0.21.5", "base64 0.21.5",
@ -1834,7 +1834,7 @@ dependencies = [
[[package]] [[package]]
name = "imap-types" name = "imap-types"
version = "2.0.0" version = "2.0.0"
source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#88bdca2b571f02bccb52257bee7355daebe7d123" source = "git+https://github.com/superboum/imap-codec?branch=custom/aerogramme#eb37f06a0e8d2543f60063ec80cde9e9dcb150f1"
dependencies = [ dependencies = [
"base64 0.21.5", "base64 0.21.5",
"bounded-static", "bounded-static",

View file

@ -11,9 +11,11 @@ fn capability_condstore() -> Capability<'static> {
Capability::try_from("CONDSTORE").unwrap() Capability::try_from("CONDSTORE").unwrap()
} }
/*
fn capability_qresync() -> Capability<'static> { fn capability_qresync() -> Capability<'static> {
Capability::try_from("QRESYNC").unwrap() Capability::try_from("QRESYNC").unwrap()
} }
*/
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ServerCapability(HashSet<Capability<'static>>); pub struct ServerCapability(HashSet<Capability<'static>>);
@ -84,10 +86,14 @@ impl ClientCapability {
} }
} }
pub fn enable_condstore(&mut self) {
self.condstore = self.condstore.enable();
}
pub fn select_enable(&mut self, atoms: &[Atom]) { pub fn select_enable(&mut self, atoms: &[Atom]) {
for at in atoms.iter() { for at in atoms.iter() {
if at.as_ref().to_uppercase() == "CONDSTORE" { if at.as_ref().to_uppercase() == "CONDSTORE" {
self.condstore = self.condstore.enable(); self.enable_condstore();
} }
} }
} }

View file

@ -311,8 +311,9 @@ impl<'a> AuthenticatedContext<'a> {
bail!("quota not implemented, can't return freed storage after EXPUNGE will be run"); bail!("quota not implemented, can't return freed storage after EXPUNGE will be run");
}, },
StatusDataItemName::HighestModSeq => { StatusDataItemName::HighestModSeq => {
bail!("highestmodseq not yet implemented"); self.client_capabilities.enable_condstore();
} StatusDataItem::HighestModSeq(view.highestmodseq().get())
},
}); });
} }

View file

@ -15,7 +15,7 @@ use imap_codec::imap_types::sequence::SequenceSet;
use crate::mail::mailbox::Mailbox; use crate::mail::mailbox::Mailbox;
use crate::mail::query::QueryScope; use crate::mail::query::QueryScope;
use crate::mail::snapshot::FrozenMailbox; use crate::mail::snapshot::FrozenMailbox;
use crate::mail::uidindex::{ImapUid, ImapUidvalidity}; use crate::mail::uidindex::{ImapUid, ImapUidvalidity, ModSeq};
use crate::imap::attributes::AttributesProxy; use crate::imap::attributes::AttributesProxy;
use crate::imap::flags; use crate::imap::flags;
@ -399,11 +399,15 @@ impl MailboxView {
pub(crate) fn highestmodseq_status(&self) -> Result<Body<'static>> { pub(crate) fn highestmodseq_status(&self) -> Result<Body<'static>> {
Ok(Body::Status(Status::ok( Ok(Body::Status(Status::ok(
None, None,
Some(Code::Other(CodeOther::unvalidated(format!("HIGHESTMODSEQ {}", self.internal.snapshot.highestmodseq).into_bytes()))), Some(Code::Other(CodeOther::unvalidated(format!("HIGHESTMODSEQ {}", self.highestmodseq()).into_bytes()))),
"Highest", "Highest",
)?)) )?))
} }
pub(crate) fn highestmodseq(&self) -> ModSeq {
self.internal.snapshot.highestmodseq
}
/// Produce an EXISTS message corresponding to the number of mails /// Produce an EXISTS message corresponding to the number of mails
/// in `known_state` /// in `known_state`
fn exists_status(&self) -> Result<Body<'static>> { fn exists_status(&self) -> Result<Body<'static>> {

View file

@ -465,6 +465,9 @@ impl MailboxInternal {
} }
} }
// Can be useful to debug so we want this code
// to be available to developers
#[allow(dead_code)]
fn dump(uid_index: &Bayou<UidIndex>) { fn dump(uid_index: &Bayou<UidIndex>) {
let s = uid_index.state(); let s = uid_index.state();
println!("---- MAILBOX STATE ----"); println!("---- MAILBOX STATE ----");

View file

@ -125,13 +125,6 @@ impl QueryResult {
} }
} }
fn into_partial(self, metadata: MailMeta) -> Option<Self> {
match self {
Self::IndexResult { uuid } => Some(Self::PartialResult { uuid, metadata }),
_ => None,
}
}
fn into_full(self, content: Vec<u8>) -> Option<Self> { fn into_full(self, content: Vec<u8>) -> Option<Self> {
match self { match self {
Self::PartialResult { uuid, metadata } => Some(Self::FullResult { Self::PartialResult { uuid, metadata } => Some(Self::FullResult {

View file

@ -1,4 +1,4 @@
use std::num::NonZeroU32; use std::num::{NonZeroU32, NonZeroU64};
use im::{HashMap, OrdMap, OrdSet}; use im::{HashMap, OrdMap, OrdSet};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -6,7 +6,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::bayou::*; use crate::bayou::*;
use crate::mail::unique_ident::UniqueIdent; use crate::mail::unique_ident::UniqueIdent;
pub type ModSeq = NonZeroU32; pub type ModSeq = NonZeroU64;
pub type ImapUid = NonZeroU32; pub type ImapUid = NonZeroU32;
pub type ImapUidvalidity = NonZeroU32; pub type ImapUidvalidity = NonZeroU32;
pub type Flag = String; pub type Flag = String;
@ -118,10 +118,10 @@ impl Default for UidIndex {
uidvalidity: NonZeroU32::new(1).unwrap(), uidvalidity: NonZeroU32::new(1).unwrap(),
uidnext: NonZeroU32::new(1).unwrap(), uidnext: NonZeroU32::new(1).unwrap(),
highestmodseq: NonZeroU32::new(1).unwrap(), highestmodseq: NonZeroU64::new(1).unwrap(),
internalseq: NonZeroU32::new(1).unwrap(), internalseq: NonZeroU32::new(1).unwrap(),
internalmodseq: NonZeroU32::new(1).unwrap(), internalmodseq: NonZeroU64::new(1).unwrap(),
} }
} }
} }
@ -138,7 +138,7 @@ impl BayouState for UidIndex {
// The intuition: we increase the UIDValidity by the number of possible conflicts // The intuition: we increase the UIDValidity by the number of possible conflicts
if *uid < new.internalseq || *modseq < new.internalmodseq { if *uid < new.internalseq || *modseq < new.internalmodseq {
let bump_uid = new.internalseq.get() - uid.get(); let bump_uid = new.internalseq.get() - uid.get();
let bump_modseq = new.internalmodseq.get() - modseq.get(); let bump_modseq = (new.internalmodseq.get() - modseq.get()) as u32;
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_uid + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_uid + bump_modseq)
.unwrap(); .unwrap();
@ -164,7 +164,7 @@ impl BayouState for UidIndex {
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;
new.internalseq = NonZeroU32::new(new.internalseq.get() + 1).unwrap(); new.internalseq = NonZeroU32::new(new.internalseq.get() + 1).unwrap();
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU64::new(new.internalmodseq.get() + 1).unwrap();
new.uidnext = new.internalseq; new.uidnext = new.internalseq;
} }
@ -179,7 +179,7 @@ impl BayouState for UidIndex {
if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required // Bump UIDValidity if required
if *candidate_modseq < new.internalmodseq { if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - candidate_modseq.get(); let bump_modseq = (new.internalmodseq.get() - candidate_modseq.get()) as u32;
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap(); .unwrap();
@ -198,14 +198,14 @@ impl BayouState for UidIndex {
// Update counters // Update counters
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU64::new(new.internalmodseq.get() + 1).unwrap();
} }
} }
UidIndexOp::FlagDel(ident, candidate_modseq, rm_flags) => { UidIndexOp::FlagDel(ident, candidate_modseq, rm_flags) => {
if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required // Bump UIDValidity if required
if *candidate_modseq < new.internalmodseq { if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - candidate_modseq.get(); let bump_modseq = (new.internalmodseq.get() - candidate_modseq.get()) as u32;
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap(); .unwrap();
@ -221,14 +221,14 @@ impl BayouState for UidIndex {
// Update counters // Update counters
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU64::new(new.internalmodseq.get() + 1).unwrap();
} }
} }
UidIndexOp::FlagSet(ident, candidate_modseq, new_flags) => { UidIndexOp::FlagSet(ident, candidate_modseq, new_flags) => {
if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required // Bump UIDValidity if required
if *candidate_modseq < new.internalmodseq { if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - candidate_modseq.get(); let bump_modseq = (new.internalmodseq.get() - candidate_modseq.get()) as u32;
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap(); .unwrap();
@ -255,7 +255,7 @@ impl BayouState for UidIndex {
// Update counters // Update counters
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU64::new(new.internalmodseq.get() + 1).unwrap();
} }
} }
UidIndexOp::BumpUidvalidity(count) => { UidIndexOp::BumpUidvalidity(count) => {