2022-06-14 09:10:21 +00:00
|
|
|
use im::{HashMap, HashSet, OrdSet, OrdMap};
|
2022-05-18 10:24:37 +00:00
|
|
|
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
|
|
|
|
|
|
|
|
use crate::bayou::*;
|
|
|
|
|
2022-06-13 16:01:07 +00:00
|
|
|
pub type ImapUid = u32;
|
|
|
|
pub type ImapUidvalidity = u32;
|
2022-06-14 08:35:12 +00:00
|
|
|
pub type Flag = String;
|
2022-05-18 10:24:37 +00:00
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
/// Mail Identifier (MailIdent) are composed of two components:
|
2022-05-18 10:24:37 +00:00
|
|
|
/// - a process identifier, 128 bits
|
|
|
|
/// - a sequence number, 64 bits
|
2022-06-14 09:10:21 +00:00
|
|
|
/// They are not part of the protocol but an internal representation
|
|
|
|
/// required by Mailrage/Aerogramme.
|
|
|
|
/// Their main property is to be unique without having to rely
|
|
|
|
/// on synchronization between IMAP processes.
|
2022-06-14 08:19:24 +00:00
|
|
|
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
|
2022-06-14 09:10:21 +00:00
|
|
|
pub struct MailIdent(pub [u8; 24]);
|
2022-05-18 10:24:37 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
2022-06-14 08:19:24 +00:00
|
|
|
/// A UidIndex handles the mutable part of a mailbox
|
|
|
|
/// It is built by running the event log on it
|
|
|
|
/// Each applied log generates a new UidIndex by cloning the previous one
|
|
|
|
/// and applying the event. This is why we use immutable datastructures
|
|
|
|
/// that are optimized for cloning (they clone underlying values only if they are modified)
|
2022-05-18 10:24:37 +00:00
|
|
|
pub struct UidIndex {
|
2022-06-14 09:10:21 +00:00
|
|
|
pub mail_uid: OrdMap<MailIdent, ImapUid>,
|
|
|
|
pub mail_flags: OrdMap<MailIdent, Vec<Flag>>,
|
|
|
|
pub mails_by_uid: OrdMap<ImapUid, MailIdent>,
|
|
|
|
pub flags: HashMap<Flag, OrdSet<ImapUid>>,
|
2022-06-13 16:01:07 +00:00
|
|
|
|
2022-05-18 12:54:48 +00:00
|
|
|
pub uidvalidity: ImapUidvalidity,
|
|
|
|
pub uidnext: ImapUid,
|
|
|
|
pub internalseq: ImapUid,
|
2022-05-18 10:24:37 +00:00
|
|
|
}
|
|
|
|
|
2022-05-18 12:54:48 +00:00
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
2022-05-18 10:24:37 +00:00
|
|
|
pub enum UidIndexOp {
|
2022-06-14 09:10:21 +00:00
|
|
|
MailAdd(MailIdent, ImapUid, Vec<Flag>),
|
|
|
|
MailDel(MailIdent),
|
|
|
|
FlagAdd(MailIdent, Vec<Flag>),
|
|
|
|
FlagDel(MailIdent, Vec<Flag>),
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UidIndex {
|
|
|
|
#[must_use]
|
2022-06-14 09:10:21 +00:00
|
|
|
pub fn op_mail_add(&self, ident: MailIdent, flags: Vec<Flag>) -> UidIndexOp {
|
|
|
|
UidIndexOp::MailAdd(ident, self.internalseq, flags)
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
2022-06-14 09:10:21 +00:00
|
|
|
pub fn op_mail_del(&self, ident: MailIdent) -> UidIndexOp {
|
|
|
|
UidIndexOp::MailDel(ident)
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
2022-06-14 09:10:21 +00:00
|
|
|
pub fn op_flag_add(&self, ident: MailIdent, flags: Vec<Flag>) -> UidIndexOp {
|
|
|
|
UidIndexOp::FlagAdd(ident, flags)
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
2022-06-14 09:10:21 +00:00
|
|
|
pub fn op_flag_del(&self, ident: MailIdent, flags: Vec<Flag>) -> UidIndexOp {
|
|
|
|
UidIndexOp::FlagDel(ident, flags)
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
2022-05-18 10:24:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for UidIndex {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
mail_flags: OrdMap::new(),
|
|
|
|
mail_uid: OrdMap::new(),
|
|
|
|
mails_by_uid: OrdMap::new(),
|
2022-06-14 08:19:24 +00:00
|
|
|
flags: HashMap::new(),
|
2022-05-18 10:24:37 +00:00
|
|
|
uidvalidity: 1,
|
|
|
|
uidnext: 1,
|
|
|
|
internalseq: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BayouState for UidIndex {
|
|
|
|
type Op = UidIndexOp;
|
|
|
|
|
|
|
|
fn apply(&self, op: &UidIndexOp) -> Self {
|
|
|
|
let mut new = self.clone();
|
|
|
|
match op {
|
2022-06-14 09:10:21 +00:00
|
|
|
UidIndexOp::MailAdd(ident, uid, flags) => {
|
|
|
|
// Change UIDValidity if there is a conflict
|
2022-05-18 10:24:37 +00:00
|
|
|
if *uid < new.internalseq {
|
|
|
|
new.uidvalidity += new.internalseq - *uid;
|
|
|
|
}
|
2022-06-14 09:10:21 +00:00
|
|
|
|
|
|
|
// Assign the real uid
|
2022-05-18 10:24:37 +00:00
|
|
|
let new_uid = new.internalseq;
|
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
if let Some(prev_uid) = new.mail_uid.get(ident) {
|
2022-05-18 10:24:37 +00:00
|
|
|
new.mails_by_uid.remove(prev_uid);
|
|
|
|
} else {
|
2022-06-14 09:10:21 +00:00
|
|
|
new.mail_flags.insert(*ident, flags.clone());
|
2022-05-18 10:24:37 +00:00
|
|
|
}
|
2022-06-14 09:10:21 +00:00
|
|
|
new.mails_by_uid.insert(new_uid, *ident);
|
|
|
|
new.mail_uid.insert(*ident, new_uid);
|
2022-05-18 10:24:37 +00:00
|
|
|
|
|
|
|
new.internalseq += 1;
|
|
|
|
new.uidnext = new.internalseq;
|
|
|
|
}
|
2022-06-14 09:10:21 +00:00
|
|
|
UidIndexOp::MailDel(ident) => {
|
|
|
|
if let Some(uid) = new.mail_uid.get(ident) {
|
2022-05-18 10:24:37 +00:00
|
|
|
new.mails_by_uid.remove(uid);
|
2022-06-14 09:10:21 +00:00
|
|
|
new.mail_uid.remove(ident);
|
|
|
|
new.mail_flags.remove(ident);
|
2022-05-18 10:24:37 +00:00
|
|
|
}
|
|
|
|
new.internalseq += 1;
|
|
|
|
}
|
2022-06-14 09:10:21 +00:00
|
|
|
UidIndexOp::FlagAdd(ident, new_flags) => {
|
2022-06-14 08:19:24 +00:00
|
|
|
// Upate mapping Email -> Flag
|
2022-06-14 09:10:21 +00:00
|
|
|
let mail_flags = new.mail_flags.entry(*ident).or_insert(vec![]);
|
2022-05-18 10:42:25 +00:00
|
|
|
for flag in new_flags {
|
|
|
|
if !mail_flags.contains(flag) {
|
|
|
|
mail_flags.push(flag.to_string());
|
|
|
|
}
|
|
|
|
}
|
2022-06-14 08:19:24 +00:00
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
// Update mapping Flag -> ImapUid
|
|
|
|
|
|
|
|
/*
|
2022-06-14 08:19:24 +00:00
|
|
|
let _ = new_flags.iter().map(|flag| {
|
|
|
|
new.flags
|
|
|
|
.entry(flag.clone())
|
2022-06-14 09:10:21 +00:00
|
|
|
.or_insert(OrdSet::new())
|
2022-06-14 08:19:24 +00:00
|
|
|
.update(*uuid)
|
2022-06-14 09:10:21 +00:00
|
|
|
});*/
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
2022-06-14 09:10:21 +00:00
|
|
|
UidIndexOp::FlagDel(ident, rm_flags) => {
|
2022-06-14 08:35:12 +00:00
|
|
|
// Upate mapping Email -> Flag
|
2022-06-14 09:10:21 +00:00
|
|
|
if let Some(mail_flags) = new.mail_flags.get_mut(ident) {
|
2022-05-18 10:42:25 +00:00
|
|
|
mail_flags.retain(|x| !rm_flags.contains(x));
|
|
|
|
}
|
2022-06-14 08:35:12 +00:00
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
// Update mapping Flag -> ImapUid
|
|
|
|
/*rm_flags.iter().for_each(|flag| {
|
2022-06-14 08:35:12 +00:00
|
|
|
new.flags
|
|
|
|
.entry(flag.clone())
|
|
|
|
.and_modify(|hs| { hs.remove(uuid); });
|
2022-06-14 09:10:21 +00:00
|
|
|
});*/
|
2022-05-18 10:42:25 +00:00
|
|
|
}
|
2022-05-18 10:24:37 +00:00
|
|
|
}
|
|
|
|
new
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---- CUSTOM SERIALIZATION AND DESERIALIZATION ----
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
struct UidIndexSerializedRepr {
|
2022-06-14 09:10:21 +00:00
|
|
|
mails: Vec<(ImapUid, MailIdent, Vec<Flag>)>,
|
2022-05-18 10:24:37 +00:00
|
|
|
uidvalidity: ImapUidvalidity,
|
|
|
|
uidnext: ImapUid,
|
|
|
|
internalseq: ImapUid,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for UidIndex {
|
|
|
|
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
let val: UidIndexSerializedRepr = UidIndexSerializedRepr::deserialize(d)?;
|
|
|
|
|
|
|
|
let mut uidindex = UidIndex {
|
|
|
|
mail_flags: OrdMap::new(),
|
|
|
|
mail_uid: OrdMap::new(),
|
|
|
|
mails_by_uid: OrdMap::new(),
|
2022-06-14 08:19:24 +00:00
|
|
|
flags: HashMap::new(),
|
2022-05-18 10:24:37 +00:00
|
|
|
uidvalidity: val.uidvalidity,
|
|
|
|
uidnext: val.uidnext,
|
|
|
|
internalseq: val.internalseq,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (uid, uuid, flags) in val.mails {
|
|
|
|
uidindex.mail_flags.insert(uuid, flags);
|
|
|
|
uidindex.mail_uid.insert(uuid, uid);
|
|
|
|
uidindex.mails_by_uid.insert(uid, uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(uidindex)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for UidIndex {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
let mut mails = vec![];
|
|
|
|
for (uid, uuid) in self.mails_by_uid.iter() {
|
|
|
|
mails.push((
|
|
|
|
*uid,
|
|
|
|
*uuid,
|
|
|
|
self.mail_flags.get(uuid).cloned().unwrap_or_default(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let val = UidIndexSerializedRepr {
|
|
|
|
mails,
|
|
|
|
uidvalidity: self.uidvalidity,
|
|
|
|
uidnext: self.uidnext,
|
|
|
|
internalseq: self.internalseq,
|
|
|
|
};
|
|
|
|
|
|
|
|
val.serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
impl<'de> Deserialize<'de> for MailIdent {
|
2022-05-18 10:24:37 +00:00
|
|
|
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
let v = String::deserialize(d)?;
|
|
|
|
let bytes = hex::decode(v).map_err(|_| D::Error::custom("invalid hex"))?;
|
|
|
|
|
|
|
|
if bytes.len() != 24 {
|
|
|
|
return Err(D::Error::custom("bad length"));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut tmp = [0u8; 24];
|
|
|
|
tmp[..].copy_from_slice(&bytes);
|
|
|
|
Ok(Self(tmp))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:21 +00:00
|
|
|
impl Serialize for MailIdent {
|
2022-05-18 10:24:37 +00:00
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
serializer.serialize_str(&hex::encode(self.0))
|
|
|
|
}
|
|
|
|
}
|