From ceaa25c8baf2294458c1560b3292c00c57b0fa1b Mon Sep 17 00:00:00 2001 From: Mroik Date: Tue, 7 Apr 2026 10:35:35 +0200 Subject: Add SMTP server scaffolding Signed-off-by: Mroik --- src/main.rs | 1 + src/smtp.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/smtp.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 60b75af..075dc7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod database; mod list; +mod smtp; fn main() { println!("Hello, world!"); diff --git a/src/smtp.rs b/src/smtp.rs new file mode 100644 index 0000000..affac8b --- /dev/null +++ b/src/smtp.rs @@ -0,0 +1,71 @@ +use std::{ + io::{BufRead, BufReader}, + net::{IpAddr, SocketAddr, TcpListener, TcpStream}, +}; + +use anyhow::Result; +use tokio::spawn; + +pub struct SmtpServer { + listener: TcpListener, + running: bool, +} + +impl SmtpServer { + pub fn new(ip: [u8; 4], port: u16) -> Result { + Ok(Self { + listener: TcpListener::bind((IpAddr::from(ip), port))?, + running: false, + }) + } + + // TODO: trap SIGINT to stop server? + pub async fn run(&mut self) -> Result<()> { + self.running = true; + while self.running { + let (stream, addr) = self.listener.accept()?; + let session = SessionHandler { + stream, + addr, + state: SessionState::default(), + }; + spawn(session.run()); + } + Ok(()) + } +} + +struct SessionHandler { + stream: TcpStream, + addr: SocketAddr, + state: SessionState, +} + +impl SessionHandler { + async fn run(mut self) -> Result<()> { + let mut r = BufReader::new(&self.stream); + let mut buffer = String::new(); + + loop { + if r.read_line(&mut buffer)? == 0 { + break; + } + + log::debug!("Received '{}' from '{}'", buffer.trim(), self.addr); + self.state.apply().await; + buffer.clear(); + } + + log::info!("Connection closed by {}", self.addr); + Ok(()) + } +} + +#[derive(Default)] +struct SessionState {} + +impl SessionState { + async fn apply(&mut self) { + todo!() + } +} -- cgit v1.3