diff --git a/src/mailstore/filesystem.rs b/src/mailstore/filesystem.rs index 1d2e133..b982042 100644 --- a/src/mailstore/filesystem.rs +++ b/src/mailstore/filesystem.rs @@ -1,11 +1,12 @@ -use crate::message::Parser as MessageParser; - -use super::*; -use std::{ - fs::{self, File}, - io::{self, Write}, - os::unix::fs::DirBuilderExt, - path::PathBuf, +use { + super::*, + crate::{message::Parser as MessageParser, prelude::ParseMailboxError}, + std::{ + fs::{self, File}, + io::{self, BufWriter, Write}, + os::unix::fs::DirBuilderExt, + path::PathBuf, + }, }; pub trait MultiDomain: MailStore { @@ -28,7 +29,38 @@ impl MailStore for Filesystem { type Error = io::Error; fn users(&self) -> Vec { - todo!() + let mut users = vec![]; + let Ok(domains) = fs::read_dir(&self.path) else { + return users; + }; + for d in domains { + let Ok(dom) = d else { + continue; + }; + let name = dom.file_name().to_string_lossy().to_string(); + let Ok(host) = name.parse::() else { + continue; + }; + let dom_path = dom.path(); + let Ok(dom_users) = fs::read_dir(&dom_path) else { + continue; + }; + for u in dom_users { + let Ok(user) = u else { + continue; + }; + if let Ok(ft) = user.file_type() { + if ft.is_dir() { + let username = user.file_name().to_string_lossy().to_string(); + users.push(Mailuser { + username, + host: host.clone(), + }); + } + } + } + } + users } fn serves_domain(&self, domain: &str) -> bool { @@ -143,11 +175,41 @@ impl MailStore for Filesystem { } fn add_user(&mut self, user: &str) -> Result<(), Self::Error> { - todo!() + let mb: Mailbox = user + .parse() + .map_err(|e: ParseMailboxError| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + let mut path = self.path.clone(); + path.push(&mb.host.to_string()); + path.push(&mb.username); + path.push("Inbox"); + fs::create_dir_all(&path)?; + if let Some(ref blurb) = mb.blurb { + let _last = path.pop(); + path.push("blurb"); + let fd = File::options() + .create(true) + .write(true) + .truncate(true) + .open(path)?; + let mut writer = BufWriter::new(fd); + writer.write_all(blurb.as_bytes())?; + } + Ok(()) } fn remove_user(&mut self, user: &str) -> bool { - todo!() + let Ok(mu) = user.parse::() else { + return false; + }; + let mut path = self.path.clone(); + path.push(&mu.host.to_string()); + path.push(&mu.username); + if path.exists() { + if fs::remove_dir_all(path).is_ok() { + return true; + } + } + false } } diff --git a/src/mailstore/mod.rs b/src/mailstore/mod.rs index e167f79..b7febb6 100644 --- a/src/mailstore/mod.rs +++ b/src/mailstore/mod.rs @@ -144,10 +144,31 @@ impl MailStore for Domain { folder: &str, message: Message, ) -> Result<(), Self::Error> { - todo!() + let user = self + .users + .get_mut(user) + .ok_or(io::Error::new(io::ErrorKind::Other, "No such user"))?; + let folder = match user.folders.get_mut(folder) { + Some(f) => f, + _ => { + let f = Folder { + name: folder.to_string(), + messages: HashMap::new(), + }; + user.folders.insert(folder.to_string(), f); + user.folders.get_mut(folder).unwrap() + } + }; + folder.messages.insert(message.id.clone(), message); + Ok(()) } fn delete_message(&mut self, user: &str, folder: &str, id: &str) -> Result<(), Self::Error> { - todo!() + if let Some(user) = self.users.get_mut(user) { + if let Some(folder) = user.folders.get_mut(folder) { + let _msg = folder.messages.remove(id); + } + } + Ok(()) } } diff --git a/src/time/mod.rs b/src/time/mod.rs index f6d7ff3..3edd7c3 100644 --- a/src/time/mod.rs +++ b/src/time/mod.rs @@ -18,6 +18,10 @@ fn is_leap(year: i64) -> bool { year % 4 == 0 && (year % 100 != 0 || year % 16 == 0) } +/// Returns the number of days in a given month. If the +/// given month is February, then we also need to know +/// whether it is a leap year or not, hence this function +/// takes the year as an argument as well. pub fn days_in_month(month: u8, year: i64) -> i64 { assert!(month < 13); match month {