use abnf_core::streaming::CRLF;
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,
};
pub fn Return_path_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
let parser = tuple((tag_no_case(b"Return-Path:"), FWS, Reverse_path, CRLF));
let (remaining, parsed) = recognize(parser)(input)?;
Ok((remaining, parsed))
}
pub fn Time_stamp_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
let parser = tuple((tag_no_case(b"Received:"), FWS, Stamp, CRLF));
let (remaining, parsed) = recognize(parser)(input)?;
Ok((remaining, parsed))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
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))
}
pub fn Link(input: &[u8]) -> IResult<&[u8], &str> {
alt((map_res(tag_no_case("TCP"), std::str::from_utf8), Addtl_Link))(input)
}
pub fn Addtl_Link(input: &[u8]) -> IResult<&[u8], &str> {
Atom(input)
}
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)
}
pub fn Attdl_Protocol(input: &[u8]) -> IResult<&[u8], &str> {
Atom(input)
}