Create error type for Filesystem
instead of using io::Error; Fix
creation of user account folder so that the entire directory has the correct permissions, bot just the Inbox folder
This commit is contained in:
parent
f17bda9349
commit
c6675cb024
4 changed files with 83 additions and 55 deletions
|
@ -1,27 +1,21 @@
|
|||
use std::{
|
||||
ffi::CString,
|
||||
io::BufReader,
|
||||
os::{fd::AsRawFd, unix::prelude::OpenOptionsExt},
|
||||
};
|
||||
|
||||
use crate::prelude::Certificate;
|
||||
|
||||
use {
|
||||
super::*,
|
||||
crate::{
|
||||
message::Parser as MessageParser,
|
||||
prelude::{ClientCertificateStore, ParseMailboxError},
|
||||
prelude::{ClientCertificateStore, Certificate, ParseMailboxError},
|
||||
},
|
||||
rustls_pemfile::{read_one, Item},
|
||||
std::{
|
||||
ffi::OsString,
|
||||
fs::{self, File},
|
||||
io::{self, BufWriter, Write},
|
||||
io::{self, BufReader, BufWriter, Write},
|
||||
iter,
|
||||
os::unix::fs::DirBuilderExt,
|
||||
os::{fd::AsRawFd, unix::{fs::DirBuilderExt, prelude::OpenOptionsExt}},
|
||||
path::{Path, PathBuf},
|
||||
},
|
||||
};
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
|
||||
pub trait MultiDomain: MailStore {
|
||||
type Error;
|
||||
|
@ -107,7 +101,7 @@ impl From<OsString> for Filesystem {
|
|||
}
|
||||
|
||||
impl MailStore for Filesystem {
|
||||
type Error = io::Error;
|
||||
type Error = Error;
|
||||
|
||||
fn users(&self) -> Vec<Mailuser> {
|
||||
let mut users = vec![];
|
||||
|
@ -190,11 +184,9 @@ impl MailStore for Filesystem {
|
|||
Some(folder)
|
||||
}
|
||||
|
||||
fn create_folder(&self, user: &str, folder: &str) -> Result<(), io::Error> {
|
||||
fn create_folder(&self, user: &str, folder: &str) -> Result<(), Error> {
|
||||
if self.has_mailuser(user) {
|
||||
let user: Mailbox = user.parse().map_err(|e: ParseMailboxError| {
|
||||
io::Error::new(io::ErrorKind::Other, e.to_string())
|
||||
})?;
|
||||
let user: Mailbox = user.parse()?;
|
||||
let user: Mailuser = user.into();
|
||||
let mut path = self.path.clone();
|
||||
path.push(&user.host.to_string());
|
||||
|
@ -216,26 +208,23 @@ impl MailStore for Filesystem {
|
|||
folder: &str,
|
||||
message: Message,
|
||||
) -> Result<(), Self::Error> {
|
||||
let Some((user, host)) = user.rsplit_once('@') else {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
||||
};
|
||||
let mb: Mailbox = user.parse()?;
|
||||
let mut path = self.path.clone();
|
||||
path.push(host);
|
||||
path.push(user);
|
||||
path.push(&mb.host.to_string());
|
||||
path.push(&mb.username);
|
||||
path.push(folder);
|
||||
path.push(&message.id);
|
||||
path.set_extension("gmi");
|
||||
let mut fd = File::create(path)?;
|
||||
write!(fd, "{message}")
|
||||
write!(fd, "{message}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_message(&mut self, user: &str, folder: &str, id: &str) -> Result<(), Self::Error> {
|
||||
let Some((user, host)) = user.rsplit_once('@') else {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
||||
};
|
||||
let mb: Mailbox = user.parse()?;
|
||||
let mut path = self.path.clone();
|
||||
path.push(host);
|
||||
path.push(user);
|
||||
path.push(&mb.host.to_string());
|
||||
path.push(&mb.username);
|
||||
path.push(folder);
|
||||
path.push(id);
|
||||
path.set_extension("gmi");
|
||||
|
@ -251,13 +240,11 @@ impl MailStore for Filesystem {
|
|||
id: &str,
|
||||
folder1: &str,
|
||||
folder2: &str,
|
||||
) -> Result<(), io::Error> {
|
||||
let Some((user, host)) = user.rsplit_once('@') else {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
||||
};
|
||||
) -> Result<(), Self::Error> {
|
||||
let mb: Mailbox = user.parse()?;
|
||||
let mut infile = self.path.clone();
|
||||
infile.push(host);
|
||||
infile.push(user);
|
||||
infile.push(&mb.host.to_string());
|
||||
infile.push(&mb.username);
|
||||
let mut outfile = infile.clone();
|
||||
infile.push(folder1);
|
||||
infile.push(id);
|
||||
|
@ -271,33 +258,26 @@ impl MailStore for Filesystem {
|
|||
}
|
||||
|
||||
fn add_user(&mut self, user: &str) -> Result<(), Self::Error> {
|
||||
let mb: Mailbox = user
|
||||
.parse()
|
||||
.map_err(|e: ParseMailboxError| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
|
||||
let mb: Mailbox = user.parse()?;
|
||||
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)
|
||||
.mode(0o2770)
|
||||
.open(path)?;
|
||||
if let Some(pw) = pw::Passwd::getpw()
|
||||
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?
|
||||
.open(&path)?;
|
||||
if let Some(pw) = pw::Passwd::getpw()?
|
||||
{
|
||||
let groups = pw
|
||||
.groups()
|
||||
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
|
||||
let groups = pw.groups()?;
|
||||
if let Some(gr) = groups.iter().find(|g| g.name == mb.username) {
|
||||
unsafe {
|
||||
if libc::fchown(fd.as_raw_fd(), pw.uid, gr.gid) != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -305,16 +285,19 @@ impl MailStore for Filesystem {
|
|||
let mut writer = BufWriter::new(fd);
|
||||
writer.write_all(blurb.as_bytes())?;
|
||||
}
|
||||
let _last = path.pop();
|
||||
path.push("Inbox");
|
||||
fs::create_dir_all(&path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_user(&mut self, user: &str) -> bool {
|
||||
let Ok(mu) = user.parse::<Mailbox>() else {
|
||||
let Ok(mb) = user.parse::<Mailbox>() else {
|
||||
return false;
|
||||
};
|
||||
let mut path = self.path.clone();
|
||||
path.push(&mu.host.to_string());
|
||||
path.push(&mu.username);
|
||||
path.push(&mb.host.to_string());
|
||||
path.push(&mb.username);
|
||||
if path.exists() {
|
||||
if fs::remove_dir_all(path).is_ok() {
|
||||
return true;
|
||||
|
|
49
src/mailstore/filesystem/error.rs
Normal file
49
src/mailstore/filesystem/error.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use {
|
||||
crate::prelude::ParseMailboxError,
|
||||
std::{fmt, io},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Io(io::Error),
|
||||
MailBox(ParseMailboxError),
|
||||
Permissions(pw::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(e) => write!(f, "Filesystem error: {e}"),
|
||||
Self::MailBox(e) => write!(f, "Filesystem error: {e}"),
|
||||
Self::Permissions(e) => write!(f, "Filesystem error: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Io(e) => Some(e),
|
||||
Self::MailBox(e) => Some(e),
|
||||
Self::Permissions(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseMailboxError> for Error {
|
||||
fn from(value: ParseMailboxError) -> Self {
|
||||
Self::MailBox(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pw::Error> for Error {
|
||||
fn from(value: pw::Error) -> Self {
|
||||
Self::Permissions(value)
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@ use std::{collections::HashMap, io, str::FromStr};
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod filesystem;
|
||||
mod filesystem;
|
||||
pub use filesystem::{Error as FilesystemError, Filesystem, MultiDomain};
|
||||
|
||||
pub trait MailStore {
|
||||
type Error;
|
||||
|
@ -68,12 +69,6 @@ pub struct Folder {
|
|||
pub messages: HashMap<String, Message>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct MultiDomain {
|
||||
pub domains: HashMap<String, Domain>,
|
||||
}
|
||||
|
||||
impl MailStore for Domain {
|
||||
type Error = io::Error;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ pub use super::{
|
|||
host::{Error as ParseHostError, Host},
|
||||
mailbox::{Error as ParseMailboxError, Mailbox},
|
||||
mailuser::Mailuser,
|
||||
mailstore::{Account, Domain, Folder, Filesystem, FilesystemError, MailStore},
|
||||
message::{Error as ParseMessageError, Link, Message, Recipients},
|
||||
//receiver,
|
||||
request::{Error as ParseRequestError, Request},
|
||||
|
|
Loading…
Add table
Reference in a new issue