Implement Recent in Select

This commit is contained in:
Quentin 2022-06-24 10:27:26 +02:00
parent 8a0df56cde
commit 22d0f11173
Signed by: quentin
GPG key ID: E9602264D639FF68
3 changed files with 62 additions and 33 deletions

View file

@ -106,8 +106,6 @@ impl<'a> StateContext<'a> {
let sum = mb.summary().await?; let sum = mb.summary().await?;
tracing::trace!(summary=%sum, "mailbox.summary"); tracing::trace!(summary=%sum, "mailbox.summary");
let body = vec![Data::Exists(sum.exists.try_into()?), Data::Recent(0)];
let r_unseen = Status::ok( let r_unseen = Status::ok(
None, None,
Some(Code::Unseen( Some(Code::Unseen(
@ -118,33 +116,47 @@ impl<'a> StateContext<'a> {
.map_err(Error::msg)?; .map_err(Error::msg)?;
//let r_permanentflags = Status::ok(None, Some(Code:: //let r_permanentflags = Status::ok(None, Some(Code::
let tr = flow::Transition::Select(mb); let mut res = Vec::<ImapRes>::new();
Ok(( res.push(ImapRes::Data(Data::Exists(sum.exists)));
vec![
ImapRes::Data(Data::Exists(0)), res.push(ImapRes::Data(Data::Recent(sum.recent)));
ImapRes::Data(Data::Recent(0)),
ImapRes::Data(Data::Flags(vec![])), res.push(ImapRes::Data(Data::Flags(vec![])));
ImapRes::Status(
Status::ok( let uid_validity = Status::ok(
None, None,
Some(Code::UidValidity(sum.validity)), Some(Code::UidValidity(sum.validity)),
"UIDs valid" "UIDs valid"
) )
.map_err(Error::msg)?, .map_err(Error::msg)?;
), res.push(ImapRes::Status(uid_validity));
/*ImapRes::Status(),
ImapRes::Status(),*/ let next_uid = Status::ok(
ImapRes::Status( None,
Status::ok( Some(Code::UidNext(sum.next)),
"Predict next UID"
).map_err(Error::msg)?;
res.push(ImapRes::Status(next_uid));
if let Some(unseen) = sum.unseen {
let status_unseen = Status::ok(
None,
Some(Code::Unseen(unseen.clone())),
"First unseen UID",
)
.map_err(Error::msg)?;
res.push(ImapRes::Status(status_unseen));
}
let last = Status::ok(
Some(self.tag.clone()), Some(self.tag.clone()),
Some(Code::ReadWrite), Some(Code::ReadWrite),
"Select completed", "Select completed",
) ).map_err(Error::msg)?;
.map_err(Error::msg)?, res.push(ImapRes::Status(last));
),
], let tr = flow::Transition::Select(mb);
tr, Ok((res, tr))
))
} }
} }

View file

@ -1,3 +1,5 @@
use std::convert::TryFrom;
use anyhow::Result; use anyhow::Result;
use k2v_client::K2vClient; use k2v_client::K2vClient;
use rusoto_s3::S3Client; use rusoto_s3::S3Client;
@ -8,12 +10,14 @@ use crate::login::Credentials;
use crate::mail_ident::*; use crate::mail_ident::*;
use crate::uidindex::*; use crate::uidindex::*;
pub struct Summary { pub struct Summary<'a> {
pub validity: ImapUidvalidity, pub validity: ImapUidvalidity,
pub next: ImapUid, pub next: ImapUid,
pub exists: usize, pub exists: u32,
pub recent: u32,
pub unseen: Option<&'a ImapUid>,
} }
impl std::fmt::Display for Summary { impl std::fmt::Display for Summary<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( write!(
f, f,
@ -23,6 +27,9 @@ impl std::fmt::Display for Summary {
} }
} }
// Non standard but common flags:
// https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml
pub struct Mailbox { pub struct Mailbox {
bucket: String, bucket: String,
pub name: String, pub name: String,
@ -34,6 +41,8 @@ pub struct Mailbox {
uid_index: Bayou<UidIndex>, uid_index: Bayou<UidIndex>,
} }
// IDEA: We store a specific flag named $unseen.
// If it is not present, we add the virtual flag \Seen
impl Mailbox { impl Mailbox {
pub fn new(creds: &Credentials, name: String) -> Result<Self> { pub fn new(creds: &Credentials, name: String) -> Result<Self> {
let uid_index = Bayou::<UidIndex>::new(creds, name.clone())?; let uid_index = Bayou::<UidIndex>::new(creds, name.clone())?;
@ -52,10 +61,15 @@ impl Mailbox {
self.uid_index.sync().await?; self.uid_index.sync().await?;
let state = self.uid_index.state(); let state = self.uid_index.state();
let unseen = state.idx_by_flag.get(&"$unseen".to_string()).and_then(|os| os.get_min());
let recent = state.idx_by_flag.get(&"\\Recent".to_string()).map(|os| os.len()).unwrap_or(0);
return Ok(Summary { return Ok(Summary {
validity: state.uidvalidity, validity: state.uidvalidity,
next: state.uidnext, next: state.uidnext,
exists: state.idx_by_uid.len(), exists: u32::try_from(state.idx_by_uid.len())?,
recent: u32::try_from(recent)?,
unseen,
}); });
} }

View file

@ -182,6 +182,9 @@ impl FlagIndex {
self.0.get_mut(flag).and_then(|set| set.remove(&uid)); self.0.get_mut(flag).and_then(|set| set.remove(&uid));
}); });
} }
pub fn get(&self, f: &Flag) -> Option<&OrdSet<ImapUid>> {
self.0.get(f)
}
} }
// ---- CUSTOM SERIALIZATION AND DESERIALIZATION ---- // ---- CUSTOM SERIALIZATION AND DESERIALIZATION ----