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
pub use super::commands::*;
use super::SmtpReply;
use crate::{common::*, smtp::state::SmtpState};
use std::fmt;

pub trait SmtpSessionCommand: Sync + Send + fmt::Debug {
    fn verb(&self) -> &str;
    #[must_use = "apply must be awaited"]
    fn apply(&self, state: SmtpState) -> S2Fut<SmtpState>;
}

pub trait ApplyCommand<Data> {
    #[must_use = "apply must be awaited"]
    fn apply_cmd(data: &Data, state: SmtpState) -> S2Fut<SmtpState>;
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum SmtpCommand {
    StartTls,
    Helo(SmtpHelo),
    Mail(SmtpMail),
    Rcpt(SmtpRcpt),
    Expn(String),
    Vrfy(String),
    Help(Vec<String>),
    Noop(Vec<String>),
    Quit,
    Rset,
    Data,
    Turn,
    /// Command outside of the base implementation.
    /// First string is the command verb, next the parameters
    Other(String, Vec<String>),
}

impl SmtpCommand {
    pub fn verb(&self) -> &str {
        use SmtpCommand as C;
        match self {
            C::Helo(ref helo) => helo.verb.as_ref(),
            C::Mail(ref mail) => mail.verb(),
            C::Rcpt(_) => "RCPT",
            C::Data => "DATA",
            C::Quit => "QUIT",
            C::Rset => "RSET",
            C::Noop(_) => "NOOP",
            C::StartTls => "STARTTLS",
            C::Expn(_) => "EXPN",
            C::Vrfy(_) => "VRFY",
            C::Help(_) => "HELP",
            C::Turn => "TURN",
            C::Other(ref verb, _) => verb.as_str(),
        }
    }
}

impl<T, E> SmtpSessionCommand for std::result::Result<T, E>
where
    T: SmtpSessionCommand,
    E: fmt::Debug + Sync + Send,
{
    fn verb(&self) -> &str {
        ""
    }

    fn apply(&self, mut state: SmtpState) -> S2Fut<SmtpState> {
        match self {
            Ok(command) => Box::pin(async move { command.apply(state).await }),
            Err(e) => {
                error!("reading SMTP input failed: {:?}", e);
                state.say_shutdown(SmtpReply::ProcesingError);
                Box::pin(ready(state))
            }
        }
    }
}