samotop_core/smtp/
parser.rs

1use crate::{
2    common::Dummy,
3    smtp::{command::SmtpUnknownCommand, SmtpContext},
4};
5use std::{
6    fmt::{self, Debug},
7    ops::Deref,
8};
9
10#[derive(Debug)]
11pub enum ParseError {
12    Incomplete,
13    Failed(String),
14    Mismatch(String),
15}
16impl fmt::Display for ParseError {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        match self {
19            ParseError::Incomplete => write!(f, "The input is not complete"),
20            ParseError::Failed(e) => write!(f, "The input is invalid, parsing failed: {}", e),
21            ParseError::Mismatch(e) => write!(f, "Parser did not match the input: {}", e),
22        }
23    }
24}
25impl std::error::Error for ParseError {}
26
27pub type ParseResult<T> = std::result::Result<(usize, T), ParseError>;
28
29pub trait Parser<CMD>: fmt::Debug {
30    fn parse(&self, input: &[u8], state: &SmtpContext) -> ParseResult<CMD>;
31}
32
33impl<CMD, S: Parser<CMD>, T: Deref<Target = S> + Debug> Parser<CMD> for T {
34    fn parse(&self, input: &[u8], state: &SmtpContext) -> ParseResult<CMD> {
35        S::parse(Deref::deref(self), input, state)
36    }
37}
38
39impl Parser<SmtpUnknownCommand> for Dummy {
40    fn parse(&self, input: &[u8], _state: &SmtpContext) -> ParseResult<SmtpUnknownCommand> {
41        if let Some(line) = input.split(|b| *b == b'\n').next() {
42            Ok((line.len(), Default::default()))
43        } else {
44            Err(ParseError::Incomplete)
45        }
46    }
47}