use crate::errors::Error; use nom::{alt, alt_complete, call, complete, cond, do_parse, error_position, map_res, named, opt, tag, take_until, take_while}; #[derive(Clone, Debug, PartialEq)] pub enum Kind { Report, Filter, } #[derive(Clone, Debug, PartialEq)] pub enum Subsystem { SmtpIn, SmtpOut, } #[derive(Clone, Debug, PartialEq)] pub enum Event { LinkConnect, LinkDisconnect, LinkIdentify, LinkTls, TxBegin, TxMail, TxRcpt, TxEnvelope, TxData, TxCommit, TxRollback, ProtocolClient, ProtocolServer, Timeout, FilterResponse, } #[derive(Debug)] pub struct TimeVal { pub sec: i64, pub usec: i64, } impl TimeVal { pub fn to_string(&self) -> String { format!("{}.{}", self.sec, self.usec) } } #[derive(Debug)] pub struct Entry { pub kind: Kind, pub version: u8, pub timestamp: TimeVal, pub subsystem: Subsystem, pub event: Event, pub token: Option, pub session_id: u64, pub params: Option, } impl Entry { pub fn from_str(entry: &str) -> Result { let (_, res) = parse_entry(entry)?; Ok(res) } } fn is_ascii_digit(c: char) -> bool { c.is_ascii_digit() } fn is_ascii_digit_or_neg(c: char) -> bool { c.is_ascii_digit() || c == '-' } fn is_ascii_hexdigit(c: char) -> bool { c.is_ascii_hexdigit() } fn to_u8(s: &str) -> Result { s.parse() } fn to_i64(s: &str) -> Result { s.parse() } fn to_u64_hex(s: &str) -> Result { u64::from_str_radix(s, 16) } 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) ); named!(parse_kind<&str, Kind>, alt_complete!( tag!("report") => { |_| Kind::Report } | tag!("filter") => { |_| Kind::Filter } ) ); 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}) ) ); named!(parse_subsystem<&str, Subsystem>, alt_complete! ( tag!("smtp-in") => { |_| Subsystem::SmtpIn } | tag!("smtp-out") => { |_| Subsystem::SmtpOut } ) ); named!(parse_event<&str, Event>, 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 } | tag!("tx-mail") => { |_| Event::TxMail } | 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 } | tag!("timeout") => { |_| Event::Timeout } | tag!("filter-response") => { |_| Event::FilterResponse } ) ); named!(parse_token<&str, u64>, do_parse!( token: parse_u64_hex >> tag!("|") >> (token) ) ); named!(parse_params<&str, String>, do_parse!( tag!("|") >> s: take_until!("\n") >> (s.to_string()) ) ); named!( parse_entry<&str, Entry>, do_parse!( kind: parse_kind >> tag!("|") >> version: parse_version >> tag!("|") >> timestamp: parse_timestamp >> tag!("|") >> subsystem: parse_subsystem >> tag!("|") >> event: parse_event >> tag!("|") >> token: cond!(kind == Kind::Filter, parse_token) >> session_id: parse_u64_hex >> params: opt!(parse_params) >> (Entry { kind, version, timestamp, subsystem, event, token, session_id, params, }) ) );