use core::num::NonZeroU32;
use alloc::{
format,
string::{String, ToString},
vec,
vec::Vec,
};
use io_imap::types::{
fetch::{MacroOrMessageDataItemNames, MessageDataItem, MessageDataItemName},
flag::FlagFetch,
};
use crate::{
envelope::{
imap::list::envelope_from,
types::{Envelope, FlagUpdate},
},
flag::types::Flag,
};
const STATE_BYTES: usize = 4 + 8 + 4;
#[derive(Clone, Copy, Debug, Default)]
pub struct ImapState {
pub uid_validity: u32,
pub highest_mod_seq: u64,
pub highest_uid: u32,
}
impl ImapState {
pub fn decode(bytes: &[u8]) -> Option<Self> {
if bytes.len() != STATE_BYTES {
return None;
}
let uid_validity = u32::from_le_bytes(bytes[0..4].try_into().ok()?);
let highest_mod_seq = u64::from_le_bytes(bytes[4..12].try_into().ok()?);
let highest_uid = u32::from_le_bytes(bytes[12..16].try_into().ok()?);
Some(Self {
uid_validity,
highest_mod_seq,
highest_uid,
})
}
pub fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(STATE_BYTES);
out.extend_from_slice(&self.uid_validity.to_le_bytes());
out.extend_from_slice(&self.highest_mod_seq.to_le_bytes());
out.extend_from_slice(&self.highest_uid.to_le_bytes());
out
}
}
pub fn new_message_item_names() -> MacroOrMessageDataItemNames<'static> {
MacroOrMessageDataItemNames::MessageDataItemNames(vec![
MessageDataItemName::Uid,
MessageDataItemName::Flags,
MessageDataItemName::Envelope,
MessageDataItemName::Rfc822Size,
])
}
pub fn new_message_window(high: u32) -> Option<String> {
let start = high.checked_add(1)?;
Some(format!("{start}:*"))
}
pub fn flag_update_from_items(items: &[MessageDataItem<'static>]) -> Option<FlagUpdate> {
let mut uid: Option<NonZeroU32> = None;
let mut flags: Option<alloc::collections::BTreeSet<Flag>> = None;
for item in items {
match item {
MessageDataItem::Uid(u) => uid = Some(*u),
MessageDataItem::Flags(fs) => {
flags = Some(
fs.iter()
.filter_map(|f| match f {
FlagFetch::Flag(flag) => Some(Flag::from_raw(flag.to_string())),
_ => None,
})
.collect(),
);
}
_ => {}
}
}
Some(FlagUpdate {
id: uid?.get().to_string(),
flags: flags?,
})
}
pub fn envelope_from_items(items: Vec<MessageDataItem<'static>>) -> Envelope {
envelope_from(0, items)
}