CONDSTORE #71
7 changed files with 33 additions and 26 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
|
@ -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 ----");
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
Loading…
Reference in a new issue