aboutsummaryrefslogtreecommitdiff
path: root/src/mail/mod.rs
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2022-06-27 16:56:20 +0200
committerQuentin Dufour <quentin@deuxfleurs.fr>2022-06-27 16:56:20 +0200
commit390bad0ec451a571e119903054b581a9d9a00cbe (patch)
tree467fdf3ade0325b8c69ea8350a2f15fa181d8981 /src/mail/mod.rs
parentd3f8a6627ca13a020bac9936d1f40a18239b6d6d (diff)
downloadaerogramme-390bad0ec451a571e119903054b581a9d9a00cbe.tar.gz
aerogramme-390bad0ec451a571e119903054b581a9d9a00cbe.zip
Refactor files in a "mail" crate
Diffstat (limited to 'src/mail/mod.rs')
-rw-r--r--src/mail/mod.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/mail/mod.rs b/src/mail/mod.rs
new file mode 100644
index 0000000..2edcaa7
--- /dev/null
+++ b/src/mail/mod.rs
@@ -0,0 +1,130 @@
+pub mod mail_ident;
+mod uidindex;
+
+use std::convert::TryFrom;
+
+use anyhow::Result;
+use k2v_client::K2vClient;
+use rusoto_s3::S3Client;
+
+use crate::bayou::Bayou;
+use crate::cryptoblob::Key;
+use crate::login::Credentials;
+use crate::mail::mail_ident::*;
+use crate::mail::uidindex::*;
+
+pub struct Summary<'a> {
+ pub validity: ImapUidvalidity,
+ pub next: ImapUid,
+ pub exists: u32,
+ pub recent: u32,
+ pub flags: FlagIter<'a>,
+ pub unseen: Option<&'a ImapUid>,
+}
+impl std::fmt::Display for Summary<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ f,
+ "uidvalidity: {}, uidnext: {}, exists: {}",
+ self.validity, self.next, self.exists
+ )
+ }
+}
+
+
+// Non standard but common flags:
+// https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml
+pub struct Mailbox {
+ bucket: String,
+ pub name: String,
+ key: Key,
+
+ k2v: K2vClient,
+ s3: S3Client,
+
+ 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 {
+ pub fn new(creds: &Credentials, name: String) -> Result<Self> {
+ let uid_index = Bayou::<UidIndex>::new(creds, name.clone())?;
+
+ Ok(Self {
+ bucket: creds.bucket().to_string(),
+ name,
+ key: creds.keys.master.clone(),
+ k2v: creds.k2v_client()?,
+ s3: creds.s3_client()?,
+ uid_index,
+ })
+ }
+
+ pub async fn summary(&mut self) -> Result<Summary> {
+ self.uid_index.sync().await?;
+ 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 {
+ validity: state.uidvalidity,
+ next: state.uidnext,
+ exists: u32::try_from(state.idx_by_uid.len())?,
+ recent: u32::try_from(recent)?,
+ flags: state.idx_by_flag.flags(),
+ unseen,
+ });
+ }
+
+ pub async fn test(&mut self) -> Result<()> {
+ self.uid_index.sync().await?;
+
+ dump(&self.uid_index);
+
+ let add_mail_op = self
+ .uid_index
+ .state()
+ .op_mail_add(gen_ident(), vec!["\\Unseen".into()]);
+ self.uid_index.push(add_mail_op).await?;
+
+ dump(&self.uid_index);
+
+ if self.uid_index.state().idx_by_uid.len() > 6 {
+ for i in 0..2 {
+ let (_, ident) = self
+ .uid_index
+ .state()
+ .idx_by_uid
+ .iter()
+ .skip(3 + i)
+ .next()
+ .unwrap();
+ let del_mail_op = self.uid_index.state().op_mail_del(*ident);
+ self.uid_index.push(del_mail_op).await?;
+
+ dump(&self.uid_index);
+ }
+ }
+
+ Ok(())
+ }
+}
+
+fn dump(uid_index: &Bayou<UidIndex>) {
+ let s = uid_index.state();
+ println!("---- MAILBOX STATE ----");
+ println!("UIDVALIDITY {}", s.uidvalidity);
+ println!("UIDNEXT {}", s.uidnext);
+ println!("INTERNALSEQ {}", s.internalseq);
+ for (uid, ident) in s.idx_by_uid.iter() {
+ println!(
+ "{} {} {}",
+ uid,
+ hex::encode(ident.0),
+ s.table.get(ident).cloned().unwrap().1.join(", ")
+ );
+ }
+ println!("");
+}