From 9f8232f7f1577b30ef42f4528c1570e847b60e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodolphe=20Br=C3=A9ard?= Date: Sun, 19 Mar 2023 19:06:29 +0100 Subject: [PATCH] Read entries --- Cargo.toml | 1 + src/entry.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ src/handshake.rs | 4 ++- src/main.rs | 33 +++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/entry.rs diff --git a/Cargo.toml b/Cargo.toml index e433ea2..584c1df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] +nom = "^7.1" diff --git a/src/entry.rs b/src/entry.rs new file mode 100644 index 0000000..81ca0fc --- /dev/null +++ b/src/entry.rs @@ -0,0 +1,82 @@ +use nom::bytes::streaming::{tag, take_till1, take_while1}; +use nom::IResult; + +#[derive(Debug)] +pub struct Entry { + session_id: String, + token: String, + data: Vec, +} + +impl Entry { + pub fn get_session_id(&self) -> &str { + &self.session_id + } + + pub fn get_token(&self) -> &str { + &self.token + } + + pub fn get_data(&self) -> &[u8] { + &self.data + } + + pub fn is_end_of_message(&self) -> bool { + self.data == vec![b'.'] + } + + pub fn from_bytes(input: &[u8]) -> Result { + let (_, entry) = parse_entry(input).map_err(|e| format!("parsing error: {e}"))?; + Ok(entry) + } +} + +fn is_eol(c: u8) -> bool { + c == b'\n' +} + +fn is_body_char(c: u8) -> bool { + !(c as char).is_control() +} + +fn is_parameter_char(c: u8) -> bool { + is_body_char(c) && (c as char) != '|' +} + +fn parse_string_parameter(input: &[u8]) -> IResult<&[u8], String> { + let (input, s) = take_while1(is_parameter_char)(input)?; + Ok((input, String::from_utf8(s.to_vec()).unwrap())) +} + +fn parse_delimiter(input: &[u8]) -> IResult<&[u8], &[u8]> { + tag("|")(input) +} + +fn parse_data(input: &[u8]) -> IResult<&[u8], Vec> { + let (input, s) = take_till1(is_eol)(input)?; + Ok((input, s.to_vec())) +} + +fn parse_entry(input: &[u8]) -> IResult<&[u8], Entry> { + let (input, _type) = tag("filter")(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, _version) = parse_string_parameter(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, _timestamp) = parse_string_parameter(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, _subsystem) = tag("smtp-in")(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, _phase) = tag("data-line")(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, session_id) = parse_string_parameter(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, token) = parse_string_parameter(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, data) = parse_data(input)?; + let entry = Entry { + session_id, + token, + data, + }; + Ok((input, entry)) +} diff --git a/src/handshake.rs b/src/handshake.rs index c293387..9086587 100644 --- a/src/handshake.rs +++ b/src/handshake.rs @@ -6,7 +6,9 @@ pub fn read_config() { let stdin = std::io::stdin(); loop { buffer.clear(); - stdin.read_line(&mut buffer).unwrap(); + if stdin.read_line(&mut buffer).unwrap() == 0 { + crate::eof(); + } let entry = buffer.trim_end(); if entry == CONFIG_END { return; diff --git a/src/main.rs b/src/main.rs index b0e76f1..255cacc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,39 @@ +mod entry; mod handshake; +use entry::Entry; +use std::io::{BufRead, BufReader}; + +const DEFAULT_BUFF_SIZE: usize = 1024; + fn main() { handshake::read_config(); handshake::register_filter(); + loop { + match read_line() { + Ok(entry) => { + if !entry.is_end_of_message() { + println!("Debug: {entry:?}"); + } else { + println!("Debug: end of message: {entry:?}"); + } + } + Err(err) => { + eprintln!("{err}"); + } + } + } +} + +pub fn read_line() -> Result { + let mut buffer = Vec::with_capacity(DEFAULT_BUFF_SIZE); + let mut stdin = BufReader::new(std::io::stdin()); + if stdin.read_until(b'\n', &mut buffer).unwrap() == 0 { + crate::eof(); + } + Entry::from_bytes(&buffer) +} + +fn eof() { + std::process::exit(0x2a) }