aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/smtp.rs30
1 files changed, 30 insertions, 0 deletions
diff --git a/src/smtp.rs b/src/smtp.rs
index 2ab79f8..00e2ae8 100644
--- a/src/smtp.rs
+++ b/src/smtp.rs
@@ -31,6 +31,7 @@ impl SmtpServer {
state: SessionState::default(),
client_host: String::new(),
from: None,
+ to: Vec::new(),
};
spawn(session.run(stream));
}
@@ -43,6 +44,7 @@ struct SessionHandler {
state: SessionState,
client_host: String,
from: Option<String>,
+ to: Vec<String>,
}
impl SessionHandler {
@@ -84,6 +86,7 @@ impl SessionHandler {
match &command {
Command::HELO(hostname) => self.helo(hostname).await,
Command::MAIL(from) => self.mail(from).await,
+ Command::RCPT(to) => self.rcpt(to).await,
}
}
@@ -92,6 +95,7 @@ impl SessionHandler {
self.client_host = String::from(hostname);
self.state = SessionState::Normal;
self.from = None;
+ self.to.clear();
Ok(Reply::Completed(String::from(SERVER_NAME)))
}
@@ -103,12 +107,29 @@ impl SessionHandler {
}
self.from = Some(String::from(from));
+ self.to.clear();
self.state = SessionState::MailTransaction;
Ok(Reply::Completed(String::from("Ok")))
}
+
+ /// TODO: Validate email addresses
+ /// Only after having started a mail transaction
+ async fn rcpt(&mut self, to: &str) -> Result<Reply> {
+ if self.state != SessionState::MailTransaction {
+ return Ok(Reply::BadSequence);
+ }
+
+ if to.is_empty() {
+ return Ok(Reply::InvalidParameter);
+ }
+
+ self.to.push(String::from(to));
+ Ok(Reply::Completed(String::from("Ok")))
+ }
}
+#[derive(PartialEq)]
enum SessionState {
WaitingHelo,
MailTransaction,
@@ -126,6 +147,7 @@ enum Reply {
Completed(String),
InvalidCommand,
InvalidParameter,
+ BadSequence,
}
impl ToString for Reply {
@@ -135,6 +157,7 @@ impl ToString for Reply {
Reply::Completed(hostname) => format!("250 {}", hostname),
Reply::InvalidCommand => format!("500 Command not recognized"),
Reply::InvalidParameter => format!("501 Parameter error"),
+ Reply::BadSequence => format!("503 Bad sequence of commands"),
}
}
}
@@ -142,6 +165,7 @@ impl ToString for Reply {
enum Command {
HELO(String),
MAIL(String),
+ RCPT(String),
}
impl TryFrom<&str> for Command {
@@ -160,6 +184,12 @@ impl TryFrom<&str> for Command {
return Ok(Command::MAIL(String::from(from)));
}
+ if value.len() >= 9 && value.to_lowercase().starts_with("rcpt to:<") && value.contains('>')
+ {
+ let to = &value[9..value.find('>').unwrap()];
+ return Ok(Command::RCPT(String::from(to)));
+ }
+
Err(anyhow::format_err!("Invalid command"))
}
}
XMR address: 854DmXNrxULU3ZFJVs4Wc8PFhbq29RhqHhY8W6cdWrtFN3qmooKyyeYPcDzZTNRxphhJ5UzASQfAdEMwSteVqymk28aLhqj