2018-12-29 16:56:56 +01:00
|
|
|
use crate::errors::Error;
|
2019-01-05 11:40:19 +01:00
|
|
|
use nom::{alt, alt_complete, call, complete, cond, do_parse, error_position, map_res, named, opt,
|
|
|
|
tag, take_until, take_while};
|
2019-01-06 16:37:07 +01:00
|
|
|
use std::str::FromStr;
|
2018-12-29 16:56:56 +01:00
|
|
|
|
2019-01-05 11:40:19 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2018-12-29 16:56:56 +01:00
|
|
|
pub enum Kind {
|
|
|
|
Report,
|
|
|
|
Filter,
|
|
|
|
}
|
|
|
|
|
2019-01-05 11:40:19 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2018-12-29 16:56:56 +01:00
|
|
|
pub enum Subsystem {
|
|
|
|
SmtpIn,
|
2018-12-29 18:34:23 +01:00
|
|
|
SmtpOut,
|
2018-12-29 16:56:56 +01:00
|
|
|
}
|
|
|
|
|
2019-01-05 11:40:19 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2018-12-29 16:56:56 +01:00
|
|
|
pub enum Event {
|
2018-12-29 18:34:23 +01:00
|
|
|
LinkConnect,
|
|
|
|
LinkDisconnect,
|
|
|
|
LinkIdentify,
|
|
|
|
LinkTls,
|
|
|
|
TxBegin,
|
2018-12-29 16:56:56 +01:00
|
|
|
TxMail,
|
|
|
|
TxRcpt,
|
2018-12-29 18:34:23 +01:00
|
|
|
TxEnvelope,
|
|
|
|
TxData,
|
|
|
|
TxCommit,
|
|
|
|
TxRollback,
|
|
|
|
ProtocolClient,
|
|
|
|
ProtocolServer,
|
2019-01-05 11:40:19 +01:00
|
|
|
Timeout,
|
2018-12-29 18:34:23 +01:00
|
|
|
FilterResponse,
|
2018-12-29 16:56:56 +01:00
|
|
|
}
|
|
|
|
|
2019-01-06 16:37:07 +01:00
|
|
|
impl FromStr for Event {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2019-01-06 15:41:30 +01:00
|
|
|
let s = s.to_lowercase()
|
|
|
|
.replace("link", "link-")
|
|
|
|
.replace("tx", "tx-")
|
|
|
|
.replace("protocol", "protocol-")
|
|
|
|
.replace("filter", "filter-");
|
|
|
|
let (_, evt) = parse_event(&s)?;
|
|
|
|
Ok(evt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-12 10:42:37 +01:00
|
|
|
impl ToString for Event {
|
|
|
|
fn to_string(&self) -> String {
|
|
|
|
let s = match self {
|
|
|
|
Event::LinkConnect => "link-connect",
|
|
|
|
Event::LinkDisconnect => "link-disconnect",
|
|
|
|
Event::LinkIdentify => "link-identify",
|
|
|
|
Event::LinkTls => "link-tls",
|
|
|
|
Event::TxBegin => "tx-begin",
|
|
|
|
Event::TxMail => "tx-mail",
|
|
|
|
Event::TxRcpt => "tx-rcpt",
|
|
|
|
Event::TxEnvelope => "tx-envelope",
|
|
|
|
Event::TxData => "tx-data",
|
|
|
|
Event::TxCommit => "tx-commit",
|
|
|
|
Event::TxRollback => "tx-rollback",
|
|
|
|
Event::ProtocolClient => "protocol-client",
|
|
|
|
Event::ProtocolServer => "protocol-server",
|
|
|
|
Event::Timeout => "timeout",
|
|
|
|
Event::FilterResponse => "filter-response",
|
|
|
|
};
|
|
|
|
String::from(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-05 13:02:20 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TimeVal {
|
|
|
|
pub sec: i64,
|
|
|
|
pub usec: i64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TimeVal {
|
|
|
|
pub fn to_string(&self) -> String {
|
|
|
|
format!("{}.{}", self.sec, self.usec)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 16:56:56 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Entry {
|
|
|
|
pub kind: Kind,
|
|
|
|
pub version: u8,
|
2019-01-05 13:02:20 +01:00
|
|
|
pub timestamp: TimeVal,
|
2018-12-29 16:56:56 +01:00
|
|
|
pub subsystem: Subsystem,
|
|
|
|
pub event: Event,
|
|
|
|
pub token: Option<u64>,
|
|
|
|
pub session_id: u64,
|
2019-01-05 11:40:19 +01:00
|
|
|
pub params: Option<String>,
|
2018-12-29 16:56:56 +01:00
|
|
|
}
|
|
|
|
|
2019-01-06 16:37:07 +01:00
|
|
|
impl FromStr for Entry {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(entry: &str) -> Result<Self, Self::Err> {
|
2019-01-05 17:53:56 +01:00
|
|
|
let (_, res) = parse_entry(entry)?;
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 16:56:56 +01:00
|
|
|
fn is_ascii_digit(c: char) -> bool {
|
|
|
|
c.is_ascii_digit()
|
|
|
|
}
|
|
|
|
|
2019-01-05 17:53:56 +01:00
|
|
|
fn is_ascii_digit_or_neg(c: char) -> bool {
|
|
|
|
c.is_ascii_digit() || c == '-'
|
|
|
|
}
|
|
|
|
|
2018-12-29 16:56:56 +01:00
|
|
|
fn is_ascii_hexdigit(c: char) -> bool {
|
|
|
|
c.is_ascii_hexdigit()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_u8(s: &str) -> Result<u8, std::num::ParseIntError> {
|
|
|
|
s.parse()
|
|
|
|
}
|
|
|
|
|
2019-01-05 13:02:20 +01:00
|
|
|
fn to_i64(s: &str) -> Result<i64, std::num::ParseIntError> {
|
2018-12-29 16:56:56 +01:00
|
|
|
s.parse()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_u64_hex(s: &str) -> Result<u64, std::num::ParseIntError> {
|
|
|
|
u64::from_str_radix(s, 16)
|
|
|
|
}
|
|
|
|
|
2019-01-05 17:53:56 +01:00
|
|
|
named!(parse_i64<&str, i64>,
|
|
|
|
map_res!(take_while!(is_ascii_digit_or_neg), to_i64)
|
|
|
|
);
|
|
|
|
|
|
|
|
named!(parse_u64_hex<&str, u64>,
|
|
|
|
map_res!(take_while!(is_ascii_hexdigit), to_u64_hex)
|
|
|
|
);
|
|
|
|
|
2018-12-29 16:56:56 +01:00
|
|
|
named!(parse_kind<&str, Kind>,
|
2018-12-29 18:34:23 +01:00
|
|
|
alt_complete!(
|
2018-12-29 16:56:56 +01:00
|
|
|
tag!("report") => { |_| Kind::Report } |
|
|
|
|
tag!("filter") => { |_| Kind::Filter }
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2019-01-05 17:53:56 +01:00
|
|
|
named!(parse_version<&str, u8>,
|
|
|
|
map_res!(take_while!(is_ascii_digit), to_u8)
|
|
|
|
);
|
|
|
|
|
|
|
|
named!(parse_timestamp<&str, TimeVal>,
|
|
|
|
do_parse!(
|
|
|
|
sec: parse_i64 >>
|
|
|
|
tag!(".") >>
|
|
|
|
usec: parse_i64 >>
|
|
|
|
(TimeVal { sec, usec})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2018-12-29 16:56:56 +01:00
|
|
|
named!(parse_subsystem<&str, Subsystem>,
|
2018-12-29 18:34:23 +01:00
|
|
|
alt_complete! (
|
|
|
|
tag!("smtp-in") => { |_| Subsystem::SmtpIn } |
|
|
|
|
tag!("smtp-out") => { |_| Subsystem::SmtpOut }
|
2018-12-29 16:56:56 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
named!(parse_event<&str, Event>,
|
2018-12-29 18:34:23 +01:00
|
|
|
alt_complete!(
|
|
|
|
tag!("link-connect") => { |_| Event::LinkConnect } |
|
|
|
|
tag!("link-disconnect") => { |_| Event::LinkDisconnect } |
|
|
|
|
tag!("link-identify") => { |_| Event::LinkIdentify } |
|
|
|
|
tag!("link-tls") => { |_| Event::LinkTls } |
|
|
|
|
tag!("tx-begin") => { |_| Event::TxBegin } |
|
2018-12-29 16:56:56 +01:00
|
|
|
tag!("tx-mail") => { |_| Event::TxMail } |
|
2018-12-29 18:34:23 +01:00
|
|
|
tag!("tx-rcpt") => { |_| Event::TxRcpt } |
|
|
|
|
tag!("tx-envelope") => { |_| Event::TxEnvelope } |
|
|
|
|
tag!("tx-data") => { |_| Event::TxData } |
|
|
|
|
tag!("tx-commit") => { |_| Event::TxCommit } |
|
|
|
|
tag!("tx-rollback") => { |_| Event::TxRollback } |
|
|
|
|
tag!("protocol-client") => { |_| Event::ProtocolClient } |
|
|
|
|
tag!("protocol-server") => { |_| Event::ProtocolServer } |
|
2019-01-05 11:40:19 +01:00
|
|
|
tag!("timeout") => { |_| Event::Timeout } |
|
2018-12-29 18:34:23 +01:00
|
|
|
tag!("filter-response") => { |_| Event::FilterResponse }
|
2018-12-29 16:56:56 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
named!(parse_token<&str, u64>,
|
|
|
|
do_parse!(
|
|
|
|
token: parse_u64_hex >>
|
|
|
|
tag!("|") >>
|
|
|
|
(token)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2019-01-05 11:40:19 +01:00
|
|
|
named!(parse_params<&str, String>,
|
|
|
|
do_parse!(
|
|
|
|
tag!("|") >>
|
|
|
|
s: take_until!("\n") >>
|
|
|
|
(s.to_string())
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2019-01-06 15:41:30 +01:00
|
|
|
named!(parse_entry<&str, Entry>,
|
2018-12-29 16:56:56 +01:00
|
|
|
do_parse!(
|
|
|
|
kind: parse_kind >>
|
|
|
|
tag!("|") >>
|
|
|
|
version: parse_version >>
|
|
|
|
tag!("|") >>
|
2019-01-05 11:40:19 +01:00
|
|
|
timestamp: parse_timestamp >>
|
2018-12-29 16:56:56 +01:00
|
|
|
tag!("|") >>
|
|
|
|
subsystem: parse_subsystem >>
|
|
|
|
tag!("|") >>
|
|
|
|
event: parse_event >>
|
|
|
|
tag!("|") >>
|
|
|
|
token: cond!(kind == Kind::Filter, parse_token) >>
|
|
|
|
session_id: parse_u64_hex >>
|
2019-01-05 11:40:19 +01:00
|
|
|
params: opt!(parse_params) >>
|
2018-12-29 16:56:56 +01:00
|
|
|
(Entry {
|
|
|
|
kind,
|
|
|
|
version,
|
|
|
|
timestamp,
|
|
|
|
subsystem,
|
|
|
|
event,
|
|
|
|
token,
|
|
|
|
session_id,
|
2019-01-05 17:53:56 +01:00
|
|
|
params,
|
2018-12-29 16:56:56 +01:00
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|