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
use crate::common::*;
use crate::model::io::Connection;
use crate::model::smtp::SmtpExtension;
use crate::protocol::tls::{TlsCapable, TlsDisabled};
use crate::service::tcp::TcpService;

pub trait TlsProvider<IO> {
    type EncryptedIO: Read + Write + Unpin;
    type UpgradeFuture: Future<Output = std::io::Result<Self::EncryptedIO>>;
    fn upgrade_to_tls(&self, io: IO) -> Self::UpgradeFuture;
}

#[doc = "Dummy TCP service for testing samotop server"]
#[derive(Clone)]
pub struct TlsEnabled<T, P> {
    provider: Option<P>,
    wrapped: T,
}
impl<T> TlsEnabled<T, TlsDisabled> {
    pub fn disabled(wrapped: T) -> Self {
        TlsEnabled::no(wrapped)
    }
}
impl<T, P> TlsEnabled<T, P> {
    pub fn yes(wrapped: T, provider: P) -> Self {
        TlsEnabled::new(wrapped, Some(provider))
    }
    pub fn no(wrapped: T) -> Self {
        TlsEnabled::new(wrapped, None)
    }
    pub fn new(wrapped: T, provider: Option<P>) -> Self {
        TlsEnabled { wrapped, provider }
    }
}

impl<T, IO, P> TcpService<IO> for TlsEnabled<T, P>
where
    T: TcpService<TlsCapable<IO, P>>,
    IO: Read + Write + Unpin,
    P: TlsProvider<IO>,
{
    type Future = T::Future;
    fn handle(self, io: Result<IO>, mut conn: Connection) -> Self::Future {
        let TlsEnabled { provider, wrapped } = self;
        let tls = if let Some(provider) = provider {
            conn.extensions_mut().enable(SmtpExtension::STARTTLS);
            io.map(|io| TlsCapable::yes(io, provider))
        } else {
            io.map(|io| TlsCapable::no(io))
        };
        wrapped.handle(tls, conn)
    }
}