Commit
+59 -23 +/-6 browse
1 | diff --git a/maitred/Cargo.toml b/maitred/Cargo.toml |
2 | index fb2c193..6db3845 100644 |
3 | --- a/maitred/Cargo.toml |
4 | +++ b/maitred/Cargo.toml |
5 | @@ -33,5 +33,6 @@ tracing-subscriber = "0.3.18" |
6 | |
7 | [features] |
8 | default = [] |
9 | - full = ["server"] |
10 | + full = ["server", "auth"] |
11 | server = [] |
12 | + auth = ["server"] |
13 | diff --git a/maitred/src/auth.rs b/maitred/src/auth.rs |
14 | index 133acff..0494e65 100644 |
15 | --- a/maitred/src/auth.rs |
16 | +++ b/maitred/src/auth.rs |
17 | @@ -8,6 +8,7 @@ use crate::smtp_response; |
18 | use crate::session::Response; |
19 | use smtp_proto::Response as SmtpResponse; |
20 | |
21 | + /// Any error that occurred during authentication. |
22 | #[derive(Debug, thiserror::Error)] |
23 | pub enum AuthError { |
24 | #[error("Unauthorized")] |
25 | @@ -51,6 +52,7 @@ impl Into<Response<String>> for AuthError { |
26 | } |
27 | } |
28 | |
29 | + /// Authentication trait for handling PLAIN SASL auth as defined in RFC4616 |
30 | #[async_trait] |
31 | pub trait PlainAuth: Sync + Send { |
32 | /// authenticate is passed the plaintext authcid, authzid, and passwd |
33 | @@ -64,6 +66,7 @@ pub trait PlainAuth: Sync + Send { |
34 | ) -> Result<(), AuthError>; |
35 | } |
36 | |
37 | + /// Convenience function implementing PlainAuth |
38 | pub struct PlainAuthFunc<F, T>(pub F) |
39 | where |
40 | F: Fn(&str, &str, &str) -> T + Sync + Send, |
41 | diff --git a/maitred/src/delivery.rs b/maitred/src/delivery.rs |
42 | index 4e402f0..d7cd878 100644 |
43 | --- a/maitred/src/delivery.rs |
44 | +++ b/maitred/src/delivery.rs |
45 | @@ -4,6 +4,7 @@ use async_trait::async_trait; |
46 | |
47 | use crate::session::Envelope; |
48 | |
49 | + /// Error that occurred delivering mail |
50 | #[derive(Debug, thiserror::Error)] |
51 | pub enum DeliveryError { |
52 | /// Indicates an unspecified error that occurred during milting. |
53 | @@ -22,7 +23,7 @@ pub trait Delivery: Sync + Send { |
54 | } |
55 | |
56 | /// DeliveryFunc wraps an async closure implementing the Delivery trait. |
57 | - /// ```FIXME |
58 | + /// ```rust |
59 | /// use maitred::delivery::DeliveryFunc; |
60 | /// use maitred::Envelope; |
61 | /// |
62 | diff --git a/maitred/src/lib.rs b/maitred/src/lib.rs |
63 | index 07d67d0..ec4e5f2 100644 |
64 | --- a/maitred/src/lib.rs |
65 | +++ b/maitred/src/lib.rs |
66 | @@ -1,7 +1,4 @@ |
67 | - //! Maitred is a flexible and embedable SMTP server for handling e-mail from |
68 | - //! within a Rust program. Designed for use in [ayllu](https://ayllu-forge.org) |
69 | - //! but also for general use. |
70 | - //! |
71 | + #![doc = include_str!("../../README.md")] |
72 | //! # Example SMTP Server |
73 | //! ```rust,no_run |
74 | //! use maitred::auth::PlainAuthFunc; |
75 | @@ -13,7 +10,7 @@ |
76 | //! |
77 | //! use tracing::Level; |
78 | //! |
79 | - //! async fn print_message(envelope: &Envelope) -> Result<(), DeliveryError> { |
80 | + //! fn print_message(envelope: &Envelope) { |
81 | //! println!("New SMTP Message:"); |
82 | //! println!("{:?}", envelope.body.headers()); |
83 | //! println!("Subject: {:?}", envelope.body.subject()); |
84 | @@ -24,7 +21,6 @@ |
85 | //! .map(|text| String::from_utf8_lossy(text.as_bytes()).to_string()) |
86 | //! .unwrap_or_default() |
87 | //! ); |
88 | - //! Ok(()) |
89 | //! } |
90 | //! |
91 | //! #[tokio::main] |
92 | @@ -39,8 +35,8 @@ |
93 | //! let mut mail_server = Server::default() |
94 | //! .address("127.0.0.1:2525") |
95 | //! .with_delivery(DeliveryFunc(|envelope: &Envelope| { |
96 | - //! let envelope = envelope.clone(); |
97 | - //! async move { print_message(&envelope).await } |
98 | + //! print_message(envelope); |
99 | + //! async move { Ok(()) } |
100 | //! })); |
101 | //! mail_server.listen().await?; |
102 | //! Ok(()) |
103 | @@ -55,28 +51,58 @@ mod opportunistic; |
104 | mod rewrite; |
105 | |
106 | /// SMTP Authentication |
107 | + #[cfg(feature = "auth")] |
108 | pub mod auth; |
109 | - /// Message Delivery |
110 | - pub mod delivery; |
111 | - /// Callback for implementing SMTP command EXPN |
112 | - pub mod expand; |
113 | - /// Message and envelope manipulation |
114 | - pub mod milter; |
115 | - /// Callback for implementing SMPT command VRFY |
116 | - pub mod verify; |
117 | + #[cfg(feature = "auth")] |
118 | + #[doc(inline)] |
119 | + pub use auth::{AuthError, PlainAuth, PlainAuthFunc}; |
120 | + |
121 | /// Low level SMTP session without network transport |
122 | pub mod session; |
123 | + #[doc(inline)] |
124 | + pub use session::{ |
125 | + Action, Envelope, Response, Session, DEFAULT_CAPABILITIES, DEFAULT_GREETING, |
126 | + DEFAULT_HELP_BANNER, DEFAULT_MAXIMUM_MESSAGE_SIZE, |
127 | + }; |
128 | |
129 | /// Full featured tokio based TCP server for handling SMTP sessions |
130 | #[cfg(feature = "server")] |
131 | pub mod server; |
132 | #[cfg(feature = "server")] |
133 | - mod transport; |
134 | + /// Low level line oriented transport for SMTP messages |
135 | + pub mod transport; |
136 | #[cfg(feature = "server")] |
137 | mod validation; |
138 | #[cfg(feature = "server")] |
139 | mod worker; |
140 | |
141 | + #[cfg(feature = "server")] |
142 | + #[doc(inline)] |
143 | + pub use server::{Server, ServerError, DEFAULT_GLOBAL_TIMEOUT_SECS, DEFAULT_LISTEN_ADDR}; |
144 | + #[cfg(feature = "server")] |
145 | + #[doc(inline)] |
146 | + pub use transport::{Command, Transport, TransportError}; |
147 | + /// Message Delivery |
148 | + #[cfg(feature = "server")] |
149 | + pub mod delivery; |
150 | + #[doc(inline)] |
151 | + pub use delivery::{Delivery, DeliveryError, DeliveryFunc}; |
152 | + /// Callback for implementing SMTP command EXPN |
153 | + #[cfg(feature = "server")] |
154 | + pub mod expand; |
155 | + #[doc(inline)] |
156 | + pub use expand::{Expansion, ExpansionError, ExpansionFunc}; |
157 | + /// Message and envelope manipulation |
158 | + #[cfg(feature = "server")] |
159 | + pub mod milter; |
160 | + #[doc(inline)] |
161 | + pub use milter::{Milter, MilterError, MilterFunc}; |
162 | + /// Callback for implementing SMPT command VRFY |
163 | + #[cfg(feature = "server")] |
164 | + pub mod verify; |
165 | + #[doc(inline)] |
166 | + pub use verify::{Verify, VerifyError, VerifyFunc}; |
167 | + |
168 | /// Generate a single smtp_response |
169 | macro_rules! smtp_response { |
170 | ($code:expr, $e1:expr, $e2:expr, $e3:expr, $name:expr) => { |
171 | diff --git a/maitred/src/session.rs b/maitred/src/session.rs |
172 | index 51d1c2d..8f9558b 100644 |
173 | --- a/maitred/src/session.rs |
174 | +++ b/maitred/src/session.rs |
175 | @@ -31,12 +31,13 @@ pub const DEFAULT_GREETING: &str = "Maitred ESMTP Server"; |
176 | // 250-DSN |
177 | // 250-SMTPUTF8 |
178 | |
179 | - /// Default SMTP capabilities advertised by the server |
180 | + /// Default SMTP capabilities advertised by the server. |
181 | pub const DEFAULT_CAPABILITIES: u32 = smtp_proto::EXT_SIZE |
182 | | smtp_proto::EXT_ENHANCED_STATUS_CODES |
183 | | smtp_proto::EXT_PIPELINING |
184 | | smtp_proto::EXT_8BIT_MIME; |
185 | |
186 | + /// Wrapper around an SMTP message to send to the client. |
187 | #[derive(Debug, Clone)] |
188 | pub enum Response<T> |
189 | where |
190 | @@ -84,7 +85,7 @@ where |
191 | |
192 | impl<T> Eq for Response<T> where T: Display {} |
193 | |
194 | - /// An Envelope containing an e-mail message created from the session |
195 | + /// An Envelope containing an e-mail message created from the session. |
196 | #[derive(Clone, Debug)] |
197 | pub struct Envelope { |
198 | pub body: Message<'static>, |
199 | @@ -93,6 +94,7 @@ pub struct Envelope { |
200 | pub hostname: Host, |
201 | } |
202 | |
203 | + /// Action for the server implementor to take probably asynchronously. |
204 | pub enum Action<'a> { |
205 | Send(Response<String>), |
206 | SendMany(Vec<Response<String>>), |
207 | diff --git a/maitred/src/transport.rs b/maitred/src/transport.rs |
208 | index 9a62879..c5da76a 100644 |
209 | --- a/maitred/src/transport.rs |
210 | +++ b/maitred/src/transport.rs |
211 | @@ -8,6 +8,7 @@ use tokio_util::codec::{Decoder, Encoder}; |
212 | |
213 | use crate::session::Response; |
214 | |
215 | + /// Error that occurred at the transport layer |
216 | #[derive(Debug, thiserror::Error)] |
217 | pub enum TransportError { |
218 | /// Returned when a client attempts to send multiple commands sequentially |
219 | @@ -44,7 +45,9 @@ pub(crate) enum Receiver { |
220 | /// Command from the client with an optional attached payload. |
221 | #[derive(Debug)] |
222 | pub enum Command { |
223 | + /// One or more requests depending if PIPELINING is enabled. |
224 | Requests(Vec<Request<String>>), |
225 | + /// Message payload possibily sent over multiple frames. |
226 | Payload(Bytes), |
227 | } |
228 | |
229 | @@ -57,8 +60,8 @@ impl Display for Command { |
230 | } |
231 | } |
232 | |
233 | - /// Line oriented transport |
234 | - /// TODO: BINARYMIME |
235 | + /// Low-level line oriented transport for handling SMTP connections. |
236 | + // TODO: BINARYMIME |
237 | #[derive(Default)] |
238 | pub struct Transport { |
239 | receiver: Option<Box<Receiver>>, |