rust_smtp_server/
server.rs1use crate::backend::{
2 Backend,
3 Session,
4};
5use crate::conn::Conn;
6use crate::parse::parse_cmd;
7use std::pin::Pin;
8use std::sync::Arc;
9
10
11use anyhow::Result;
12use tokio::sync::Mutex;
13use std::time::Duration;
14
15use tokio::io::{self, BufWriter, AsyncBufReadExt, AsyncReadExt};
16use tokio::net::{TcpListener, TcpStream};
17use tokio_rustls::TlsAcceptor;
18
19
20const ERR_TCP_AND_LMTP: &str = "smtp: cannot start LMTP server listening on a TCP socket";
21
22pub struct Server<B: Backend> {
23 pub addr: String,
24 pub tls_acceptor: Option<TlsAcceptor>,
25
26 pub domain: String,
27 pub max_recipients: usize,
28 pub max_message_bytes: usize,
29 pub max_line_length: usize,
30 pub allow_insecure_auth: bool,
31 pub strict: bool,
32
33 pub read_timeout: Duration,
34 pub write_timeout: Duration,
35
36 pub enable_smtputf8: bool,
37 pub enable_requiretls: bool,
38 pub enable_binarymime: bool,
39
40 pub auth_disabled: bool,
41
42 pub backend: B,
43
44 pub caps: Vec<String>,
45
46 }
50
51impl<B: Backend> Server<B> {
52 pub fn new(be: B) -> Self {
53 return Server{
54 addr: String::new(),
55 tls_acceptor: None,
56 domain: String::new(),
57 max_recipients: 0,
58 max_message_bytes: 0,
59 max_line_length: 2000,
60 allow_insecure_auth: true,
61 strict: false,
62 read_timeout: Duration::from_secs(0),
63 write_timeout: Duration::from_secs(0),
64 enable_smtputf8: false,
65 enable_requiretls: false,
66 enable_binarymime: false,
67 auth_disabled: false,
68 backend: be,
69 caps: vec!["PIPELINING".to_string(), "8BITMIME".to_string(), "ENHANCEDSTATUSCODES".to_string(), "CHUNKING".to_string()],
70 }
72 }
73
74 pub async fn serve(self, l: TcpListener) -> Result<()> {
75 let mut server = Arc::new(self);
76 loop {
77 match l.accept().await {
78 Ok((conn, _)) => {
79 let mut server = server.clone();
80 tokio::spawn(async move {
81 if let Err(err) = server.handle_conn(Conn::new(conn, server.max_line_length)).await {
82 println!("Error: {}", err);
83 }
84 });
85 }
86 Err(e) => {
87 println!("Error: {}", e);
88 }
89 }
90 }
91 }
92
93 pub async fn handle_conn(&self, mut c: Conn<B>) -> Result<()> {
94 c.greet(self.domain.clone()).await;
95
96 let mut buf_reader = io::BufReader::new(c.text.conn.clone());
97
98 loop {
99 let mut line = String::new();
100 match buf_reader.read_line(&mut line).await {
101 Ok(0) => {
102 return Ok(());
103 }
104 Ok(_) => {
105 match parse_cmd(line) {
106 Ok((cmd, arg)) => {
107 c.handle(cmd, arg, self).await;
108 }
109 Err(err) => {
110 println!("Error: {}", err);
111 c.write_response(501, [5,5,2], &["Bad command"]).await;
112 continue;
113 }
114 }
115 }
116 Err(err) => {
117 match err.kind() {
118 std::io::ErrorKind::TimedOut => {
119 c.write_response(221, [2,4,2], &["Idle timeout, bye bye"]).await;
120 return Ok(());
121 }
122 _ => {
123 c.write_response(221, [2,4,0], &["Connection error, sorry"]).await;
124 return Err(err.into());
125 }
126 }
127 }
128 }
129 }
130 }
131
132 pub async fn listen_and_serve(self) -> Result<()> {
133 let l = TcpListener::bind(&self.addr).await?;
134 self.serve(l).await
135 }
136
137 }