use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::{atomic::AtomicBool, Arc, Mutex};
use crate::account::hier_id_scheme::HierIdScheme;
use crate::account::key_store::KeyStore;
use crate::account::mailbox_path::*;
use crate::account::mailbox_state::*;
use crate::account::model::*;
use crate::support::error::Error;
#[derive(Clone)]
pub struct StatelessMailbox {
pub(super) log_prefix: String,
pub(super) path: MailboxPath,
pub(super) root: PathBuf,
pub(super) read_only: bool,
pub(super) key_store: Arc<Mutex<KeyStore>>,
pub(super) common_paths: Arc<CommonPaths>,
}
#[derive(Clone)]
pub struct StatefulMailbox {
pub(super) s: StatelessMailbox,
pub(super) state: MailboxState,
pub(super) recency_frontier: Option<Uid>,
pub(super) fetch_loopbreaker: HashSet<Uid>,
pub(super) client_known_flags: Vec<Flag>,
pub(super) suggest_rollup: u32,
pub(super) rollups_since_gc: u32,
pub(super) gc_in_progress: Arc<AtomicBool>,
pub(super) synchronous_gc: bool,
}
impl StatelessMailbox {
pub fn new(
mut log_prefix: String,
path: MailboxPath,
read_only: bool,
key_store: Arc<Mutex<KeyStore>>,
common_paths: Arc<CommonPaths>,
) -> Result<Self, Error> {
log_prefix.push(':');
log_prefix.push_str(path.name());
let root = path.scoped_data_path()?;
Ok(StatelessMailbox {
log_prefix,
path,
root,
read_only,
key_store,
common_paths,
})
}
pub fn path(&self) -> &MailboxPath {
&self.path
}
pub fn uid_validity(&self) -> Result<u32, Error> {
parse_uid_validity(&self.root)
}
pub fn is_ok(&self) -> bool {
self.root.is_dir()
}
pub fn log_prefix(&self) -> &str {
&self.log_prefix
}
pub fn read_only(&self) -> bool {
self.read_only
}
pub(super) fn message_scheme(&self) -> HierIdScheme<'_> {
HierIdScheme {
root: &self.root,
prefix: b'u',
extension: "eml",
}
}
pub(super) fn change_scheme(&self) -> HierIdScheme<'_> {
HierIdScheme {
root: &self.root,
prefix: b'c',
extension: "tx",
}
}
pub(super) fn not_read_only(&self) -> Result<(), Error> {
if self.read_only {
Err(Error::MailboxReadOnly)
} else {
Ok(())
}
}
}
impl StatefulMailbox {
pub fn stateless(&self) -> &StatelessMailbox {
&self.s
}
pub fn max_seqnum(&self) -> Option<Seqnum> {
self.state.max_seqnum()
}
pub fn max_uid(&self) -> Option<Uid> {
self.state.max_uid()
}
pub fn report_max_modseq(&self) -> Option<Modseq> {
self.state.report_max_modseq()
}
pub fn divergent_modseq(&self) -> Option<Modseq> {
if self.state.report_max_modseq() != self.state.max_modseq() {
self.state.report_max_modseq()
} else {
None
}
}
pub fn has_pending_expunge(&self) -> bool {
self.state.has_pending_expunge()
}
pub fn uid_range_to_seqnum(
&self,
range: &SeqRange<Uid>,
) -> SeqRange<Seqnum> {
self.state
.uid_range_to_seqnum(range, true)
.expect("silent uid_range_to_seqnum should never fail")
}
}
#[cfg(test)]
mod test {
use super::super::test_prelude::*;
use super::*;
#[test]
fn delete_open_mailbox() {
let setup = set_up();
assert!(setup.stateless.is_ok());
assert_eq!(
setup.stateless.uid_validity().unwrap(),
setup.stateless.path().current_uid_validity().unwrap()
);
setup.stateless.path().delete(setup.root.path()).unwrap();
assert!(!setup.stateless.is_ok());
assert!(matches!(
setup.stateless.path().current_uid_validity(),
Err(Error::NxMailbox)
));
setup
.stateless
.path()
.create(setup.root.path(), None)
.unwrap();
assert_ne!(
setup.stateless.uid_validity().unwrap(),
setup.stateless.path().current_uid_validity().unwrap()
);
assert!(!setup.stateless.is_ok());
}
}