diff --git a/Cargo.lock b/Cargo.lock index 39bc590..e2992b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1807,7 +1807,7 @@ dependencies = [ [[package]] name = "imap-codec" 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 = [ "abnf-core", "base64 0.21.5", @@ -1834,7 +1834,7 @@ dependencies = [ [[package]] name = "imap-types" 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 = [ "base64 0.21.5", "bounded-static", diff --git a/src/imap/capability.rs b/src/imap/capability.rs index be1d4b6..37f14df 100644 --- a/src/imap/capability.rs +++ b/src/imap/capability.rs @@ -11,9 +11,11 @@ fn capability_condstore() -> Capability<'static> { Capability::try_from("CONDSTORE").unwrap() } +/* fn capability_qresync() -> Capability<'static> { Capability::try_from("QRESYNC").unwrap() } +*/ #[derive(Debug, Clone)] pub struct ServerCapability(HashSet>); @@ -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]) { for at in atoms.iter() { if at.as_ref().to_uppercase() == "CONDSTORE" { - self.condstore = self.condstore.enable(); + self.enable_condstore(); } } } diff --git a/src/imap/command/authenticated.rs b/src/imap/command/authenticated.rs index f083ac8..da41182 100644 --- a/src/imap/command/authenticated.rs +++ b/src/imap/command/authenticated.rs @@ -311,8 +311,9 @@ impl<'a> AuthenticatedContext<'a> { bail!("quota not implemented, can't return freed storage after EXPUNGE will be run"); }, StatusDataItemName::HighestModSeq => { - bail!("highestmodseq not yet implemented"); - } + self.client_capabilities.enable_condstore(); + StatusDataItem::HighestModSeq(view.highestmodseq().get()) + }, }); } diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs index a3d56f0..b3848b2 100644 --- a/src/imap/mailbox_view.rs +++ b/src/imap/mailbox_view.rs @@ -15,7 +15,7 @@ use imap_codec::imap_types::sequence::SequenceSet; use crate::mail::mailbox::Mailbox; use crate::mail::query::QueryScope; 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::flags; @@ -399,11 +399,15 @@ impl MailboxView { pub(crate) fn highestmodseq_status(&self) -> Result> { Ok(Body::Status(Status::ok( 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", )?)) } + pub(crate) fn highestmodseq(&self) -> ModSeq { + self.internal.snapshot.highestmodseq + } + /// Produce an EXISTS message corresponding to the number of mails /// in `known_state` fn exists_status(&self) -> Result> { diff --git a/src/mail/mailbox.rs b/src/mail/mailbox.rs index 84fa5af..5e95f32 100644 --- a/src/mail/mailbox.rs +++ b/src/mail/mailbox.rs @@ -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) { let s = uid_index.state(); println!("---- MAILBOX STATE ----"); diff --git a/src/mail/query.rs b/src/mail/query.rs index 0838800..a183c5a 100644 --- a/src/mail/query.rs +++ b/src/mail/query.rs @@ -125,13 +125,6 @@ impl QueryResult { } } - fn into_partial(self, metadata: MailMeta) -> Option { - match self { - Self::IndexResult { uuid } => Some(Self::PartialResult { uuid, metadata }), - _ => None, - } - } - fn into_full(self, content: Vec) -> Option { match self { Self::PartialResult { uuid, metadata } => Some(Self::FullResult { diff --git a/src/mail/uidindex.rs b/src/mail/uidindex.rs index e7023cf..f703d04 100644 --- a/src/mail/uidindex.rs +++ b/src/mail/uidindex.rs @@ -1,4 +1,4 @@ -use std::num::NonZeroU32; +use std::num::{NonZeroU32, NonZeroU64}; use im::{HashMap, OrdMap, OrdSet}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -6,7 +6,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::bayou::*; use crate::mail::unique_ident::UniqueIdent; -pub type ModSeq = NonZeroU32; +pub type ModSeq = NonZeroU64; pub type ImapUid = NonZeroU32; pub type ImapUidvalidity = NonZeroU32; pub type Flag = String; @@ -118,10 +118,10 @@ impl Default for UidIndex { uidvalidity: NonZeroU32::new(1).unwrap(), uidnext: NonZeroU32::new(1).unwrap(), - highestmodseq: NonZeroU32::new(1).unwrap(), + highestmodseq: NonZeroU64::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 if *uid < new.internalseq || *modseq < new.internalmodseq { 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 = NonZeroU32::new(new.uidvalidity.get() + bump_uid + bump_modseq) .unwrap(); @@ -164,7 +164,7 @@ impl BayouState for UidIndex { new.highestmodseq = new.internalmodseq; 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; } @@ -179,7 +179,7 @@ impl BayouState for UidIndex { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { // Bump UIDValidity if required 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 = NonZeroU32::new(new.uidvalidity.get() + bump_modseq) .unwrap(); @@ -198,14 +198,14 @@ impl BayouState for UidIndex { // Update counters 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) => { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { // Bump UIDValidity if required 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 = NonZeroU32::new(new.uidvalidity.get() + bump_modseq) .unwrap(); @@ -221,14 +221,14 @@ impl BayouState for UidIndex { // Update counters 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) => { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) { // Bump UIDValidity if required 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 = NonZeroU32::new(new.uidvalidity.get() + bump_modseq) .unwrap(); @@ -255,7 +255,7 @@ impl BayouState for UidIndex { // Update counters 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) => {