1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use smtp_proto::{
response::parser::{ResponseReceiver, MAX_REPONSE_LENGTH},
EhloResponse,
};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use crate::SmtpClient;
impl<T: AsyncRead + AsyncWrite + Unpin> SmtpClient<T> {
pub async fn ehlo(&mut self, hostname: &str) -> crate::Result<EhloResponse<String>> {
tokio::time::timeout(self.timeout, async {
self.stream
.write_all(format!("EHLO {hostname}\r\n").as_bytes())
.await?;
self.stream.flush().await?;
self.read_ehlo().await
})
.await
.map_err(|_| crate::Error::Timeout)?
}
pub async fn lhlo(&mut self, hostname: &str) -> crate::Result<EhloResponse<String>> {
tokio::time::timeout(self.timeout, async {
self.stream
.write_all(format!("LHLO {hostname}\r\n").as_bytes())
.await?;
self.stream.flush().await?;
self.read_ehlo().await
})
.await
.map_err(|_| crate::Error::Timeout)?
}
pub async fn read_ehlo(&mut self) -> crate::Result<EhloResponse<String>> {
let mut buf = vec![0u8; 1024];
let mut buf_concat = Vec::with_capacity(0);
loop {
let br = self.stream.read(&mut buf).await?;
if br == 0 {
return Err(crate::Error::UnparseableReply);
}
let mut iter = if buf_concat.is_empty() {
buf[..br].iter()
} else if br + buf_concat.len() < MAX_REPONSE_LENGTH {
buf_concat.extend_from_slice(&buf[..br]);
buf_concat.iter()
} else {
return Err(crate::Error::UnparseableReply);
};
match EhloResponse::parse(&mut iter) {
Ok(reply) => return Ok(reply),
Err(err) => match err {
smtp_proto::Error::NeedsMoreData { .. } => {
if buf_concat.is_empty() {
buf_concat = buf.to_vec();
}
}
smtp_proto::Error::InvalidResponse { code } => {
match ResponseReceiver::from_code(code).parse(&mut iter) {
Ok(response) => {
return Err(crate::Error::UnexpectedReply(response));
}
Err(smtp_proto::Error::NeedsMoreData { .. }) => {
if buf_concat.is_empty() {
buf_concat = buf.to_vec();
}
}
Err(_) => return Err(crate::Error::UnparseableReply),
}
}
_ => {
return Err(crate::Error::UnparseableReply);
}
},
}
}
}
}