Merge branch 'odin' of git.hitchhiker-linux.org:jeang3nie/dory into odin
This commit is contained in:
commit
0a30c49d49
6 changed files with 116 additions and 38 deletions
|
@ -37,11 +37,19 @@ impl MailStore for Filesystem {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_user_messages(&self, user: &str) -> Option<BTreeMap<String, Message>> {
|
fn get_folder(&self, user: &str, folder: &str) -> Option<Folder> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_message(&self, user: &str, title: &str) -> Option<Message> {
|
fn get_message(&self, user: &str, folder: &str, title: &str) -> Option<Message> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_message(&mut self, user: &str, folder: &str, message: Message) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_message(&mut self, user: &str, folder: &str, key: &str) -> bool {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
use crate::prelude::{Host, Mailbox, Mailuser, Message, ParseMailboxError};
|
use crate::prelude::{Host, Mailbox, Mailuser, Message, ParseMailboxError};
|
||||||
use std::{
|
use std::{collections::HashMap, str::FromStr};
|
||||||
collections::{BTreeMap, HashMap},
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -17,12 +14,16 @@ pub trait MailStore {
|
||||||
/// Checks whether this server has the given mailuser
|
/// Checks whether this server has the given mailuser
|
||||||
fn has_mailuser(&self, mailuser: &str) -> bool;
|
fn has_mailuser(&self, mailuser: &str) -> bool;
|
||||||
/// Retreives all of the messages for this user
|
/// Retreives all of the messages for this user
|
||||||
fn get_user_messages(&self, user: &str) -> Option<BTreeMap<String, Message>>;
|
fn get_folder(&self, user: &str, folder: &str) -> Option<Folder>;
|
||||||
/// Checks whether this server has a message with the given title for this user and if so
|
/// Checks whether this server has a message with the given title for this user and if so
|
||||||
/// returns the message
|
/// returns the message
|
||||||
fn get_message(&self, user: &str, title: &str) -> Option<Message>;
|
fn get_message(&self, user: &str, folder: &str, title: &str) -> Option<Message>;
|
||||||
/// Move a message to a new folder
|
/// Move a message to a new folder
|
||||||
fn move_message(&mut self, user: &str, title: &str, folder: &str);
|
fn move_message(&mut self, user: &str, title: &str, folder: &str);
|
||||||
|
/// Deletes a message it it exists
|
||||||
|
fn delete_message(&mut self, user: &str, folder: &str, key: &str) -> bool;
|
||||||
|
/// Adds a message
|
||||||
|
fn add_message(&mut self, user: &str, folder: &str, message: Message);
|
||||||
/// Adds a new mailuser to the given domain
|
/// Adds a new mailuser to the given domain
|
||||||
fn add_user(&mut self, user: &str) -> Result<(), ParseMailboxError>;
|
fn add_user(&mut self, user: &str) -> Result<(), ParseMailboxError>;
|
||||||
/// Removes the given user if the account exists
|
/// Removes the given user if the account exists
|
||||||
|
@ -40,7 +41,14 @@ pub struct Domain {
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
pub user: Mailbox,
|
pub user: Mailbox,
|
||||||
pub messages: BTreeMap<String, Message>,
|
pub folders: HashMap<String, Folder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub struct Folder {
|
||||||
|
pub name: String,
|
||||||
|
pub messages: HashMap<String, Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -68,19 +76,23 @@ impl MailStore for Domain {
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_user_messages(&self, user: &str) -> Option<BTreeMap<String, Message>> {
|
fn get_folder(&self, user: &str, folder: &str) -> Option<Folder> {
|
||||||
self.users.get(user).cloned().map(|u| u.messages)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_message(&self, user: &str, title: &str) -> Option<Message> {
|
|
||||||
self.users
|
self.users
|
||||||
.get(user)
|
.get(user)
|
||||||
.map(|u| {
|
.cloned()
|
||||||
u.messages
|
.and_then(|u| u.folders.get(folder).cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_message(&self, user: &str, folder: &str, title: &str) -> Option<Message> {
|
||||||
|
self.users
|
||||||
|
.get(user)
|
||||||
|
.and_then(|u| {
|
||||||
|
u.folders.get(folder).and_then(|f| {
|
||||||
|
f.messages
|
||||||
.values()
|
.values()
|
||||||
.find(|m| m.title.as_ref().map(|x| x.as_str()) == Some(title))
|
.find(|m| m.title.as_ref().map(|x| x.as_str()) == Some(title))
|
||||||
})
|
})
|
||||||
.flatten()
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +105,10 @@ impl MailStore for Domain {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mbox = Mailbox::from_str(&format!("{user}@{}", self.host.to_string()))?;
|
let mbox = Mailbox::from_str(&format!("{user}@{}", self.host.to_string()))?;
|
||||||
let messages = BTreeMap::new();
|
let folders = HashMap::new();
|
||||||
let acct = Account {
|
let acct = Account {
|
||||||
user: mbox,
|
user: mbox,
|
||||||
messages,
|
folders,
|
||||||
};
|
};
|
||||||
self.users.insert(user.to_string(), acct);
|
self.users.insert(user.to_string(), acct);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -105,4 +117,12 @@ impl MailStore for Domain {
|
||||||
fn remove_user(&mut self, user: &str) -> bool {
|
fn remove_user(&mut self, user: &str) -> bool {
|
||||||
self.users.remove(user).is_some()
|
self.users.remove(user).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_message(&mut self, user: &str, folder: &str, message: Message) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_message(&mut self, user: &str, folder: &str, key: &str) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ impl fmt::Display for Lines {
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
|
pub id: String,
|
||||||
pub senders: Vec<Mailbox>,
|
pub senders: Vec<Mailbox>,
|
||||||
pub recipients: Vec<Mailbox>,
|
pub recipients: Vec<Mailbox>,
|
||||||
pub timstamp: Option<String>,
|
pub timstamp: Option<String>,
|
||||||
|
|
|
@ -12,14 +12,14 @@ pub use error::Error;
|
||||||
/// The full request as sent by the `Sender` and received by the `Receiver`
|
/// The full request as sent by the `Sender` and received by the `Receiver`
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
/// The sender of the message
|
/// The sender of the message
|
||||||
pub sender: Mailuser,
|
pub recipient: Mailuser,
|
||||||
/// The message body
|
/// The message body
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Request {
|
impl fmt::Display for Request {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "misfin://{} {}\r\n", self.sender, self.message)
|
write!(f, "misfin://{} {}\r\n", self.recipient, self.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ impl FromStr for Request {
|
||||||
let Some(user) = user.strip_prefix("misfin://") else {
|
let Some(user) = user.strip_prefix("misfin://") else {
|
||||||
return Err(Error::Malformed);
|
return Err(Error::Malformed);
|
||||||
};
|
};
|
||||||
let sender = user.parse()?;
|
let recipient = user.parse()?;
|
||||||
Ok(Request { sender, message })
|
Ok(Request { recipient, message })
|
||||||
} else {
|
} else {
|
||||||
Err(Error::MissingSeparator)
|
Err(Error::MissingSeparator)
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ mod tests {
|
||||||
|
|
||||||
fn req() -> Request {
|
fn req() -> Request {
|
||||||
Request {
|
Request {
|
||||||
sender: Mailuser {
|
recipient: Mailuser {
|
||||||
username: "john".to_string(),
|
username: "john".to_string(),
|
||||||
host: Host {
|
host: Host {
|
||||||
subdomain: Some("misfin".into()),
|
subdomain: Some("misfin".into()),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::prelude::{ParseRequestError, ParseResponseError},
|
crate::prelude::{ParseMailboxError, ParseRequestError, ParseResponseError},
|
||||||
rustls::InvalidMessage,
|
rustls::InvalidMessage,
|
||||||
std::{fmt, io},
|
std::{fmt, io},
|
||||||
};
|
};
|
||||||
|
@ -9,10 +9,11 @@ use {
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
CertificateError(InvalidMessage),
|
CertificateError(InvalidMessage),
|
||||||
DnsError,
|
DnsError,
|
||||||
TlsError(rustls::Error),
|
IoError(io::Error),
|
||||||
|
MailboxError(ParseMailboxError),
|
||||||
RequestError(ParseRequestError),
|
RequestError(ParseRequestError),
|
||||||
ResponseError(ParseResponseError),
|
ResponseError(ParseResponseError),
|
||||||
IoError(io::Error),
|
TlsError(rustls::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -20,10 +21,11 @@ impl fmt::Display for Error {
|
||||||
match self {
|
match self {
|
||||||
Self::CertificateError(e) => write!(f, "{e:?}"),
|
Self::CertificateError(e) => write!(f, "{e:?}"),
|
||||||
Self::DnsError => write!(f, "Dns Error"),
|
Self::DnsError => write!(f, "Dns Error"),
|
||||||
Self::TlsError(e) => write!(f, "{e}"),
|
Self::IoError(e) => write!(f, "{e}"),
|
||||||
|
Self::MailboxError(e) => write!(f, "{e}"),
|
||||||
Self::RequestError(e) => write!(f, "{e}"),
|
Self::RequestError(e) => write!(f, "{e}"),
|
||||||
Self::ResponseError(e) => write!(f, "{e}"),
|
Self::ResponseError(e) => write!(f, "{e}"),
|
||||||
Self::IoError(e) => write!(f, "{e}"),
|
Self::TlsError(e) => write!(f, "{e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,10 +33,11 @@ impl fmt::Display for Error {
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
|
Self::IoError(e) => Some(e),
|
||||||
|
Self::MailboxError(e) => Some(e),
|
||||||
Self::RequestError(e) => Some(e),
|
Self::RequestError(e) => Some(e),
|
||||||
Self::ResponseError(e) => Some(e),
|
Self::ResponseError(e) => Some(e),
|
||||||
Self::TlsError(e) => Some(e),
|
Self::TlsError(e) => Some(e),
|
||||||
Self::IoError(e) => Some(e),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +55,12 @@ impl From<rustls::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParseMailboxError> for Error {
|
||||||
|
fn from(value: ParseMailboxError) -> Self {
|
||||||
|
Self::MailboxError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ParseRequestError> for Error {
|
impl From<ParseRequestError> for Error {
|
||||||
fn from(value: ParseRequestError) -> Self {
|
fn from(value: ParseRequestError) -> Self {
|
||||||
Self::RequestError(value)
|
Self::RequestError(value)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::prelude::{CertificateStore, ClientCertificateStore, Request, Response},
|
crate::prelude::{CertificateStore, ClientCertificateStore, Mailuser, Request, Response},
|
||||||
rustls::{internal::msgs::codec::Codec, ClientConfig, ClientConnection, StreamOwned},
|
rustls::{internal::msgs::codec::Codec, ClientConfig, ClientConnection, StreamOwned},
|
||||||
std::{
|
std::{
|
||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
|
@ -21,11 +21,13 @@ where
|
||||||
S: CertificateStore,
|
S: CertificateStore,
|
||||||
C: ClientCertificateStore,
|
C: ClientCertificateStore,
|
||||||
{
|
{
|
||||||
|
/// The address of the sender
|
||||||
|
pub sender: Mailuser,
|
||||||
/// The full message text to be sent
|
/// The full message text to be sent
|
||||||
pub request: Request,
|
pub request: Request,
|
||||||
/// A [CertificateStore] for servers known to us
|
/// A [CertificateStore] for servers known to us
|
||||||
pub store: S,
|
pub store: S,
|
||||||
/// A [CertificateStore] for mailboxes which exist on this system
|
/// A [ClientCertificateStore] for mailboxes which exist on this system
|
||||||
pub client_store: C,
|
pub client_store: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +36,11 @@ where
|
||||||
S: CertificateStore + 'static,
|
S: CertificateStore + 'static,
|
||||||
C: ClientCertificateStore,
|
C: ClientCertificateStore,
|
||||||
{
|
{
|
||||||
pub fn new(request_str: &str, store: S, client_store: C) -> Result<Self, Error> {
|
pub fn new(sender: &str, request_str: &str, store: S, client_store: C) -> Result<Self, Error> {
|
||||||
|
let sender = sender.parse()?;
|
||||||
let request: Request = request_str.parse()?;
|
let request: Request = request_str.parse()?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
sender,
|
||||||
request,
|
request,
|
||||||
store,
|
store,
|
||||||
client_store,
|
client_store,
|
||||||
|
@ -44,7 +48,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn host_string(&self) -> String {
|
fn host_string(&self) -> String {
|
||||||
self.request.sender.host.to_string()
|
self.request.recipient.host.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(self) -> Result<Response, Error> {
|
pub fn send(self) -> Result<Response, Error> {
|
||||||
|
@ -53,8 +57,8 @@ where
|
||||||
.as_str()
|
.as_str()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| Error::DnsError)?;
|
.map_err(|_| Error::DnsError)?;
|
||||||
let mut it = self.request.sender.host.to_socket_addrs()?;
|
let mut it = self.request.recipient.host.to_socket_addrs()?;
|
||||||
let client_cert = self.client_store.get_certificate(&self.request.sender);
|
let client_cert = self.client_store.get_certificate(&self.sender);
|
||||||
let verifier = Arc::new(Verifier::new(self.store));
|
let verifier = Arc::new(Verifier::new(self.store));
|
||||||
let Some(socket_addrs) = it.next() else {
|
let Some(socket_addrs) = it.next() else {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "no data retrieved").into());
|
return Err(io::Error::new(io::ErrorKind::Other, "no data retrieved").into());
|
||||||
|
@ -83,3 +87,39 @@ where
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MultiSender<S, C>
|
||||||
|
where
|
||||||
|
S: CertificateStore,
|
||||||
|
C: ClientCertificateStore,
|
||||||
|
{
|
||||||
|
pub sender: Mailuser,
|
||||||
|
pub recipients: Vec<Mailuser>,
|
||||||
|
pub store: S,
|
||||||
|
pub client_store: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, C> MultiSender<S, C>
|
||||||
|
where
|
||||||
|
S: CertificateStore + 'static + Clone,
|
||||||
|
C: ClientCertificateStore + Clone,
|
||||||
|
{
|
||||||
|
pub fn new(sender: &str, recipients: &[&str], store: S, client_store: C) -> Result<Self, Error> {
|
||||||
|
let mut rec = vec![];
|
||||||
|
for r in recipients {
|
||||||
|
let r = r.parse()?;
|
||||||
|
rec.push(r);
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
sender: sender.parse()?,
|
||||||
|
recipients: rec,
|
||||||
|
store,
|
||||||
|
client_store
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self, f: &dyn Fn(Result<Response, Error>)) -> Result<(), Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue