Remove unused parser code
This commit is contained in:
parent
a48a27a367
commit
263c2c16cd
|
@ -1,6 +1,6 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use instant_smtp::parse::command::command;
|
use instant_smtp::types::Command;
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
|
@ -8,7 +8,7 @@ fn main() -> std::io::Result<()> {
|
||||||
if let Some(path) = args.nth(1) {
|
if let Some(path) = args.nth(1) {
|
||||||
let data = std::fs::read(path).unwrap();
|
let data = std::fs::read(path).unwrap();
|
||||||
|
|
||||||
match command(&data) {
|
match Command::from_bytes(&data) {
|
||||||
Ok((remaining, command)) => {
|
Ok((remaining, command)) => {
|
||||||
println!("[!] {:#?}", command);
|
println!("[!] {:#?}", command);
|
||||||
let serialized = {
|
let serialized = {
|
||||||
|
@ -44,7 +44,7 @@ fn main() -> std::io::Result<()> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
match command(line.as_bytes()) {
|
match Command::from_bytes(line.as_bytes()) {
|
||||||
Ok((remaining, command)) => {
|
Ok((remaining, command)) => {
|
||||||
println!("[!] {:#?}", command);
|
println!("[!] {:#?}", command);
|
||||||
let serialized = {
|
let serialized = {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use instant_smtp::parse::command::command;
|
use instant_smtp::types::Command;
|
||||||
|
|
||||||
fuzz_target!(|data: &[u8]| {
|
fuzz_target!(|data: &[u8]| {
|
||||||
if let Ok((_, cmd)) = command(data) {
|
if let Ok((_, cmd)) = Command::from_bytes(data) {
|
||||||
// Fuzzer created a valid SMTP command.
|
// Fuzzer created a valid SMTP command.
|
||||||
// dbg!(&cmd);
|
// dbg!(&cmd);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ fuzz_target!(|data: &[u8]| {
|
||||||
cmd.serialize(&mut buf).unwrap();
|
cmd.serialize(&mut buf).unwrap();
|
||||||
|
|
||||||
// ... parse it again ...
|
// ... parse it again ...
|
||||||
let (rem, cmd2) = command(&buf).unwrap();
|
let (rem, cmd2) = Command::from_bytes(&buf).unwrap();
|
||||||
assert!(rem.is_empty());
|
assert!(rem.is_empty());
|
||||||
|
|
||||||
// dbg!(&cmd2);
|
// dbg!(&cmd2);
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod parse;
|
mod parse;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
610
src/parse/imf.rs
610
src/parse/imf.rs
|
@ -1,610 +0,0 @@
|
||||||
//! Internet Message Format (RFC 5322)
|
|
||||||
//!
|
|
||||||
//! TODO: replace this with an IMF library, e.g. rustyknife?
|
|
||||||
|
|
||||||
/// 3.2.1. Quoted characters
|
|
||||||
pub mod quoted_characters {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, take_while_m_n},
|
|
||||||
combinator::recognize,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::obsolete::obs_qp;
|
|
||||||
|
|
||||||
/// quoted-pair = ("\" (VCHAR / WSP)) / obs-qp
|
|
||||||
pub fn quoted_pair(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((
|
|
||||||
recognize(tuple((
|
|
||||||
tag(b"\\"),
|
|
||||||
alt((
|
|
||||||
take_while_m_n(1, 1, |byte| matches!(byte, 0x21..=0x7E)),
|
|
||||||
alt((tag(" "), tag("\t"))),
|
|
||||||
)),
|
|
||||||
))),
|
|
||||||
obs_qp,
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.2.2. Folding White Space and Comments
|
|
||||||
pub mod folding_ws_and_comment {
|
|
||||||
use nom::IResult;
|
|
||||||
|
|
||||||
/// Folding white space
|
|
||||||
///
|
|
||||||
/// FWS = ([*WSP CRLF] 1*WSP) / obs-FWS
|
|
||||||
pub fn FWS(_input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printable US-ASCII characters not including "(", ")", or "\"
|
|
||||||
//
|
|
||||||
// ctext = %d33-39 / %d42-91 / %d93-126 / obs-ctext
|
|
||||||
|
|
||||||
// ccontent = ctext / quoted-pair / comment
|
|
||||||
|
|
||||||
// comment = "(" *([FWS] ccontent) [FWS] ")"
|
|
||||||
|
|
||||||
/// CFWS = (1*([FWS] comment) [FWS]) / FWS
|
|
||||||
pub fn CFWS(_input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.2.3. Atom
|
|
||||||
pub mod atom {
|
|
||||||
use nom::{
|
|
||||||
bytes::streaming::{tag, take_while1},
|
|
||||||
character::{is_alphabetic, is_digit},
|
|
||||||
combinator::{opt, recognize},
|
|
||||||
multi::many0,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::folding_ws_and_comment::CFWS;
|
|
||||||
|
|
||||||
/// Printable US-ASCII characters not including specials.
|
|
||||||
/// Used for atoms.
|
|
||||||
///
|
|
||||||
/// atext = ALPHA / DIGIT /
|
|
||||||
/// "!" / "#" /
|
|
||||||
/// "$" / "%" /
|
|
||||||
/// "&" / "'" /
|
|
||||||
/// "*" / "+" /
|
|
||||||
/// "-" / "/" /
|
|
||||||
/// "=" / "?" /
|
|
||||||
/// "^" / "_" /
|
|
||||||
/// "`" / "{" /
|
|
||||||
/// "|" / "}" /
|
|
||||||
/// "~"
|
|
||||||
pub fn is_atext(byte: u8) -> bool {
|
|
||||||
let allowed = b"!#$%&'*+-/=?^_`{|}~";
|
|
||||||
|
|
||||||
is_alphabetic(byte) || is_digit(byte) || allowed.contains(&byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// atom = [CFWS] 1*atext [CFWS]
|
|
||||||
pub fn atom(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((opt(CFWS), take_while1(is_atext), opt(CFWS)));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dot-atom-text = 1*atext *("." 1*atext)
|
|
||||||
pub fn dot_atom_text(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
take_while1(is_atext),
|
|
||||||
many0(tuple((tag(b"."), take_while1(is_atext)))),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// dot-atom = [CFWS] dot-atom-text [CFWS]
|
|
||||||
pub fn dot_atom(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((opt(CFWS), dot_atom_text, opt(CFWS)));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special characters that do not appear in atext.
|
|
||||||
//
|
|
||||||
// specials = "(" / ")" /
|
|
||||||
// "<" / ">" /
|
|
||||||
// "[" / "]" /
|
|
||||||
// ":" / ";" /
|
|
||||||
// "@" / "\" /
|
|
||||||
// "," / "." /
|
|
||||||
// DQUOTE
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.2.4. Quoted Strings
|
|
||||||
pub mod quoted_strings {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, take_while_m_n},
|
|
||||||
combinator::{opt, recognize},
|
|
||||||
multi::many0,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
folding_ws_and_comment::{CFWS, FWS},
|
|
||||||
obsolete::is_obs_qtext,
|
|
||||||
quoted_characters::quoted_pair,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Printable US-ASCII characters not including "\" or the quote character.
|
|
||||||
///
|
|
||||||
/// qtext = %d33 / %d35-91 / %d93-126 / obs-qtext
|
|
||||||
pub fn is_qtext(byte: u8) -> bool {
|
|
||||||
match byte {
|
|
||||||
33 | 35..=91 | 93..=126 => true,
|
|
||||||
_ if is_obs_qtext(byte) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// qcontent = qtext / quoted-pair
|
|
||||||
pub fn qcontent(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((take_while_m_n(1, 1, is_qtext), quoted_pair));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]
|
|
||||||
pub fn quoted_string(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
opt(CFWS),
|
|
||||||
tag("\""),
|
|
||||||
many0(tuple((opt(FWS), qcontent))),
|
|
||||||
opt(FWS),
|
|
||||||
tag("\""),
|
|
||||||
opt(CFWS),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.2.5. Miscellaneous Tokens
|
|
||||||
pub mod miscellaneous {
|
|
||||||
use nom::{branch::alt, IResult};
|
|
||||||
|
|
||||||
use super::{atom::atom, quoted_strings::quoted_string};
|
|
||||||
|
|
||||||
/// word = atom / quoted-string
|
|
||||||
pub fn word(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
alt((atom, quoted_string))(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
// phrase = 1*word / obs-phrase
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// unstructured = (*([FWS] VCHAR) *WSP) / obs-unstruct
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.3. Date and Time Specification
|
|
||||||
pub mod datetime {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, tag_no_case, take_while_m_n},
|
|
||||||
character::is_digit,
|
|
||||||
combinator::{opt, recognize},
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::folding_ws_and_comment::{CFWS, FWS};
|
|
||||||
|
|
||||||
// date-time = [ day-of-week "," ] date time [CFWS]
|
|
||||||
pub fn date_time(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((opt(tuple((day_of_week, tag(b",")))), date, time, opt(CFWS)));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// day-of-week = ([FWS] day-name) / obs-day-of-week
|
|
||||||
pub fn day_of_week(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((opt(FWS), day_name));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
|
|
||||||
pub fn day_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((
|
|
||||||
tag_no_case(b"Mon"),
|
|
||||||
tag_no_case(b"Tue"),
|
|
||||||
tag_no_case(b"Wed"),
|
|
||||||
tag_no_case(b"Thu"),
|
|
||||||
tag_no_case(b"Fri"),
|
|
||||||
tag_no_case(b"Sat"),
|
|
||||||
tag_no_case(b"Sun"),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// date = day month year
|
|
||||||
pub fn date(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((day, month, year));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// day = ([FWS] 1*2DIGIT FWS) / obs-day
|
|
||||||
pub fn day(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((opt(FWS), take_while_m_n(1, 2, is_digit), FWS));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
|
|
||||||
pub fn month(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((
|
|
||||||
tag_no_case(b"Jan"),
|
|
||||||
tag_no_case(b"Feb"),
|
|
||||||
tag_no_case(b"Mar"),
|
|
||||||
tag_no_case(b"Apr"),
|
|
||||||
tag_no_case(b"May"),
|
|
||||||
tag_no_case(b"Jun"),
|
|
||||||
tag_no_case(b"Jul"),
|
|
||||||
tag_no_case(b"Aug"),
|
|
||||||
tag_no_case(b"Sep"),
|
|
||||||
tag_no_case(b"Oct"),
|
|
||||||
tag_no_case(b"Nov"),
|
|
||||||
tag_no_case(b"Dec"),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// year = (FWS 4*DIGIT FWS) / obs-year
|
|
||||||
pub fn year(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((FWS, take_while_m_n(4, 8, is_digit), FWS)); // FIXME: 4*?!
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// time = time-of-day zone
|
|
||||||
pub fn time(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((time_of_day, zone));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// time-of-day = hour ":" minute [ ":" second ]
|
|
||||||
pub fn time_of_day(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((hour, tag(b":"), minute, opt(tuple((tag(b":"), second)))));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// hour = 2DIGIT / obs-hour
|
|
||||||
pub fn hour(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
// FIXME: obs- forms must not be used in SMTP. Never?
|
|
||||||
|
|
||||||
let parser = take_while_m_n(2, 2, is_digit);
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// minute = 2DIGIT / obs-minute
|
|
||||||
pub fn minute(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
// FIXME: obs- forms must not be used in SMTP. Never?
|
|
||||||
|
|
||||||
let parser = take_while_m_n(2, 2, is_digit);
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// second = 2DIGIT / obs-second
|
|
||||||
pub fn second(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
// FIXME: obs- forms must not be used in SMTP. Never?
|
|
||||||
|
|
||||||
let parser = take_while_m_n(2, 2, is_digit);
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// zone = (FWS ( "+" / "-" ) 4DIGIT) / obs-zone
|
|
||||||
pub fn zone(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
// FIXME: obs- forms must not be used in SMTP. Never?
|
|
||||||
|
|
||||||
let parser = tuple((
|
|
||||||
FWS,
|
|
||||||
alt((tag(b"+"), tag(b"-"))),
|
|
||||||
take_while_m_n(4, 4, is_digit),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.4.1. Addr-Spec Specification
|
|
||||||
pub mod addr_spec {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, take_while_m_n},
|
|
||||||
combinator::{opt, recognize},
|
|
||||||
multi::many0,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
atom::dot_atom,
|
|
||||||
folding_ws_and_comment::{CFWS, FWS},
|
|
||||||
obsolete::{obs_domain, obs_dtext, obs_local_part},
|
|
||||||
quoted_strings::quoted_string,
|
|
||||||
};
|
|
||||||
|
|
||||||
// addr-spec = local-part "@" domain
|
|
||||||
|
|
||||||
/// local-part = dot-atom / quoted-string / obs-local-part
|
|
||||||
pub fn local_part(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((dot_atom, quoted_string, obs_local_part));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// domain = dot-atom / domain-literal / obs-domain
|
|
||||||
pub fn domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((dot_atom, domain_literal, obs_domain));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
|
|
||||||
pub fn domain_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
opt(CFWS),
|
|
||||||
tag(b"["),
|
|
||||||
many0(tuple((opt(FWS), dtext))),
|
|
||||||
opt(FWS),
|
|
||||||
tag(b"]"),
|
|
||||||
opt(CFWS),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Printable US-ASCII characters not including "[", "]", or "\".
|
|
||||||
///
|
|
||||||
/// dtext = %d33-90 / %d94-126 / obs-dtext
|
|
||||||
pub fn dtext(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
fn is_a(byte: u8) -> bool {
|
|
||||||
matches!(byte, 33..=90)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_b(byte: u8) -> bool {
|
|
||||||
matches!(byte, 94..=126)
|
|
||||||
}
|
|
||||||
|
|
||||||
let parser = alt((
|
|
||||||
take_while_m_n(1, 1, is_a),
|
|
||||||
take_while_m_n(1, 1, is_b),
|
|
||||||
obs_dtext,
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3.6.4. Identification Fields
|
|
||||||
pub mod identification {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::tag,
|
|
||||||
combinator::{opt, recognize},
|
|
||||||
multi::many0,
|
|
||||||
sequence::{delimited, tuple},
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
addr_spec::dtext,
|
|
||||||
atom::dot_atom_text,
|
|
||||||
folding_ws_and_comment::CFWS,
|
|
||||||
obsolete::{obs_id_left, obs_id_right},
|
|
||||||
};
|
|
||||||
|
|
||||||
// message-id = "Message-ID:" msg-id CRLF
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// in-reply-to = "In-Reply-To:" 1*msg-id CRLF
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// references = "References:" 1*msg-id CRLF
|
|
||||||
// ...
|
|
||||||
|
|
||||||
/// msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
|
|
||||||
pub fn msg_id(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
opt(CFWS),
|
|
||||||
tag(b"<"),
|
|
||||||
id_left,
|
|
||||||
tag(b"@"),
|
|
||||||
id_right,
|
|
||||||
tag(b">"),
|
|
||||||
opt(CFWS),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// id-left = dot-atom-text / obs-id-left
|
|
||||||
pub fn id_left(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((dot_atom_text, obs_id_left));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// id-right = dot-atom-text / no-fold-literal / obs-id-right
|
|
||||||
pub fn id_right(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((dot_atom_text, no_fold_literal, obs_id_right));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// no-fold-literal = "[" *dtext "]"
|
|
||||||
pub fn no_fold_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = delimited(tag(b"["), many0(dtext), tag(b"]"));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 4.1. Miscellaneous Obsolete Tokens
|
|
||||||
pub mod obsolete {
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, take_while_m_n},
|
|
||||||
combinator::recognize,
|
|
||||||
multi::many0,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
addr_spec::{domain, local_part},
|
|
||||||
atom::atom,
|
|
||||||
miscellaneous::word,
|
|
||||||
quoted_characters::quoted_pair,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// US-ASCII control characters that do not include the carriage
|
|
||||||
/// return, line feed, and white space characters
|
|
||||||
///
|
|
||||||
/// obs-NO-WS-CTL = %d1-8 / %d11 / %d12 / %d14-31 / %d127
|
|
||||||
pub fn is_obs_NO_WS_CTL(byte: u8) -> bool {
|
|
||||||
matches!(byte, 1..=8 | 11 | 12 | 14..=31 | 127)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// obs-qtext = obs-NO-WS-CTL
|
|
||||||
pub fn is_obs_qtext(byte: u8) -> bool {
|
|
||||||
is_obs_NO_WS_CTL(byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR)
|
|
||||||
pub fn obs_qp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
tag(b"\\"),
|
|
||||||
alt((
|
|
||||||
take_while_m_n(1, 1, |x| x == 0x00),
|
|
||||||
take_while_m_n(1, 1, is_obs_NO_WS_CTL),
|
|
||||||
tag("\n"),
|
|
||||||
tag("\r"),
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4.4. Obsolete Addressing (RFC 5322)
|
|
||||||
|
|
||||||
/// obs-local-part = word *("." word)
|
|
||||||
pub fn obs_local_part(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((word, many0(tuple((tag(b"."), word)))));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// obs-domain = atom *("." atom)
|
|
||||||
pub fn obs_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((atom, many0(tuple((tag(b"."), atom)))));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// obs-dtext = obs-NO-WS-CTL / quoted-pair
|
|
||||||
pub fn obs_dtext(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((take_while_m_n(1, 1, is_obs_NO_WS_CTL), quoted_pair));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4.5.4. Obsolete Identification Fields (RFC 5322)
|
|
||||||
|
|
||||||
/// obs-id-left = local-part
|
|
||||||
pub fn obs_id_left(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
local_part(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// obs-id-right = domain
|
|
||||||
pub fn obs_id_right(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
domain(input)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,13 +13,11 @@ use nom::{
|
||||||
IResult,
|
IResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{parse::imf::atom::is_atext, types::AtomOrQuoted};
|
use crate::types::AtomOrQuoted;
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod imf;
|
|
||||||
pub mod response;
|
pub mod response;
|
||||||
pub mod trace;
|
|
||||||
|
|
||||||
pub fn base64(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn base64(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
let mut parser = map_res(
|
let mut parser = map_res(
|
||||||
|
@ -58,6 +56,26 @@ pub fn Atom(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
map_res(take_while1(is_atext), std::str::from_utf8)(input)
|
map_res(take_while1(is_atext), std::str::from_utf8)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Printable US-ASCII characters not including specials.
|
||||||
|
/// Used for atoms.
|
||||||
|
///
|
||||||
|
/// atext = ALPHA / DIGIT /
|
||||||
|
/// "!" / "#" /
|
||||||
|
/// "$" / "%" /
|
||||||
|
/// "&" / "'" /
|
||||||
|
/// "*" / "+" /
|
||||||
|
/// "-" / "/" /
|
||||||
|
/// "=" / "?" /
|
||||||
|
/// "^" / "_" /
|
||||||
|
/// "`" / "{" /
|
||||||
|
/// "|" / "}" /
|
||||||
|
/// "~"
|
||||||
|
pub fn is_atext(byte: u8) -> bool {
|
||||||
|
let allowed = b"!#$%&'*+-/=?^_`{|}~";
|
||||||
|
|
||||||
|
is_alphabetic(byte) || is_digit(byte) || allowed.contains(&byte)
|
||||||
|
}
|
||||||
|
|
||||||
/// Quoted-string = DQUOTE *QcontentSMTP DQUOTE
|
/// Quoted-string = DQUOTE *QcontentSMTP DQUOTE
|
||||||
pub fn Quoted_string(input: &[u8]) -> IResult<&[u8], Cow<'_, str>> {
|
pub fn Quoted_string(input: &[u8]) -> IResult<&[u8], Cow<'_, str>> {
|
||||||
map(
|
map(
|
||||||
|
|
|
@ -1,218 +0,0 @@
|
||||||
/// 4.4. Trace Information (RFC 5321)
|
|
||||||
use nom::{
|
|
||||||
branch::alt,
|
|
||||||
bytes::streaming::{tag, tag_no_case},
|
|
||||||
combinator::{map_res, opt, recognize},
|
|
||||||
multi::many1,
|
|
||||||
sequence::tuple,
|
|
||||||
IResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::parse::{
|
|
||||||
address::address_literal,
|
|
||||||
command::{Mailbox, Path, Reverse_path},
|
|
||||||
imf::{
|
|
||||||
datetime::date_time,
|
|
||||||
folding_ws_and_comment::{CFWS, FWS},
|
|
||||||
identification::msg_id,
|
|
||||||
},
|
|
||||||
Atom, Domain, String,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Return-path-line = "Return-Path:" FWS Reverse-path <CRLF>
|
|
||||||
pub fn Return_path_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((tag_no_case(b"Return-Path:"), FWS, Reverse_path, tag("\r\n")));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Time-stamp-line = "Received:" FWS Stamp <CRLF>
|
|
||||||
pub fn Time_stamp_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((tag_no_case(b"Received:"), FWS, Stamp, tag("\r\n")));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stamp = From-domain By-domain Opt-info [CFWS] ";" FWS date-time
|
|
||||||
///
|
|
||||||
/// Caution: Where "date-time" is as defined in RFC 5322 [4]
|
|
||||||
/// but the "obs-" forms, especially two-digit
|
|
||||||
/// years, are prohibited in SMTP and MUST NOT be used.
|
|
||||||
pub fn Stamp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
From_domain,
|
|
||||||
By_domain,
|
|
||||||
Opt_info,
|
|
||||||
opt(CFWS),
|
|
||||||
tag(b";"),
|
|
||||||
FWS,
|
|
||||||
date_time,
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// From-domain = "FROM" FWS Extended-Domain
|
|
||||||
pub fn From_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((tag_no_case(b"FROM"), FWS, Extended_Domain));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// By-domain = CFWS "BY" FWS Extended-Domain
|
|
||||||
pub fn By_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((CFWS, tag_no_case(b"BY"), FWS, Extended_Domain));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extended-Domain = Domain /
|
|
||||||
/// ( Domain FWS "(" TCP-info ")" ) /
|
|
||||||
/// ( address-literal FWS "(" TCP-info ")" )
|
|
||||||
pub fn Extended_Domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((
|
|
||||||
recognize(Domain),
|
|
||||||
recognize(tuple((Domain, FWS, tag(b"("), TCP_info, tag(b")")))),
|
|
||||||
recognize(tuple((
|
|
||||||
address_literal,
|
|
||||||
FWS,
|
|
||||||
tag(b"("),
|
|
||||||
TCP_info,
|
|
||||||
tag(b")"),
|
|
||||||
))),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information derived by server from TCP connection not client EHLO.
|
|
||||||
///
|
|
||||||
/// TCP-info = address-literal / ( Domain FWS address-literal )
|
|
||||||
pub fn TCP_info(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = alt((
|
|
||||||
recognize(address_literal),
|
|
||||||
recognize(tuple((Domain, FWS, address_literal))),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Opt-info = [Via] [With] [ID] [For] [Additional-Registered-Clauses]
|
|
||||||
pub fn Opt_info(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
opt(Via),
|
|
||||||
opt(With),
|
|
||||||
opt(ID),
|
|
||||||
opt(For),
|
|
||||||
opt(Additional_Registered_Clauses),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Via = CFWS "VIA" FWS Link
|
|
||||||
pub fn Via(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((CFWS, tag_no_case(b"VIA"), FWS, Link));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// With = CFWS "WITH" FWS Protocol
|
|
||||||
pub fn With(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((CFWS, tag_no_case(b"WITH"), FWS, Protocol));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ID = CFWS "ID" FWS ( Atom / msg-id )
|
|
||||||
/// ; msg-id is defined in RFC 5322 [4]
|
|
||||||
pub fn ID(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
CFWS,
|
|
||||||
tag_no_case(b"ID"),
|
|
||||||
FWS,
|
|
||||||
recognize(alt((recognize(Atom), msg_id))),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For = CFWS "FOR" FWS ( Path / Mailbox )
|
|
||||||
pub fn For(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = tuple((
|
|
||||||
CFWS,
|
|
||||||
tag_no_case(b"FOR"),
|
|
||||||
FWS,
|
|
||||||
alt((recognize(Path), Mailbox)),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional standard clauses may be added in this location by future standards and registration with
|
|
||||||
/// IANA. SMTP servers SHOULD NOT use unregistered names. See Section 8.
|
|
||||||
///
|
|
||||||
/// Additional-Registered-Clauses = CFWS Atom FWS String
|
|
||||||
pub fn Additional_Registered_Clauses(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
||||||
let parser = many1(tuple((CFWS, Atom, FWS, String)));
|
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
|
||||||
|
|
||||||
Ok((remaining, parsed))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Link = "TCP" / Addtl-Link
|
|
||||||
pub fn Link(input: &[u8]) -> IResult<&[u8], &str> {
|
|
||||||
alt((map_res(tag_no_case("TCP"), std::str::from_utf8), Addtl_Link))(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional standard names for links are registered with the Internet Assigned Numbers
|
|
||||||
/// Authority (IANA). "Via" is primarily of value with non-Internet transports. SMTP servers
|
|
||||||
/// SHOULD NOT use unregistered names.
|
|
||||||
///
|
|
||||||
/// Addtl-Link = Atom
|
|
||||||
pub fn Addtl_Link(input: &[u8]) -> IResult<&[u8], &str> {
|
|
||||||
Atom(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Protocol = "ESMTP" / "SMTP" / Attdl-Protocol
|
|
||||||
pub fn Protocol(input: &[u8]) -> IResult<&[u8], &str> {
|
|
||||||
alt((
|
|
||||||
map_res(tag_no_case(b"ESMTP"), std::str::from_utf8),
|
|
||||||
map_res(tag_no_case(b"SMTP"), std::str::from_utf8),
|
|
||||||
Attdl_Protocol,
|
|
||||||
))(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Additional standard names for protocols are registered with the Internet Assigned Numbers
|
|
||||||
/// Authority (IANA) in the "mail parameters" registry [9]. SMTP servers SHOULD NOT
|
|
||||||
/// use unregistered names.
|
|
||||||
///
|
|
||||||
/// Attdl-Protocol = Atom
|
|
||||||
pub fn Attdl_Protocol(input: &[u8]) -> IResult<&[u8], &str> {
|
|
||||||
Atom(input)
|
|
||||||
}
|
|
19
src/types.rs
19
src/types.rs
|
@ -1,5 +1,6 @@
|
||||||
use std::{borrow::Cow, fmt, io::Write, ops::Deref};
|
use std::{borrow::Cow, fmt, io::Write, ops::Deref};
|
||||||
|
|
||||||
|
use nom::IResult;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -95,6 +96,12 @@ pub enum Command {
|
||||||
AuthPlain(Option<String>),
|
AuthPlain(Option<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn from_bytes(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
|
crate::parse::command::command(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum DomainOrAddress {
|
pub enum DomainOrAddress {
|
||||||
Domain(String),
|
Domain(String),
|
||||||
|
@ -308,6 +315,10 @@ pub enum Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
|
pub fn parse_greeting(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
|
crate::parse::response::Greeting(input)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn greeting<D, T>(domain: D, text: T) -> Response
|
pub fn greeting<D, T>(domain: D, text: T) -> Response
|
||||||
where
|
where
|
||||||
D: Into<String>,
|
D: Into<String>,
|
||||||
|
@ -319,6 +330,14 @@ impl Response {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_ehlo(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
|
crate::parse::response::ehlo_ok_rsp(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_other(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
|
crate::parse::response::Reply_lines(input)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ehlo<D, G>(domain: D, greet: Option<G>, capabilities: Vec<Capability>) -> Response
|
pub fn ehlo<D, G>(domain: D, greet: Option<G>, capabilities: Vec<Capability>) -> Response
|
||||||
where
|
where
|
||||||
D: Into<String>,
|
D: Into<String>,
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
use instant_smtp::{
|
use instant_smtp::types::{Command, Response};
|
||||||
parse::{
|
|
||||||
command::command,
|
|
||||||
response::{ehlo_ok_rsp, Greeting, Reply_lines},
|
|
||||||
},
|
|
||||||
types::Command,
|
|
||||||
};
|
|
||||||
use nom::FindSubstring;
|
use nom::FindSubstring;
|
||||||
|
|
||||||
fn parse_trace(mut trace: &[u8]) {
|
fn parse_trace(mut trace: &[u8]) {
|
||||||
let (rem, greeting) = Greeting(trace).unwrap();
|
let (rem, greeting) = Response::parse_greeting(trace).unwrap();
|
||||||
println!("S: {:?}", greeting);
|
println!("S: {:?}", greeting);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
|
|
||||||
|
@ -17,18 +11,18 @@ fn parse_trace(mut trace: &[u8]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (rem, cmd) = command(trace).unwrap();
|
let (rem, cmd) = Command::from_bytes(trace).unwrap();
|
||||||
println!("C: {:?}", cmd);
|
println!("C: {:?}", cmd);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
|
|
||||||
match cmd {
|
match cmd {
|
||||||
Command::Ehlo { .. } => {
|
Command::Ehlo { .. } => {
|
||||||
let (rem, rsp) = ehlo_ok_rsp(trace).unwrap();
|
let (rem, rsp) = Response::parse_ehlo(trace).unwrap();
|
||||||
println!("S: {:?}", rsp);
|
println!("S: {:?}", rsp);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
}
|
}
|
||||||
Command::Data { .. } => {
|
Command::Data { .. } => {
|
||||||
let (rem, rsp) = Reply_lines(trace).unwrap();
|
let (rem, rsp) = Response::parse_other(trace).unwrap();
|
||||||
println!("S: {:?}", rsp);
|
println!("S: {:?}", rsp);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
|
|
||||||
|
@ -37,12 +31,12 @@ fn parse_trace(mut trace: &[u8]) {
|
||||||
println!("C (data): <{}>", std::str::from_utf8(data).unwrap());
|
println!("C (data): <{}>", std::str::from_utf8(data).unwrap());
|
||||||
trace = rem;
|
trace = rem;
|
||||||
|
|
||||||
let (rem, rsp) = Reply_lines(trace).unwrap();
|
let (rem, rsp) = Response::parse_other(trace).unwrap();
|
||||||
println!("S: {:?}", rsp);
|
println!("S: {:?}", rsp);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (rem, rsp) = Reply_lines(trace).unwrap();
|
let (rem, rsp) = Response::parse_other(trace).unwrap();
|
||||||
println!("S: {:?}", rsp);
|
println!("S: {:?}", rsp);
|
||||||
trace = rem;
|
trace = rem;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue