use std::collections::BTreeSet; use std::ffi::{OsStr, OsString}; use std::path::Path; use std::sync::OnceLock; use maildir::Maildir; use crate::error::Result; static REQUIRED_MAILDIR_DIRS: OnceLock> = OnceLock::new(); fn is_mailsubdir(p: &Path) -> bool { let rmd = REQUIRED_MAILDIR_DIRS.get_or_init(|| { [ OsString::from("cur"), "new".into(), "tmp".into(), "maildirfolder".into(), ] .into() }); p.is_dir() && p.file_name() .map_or(false, |fname| fname.to_string_lossy().starts_with('.')) && p.read_dir() .map(|dir| { dir.filter_map(|child| { child .ok() .and_then(|dir_entry| dir_entry.path().file_name().map(OsStr::to_owned)) }) .collect::>() .is_superset(rmd) }) .unwrap_or_default() } pub fn folders(md: &Maildir) -> Result> { let root_path = md.path(); let subdirs = root_path .read_dir()? .filter_map(|d| d.ok()) .filter(|d| is_mailsubdir(&d.path())) .filter_map(|d| Some(d.path().file_name()?.to_string_lossy()[1..].to_owned())) .collect(); Ok(subdirs) }