Get rid of unnecessary dependency

This commit is contained in:
Dirkjan Ochtman 2022-11-21 14:46:53 -08:00
parent db7fd2300f
commit e7cf12b4a0
7 changed files with 110 additions and 97 deletions

View File

@ -9,5 +9,4 @@ edition = "2021"
[dependencies]
nom = "7"
abnf-core = "0.5"
serde = { version = "1.0", features = ["derive"], optional = true }

View File

@ -1,10 +1,9 @@
//! 4.1.3. Address Literals (RFC 5321)
use abnf_core::streaming::is_DIGIT;
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case, take_while1, take_while_m_n},
character::is_hex_digit,
character::{is_digit, is_hex_digit},
combinator::{map_res, opt, recognize},
multi::{count, many_m_n},
sequence::{delimited, tuple},
@ -47,7 +46,7 @@ pub fn IPv4_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
///
/// Snum = 1*3DIGIT
pub fn Snum(input: &[u8]) -> IResult<&[u8], &[u8]> {
take_while_m_n(1, 3, is_DIGIT)(input)
take_while_m_n(1, 3, is_digit)(input)
}
/// IPv6-address-literal = "IPv6:" IPv6-addr

View File

@ -1,7 +1,7 @@
use abnf_core::streaming::{is_ALPHA, is_DIGIT, CRLF, SP};
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case, take_while, take_while1, take_while_m_n},
character::{is_alphabetic, is_digit},
combinator::{map, map_res, opt, recognize, value},
multi::separated_list1,
sequence::{delimited, preceded, tuple},
@ -22,18 +22,18 @@ pub fn command(input: &[u8]) -> IResult<&[u8], Command> {
))(input)
}
/// helo = "HELO" SP Domain CRLF
/// helo = "HELO" tag(" ") Domain CRLF
pub fn helo(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"HELO"),
SP,
tag(" "),
alt((
map(Domain, |domain| DomainOrAddress::Domain(domain.into())),
map(address_literal, |address| {
DomainOrAddress::Address(address.into())
}),
)),
CRLF,
tag("\r\n"),
));
let (remaining, (_, _, domain_or_address, _)) = parser(input)?;
@ -41,18 +41,18 @@ pub fn helo(input: &[u8]) -> IResult<&[u8], Command> {
Ok((remaining, Command::Helo { domain_or_address }))
}
/// ehlo = "EHLO" SP ( Domain / address-literal ) CRLF
/// ehlo = "EHLO" tag(" ") ( Domain / address-literal ) CRLF
pub fn ehlo(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"EHLO"),
SP,
tag(" "),
alt((
map(Domain, |domain| DomainOrAddress::Domain(domain.into())),
map(address_literal, |address| {
DomainOrAddress::Address(address.into())
}),
)),
CRLF,
tag("\r\n"),
));
let (remaining, (_, _, domain_or_address, _)) = parser(input)?;
@ -60,14 +60,14 @@ pub fn ehlo(input: &[u8]) -> IResult<&[u8], Command> {
Ok((remaining, Command::Ehlo { domain_or_address }))
}
/// mail = "MAIL FROM:" Reverse-path [SP Mail-parameters] CRLF
/// mail = "MAIL FROM:" Reverse-path [tag(" ") Mail-parameters] CRLF
pub fn mail(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"MAIL FROM:"),
opt(SP), // Out-of-Spec, but Outlook does it ...
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
Reverse_path,
opt(preceded(SP, Mail_parameters)),
CRLF,
opt(preceded(tag(" "), Mail_parameters)),
tag("\r\n"),
));
let (remaining, (_, _, data, maybe_params, _)) = parser(input)?;
@ -81,9 +81,9 @@ pub fn mail(input: &[u8]) -> IResult<&[u8], Command> {
))
}
/// Mail-parameters = esmtp-param *(SP esmtp-param)
/// Mail-parameters = esmtp-param *(tag(" ") esmtp-param)
pub fn Mail_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
separated_list1(SP, esmtp_param)(input)
separated_list1(tag(" "), esmtp_param)(input)
}
/// esmtp-param = esmtp-keyword ["=" esmtp-value]
@ -105,8 +105,8 @@ pub fn esmtp_param(input: &[u8]) -> IResult<&[u8], Parameter> {
/// esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
pub fn esmtp_keyword(input: &[u8]) -> IResult<&[u8], &str> {
let parser = tuple((
take_while_m_n(1, 1, |byte| is_ALPHA(byte) || is_DIGIT(byte)),
take_while(|byte| is_ALPHA(byte) || is_DIGIT(byte) || byte == b'-'),
take_while_m_n(1, 1, |byte| is_alphabetic(byte) || is_digit(byte)),
take_while(|byte| is_alphabetic(byte) || is_digit(byte) || byte == b'-'),
));
let (remaining, parsed) = map_res(recognize(parser), std::str::from_utf8)(input)?;
@ -114,7 +114,7 @@ pub fn esmtp_keyword(input: &[u8]) -> IResult<&[u8], &str> {
Ok((remaining, parsed))
}
/// Any CHAR excluding "=", SP, and control characters.
/// Any CHAR excluding "=", tag(" "), and control characters.
/// If this string is an email address, i.e., a Mailbox,
/// then the "xtext" syntax [32] SHOULD be used.
///
@ -127,7 +127,7 @@ pub fn esmtp_value(input: &[u8]) -> IResult<&[u8], &str> {
map_res(take_while1(is_value_character), std::str::from_utf8)(input)
}
/// rcpt = "RCPT TO:" ( "<Postmaster@" Domain ">" / "<Postmaster>" / Forward-path ) [SP Rcpt-parameters] CRLF
/// rcpt = "RCPT TO:" ( "<Postmaster@" Domain ">" / "<Postmaster>" / Forward-path ) [tag(" ") Rcpt-parameters] CRLF
///
/// Note that, in a departure from the usual rules for
/// local-parts, the "Postmaster" string shown above is
@ -135,7 +135,7 @@ pub fn esmtp_value(input: &[u8]) -> IResult<&[u8], &str> {
pub fn rcpt(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"RCPT TO:"),
opt(SP), // Out-of-Spec, but Outlook does it ...
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
alt((
map_res(
recognize(tuple((tag_no_case("<Postmaster@"), Domain, tag(">")))),
@ -144,8 +144,8 @@ pub fn rcpt(input: &[u8]) -> IResult<&[u8], Command> {
map_res(tag_no_case("<Postmaster>"), std::str::from_utf8),
Forward_path,
)),
opt(preceded(SP, Rcpt_parameters)),
CRLF,
opt(preceded(tag(" "), Rcpt_parameters)),
tag("\r\n"),
));
let (remaining, (_, _, data, maybe_params, _)) = parser(input)?;
@ -159,24 +159,24 @@ pub fn rcpt(input: &[u8]) -> IResult<&[u8], Command> {
))
}
/// Rcpt-parameters = esmtp-param *(SP esmtp-param)
/// Rcpt-parameters = esmtp-param *(tag(" ") esmtp-param)
pub fn Rcpt_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
separated_list1(SP, esmtp_param)(input)
separated_list1(tag(" "), esmtp_param)(input)
}
/// data = "DATA" CRLF
pub fn data(input: &[u8]) -> IResult<&[u8], Command> {
value(Command::Data, tuple((tag_no_case(b"DATA"), CRLF)))(input)
value(Command::Data, tuple((tag_no_case(b"DATA"), tag("\r\n"))))(input)
}
/// rset = "RSET" CRLF
pub fn rset(input: &[u8]) -> IResult<&[u8], Command> {
value(Command::Rset, tuple((tag_no_case(b"RSET"), CRLF)))(input)
value(Command::Rset, tuple((tag_no_case(b"RSET"), tag("\r\n"))))(input)
}
/// vrfy = "VRFY" SP String CRLF
/// vrfy = "VRFY" tag(" ") String CRLF
pub fn vrfy(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((tag_no_case(b"VRFY"), SP, String, CRLF));
let mut parser = tuple((tag_no_case(b"VRFY"), tag(" "), String, tag("\r\n")));
let (remaining, (_, _, data, _)) = parser(input)?;
@ -188,18 +188,22 @@ pub fn vrfy(input: &[u8]) -> IResult<&[u8], Command> {
))
}
/// expn = "EXPN" SP String CRLF
/// expn = "EXPN" tag(" ") String CRLF
pub fn expn(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((tag_no_case(b"EXPN"), SP, String, CRLF));
let mut parser = tuple((tag_no_case(b"EXPN"), tag(" "), String, tag("\r\n")));
let (remaining, (_, _, data, _)) = parser(input)?;
Ok((remaining, Command::Expn { mailing_list: data }))
}
/// help = "HELP" [ SP String ] CRLF
/// help = "HELP" [ tag(" ") String ] CRLF
pub fn help(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((tag_no_case(b"HELP"), opt(preceded(SP, String)), CRLF));
let mut parser = tuple((
tag_no_case(b"HELP"),
opt(preceded(tag(" "), String)),
tag("\r\n"),
));
let (remaining, (_, maybe_data, _)) = parser(input)?;
@ -211,9 +215,13 @@ pub fn help(input: &[u8]) -> IResult<&[u8], Command> {
))
}
/// noop = "NOOP" [ SP String ] CRLF
/// noop = "NOOP" [ tag(" ") String ] CRLF
pub fn noop(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((tag_no_case(b"NOOP"), opt(preceded(SP, String)), CRLF));
let mut parser = tuple((
tag_no_case(b"NOOP"),
opt(preceded(tag(" "), String)),
tag("\r\n"),
));
let (remaining, (_, maybe_data, _)) = parser(input)?;
@ -227,11 +235,14 @@ pub fn noop(input: &[u8]) -> IResult<&[u8], Command> {
/// quit = "QUIT" CRLF
pub fn quit(input: &[u8]) -> IResult<&[u8], Command> {
value(Command::Quit, tuple((tag_no_case(b"QUIT"), CRLF)))(input)
value(Command::Quit, tuple((tag_no_case(b"QUIT"), tag("\r\n"))))(input)
}
pub fn starttls(input: &[u8]) -> IResult<&[u8], Command> {
value(Command::StartTLS, tuple((tag_no_case(b"STARTTLS"), CRLF)))(input)
value(
Command::StartTLS,
tuple((tag_no_case(b"STARTTLS"), tag("\r\n"))),
)(input)
}
/// https://interoperability.blob.core.windows.net/files/MS-XLOGIN/[MS-XLOGIN].pdf
@ -239,19 +250,19 @@ pub fn starttls(input: &[u8]) -> IResult<&[u8], Command> {
/// username = 1*CHAR ; Base64-encoded username
/// password = 1*CHAR ; Base64-encoded password
///
/// auth_login_command = "AUTH LOGIN" [SP username] CRLF
/// auth_login_command = "AUTH LOGIN" [tag(" ") username] CRLF
///
/// auth_login_username_challenge = "334 VXNlcm5hbWU6" CRLF
/// auth_login_username_response = username CRLF
/// auth_login_username_retag(" ")onse = username CRLF
/// auth_login_password_challenge = "334 UGFzc3dvcmQ6" CRLF
/// auth_login_password_response = password CRLF
/// auth_login_password_retag(" ")onse = password CRLF
pub fn auth_login(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"AUTH"),
SP,
tag(" "),
tag_no_case("LOGIN"),
opt(preceded(SP, base64)),
CRLF,
opt(preceded(tag(" "), base64)),
tag("\r\n"),
));
let (remaining, (_, _, _, maybe_username_b64, _)) = parser(input)?;
@ -265,10 +276,10 @@ pub fn auth_login(input: &[u8]) -> IResult<&[u8], Command> {
pub fn auth_plain(input: &[u8]) -> IResult<&[u8], Command> {
let mut parser = tuple((
tag_no_case(b"AUTH"),
SP,
tag(" "),
tag_no_case("PLAIN"),
opt(preceded(SP, base64)),
CRLF,
opt(preceded(tag(" "), base64)),
tag("\r\n"),
));
let (remaining, (_, _, _, maybe_credentials_b64, _)) = parser(input)?;

View File

@ -4,7 +4,6 @@
/// 3.2.1. Quoted characters
pub mod quoted_characters {
use abnf_core::streaming::{is_VCHAR, WSP};
use nom::{
branch::alt,
bytes::streaming::{tag, take_while_m_n},
@ -20,7 +19,10 @@ pub mod quoted_characters {
let parser = alt((
recognize(tuple((
tag(b"\\"),
alt((take_while_m_n(1, 1, is_VCHAR), WSP)),
alt((
take_while_m_n(1, 1, |byte| matches!(byte, 0x21..=0x7E)),
alt((tag(" "), tag("\t"))),
)),
))),
obs_qp,
));
@ -58,9 +60,9 @@ pub mod folding_ws_and_comment {
/// 3.2.3. Atom
pub mod atom {
use abnf_core::streaming::{is_ALPHA, is_DIGIT};
use nom::{
bytes::streaming::{tag, take_while1},
character::{is_alphabetic, is_digit},
combinator::{opt, recognize},
multi::many0,
sequence::tuple,
@ -86,7 +88,7 @@ pub mod atom {
pub fn is_atext(byte: u8) -> bool {
let allowed = b"!#$%&'*+-/=?^_`{|}~";
is_ALPHA(byte) || is_DIGIT(byte) || allowed.contains(&byte)
is_alphabetic(byte) || is_digit(byte) || allowed.contains(&byte)
}
/// atom = [CFWS] 1*atext [CFWS]
@ -133,10 +135,9 @@ pub mod atom {
/// 3.2.4. Quoted Strings
pub mod quoted_strings {
use abnf_core::streaming::DQUOTE;
use nom::{
branch::alt,
bytes::streaming::take_while_m_n,
bytes::streaming::{tag, take_while_m_n},
combinator::{opt, recognize},
multi::many0,
sequence::tuple,
@ -173,10 +174,10 @@ pub mod quoted_strings {
pub fn quoted_string(input: &[u8]) -> IResult<&[u8], &[u8]> {
let parser = tuple((
opt(CFWS),
DQUOTE,
tag("\""),
many0(tuple((opt(FWS), qcontent))),
opt(FWS),
DQUOTE,
tag("\""),
opt(CFWS),
));
@ -206,10 +207,10 @@ pub mod miscellaneous {
/// 3.3. Date and Time Specification
pub mod datetime {
use abnf_core::streaming::is_DIGIT;
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case, take_while_m_n},
character::is_digit,
combinator::{opt, recognize},
sequence::tuple,
IResult,
@ -263,7 +264,7 @@ pub mod datetime {
// 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 parser = tuple((opt(FWS), take_while_m_n(1, 2, is_digit), FWS));
let (remaining, parsed) = recognize(parser)(input)?;
@ -294,7 +295,7 @@ pub mod datetime {
// 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 parser = tuple((FWS, take_while_m_n(4, 8, is_digit), FWS)); // FIXME: 4*?!
let (remaining, parsed) = recognize(parser)(input)?;
@ -323,7 +324,7 @@ pub mod datetime {
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 parser = take_while_m_n(2, 2, is_digit);
let (remaining, parsed) = recognize(parser)(input)?;
@ -334,7 +335,7 @@ pub mod datetime {
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 parser = take_while_m_n(2, 2, is_digit);
let (remaining, parsed) = recognize(parser)(input)?;
@ -345,7 +346,7 @@ pub mod datetime {
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 parser = take_while_m_n(2, 2, is_digit);
let (remaining, parsed) = recognize(parser)(input)?;
@ -359,7 +360,7 @@ pub mod datetime {
let parser = tuple((
FWS,
alt((tag(b"+"), tag(b"-"))),
take_while_m_n(4, 4, is_DIGIT),
take_while_m_n(4, 4, is_digit),
));
let (remaining, parsed) = recognize(parser)(input)?;
@ -520,7 +521,6 @@ pub mod identification {
/// 4.1. Miscellaneous Obsolete Tokens
pub mod obsolete {
use abnf_core::streaming::{CR, LF};
use nom::{
branch::alt,
bytes::streaming::{tag, take_while_m_n},
@ -557,8 +557,8 @@ pub mod obsolete {
alt((
take_while_m_n(1, 1, |x| x == 0x00),
take_while_m_n(1, 1, is_obs_NO_WS_CTL),
LF,
CR,
tag("\n"),
tag("\r"),
)),
));

View File

@ -2,11 +2,11 @@
use std::{borrow::Cow, str::from_utf8};
use abnf_core::streaming::{is_ALPHA, is_DIGIT, DQUOTE};
use nom::{
branch::alt,
bytes::streaming::{tag, take_while, take_while1, take_while_m_n},
character::streaming::digit1,
character::{is_alphabetic, is_digit},
combinator::{map, map_res, opt, recognize},
multi::{many0, separated_list1},
sequence::{delimited, tuple},
@ -37,7 +37,7 @@ pub fn base64(input: &[u8]) -> IResult<&[u8], &str> {
}
fn is_base64_char(i: u8) -> bool {
is_ALPHA(i) || is_DIGIT(i) || i == b'+' || i == b'/'
is_alphabetic(i) || is_digit(i) || i == b'+' || i == b'/'
}
pub fn number(input: &[u8]) -> IResult<&[u8], u32> {
@ -63,9 +63,9 @@ pub fn Atom(input: &[u8]) -> IResult<&[u8], &str> {
pub fn Quoted_string(input: &[u8]) -> IResult<&[u8], Cow<'_, str>> {
map(
delimited(
DQUOTE,
tag("\""),
map_res(recognize(many0(QcontentSMTP)), std::str::from_utf8),
DQUOTE,
tag("\""),
),
unescape_quoted,
)(input)
@ -132,14 +132,14 @@ pub fn sub_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
/// Let-dig = ALPHA / DIGIT
pub fn is_Let_dig(byte: u8) -> bool {
is_ALPHA(byte) || is_DIGIT(byte)
is_alphabetic(byte) || is_digit(byte)
}
/// Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
pub fn Ldh_str(input: &[u8]) -> IResult<&[u8], &[u8]> {
let parser = many0(alt((
take_while_m_n(1, 1, is_ALPHA),
take_while_m_n(1, 1, is_DIGIT),
take_while_m_n(1, 1, is_alphabetic),
take_while_m_n(1, 1, is_digit),
recognize(tuple((tag(b"-"), take_while_m_n(1, 1, is_Let_dig)))),
)));

View File

@ -1,9 +1,9 @@
use std::str::FromStr;
use abnf_core::streaming::{is_ALPHA, is_DIGIT, CRLF, SP};
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case, take_while, take_while1, take_while_m_n},
character::{is_alphabetic, is_digit},
combinator::{map, map_res, opt, recognize, value},
multi::{many0, separated_list0},
sequence::{delimited, preceded, tuple},
@ -25,8 +25,8 @@ pub fn Greeting(input: &[u8]) -> IResult<&[u8], Response> {
tuple((
tag(b"220 "),
alt((Domain, address_literal)),
opt(preceded(SP, textstring)),
CRLF,
opt(preceded(tag(" "), textstring)),
tag("\r\n"),
)),
|(_, domain, maybe_text, _)| Response::Greeting {
domain: domain.to_owned(),
@ -39,12 +39,12 @@ pub fn Greeting(input: &[u8]) -> IResult<&[u8], Response> {
tuple((
tag(b"220-"),
alt((Domain, address_literal)),
opt(preceded(SP, textstring)),
CRLF,
many0(delimited(tag(b"220-"), opt(textstring), CRLF)),
opt(preceded(tag(" "), textstring)),
tag("\r\n"),
many0(delimited(tag(b"220-"), opt(textstring), tag("\r\n"))),
tag(b"220"),
opt(preceded(SP, textstring)),
CRLF,
opt(preceded(tag(" "), textstring)),
tag("\r\n"),
)),
|(_, domain, maybe_text, _, more_text, _, moar_text, _)| Response::Greeting {
domain: domain.to_owned(),
@ -76,7 +76,7 @@ pub fn Greeting(input: &[u8]) -> IResult<&[u8], Response> {
Ok((remaining, parsed))
}
/// HT, SP, Printable US-ASCII
/// HT, tag(" "), Printable US-ASCII
///
/// textstring = 1*(%d09 / %d32-126)
pub fn textstring(input: &[u8]) -> IResult<&[u8], TextString<'_>> {
@ -97,10 +97,10 @@ pub(crate) fn is_text_string_byte(byte: u8) -> bool {
pub fn Reply_lines(input: &[u8]) -> IResult<&[u8], Response> {
let mut parser = map(
tuple((
many0(tuple((Reply_code, tag(b"-"), opt(textstring), CRLF))),
many0(tuple((Reply_code, tag(b"-"), opt(textstring), tag("\r\n")))),
Reply_code,
opt(tuple((SP, textstring))),
CRLF,
opt(tuple((tag(" "), textstring))),
tag("\r\n"),
)),
|(intermediate, code, text, _)| {
let mut lines =
@ -151,7 +151,12 @@ pub fn Reply_code(input: &[u8]) -> IResult<&[u8], ReplyCode> {
pub fn ehlo_ok_rsp(input: &[u8]) -> IResult<&[u8], Response> {
let mut parser = alt((
map(
tuple((tag(b"250 "), Domain, opt(preceded(SP, ehlo_greet)), CRLF)),
tuple((
tag(b"250 "),
Domain,
opt(preceded(tag(" "), ehlo_greet)),
tag("\r\n"),
)),
|(_, domain, maybe_ehlo, _)| Response::Ehlo {
domain: domain.to_owned(),
greet: maybe_ehlo.map(|ehlo| ehlo.to_owned()),
@ -162,12 +167,12 @@ pub fn ehlo_ok_rsp(input: &[u8]) -> IResult<&[u8], Response> {
tuple((
tag(b"250-"),
Domain,
opt(preceded(SP, ehlo_greet)),
CRLF,
many0(delimited(tag(b"250-"), ehlo_line, CRLF)),
opt(preceded(tag(" "), ehlo_greet)),
tag("\r\n"),
many0(delimited(tag(b"250-"), ehlo_line, tag("\r\n"))),
tag(b"250 "),
ehlo_line,
CRLF,
tag("\r\n"),
)),
|(_, domain, maybe_ehlo, _, mut lines, _, line, _)| Response::Ehlo {
domain: domain.to_owned(),
@ -203,14 +208,14 @@ pub fn ehlo_line(input: &[u8]) -> IResult<&[u8], Capability> {
let auth = tuple((
tag_no_case("AUTH"),
alt((tag_no_case(" "), tag_no_case("="))),
separated_list0(SP, auth_mechanism),
separated_list0(tag(" "), auth_mechanism),
));
let other = tuple((
map_res(ehlo_keyword, std::str::from_utf8),
opt(preceded(
alt((SP, tag("="))), // TODO: For Outlook?
separated_list0(SP, ehlo_param),
alt((tag(" "), tag("="))), // TODO: For Outlook?
separated_list0(tag(" "), ehlo_param),
)),
));
@ -257,8 +262,8 @@ pub fn ehlo_line(input: &[u8]) -> IResult<&[u8], Capability> {
/// ehlo-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
pub fn ehlo_keyword(input: &[u8]) -> IResult<&[u8], &[u8]> {
let parser = tuple((
take_while_m_n(1, 1, |byte| is_ALPHA(byte) || is_DIGIT(byte)),
take_while(|byte| is_ALPHA(byte) || is_DIGIT(byte) || byte == b'-'),
take_while_m_n(1, 1, |byte| is_alphabetic(byte) || is_digit(byte)),
take_while(|byte| is_alphabetic(byte) || is_digit(byte) || byte == b'-'),
));
let (remaining, parsed) = recognize(parser)(input)?;

View File

@ -1,5 +1,4 @@
/// 4.4. Trace Information (RFC 5321)
use abnf_core::streaming::CRLF;
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case},
@ -22,7 +21,7 @@ use crate::parse::{
/// 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, CRLF));
let parser = tuple((tag_no_case(b"Return-Path:"), FWS, Reverse_path, tag("\r\n")));
let (remaining, parsed) = recognize(parser)(input)?;
@ -31,7 +30,7 @@ pub fn Return_path_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
/// 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, CRLF));
let parser = tuple((tag_no_case(b"Received:"), FWS, Stamp, tag("\r\n")));
let (remaining, parsed) = recognize(parser)(input)?;