samotop_core/mail/
service.rs

1use crate::{
2    common::*,
3    io::{tls::MayBeTls, ConnectionInfo, IoService},
4    mail::{
5        AddRecipientResult, DispatchResult, MailDispatch, MailGuard, Recipient, StartMailResult,
6    },
7    smtp::{Drive, Interpret, SessionService, SmtpContext, SmtpSession},
8};
9
10/// A short hand for all the mandatory mail services
11pub trait MailService: SessionService + MailGuard + MailDispatch {}
12impl<T> MailService for T where T: SessionService + MailGuard + MailDispatch {}
13
14/// Service implements all the mandatory mail services
15/// + IoService so it can be used with `TcpServer` or `UnixServer`.
16///
17/// Build it using the `Builder`
18#[derive(Debug, Clone)]
19pub struct Service {
20    session: Arc<dyn SessionService + Sync + Send>,
21    guard: Arc<dyn MailGuard + Sync + Send>,
22    dispatch: Arc<dyn MailDispatch + Sync + Send>,
23    driver: Arc<dyn Drive + Sync + Send>,
24    interpret: Arc<dyn Interpret + Sync + Send>,
25}
26
27impl Service {
28    /// Compose the service from parts
29    pub fn new<T, I, E, G, D>(drive: T, interpret: I, session: E, guard: G, dispatch: D) -> Self
30    where
31        T: Drive + Sync + Send + 'static,
32        I: Interpret + Sync + Send + 'static,
33        E: SessionService + Sync + Send + 'static,
34        G: MailGuard + Sync + Send + 'static,
35        D: MailDispatch + Sync + Send + 'static,
36    {
37        Self {
38            session: Arc::new(session),
39            dispatch: Arc::new(dispatch),
40            guard: Arc::new(guard),
41            driver: Arc::new(drive),
42            interpret: Arc::new(interpret),
43        }
44    }
45}
46
47impl IoService for Service {
48    fn handle(
49        &self,
50        io: Result<Box<dyn MayBeTls>>,
51        connection: ConnectionInfo,
52    ) -> S1Fut<'static, Result<()>> {
53        let service = self.clone();
54        let driver = self.driver.clone();
55        let interpret = self.interpret.clone();
56
57        trace!("New peer connection {}", connection);
58        let mut state = SmtpContext::new(service, connection);
59
60        Box::pin(async move {
61            // fetch and apply commands
62            driver.drive(&mut io?, &interpret, &mut state).await?;
63            Ok(())
64        })
65    }
66}
67
68impl MailDispatch for Service {
69    fn open_mail_body<'a, 's, 'f>(
70        &'a self,
71        session: &'s mut SmtpSession,
72    ) -> S1Fut<'f, DispatchResult>
73    where
74        'a: 'f,
75        's: 'f,
76    {
77        self.dispatch.open_mail_body(session)
78    }
79}
80
81impl MailGuard for Service {
82    fn add_recipient<'a, 's, 'f>(
83        &'a self,
84        session: &'s mut SmtpSession,
85        rcpt: Recipient,
86    ) -> S2Fut<'f, AddRecipientResult>
87    where
88        'a: 'f,
89        's: 'f,
90    {
91        self.guard.add_recipient(session, rcpt)
92    }
93
94    fn start_mail<'a, 's, 'f>(&'a self, session: &'s mut SmtpSession) -> S2Fut<'f, StartMailResult>
95    where
96        'a: 'f,
97        's: 'f,
98    {
99        self.guard.start_mail(session)
100    }
101}
102
103impl SessionService for Service {
104    fn prepare_session<'a, 'i, 's, 'f>(
105        &'a self,
106        io: &'i mut Box<dyn MayBeTls>,
107        state: &'s mut SmtpContext,
108    ) -> S1Fut<'f, ()>
109    where
110        'a: 'f,
111        'i: 'f,
112        's: 'f,
113    {
114        self.session.prepare_session(io, state)
115    }
116}