aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/smtp.rs76
1 files changed, 63 insertions, 13 deletions
diff --git a/src/smtp.rs b/src/smtp.rs
index affac8b..f8cf0ee 100644
--- a/src/smtp.rs
+++ b/src/smtp.rs
@@ -1,11 +1,13 @@
use std::{
- io::{BufRead, BufReader},
+ io::{BufRead, BufReader, Write},
net::{IpAddr, SocketAddr, TcpListener, TcpStream},
};
use anyhow::Result;
use tokio::spawn;
+const SERVER_NAME: &str = "";
+
pub struct SmtpServer {
listener: TcpListener,
running: bool,
@@ -25,47 +27,95 @@ impl SmtpServer {
while self.running {
let (stream, addr) = self.listener.accept()?;
let session = SessionHandler {
- stream,
addr,
state: SessionState::default(),
+ client_host: String::new(),
};
- spawn(session.run());
+ spawn(session.run(stream));
}
Ok(())
}
}
struct SessionHandler {
- stream: TcpStream,
addr: SocketAddr,
state: SessionState,
+ client_host: String,
}
impl SessionHandler {
- async fn run(mut self) -> Result<()> {
- let mut r = BufReader::new(&self.stream);
+ async fn run(mut self, stream: TcpStream) -> Result<()> {
+ let mut writer = stream.try_clone()?;
+ let mut r = BufReader::new(&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;
+
+ let command = Command::try_from(buffer.as_str())?;
+ let res = self.apply(command).await?;
+ writer.write_all(res.to_string().as_bytes())?;
+
buffer.clear();
}
log::info!("Connection closed by {}", self.addr);
Ok(())
}
+
+ async fn apply(&mut self, command: Command) -> Result<Reply> {
+ match &command {
+ Command::HELO(hostname) => self.helo(hostname).await,
+ }
+ }
+
+ /// HELO resets buffers
+ async fn helo(&mut self, hostname: &str) -> Result<Reply> {
+ self.client_host = String::from(hostname);
+ self.state = SessionState::NextState;
+ Ok(Reply::Completed(String::from(SERVER_NAME)))
+ }
+}
+
+enum SessionState {
+ WaitingHelo,
+ /// This is a dev state
+ NextState,
+}
+
+impl Default for SessionState {
+ fn default() -> Self {
+ Self::WaitingHelo
+ }
+}
+
+enum Reply {
+ Completed(String),
+}
+
+impl ToString for Reply {
+ fn to_string(&self) -> String {
+ match self {
+ Reply::Completed(hostname) => format!("250 {}", hostname),
+ }
+ }
+}
+
+enum Command {
+ HELO(String),
}
-#[derive(Default)]
-struct SessionState {}
+impl TryFrom<&str> for Command {
+ type Error = anyhow::Error;
+
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
+ if value.len() >= 5 && value.to_lowercase().starts_with("helo ") {
+ return Ok(Command::HELO(String::from(&value[5..])));
+ }
-impl SessionState {
- async fn apply(&mut self) {
- todo!()
+ Err(anyhow::format_err!("Invalid command"))
}
}
XMR address: 854DmXNrxULU3ZFJVs4Wc8PFhbq29RhqHhY8W6cdWrtFN3qmooKyyeYPcDzZTNRxphhJ5UzASQfAdEMwSteVqymk28aLhqj