use { crate::prelude::{CertificateStore, ClientCertificateStore, Mailuser, Request, Response}, rustls::{internal::msgs::codec::Codec, ClientConfig, ClientConnection, StreamOwned}, std::{ io::{self, Read, Write}, net::{TcpStream, ToSocketAddrs}, sync::Arc, time::Duration, }, }; pub use self::{error::Error, verifier::Verifier}; mod error; mod verifier; #[derive(Debug)] /// Sends a piece of mail from the sending server to the receiving server pub struct Sender where S: CertificateStore, C: ClientCertificateStore, { /// The address of the sender pub sender: Mailuser, /// The full message text to be sent pub request: Request, /// A [CertificateStore] for servers known to us pub store: S, /// A [ClientCertificateStore] for mailboxes which exist on this system pub client_store: C, } impl Sender where S: CertificateStore + 'static, C: ClientCertificateStore, { pub fn new(sender: &str, request_str: &str, store: S, client_store: C) -> Result { let sender = sender.parse()?; let request: Request = request_str.parse()?; Ok(Self { sender, request, store, client_store, }) } fn host_string(&self) -> String { self.request.recipient.host.to_string() } pub fn send(self) -> Result { let dnsname = self .host_string() .as_str() .try_into() .map_err(|_| Error::DnsError)?; let mut it = self.request.recipient.host.to_socket_addrs()?; let client_cert = self.client_store.get_certificate(&self.sender); let verifier = Arc::new(Verifier::new(self.store)); let Some(socket_addrs) = it.next() else { return Err(io::Error::new(io::ErrorKind::Other, "no data retrieved").into()); }; let tcp_stream = TcpStream::connect_timeout(&socket_addrs, Duration::new(10, 0))?; let cfg = ClientConfig::builder() .with_safe_defaults() .with_custom_certificate_verifier(verifier); let cfg = match client_cert { None => cfg.with_no_client_auth(), Some(c) => { let rustls_cert = rustls::Certificate::read_bytes(&c.der)?; let cert_chain = vec![rustls_cert]; let key_der = rustls::PrivateKey(c.key); cfg.with_single_cert(cert_chain, key_der)? } }; let client = ClientConnection::new(Arc::new(cfg), dnsname)?; let mut stream = StreamOwned::new(client, tcp_stream); stream.write_all(self.request.to_string().as_bytes())?; let mut buf = vec![]; stream.read_to_end(&mut buf)?; stream.conn.send_close_notify(); drop(stream); let res = buf.try_into()?; Ok(res) } } #[derive(Debug)] pub struct MultiSender where S: CertificateStore, C: ClientCertificateStore, { pub sender: Mailuser, pub recipients: Vec, pub store: S, pub client_store: C, } impl MultiSender where S: CertificateStore + 'static + Clone, C: ClientCertificateStore + Clone, { pub fn new(sender: &str, recipients: &[&str], store: S, client_store: C) -> Result { 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)) -> Result<(), Error> { todo!() } }