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 {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
crate::{
|
crate::{
|
||||||
message::Parser as MessageParser,
|
message::Parser as MessageParser,
|
||||||
prelude::{ClientCertificateStore, ParseMailboxError},
|
prelude::{ClientCertificateStore, Certificate, ParseMailboxError},
|
||||||
},
|
},
|
||||||
rustls_pemfile::{read_one, Item},
|
rustls_pemfile::{read_one, Item},
|
||||||
std::{
|
std::{
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, BufWriter, Write},
|
io::{self, BufReader, BufWriter, Write},
|
||||||
iter,
|
iter,
|
||||||
os::unix::fs::DirBuilderExt,
|
os::{fd::AsRawFd, unix::{fs::DirBuilderExt, prelude::OpenOptionsExt}},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
mod error;
|
||||||
|
pub use error::Error;
|
||||||
|
|
||||||
pub trait MultiDomain: MailStore {
|
pub trait MultiDomain: MailStore {
|
||||||
type Error;
|
type Error;
|
||||||
|
@ -107,7 +101,7 @@ impl From<OsString> for Filesystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailStore for Filesystem {
|
impl MailStore for Filesystem {
|
||||||
type Error = io::Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn users(&self) -> Vec<Mailuser> {
|
fn users(&self) -> Vec<Mailuser> {
|
||||||
let mut users = vec![];
|
let mut users = vec![];
|
||||||
|
@ -190,11 +184,9 @@ impl MailStore for Filesystem {
|
||||||
Some(folder)
|
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) {
|
if self.has_mailuser(user) {
|
||||||
let user: Mailbox = user.parse().map_err(|e: ParseMailboxError| {
|
let user: Mailbox = user.parse()?;
|
||||||
io::Error::new(io::ErrorKind::Other, e.to_string())
|
|
||||||
})?;
|
|
||||||
let user: Mailuser = user.into();
|
let user: Mailuser = user.into();
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(&user.host.to_string());
|
path.push(&user.host.to_string());
|
||||||
|
@ -216,26 +208,23 @@ impl MailStore for Filesystem {
|
||||||
folder: &str,
|
folder: &str,
|
||||||
message: Message,
|
message: Message,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let Some((user, host)) = user.rsplit_once('@') else {
|
let mb: Mailbox = user.parse()?;
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
|
||||||
};
|
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(host);
|
path.push(&mb.host.to_string());
|
||||||
path.push(user);
|
path.push(&mb.username);
|
||||||
path.push(folder);
|
path.push(folder);
|
||||||
path.push(&message.id);
|
path.push(&message.id);
|
||||||
path.set_extension("gmi");
|
path.set_extension("gmi");
|
||||||
let mut fd = File::create(path)?;
|
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> {
|
fn delete_message(&mut self, user: &str, folder: &str, id: &str) -> Result<(), Self::Error> {
|
||||||
let Some((user, host)) = user.rsplit_once('@') else {
|
let mb: Mailbox = user.parse()?;
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
|
||||||
};
|
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(host);
|
path.push(&mb.host.to_string());
|
||||||
path.push(user);
|
path.push(&mb.username);
|
||||||
path.push(folder);
|
path.push(folder);
|
||||||
path.push(id);
|
path.push(id);
|
||||||
path.set_extension("gmi");
|
path.set_extension("gmi");
|
||||||
|
@ -251,13 +240,11 @@ impl MailStore for Filesystem {
|
||||||
id: &str,
|
id: &str,
|
||||||
folder1: &str,
|
folder1: &str,
|
||||||
folder2: &str,
|
folder2: &str,
|
||||||
) -> Result<(), io::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let Some((user, host)) = user.rsplit_once('@') else {
|
let mb: Mailbox = user.parse()?;
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid username"));
|
|
||||||
};
|
|
||||||
let mut infile = self.path.clone();
|
let mut infile = self.path.clone();
|
||||||
infile.push(host);
|
infile.push(&mb.host.to_string());
|
||||||
infile.push(user);
|
infile.push(&mb.username);
|
||||||
let mut outfile = infile.clone();
|
let mut outfile = infile.clone();
|
||||||
infile.push(folder1);
|
infile.push(folder1);
|
||||||
infile.push(id);
|
infile.push(id);
|
||||||
|
@ -271,33 +258,26 @@ impl MailStore for Filesystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_user(&mut self, user: &str) -> Result<(), Self::Error> {
|
fn add_user(&mut self, user: &str) -> Result<(), Self::Error> {
|
||||||
let mb: Mailbox = user
|
let mb: Mailbox = user.parse()?;
|
||||||
.parse()
|
|
||||||
.map_err(|e: ParseMailboxError| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
|
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(&mb.host.to_string());
|
path.push(&mb.host.to_string());
|
||||||
path.push(&mb.username);
|
path.push(&mb.username);
|
||||||
path.push("Inbox");
|
|
||||||
fs::create_dir_all(&path)?;
|
fs::create_dir_all(&path)?;
|
||||||
if let Some(ref blurb) = mb.blurb {
|
if let Some(ref blurb) = mb.blurb {
|
||||||
let _last = path.pop();
|
|
||||||
path.push("blurb");
|
path.push("blurb");
|
||||||
let fd = File::options()
|
let fd = File::options()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.mode(0o2770)
|
.mode(0o2770)
|
||||||
.open(path)?;
|
.open(&path)?;
|
||||||
if let Some(pw) = pw::Passwd::getpw()
|
if let Some(pw) = pw::Passwd::getpw()?
|
||||||
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?
|
|
||||||
{
|
{
|
||||||
let groups = pw
|
let groups = pw.groups()?;
|
||||||
.groups()
|
|
||||||
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
|
|
||||||
if let Some(gr) = groups.iter().find(|g| g.name == mb.username) {
|
if let Some(gr) = groups.iter().find(|g| g.name == mb.username) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if libc::fchown(fd.as_raw_fd(), pw.uid, gr.gid) != 0 {
|
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);
|
let mut writer = BufWriter::new(fd);
|
||||||
writer.write_all(blurb.as_bytes())?;
|
writer.write_all(blurb.as_bytes())?;
|
||||||
}
|
}
|
||||||
|
let _last = path.pop();
|
||||||
|
path.push("Inbox");
|
||||||
|
fs::create_dir_all(&path)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_user(&mut self, user: &str) -> bool {
|
fn remove_user(&mut self, user: &str) -> bool {
|
||||||
let Ok(mu) = user.parse::<Mailbox>() else {
|
let Ok(mb) = user.parse::<Mailbox>() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let mut path = self.path.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(&mu.host.to_string());
|
path.push(&mb.host.to_string());
|
||||||
path.push(&mu.username);
|
path.push(&mb.username);
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
if fs::remove_dir_all(path).is_ok() {
|
if fs::remove_dir_all(path).is_ok() {
|
||||||
return true;
|
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")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod filesystem;
|
mod filesystem;
|
||||||
|
pub use filesystem::{Error as FilesystemError, Filesystem, MultiDomain};
|
||||||
|
|
||||||
pub trait MailStore {
|
pub trait MailStore {
|
||||||
type Error;
|
type Error;
|
||||||
|
@ -68,12 +69,6 @@ pub struct Folder {
|
||||||
pub messages: HashMap<String, Message>,
|
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 {
|
impl MailStore for Domain {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub use super::{
|
||||||
host::{Error as ParseHostError, Host},
|
host::{Error as ParseHostError, Host},
|
||||||
mailbox::{Error as ParseMailboxError, Mailbox},
|
mailbox::{Error as ParseMailboxError, Mailbox},
|
||||||
mailuser::Mailuser,
|
mailuser::Mailuser,
|
||||||
|
mailstore::{Account, Domain, Folder, Filesystem, FilesystemError, MailStore},
|
||||||
message::{Error as ParseMessageError, Link, Message, Recipients},
|
message::{Error as ParseMessageError, Link, Message, Recipients},
|
||||||
//receiver,
|
//receiver,
|
||||||
request::{Error as ParseRequestError, Request},
|
request::{Error as ParseRequestError, Request},
|
||||||
|
|
Loading…
Add table
Reference in a new issue