Add support for flags
This commit is contained in:
parent
22d0f11173
commit
d3f8a6627c
3 changed files with 41 additions and 3 deletions
|
@ -1,7 +1,8 @@
|
||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use boitalettres::proto::Response;
|
use boitalettres::proto::Response;
|
||||||
use imap_codec::types::command::CommandBody;
|
use imap_codec::types::command::CommandBody;
|
||||||
use imap_codec::types::core::Tag;
|
use imap_codec::types::core::{Atom, Tag};
|
||||||
|
use imap_codec::types::flag::Flag;
|
||||||
use imap_codec::types::mailbox::{ListMailbox, Mailbox as MailboxCodec};
|
use imap_codec::types::mailbox::{ListMailbox, Mailbox as MailboxCodec};
|
||||||
use imap_codec::types::response::{Code, Data, Response as ImapRes, Status};
|
use imap_codec::types::response::{Code, Data, Response as ImapRes, Status};
|
||||||
|
|
||||||
|
@ -10,6 +11,14 @@ use crate::imap::flow;
|
||||||
use crate::imap::session::InnerContext;
|
use crate::imap::session::InnerContext;
|
||||||
use crate::mailbox::Mailbox;
|
use crate::mailbox::Mailbox;
|
||||||
|
|
||||||
|
const DEFAULT_FLAGS: [Flag; 5] = [
|
||||||
|
Flag::Seen,
|
||||||
|
Flag::Answered,
|
||||||
|
Flag::Flagged,
|
||||||
|
Flag::Deleted,
|
||||||
|
Flag::Draft,
|
||||||
|
];
|
||||||
|
|
||||||
pub async fn dispatch<'a>(
|
pub async fn dispatch<'a>(
|
||||||
inner: InnerContext<'a>,
|
inner: InnerContext<'a>,
|
||||||
user: &'a flow::User,
|
user: &'a flow::User,
|
||||||
|
@ -114,7 +123,6 @@ impl<'a> StateContext<'a> {
|
||||||
"First unseen UID",
|
"First unseen UID",
|
||||||
)
|
)
|
||||||
.map_err(Error::msg)?;
|
.map_err(Error::msg)?;
|
||||||
//let r_permanentflags = Status::ok(None, Some(Code::
|
|
||||||
|
|
||||||
let mut res = Vec::<ImapRes>::new();
|
let mut res = Vec::<ImapRes>::new();
|
||||||
|
|
||||||
|
@ -122,7 +130,21 @@ impl<'a> StateContext<'a> {
|
||||||
|
|
||||||
res.push(ImapRes::Data(Data::Recent(sum.recent)));
|
res.push(ImapRes::Data(Data::Recent(sum.recent)));
|
||||||
|
|
||||||
res.push(ImapRes::Data(Data::Flags(vec![])));
|
let mut flags: Vec<Flag> = sum.flags.map(|f| match f.chars().next() {
|
||||||
|
Some('\\') => None,
|
||||||
|
Some('$') if f == "$unseen" => None,
|
||||||
|
Some(_) => match Atom::try_from(f.clone()) {
|
||||||
|
Err(_) => {
|
||||||
|
tracing::error!(username=%self.user.name, mailbox=%name, flag=%f, "Unable to encode flag as IMAP atom");
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Ok(a) => Some(Flag::Keyword(a)),
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
}).flatten().collect();
|
||||||
|
flags.extend_from_slice(&DEFAULT_FLAGS);
|
||||||
|
|
||||||
|
res.push(ImapRes::Data(Data::Flags(flags.clone())));
|
||||||
|
|
||||||
let uid_validity = Status::ok(
|
let uid_validity = Status::ok(
|
||||||
None,
|
None,
|
||||||
|
@ -149,6 +171,14 @@ impl<'a> StateContext<'a> {
|
||||||
res.push(ImapRes::Status(status_unseen));
|
res.push(ImapRes::Status(status_unseen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags.push(Flag::Permanent);
|
||||||
|
let permanent_flags = Status::ok(
|
||||||
|
None,
|
||||||
|
Some(Code::PermanentFlags(flags)),
|
||||||
|
"Flags permitted",
|
||||||
|
).map_err(Error::msg)?;
|
||||||
|
res.push(ImapRes::Status(permanent_flags));
|
||||||
|
|
||||||
let last = Status::ok(
|
let last = Status::ok(
|
||||||
Some(self.tag.clone()),
|
Some(self.tag.clone()),
|
||||||
Some(Code::ReadWrite),
|
Some(Code::ReadWrite),
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub struct Summary<'a> {
|
||||||
pub next: ImapUid,
|
pub next: ImapUid,
|
||||||
pub exists: u32,
|
pub exists: u32,
|
||||||
pub recent: u32,
|
pub recent: u32,
|
||||||
|
pub flags: FlagIter<'a>,
|
||||||
pub unseen: Option<&'a ImapUid>,
|
pub unseen: Option<&'a ImapUid>,
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for Summary<'_> {
|
impl std::fmt::Display for Summary<'_> {
|
||||||
|
@ -69,6 +70,7 @@ impl Mailbox {
|
||||||
next: state.uidnext,
|
next: state.uidnext,
|
||||||
exists: u32::try_from(state.idx_by_uid.len())?,
|
exists: u32::try_from(state.idx_by_uid.len())?,
|
||||||
recent: u32::try_from(recent)?,
|
recent: u32::try_from(recent)?,
|
||||||
|
flags: state.idx_by_flag.flags(),
|
||||||
unseen,
|
unseen,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ impl BayouState for UidIndex {
|
||||||
// ---- FlagIndex implementation ----
|
// ---- FlagIndex implementation ----
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FlagIndex(HashMap<Flag, OrdSet<ImapUid>>);
|
pub struct FlagIndex(HashMap<Flag, OrdSet<ImapUid>>);
|
||||||
|
pub type FlagIter<'a> = im::hashmap::Keys<'a, Flag, OrdSet<ImapUid>>;
|
||||||
|
|
||||||
impl FlagIndex {
|
impl FlagIndex {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
@ -182,9 +183,14 @@ 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>> {
|
pub fn get(&self, f: &Flag) -> Option<&OrdSet<ImapUid>> {
|
||||||
self.0.get(f)
|
self.0.get(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flags(&self) -> FlagIter {
|
||||||
|
self.0.keys()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- CUSTOM SERIALIZATION AND DESERIALIZATION ----
|
// ---- CUSTOM SERIALIZATION AND DESERIALIZATION ----
|
||||||
|
|
Loading…
Reference in a new issue