1use std::{pin::Pin, future::Future, task::Poll};
2
3use tokio::io::{self, AsyncBufRead, AsyncRead, AsyncReadExt};
4
5use crate::{backend::{Backend}};
6
7pub type EnhancedCode = [i8; 3];
8
9pub struct SMTPError {
10 code: u16,
11 enhanced_code: EnhancedCode,
12 message: String,
13}
14
15impl std::fmt::Display for SMTPError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "{} {}", self.code, self.message)
18 }
19}
20
21pub const NO_ENHANCED_CODE: EnhancedCode = [-1, -1, -1];
22
23pub const ENHANCED_CODE_NOT_SET: EnhancedCode = [0, 0, 0];
24
25#[derive(PartialEq)]
26enum State {
27 BeginLine,
28 Dot,
29 DotCR,
30 CR,
31 Data,
32 EOF,
33}
34
35
36impl SMTPError {
37 pub fn err_data_too_large() -> Self {
38 return SMTPError {
39 code: 552,
40 enhanced_code: ENHANCED_CODE_NOT_SET,
41 message: "Requested mail action aborted: exceeded storage allocation".to_string(),
42 };
43 }
44
45 pub fn err_auth_required() -> Self {
46 return SMTPError {
47 code: 502,
48 enhanced_code: [5, 7, 0],
49 message: "Please authenticate first".to_string(),
50 };
51 }
52
53 pub fn err_auth_unsupported() -> Self {
54 return SMTPError {
55 code: 502,
56 enhanced_code: [5, 7, 0],
57 message: "Authentication not supported".to_string(),
58 };
59 }
60
61 pub fn error(&self) -> String {
62 self.message.clone()
63 }
64
65 fn is_temporary(&self) -> bool {
66 self.code >= 400 && self.code < 500
67 }
68}
69
70pub struct DataReader<R: AsyncRead + Unpin> {
71 pub r: R,
72 state: State,
73 pub limited: bool,
74 n: usize,
75}
76
77impl<R: AsyncBufRead + Unpin> DataReader<R> {
78 pub fn new<B: Backend>(r: R, max_message_bytes: usize) -> Self {
79 DataReader {
80 r,
81 state: State::BeginLine,
82 limited: max_message_bytes > 0,
83 n: max_message_bytes,
84 }
85 }
86}
87
88impl<R: AsyncBufRead + Unpin> AsyncRead for DataReader<R> {
89 fn poll_read(
90 self: std::pin::Pin<&mut Self>,
91 cx: &mut std::task::Context<'_>,
92 buf: &mut tokio::io::ReadBuf<'_>,
93 ) -> std::task::Poll<std::io::Result<()>> {
94 let mut this = self.get_mut();
95
96 if this.n == 0 || this.state == State::EOF {
97 return Poll::Ready(Ok(()));
98 }
99
100 let mut fut = Box::pin(this.r.read_u8());
101 match Pin::new(&mut fut).poll(cx) {
102 Poll::Ready(Ok(c)) => {
103 match this.state {
104 State::BeginLine => {
105 if c == b'.' {
106 this.state = State::Dot;
107 cx.waker().wake_by_ref();
108 return Poll::Pending;
109 }
110 this.state = State::Data;
111 }
112 State::Dot => {
113 if c == b'\r' {
114 this.state = State::DotCR;
115 cx.waker().wake_by_ref();
116 return Poll::Pending;
117 }
118 if c == b'\n' {
119 this.state = State::EOF;
120 return Poll::Ready(Ok(()));
121 }
122
123 this.state = State::Data;
124 }
125 State::DotCR => {
126 if c == b'\n' {
127 this.state = State::EOF;
128 return Poll::Ready(Ok(()));
129 }
130 this.state = State::Data;
131 }
132 State::CR => {
133 if c == b'\n' {
134 this.state = State::BeginLine;
135 return Poll::Ready(Ok(()));
136 }
137 this.state = State::Data;
138 }
139 State::Data => {
140 if c == b'\r' {
141 this.state = State::CR;
142 }
143 if c == b'\n' {
144 this.state = State::BeginLine;
145 }
146 }
147 State::EOF => {
148 return Poll::Ready(Ok(()));
149 }
150 }
151
152 this.n -= 1;
153 buf.put_slice(&[c]);
154 return Poll::Ready(Ok(()));
155 }
156 Poll::Ready(Err(e)) => {
157 if e.kind() == io::ErrorKind::UnexpectedEof {
158 return Poll::Ready(Ok(()));
159 }
160 return Poll::Ready(Err(e));
161 }
162 Poll::Pending => {
163 return Poll::Pending;
164 }
165 }
166
167 }
168}