Stick to idiomatic naming conventions
This commit is contained in:
parent
263c2c16cd
commit
351990b95e
|
@ -10,7 +10,7 @@ use nom::{
|
||||||
IResult,
|
IResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::parse::Ldh_str;
|
use crate::parse::ldh_str;
|
||||||
|
|
||||||
/// address-literal = "[" (
|
/// address-literal = "[" (
|
||||||
/// IPv4-address-literal /
|
/// IPv4-address-literal /
|
||||||
|
@ -23,9 +23,9 @@ pub fn address_literal(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
tag(b"["),
|
tag(b"["),
|
||||||
map_res(
|
map_res(
|
||||||
alt((
|
alt((
|
||||||
IPv4_address_literal,
|
ipv4_address_literal,
|
||||||
IPv6_address_literal,
|
ipv6_address_literal,
|
||||||
General_address_literal,
|
general_address_literal,
|
||||||
)),
|
)),
|
||||||
std::str::from_utf8,
|
std::str::from_utf8,
|
||||||
),
|
),
|
||||||
|
@ -34,8 +34,8 @@ pub fn address_literal(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv4-address-literal = Snum 3("." Snum)
|
/// IPv4-address-literal = Snum 3("." Snum)
|
||||||
pub fn IPv4_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv4_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((Snum, count(tuple((tag(b"."), Snum)), 3)));
|
let parser = tuple((snum, count(tuple((tag(b"."), snum)), 3)));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ pub fn IPv4_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// Representing a decimal integer value in the range 0 through 255
|
/// Representing a decimal integer value in the range 0 through 255
|
||||||
///
|
///
|
||||||
/// Snum = 1*3DIGIT
|
/// Snum = 1*3DIGIT
|
||||||
pub fn Snum(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
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
|
/// IPv6-address-literal = "IPv6:" IPv6-addr
|
||||||
pub fn IPv6_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((tag_no_case(b"IPv6:"), IPv6_addr));
|
let parser = tuple((tag_no_case(b"IPv6:"), ipv6_addr));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -59,8 +59,8 @@ pub fn IPv6_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
|
/// IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
|
||||||
pub fn IPv6_addr(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6_addr(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = alt((IPv6_full, IPv6_comp, IPv6v4_full, IPv6v4_comp));
|
let parser = alt((ipv6_full, ipv6_comp, ipv6v4_full, ipv6v4_comp));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ pub fn IPv6_addr(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6-full = IPv6-hex 7(":" IPv6-hex)
|
/// IPv6-full = IPv6-hex 7(":" IPv6-hex)
|
||||||
pub fn IPv6_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((IPv6_hex, count(tuple((tag(b":"), IPv6_hex)), 7)));
|
let parser = tuple((ipv6_hex, count(tuple((tag(b":"), ipv6_hex)), 7)));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ pub fn IPv6_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6-hex = 1*4HEXDIG
|
/// IPv6-hex = 1*4HEXDIG
|
||||||
pub fn IPv6_hex(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6_hex(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
take_while_m_n(1, 4, is_hex_digit)(input)
|
take_while_m_n(1, 4, is_hex_digit)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,16 +85,16 @@ pub fn IPv6_hex(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// No more than 6 groups in addition to the "::" may be present.
|
/// No more than 6 groups in addition to the "::" may be present.
|
||||||
///
|
///
|
||||||
/// IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":" IPv6-hex)]
|
/// IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":" IPv6-hex)]
|
||||||
pub fn IPv6_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((
|
let parser = tuple((
|
||||||
opt(tuple((
|
opt(tuple((
|
||||||
IPv6_hex,
|
ipv6_hex,
|
||||||
many_m_n(0, 5, tuple((tag(b":"), IPv6_hex))),
|
many_m_n(0, 5, tuple((tag(b":"), ipv6_hex))),
|
||||||
))),
|
))),
|
||||||
tag(b"::"),
|
tag(b"::"),
|
||||||
opt(tuple((
|
opt(tuple((
|
||||||
IPv6_hex,
|
ipv6_hex,
|
||||||
many_m_n(0, 5, tuple((tag(b":"), IPv6_hex))),
|
many_m_n(0, 5, tuple((tag(b":"), ipv6_hex))),
|
||||||
))),
|
))),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -104,12 +104,12 @@ pub fn IPv6_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
|
/// IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
|
||||||
pub fn IPv6v4_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6v4_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((
|
let parser = tuple((
|
||||||
IPv6_hex,
|
ipv6_hex,
|
||||||
count(tuple((tag(b":"), IPv6_hex)), 5),
|
count(tuple((tag(b":"), ipv6_hex)), 5),
|
||||||
tag(b":"),
|
tag(b":"),
|
||||||
IPv4_address_literal,
|
ipv4_address_literal,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
@ -123,19 +123,19 @@ pub fn IPv6v4_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
|
/// IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
|
||||||
/// [IPv6-hex *3(":" IPv6-hex) ":"]
|
/// [IPv6-hex *3(":" IPv6-hex) ":"]
|
||||||
/// IPv4-address-literal
|
/// IPv4-address-literal
|
||||||
pub fn IPv6v4_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ipv6v4_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((
|
let parser = tuple((
|
||||||
opt(tuple((
|
opt(tuple((
|
||||||
IPv6_hex,
|
ipv6_hex,
|
||||||
many_m_n(0, 3, tuple((tag(b":"), IPv6_hex))),
|
many_m_n(0, 3, tuple((tag(b":"), ipv6_hex))),
|
||||||
))),
|
))),
|
||||||
tag(b"::"),
|
tag(b"::"),
|
||||||
opt(tuple((
|
opt(tuple((
|
||||||
IPv6_hex,
|
ipv6_hex,
|
||||||
many_m_n(0, 3, tuple((tag(b":"), IPv6_hex))),
|
many_m_n(0, 3, tuple((tag(b":"), ipv6_hex))),
|
||||||
tag(b":"),
|
tag(b":"),
|
||||||
))),
|
))),
|
||||||
IPv4_address_literal,
|
ipv4_address_literal,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
@ -144,8 +144,8 @@ pub fn IPv6v4_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// General-address-literal = Standardized-tag ":" 1*dcontent
|
/// General-address-literal = Standardized-tag ":" 1*dcontent
|
||||||
pub fn General_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn general_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((Standardized_tag, tag(b":"), take_while1(is_dcontent)));
|
let parser = tuple((standardized_tag, tag(b":"), take_while1(is_dcontent)));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -155,8 +155,8 @@ pub fn General_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// Standardized-tag MUST be specified in a Standards-Track RFC and registered with IANA
|
/// Standardized-tag MUST be specified in a Standards-Track RFC and registered with IANA
|
||||||
///
|
///
|
||||||
/// Standardized-tag = Ldh-str
|
/// Standardized-tag = Ldh-str
|
||||||
pub fn Standardized_tag(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn standardized_tag(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
Ldh_str(input)
|
ldh_str(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Printable US-ASCII excl. "[", "\", "]"
|
/// Printable US-ASCII excl. "[", "\", "]"
|
||||||
|
|
|
@ -9,7 +9,7 @@ use nom::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parse::{address::address_literal, base64, Atom, Domain, Quoted_string, String},
|
parse::{address::address_literal, atom, base64, domain, quoted_string, string},
|
||||||
types::{Command, DomainOrAddress, Parameter},
|
types::{Command, DomainOrAddress, Parameter},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ pub fn helo(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
tag_no_case(b"HELO"),
|
tag_no_case(b"HELO"),
|
||||||
tag(" "),
|
tag(" "),
|
||||||
alt((
|
alt((
|
||||||
map(Domain, |domain| DomainOrAddress::Domain(domain.into())),
|
map(domain, |domain| DomainOrAddress::Domain(domain.into())),
|
||||||
map(address_literal, |address| {
|
map(address_literal, |address| {
|
||||||
DomainOrAddress::Address(address.into())
|
DomainOrAddress::Address(address.into())
|
||||||
}),
|
}),
|
||||||
|
@ -47,7 +47,7 @@ pub fn ehlo(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
tag_no_case(b"EHLO"),
|
tag_no_case(b"EHLO"),
|
||||||
tag(" "),
|
tag(" "),
|
||||||
alt((
|
alt((
|
||||||
map(Domain, |domain| DomainOrAddress::Domain(domain.into())),
|
map(domain, |domain| DomainOrAddress::Domain(domain.into())),
|
||||||
map(address_literal, |address| {
|
map(address_literal, |address| {
|
||||||
DomainOrAddress::Address(address.into())
|
DomainOrAddress::Address(address.into())
|
||||||
}),
|
}),
|
||||||
|
@ -65,8 +65,8 @@ pub fn mail(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
let mut parser = tuple((
|
let mut parser = tuple((
|
||||||
tag_no_case(b"MAIL FROM:"),
|
tag_no_case(b"MAIL FROM:"),
|
||||||
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
|
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
|
||||||
Reverse_path,
|
reverse_path,
|
||||||
opt(preceded(tag(" "), Mail_parameters)),
|
opt(preceded(tag(" "), mail_parameters)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ pub fn mail(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mail-parameters = esmtp-param *(tag(" ") esmtp-param)
|
/// Mail-parameters = esmtp-param *(tag(" ") esmtp-param)
|
||||||
pub fn Mail_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
pub fn mail_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
||||||
separated_list1(tag(" "), esmtp_param)(input)
|
separated_list1(tag(" "), esmtp_param)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,13 +138,13 @@ pub fn rcpt(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
|
opt(tag(" ")), // Out-of-tag(" ")ec, but Outlook does it ...
|
||||||
alt((
|
alt((
|
||||||
map_res(
|
map_res(
|
||||||
recognize(tuple((tag_no_case("<Postmaster@"), Domain, tag(">")))),
|
recognize(tuple((tag_no_case("<Postmaster@"), domain, tag(">")))),
|
||||||
std::str::from_utf8,
|
std::str::from_utf8,
|
||||||
),
|
),
|
||||||
map_res(tag_no_case("<Postmaster>"), std::str::from_utf8),
|
map_res(tag_no_case("<Postmaster>"), std::str::from_utf8),
|
||||||
Forward_path,
|
forward_path,
|
||||||
)),
|
)),
|
||||||
opt(preceded(tag(" "), Rcpt_parameters)),
|
opt(preceded(tag(" "), rcpt_parameters)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ pub fn rcpt(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rcpt-parameters = esmtp-param *(tag(" ") esmtp-param)
|
/// Rcpt-parameters = esmtp-param *(tag(" ") esmtp-param)
|
||||||
pub fn Rcpt_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
pub fn rcpt_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
||||||
separated_list1(tag(" "), esmtp_param)(input)
|
separated_list1(tag(" "), esmtp_param)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ pub fn rset(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
|
|
||||||
/// vrfy = "VRFY" tag(" ") String CRLF
|
/// vrfy = "VRFY" tag(" ") String CRLF
|
||||||
pub fn vrfy(input: &[u8]) -> IResult<&[u8], Command> {
|
pub fn vrfy(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
let mut parser = tuple((tag_no_case(b"VRFY"), tag(" "), String, tag("\r\n")));
|
let mut parser = tuple((tag_no_case(b"VRFY"), tag(" "), string, tag("\r\n")));
|
||||||
|
|
||||||
let (remaining, (_, _, data, _)) = parser(input)?;
|
let (remaining, (_, _, data, _)) = parser(input)?;
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ pub fn vrfy(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
|
|
||||||
/// expn = "EXPN" tag(" ") String CRLF
|
/// expn = "EXPN" tag(" ") String CRLF
|
||||||
pub fn expn(input: &[u8]) -> IResult<&[u8], Command> {
|
pub fn expn(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
let mut parser = tuple((tag_no_case(b"EXPN"), tag(" "), String, tag("\r\n")));
|
let mut parser = tuple((tag_no_case(b"EXPN"), tag(" "), string, tag("\r\n")));
|
||||||
|
|
||||||
let (remaining, (_, _, data, _)) = parser(input)?;
|
let (remaining, (_, _, data, _)) = parser(input)?;
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ pub fn expn(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
pub fn help(input: &[u8]) -> IResult<&[u8], Command> {
|
pub fn help(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
let mut parser = tuple((
|
let mut parser = tuple((
|
||||||
tag_no_case(b"HELP"),
|
tag_no_case(b"HELP"),
|
||||||
opt(preceded(tag(" "), String)),
|
opt(preceded(tag(" "), string)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ pub fn help(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
pub fn noop(input: &[u8]) -> IResult<&[u8], Command> {
|
pub fn noop(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
let mut parser = tuple((
|
let mut parser = tuple((
|
||||||
tag_no_case(b"NOOP"),
|
tag_no_case(b"NOOP"),
|
||||||
opt(preceded(tag(" "), String)),
|
opt(preceded(tag(" "), string)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ pub fn quit(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
|
|
||||||
pub fn starttls(input: &[u8]) -> IResult<&[u8], Command> {
|
pub fn starttls(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
value(
|
value(
|
||||||
Command::StartTLS,
|
Command::StartTls,
|
||||||
tuple((tag_no_case(b"STARTTLS"), tag("\r\n"))),
|
tuple((tag_no_case(b"STARTTLS"), tag("\r\n"))),
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
@ -293,21 +293,21 @@ pub fn auth_plain(input: &[u8]) -> IResult<&[u8], Command> {
|
||||||
// ----- 4.1.2. Command Argument Syntax (RFC 5321) -----
|
// ----- 4.1.2. Command Argument Syntax (RFC 5321) -----
|
||||||
|
|
||||||
/// Reverse-path = Path / "<>"
|
/// Reverse-path = Path / "<>"
|
||||||
pub fn Reverse_path(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn reverse_path(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
alt((Path, value("", tag("<>"))))(input)
|
alt((path, value("", tag("<>"))))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forward-path = Path
|
/// Forward-path = Path
|
||||||
pub fn Forward_path(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn forward_path(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
Path(input)
|
path(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path = "<" [ A-d-l ":" ] Mailbox ">"
|
// Path = "<" [ A-d-l ":" ] Mailbox ">"
|
||||||
pub fn Path(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn path(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
delimited(
|
delimited(
|
||||||
tag(b"<"),
|
tag(b"<"),
|
||||||
map_res(
|
map_res(
|
||||||
recognize(tuple((opt(tuple((A_d_l, tag(b":")))), Mailbox))),
|
recognize(tuple((opt(tuple((a_d_l, tag(b":")))), mailbox))),
|
||||||
std::str::from_utf8,
|
std::str::from_utf8,
|
||||||
),
|
),
|
||||||
tag(b">"),
|
tag(b">"),
|
||||||
|
@ -318,8 +318,8 @@ pub fn Path(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
/// ; Note that this form, the so-called "source
|
/// ; Note that this form, the so-called "source
|
||||||
/// ; route", MUST BE accepted, SHOULD NOT be
|
/// ; route", MUST BE accepted, SHOULD NOT be
|
||||||
/// ; generated, and SHOULD be ignored.
|
/// ; generated, and SHOULD be ignored.
|
||||||
pub fn A_d_l(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn a_d_l(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = separated_list1(tag(b","), At_domain);
|
let parser = separated_list1(tag(b","), at_domain);
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -327,8 +327,8 @@ pub fn A_d_l(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// At-domain = "@" Domain
|
/// At-domain = "@" Domain
|
||||||
pub fn At_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn at_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((tag(b"@"), Domain));
|
let parser = tuple((tag(b"@"), domain));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -336,8 +336,8 @@ pub fn At_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mailbox = Local-part "@" ( Domain / address-literal )
|
/// Mailbox = Local-part "@" ( Domain / address-literal )
|
||||||
pub fn Mailbox(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn mailbox(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((Local_part, tag(b"@"), alt((Domain, address_literal))));
|
let parser = tuple((local_part, tag(b"@"), alt((domain, address_literal))));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -346,14 +346,14 @@ pub fn Mailbox(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
|
|
||||||
/// Local-part = Dot-string / Quoted-string
|
/// Local-part = Dot-string / Quoted-string
|
||||||
/// ; MAY be case-sensitive
|
/// ; MAY be case-sensitive
|
||||||
pub fn Local_part(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn local_part(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
alt((recognize(Dot_string), recognize(Quoted_string)))(input)
|
alt((recognize(dot_string), recognize(quoted_string)))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dot-string = Atom *("." Atom)
|
/// Dot-string = Atom *("." Atom)
|
||||||
pub fn Dot_string(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn dot_string(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
map_res(
|
map_res(
|
||||||
recognize(separated_list1(tag(b"."), Atom)),
|
recognize(separated_list1(tag(b"."), atom)),
|
||||||
std::str::from_utf8,
|
std::str::from_utf8,
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![allow(non_snake_case)]
|
|
||||||
|
|
||||||
use std::{borrow::Cow, str::from_utf8};
|
use std::{borrow::Cow, str::from_utf8};
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
|
@ -44,15 +42,15 @@ pub fn number(input: &[u8]) -> IResult<&[u8], u32> {
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// String = Atom / Quoted-string
|
/// String = Atom / Quoted-string
|
||||||
pub fn String(input: &[u8]) -> IResult<&[u8], AtomOrQuoted> {
|
pub fn string(input: &[u8]) -> IResult<&[u8], AtomOrQuoted> {
|
||||||
alt((
|
alt((
|
||||||
map(Atom, |atom| AtomOrQuoted::Atom(atom.into())),
|
map(atom, |atom| AtomOrQuoted::Atom(atom.into())),
|
||||||
map(Quoted_string, |quoted| AtomOrQuoted::Quoted(quoted.into())),
|
map(quoted_string, |quoted| AtomOrQuoted::Quoted(quoted.into())),
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Atom = 1*atext
|
/// Atom = 1*atext
|
||||||
pub fn Atom(input: &[u8]) -> IResult<&[u8], &str> {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +75,11 @@ pub fn is_atext(byte: u8) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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(
|
||||||
delimited(
|
delimited(
|
||||||
tag("\""),
|
tag("\""),
|
||||||
map_res(recognize(many0(QcontentSMTP)), std::str::from_utf8),
|
map_res(recognize(many0(q_content_smtp)), std::str::from_utf8),
|
||||||
tag("\""),
|
tag("\""),
|
||||||
),
|
),
|
||||||
unescape_quoted,
|
unescape_quoted,
|
||||||
|
@ -89,8 +87,8 @@ pub fn Quoted_string(input: &[u8]) -> IResult<&[u8], Cow<'_, str>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QcontentSMTP = qtextSMTP / quoted-pairSMTP
|
/// QcontentSMTP = qtextSMTP / quoted-pairSMTP
|
||||||
pub fn QcontentSMTP(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn q_content_smtp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = alt((take_while_m_n(1, 1, is_qtextSMTP), quoted_pairSMTP));
|
let parser = alt((take_while_m_n(1, 1, is_qtext_smtp), quoted_pair_smtp));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -101,7 +99,7 @@ pub fn QcontentSMTP(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
/// without blackslash-quoting except double-quote and the backslash itself.
|
/// without blackslash-quoting except double-quote and the backslash itself.
|
||||||
///
|
///
|
||||||
/// qtextSMTP = %d32-33 / %d35-91 / %d93-126
|
/// qtextSMTP = %d32-33 / %d35-91 / %d93-126
|
||||||
pub fn is_qtextSMTP(byte: u8) -> bool {
|
pub fn is_qtext_smtp(byte: u8) -> bool {
|
||||||
matches!(byte, 32..=33 | 35..=91 | 93..=126)
|
matches!(byte, 32..=33 | 35..=91 | 93..=126)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +108,7 @@ pub fn is_qtextSMTP(byte: u8) -> bool {
|
||||||
/// quoted-pairSMTP = %d92 %d32-126
|
/// quoted-pairSMTP = %d92 %d32-126
|
||||||
///
|
///
|
||||||
/// FIXME: How should e.g. "\a" be interpreted?
|
/// FIXME: How should e.g. "\a" be interpreted?
|
||||||
pub fn quoted_pairSMTP(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn quoted_pair_smtp(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
//fn is_value(byte: u8) -> bool {
|
//fn is_value(byte: u8) -> bool {
|
||||||
// matches!(byte, 32..=126)
|
// matches!(byte, 32..=126)
|
||||||
//}
|
//}
|
||||||
|
@ -130,7 +128,7 @@ pub fn quoted_pairSMTP(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Domain = sub-domain *("." sub-domain)
|
/// Domain = sub-domain *("." sub-domain)
|
||||||
pub fn Domain(input: &[u8]) -> IResult<&[u8], &str> {
|
pub fn domain(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
let parser = separated_list1(tag(b"."), sub_domain);
|
let parser = separated_list1(tag(b"."), sub_domain);
|
||||||
|
|
||||||
let (remaining, parsed) = map_res(recognize(parser), std::str::from_utf8)(input)?;
|
let (remaining, parsed) = map_res(recognize(parser), std::str::from_utf8)(input)?;
|
||||||
|
@ -140,7 +138,7 @@ pub fn Domain(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
|
|
||||||
/// sub-domain = Let-dig [Ldh-str]
|
/// sub-domain = Let-dig [Ldh-str]
|
||||||
pub fn sub_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn sub_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = tuple((take_while_m_n(1, 1, is_Let_dig), opt(Ldh_str)));
|
let parser = tuple((take_while_m_n(1, 1, is_let_dig), opt(ldh_str)));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
||||||
|
@ -148,16 +146,16 @@ pub fn sub_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Let-dig = ALPHA / DIGIT
|
/// Let-dig = ALPHA / DIGIT
|
||||||
pub fn is_Let_dig(byte: u8) -> bool {
|
pub fn is_let_dig(byte: u8) -> bool {
|
||||||
is_alphabetic(byte) || is_digit(byte)
|
is_alphabetic(byte) || is_digit(byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
|
/// Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
|
||||||
pub fn Ldh_str(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
pub fn ldh_str(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
let parser = many0(alt((
|
let parser = many0(alt((
|
||||||
take_while_m_n(1, 1, is_alphabetic),
|
take_while_m_n(1, 1, is_alphabetic),
|
||||||
take_while_m_n(1, 1, is_digit),
|
take_while_m_n(1, 1, is_digit),
|
||||||
recognize(tuple((tag(b"-"), take_while_m_n(1, 1, is_Let_dig)))),
|
recognize(tuple((tag(b"-"), take_while_m_n(1, 1, is_let_dig)))),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let (remaining, parsed) = recognize(parser)(input)?;
|
let (remaining, parsed) = recognize(parser)(input)?;
|
||||||
|
|
|
@ -11,7 +11,7 @@ use nom::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parse::{address::address_literal, number, Domain},
|
parse::{address::address_literal, domain, number},
|
||||||
types::{AuthMechanism, Capability, ReplyCode, Response, TextString},
|
types::{AuthMechanism, Capability, ReplyCode, Response, TextString},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ use crate::{
|
||||||
/// ( "220-" (Domain / address-literal) [ SP textstring ] CRLF
|
/// ( "220-" (Domain / address-literal) [ SP textstring ] CRLF
|
||||||
/// *( "220-" [ textstring ] CRLF )
|
/// *( "220-" [ textstring ] CRLF )
|
||||||
/// "220" [ SP textstring ] CRLF )
|
/// "220" [ SP textstring ] CRLF )
|
||||||
pub fn Greeting(input: &[u8]) -> IResult<&[u8], Response> {
|
pub fn greeting(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
let mut parser = alt((
|
let mut parser = alt((
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
tag(b"220 "),
|
tag(b"220 "),
|
||||||
alt((Domain, address_literal)),
|
alt((domain, address_literal)),
|
||||||
opt(preceded(tag(" "), textstring)),
|
opt(preceded(tag(" "), textstring)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
)),
|
)),
|
||||||
|
@ -38,7 +38,7 @@ pub fn Greeting(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
tag(b"220-"),
|
tag(b"220-"),
|
||||||
alt((Domain, address_literal)),
|
alt((domain, address_literal)),
|
||||||
opt(preceded(tag(" "), textstring)),
|
opt(preceded(tag(" "), textstring)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
many0(delimited(tag(b"220-"), opt(textstring), tag("\r\n"))),
|
many0(delimited(tag(b"220-"), opt(textstring), tag("\r\n"))),
|
||||||
|
@ -94,11 +94,11 @@ pub(crate) fn is_text_string_byte(byte: u8) -> bool {
|
||||||
|
|
||||||
/// Reply-line = *( Reply-code "-" [ textstring ] CRLF )
|
/// Reply-line = *( Reply-code "-" [ textstring ] CRLF )
|
||||||
/// Reply-code [ SP textstring ] CRLF
|
/// Reply-code [ SP textstring ] CRLF
|
||||||
pub fn Reply_lines(input: &[u8]) -> IResult<&[u8], Response> {
|
pub fn reply_lines(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
let mut parser = map(
|
let mut parser = map(
|
||||||
tuple((
|
tuple((
|
||||||
many0(tuple((Reply_code, tag(b"-"), opt(textstring), tag("\r\n")))),
|
many0(tuple((reply_code, tag(b"-"), opt(textstring), tag("\r\n")))),
|
||||||
Reply_code,
|
reply_code,
|
||||||
opt(tuple((tag(" "), textstring))),
|
opt(tuple((tag(" "), textstring))),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
)),
|
)),
|
||||||
|
@ -129,7 +129,7 @@ pub fn Reply_lines(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
/// 2345
|
/// 2345
|
||||||
/// 012345
|
/// 012345
|
||||||
/// 0123456789
|
/// 0123456789
|
||||||
pub fn Reply_code(input: &[u8]) -> IResult<&[u8], ReplyCode> {
|
pub fn reply_code(input: &[u8]) -> IResult<&[u8], ReplyCode> {
|
||||||
// FIXME: do not accept all codes.
|
// FIXME: do not accept all codes.
|
||||||
map_res(
|
map_res(
|
||||||
map_res(
|
map_res(
|
||||||
|
@ -153,7 +153,7 @@ pub fn ehlo_ok_rsp(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
tag(b"250 "),
|
tag(b"250 "),
|
||||||
Domain,
|
domain,
|
||||||
opt(preceded(tag(" "), ehlo_greet)),
|
opt(preceded(tag(" "), ehlo_greet)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
)),
|
)),
|
||||||
|
@ -166,7 +166,7 @@ pub fn ehlo_ok_rsp(input: &[u8]) -> IResult<&[u8], Response> {
|
||||||
map(
|
map(
|
||||||
tuple((
|
tuple((
|
||||||
tag(b"250-"),
|
tag(b"250-"),
|
||||||
Domain,
|
domain,
|
||||||
opt(preceded(tag(" "), ehlo_greet)),
|
opt(preceded(tag(" "), ehlo_greet)),
|
||||||
tag("\r\n"),
|
tag("\r\n"),
|
||||||
many0(delimited(tag(b"250-"), ehlo_line, tag("\r\n"))),
|
many0(delimited(tag(b"250-"), ehlo_line, tag("\r\n"))),
|
||||||
|
@ -220,34 +220,34 @@ pub fn ehlo_line(input: &[u8]) -> IResult<&[u8], Capability> {
|
||||||
));
|
));
|
||||||
|
|
||||||
alt((
|
alt((
|
||||||
value(Capability::EXPN, tag_no_case("EXPN")),
|
value(Capability::Expn, tag_no_case("EXPN")),
|
||||||
value(Capability::Help, tag_no_case("HELP")),
|
value(Capability::Help, tag_no_case("HELP")),
|
||||||
value(Capability::EightBitMIME, tag_no_case("8BITMIME")),
|
value(Capability::EightBitMime, tag_no_case("8BITMIME")),
|
||||||
map(preceded(tag_no_case("SIZE "), number), Capability::Size),
|
map(preceded(tag_no_case("SIZE "), number), Capability::Size),
|
||||||
value(Capability::Chunking, tag_no_case("CHUNKING")),
|
value(Capability::Chunking, tag_no_case("CHUNKING")),
|
||||||
value(Capability::BinaryMIME, tag_no_case("BINARYMIME")),
|
value(Capability::BinaryMime, tag_no_case("BINARYMIME")),
|
||||||
value(Capability::Checkpoint, tag_no_case("CHECKPOINT")),
|
value(Capability::Checkpoint, tag_no_case("CHECKPOINT")),
|
||||||
value(Capability::DeliverBy, tag_no_case("DELIVERBY")),
|
value(Capability::DeliverBy, tag_no_case("DELIVERBY")),
|
||||||
value(Capability::Pipelining, tag_no_case("PIPELINING")),
|
value(Capability::Pipelining, tag_no_case("PIPELINING")),
|
||||||
value(Capability::DSN, tag_no_case("DSN")),
|
value(Capability::Dsn, tag_no_case("DSN")),
|
||||||
value(Capability::ETRN, tag_no_case("ETRN")),
|
value(Capability::Etrn, tag_no_case("ETRN")),
|
||||||
value(
|
value(
|
||||||
Capability::EnhancedStatusCodes,
|
Capability::EnhancedStatusCodes,
|
||||||
tag_no_case("ENHANCEDSTATUSCODES"),
|
tag_no_case("ENHANCEDSTATUSCODES"),
|
||||||
),
|
),
|
||||||
value(Capability::StartTLS, tag_no_case("STARTTLS")),
|
value(Capability::StartTls, tag_no_case("STARTTLS")),
|
||||||
// FIXME: NO-SOLICITING
|
// FIXME: NO-SOLICITING
|
||||||
value(Capability::MTRK, tag_no_case("MTRK")),
|
value(Capability::Mtrk, tag_no_case("MTRK")),
|
||||||
value(Capability::ATRN, tag_no_case("ATRN")),
|
value(Capability::Atrn, tag_no_case("ATRN")),
|
||||||
map(auth, |(_, _, mechanisms)| Capability::Auth(mechanisms)),
|
map(auth, |(_, _, mechanisms)| Capability::Auth(mechanisms)),
|
||||||
value(Capability::BURL, tag_no_case("BURL")),
|
value(Capability::Burl, tag_no_case("BURL")),
|
||||||
// FIXME: FUTURERELEASE
|
// FIXME: FUTURERELEASE
|
||||||
// FIXME: CONPERM
|
// FIXME: CONPERM
|
||||||
// FIXME: CONNEG
|
// FIXME: CONNEG
|
||||||
value(Capability::SMTPUTF8, tag_no_case("SMTPUTF8")),
|
value(Capability::SmtpUtf8, tag_no_case("SMTPUTF8")),
|
||||||
// FIXME: MT-PRIORITY
|
// FIXME: MT-PRIORITY
|
||||||
value(Capability::RRVS, tag_no_case("RRVS")),
|
value(Capability::Rrvs, tag_no_case("RRVS")),
|
||||||
value(Capability::RequireTLS, tag_no_case("REQUIRETLS")),
|
value(Capability::RequireTls, tag_no_case("REQUIRETLS")),
|
||||||
map(other, |(keyword, params)| Capability::Other {
|
map(other, |(keyword, params)| Capability::Other {
|
||||||
keyword: keyword.into(),
|
keyword: keyword.into(),
|
||||||
params: params
|
params: params
|
||||||
|
@ -287,12 +287,12 @@ pub fn auth_mechanism(input: &[u8]) -> IResult<&[u8], AuthMechanism> {
|
||||||
alt((
|
alt((
|
||||||
value(AuthMechanism::Login, tag_no_case("LOGIN")),
|
value(AuthMechanism::Login, tag_no_case("LOGIN")),
|
||||||
value(AuthMechanism::Plain, tag_no_case("PLAIN")),
|
value(AuthMechanism::Plain, tag_no_case("PLAIN")),
|
||||||
value(AuthMechanism::CramMD5, tag_no_case("CRAM-MD5")),
|
value(AuthMechanism::CramMd5, tag_no_case("CRAM-MD5")),
|
||||||
value(AuthMechanism::CramSHA1, tag_no_case("CRAM-SHA1")),
|
value(AuthMechanism::CramSha1, tag_no_case("CRAM-SHA1")),
|
||||||
value(AuthMechanism::DigestMD5, tag_no_case("DIGEST-MD5")),
|
value(AuthMechanism::DigestMd5, tag_no_case("DIGEST-MD5")),
|
||||||
value(AuthMechanism::ScramMD5, tag_no_case("SCRAM-MD5")),
|
value(AuthMechanism::ScramMd5, tag_no_case("SCRAM-MD5")),
|
||||||
value(AuthMechanism::GSSAPI, tag_no_case("GSSAPI")),
|
value(AuthMechanism::GssApi, tag_no_case("GSSAPI")),
|
||||||
value(AuthMechanism::NTLM, tag_no_case("NTLM")),
|
value(AuthMechanism::Ntlm, tag_no_case("NTLM")),
|
||||||
map(ehlo_param, |param| AuthMechanism::Other(param.to_string())),
|
map(ehlo_param, |param| AuthMechanism::Other(param.to_string())),
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
@ -305,12 +305,12 @@ mod test {
|
||||||
use crate::types::AuthMechanism;
|
use crate::types::AuthMechanism;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_Greeting() {
|
fn test_greeting() {
|
||||||
let greeting = b"220-example.org ESMTP Fake 4.93 #2 Thu, 16 Jul 2020 07:30:16 -0400\r\n\
|
let buf = b"220-example.org ESMTP Fake 4.93 #2 Thu, 16 Jul 2020 07:30:16 -0400\r\n\
|
||||||
220-We do not authorize the use of this system to transport unsolicited,\r\n\
|
220-We do not authorize the use of this system to transport unsolicited,\r\n\
|
||||||
220 and/or bulk e-mail.\r\n";
|
220 and/or bulk e-mail.\r\n";
|
||||||
|
|
||||||
let (rem, out) = Greeting(greeting).unwrap();
|
let (rem, out) = greeting(buf).unwrap();
|
||||||
assert_eq!(rem, b"");
|
assert_eq!(rem, b"");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
out,
|
out,
|
||||||
|
@ -344,17 +344,17 @@ and/or bulk e-mail."
|
||||||
capabilities: vec![
|
capabilities: vec![
|
||||||
Capability::Auth(vec![
|
Capability::Auth(vec![
|
||||||
AuthMechanism::Login,
|
AuthMechanism::Login,
|
||||||
AuthMechanism::CramMD5,
|
AuthMechanism::CramMd5,
|
||||||
AuthMechanism::Plain
|
AuthMechanism::Plain
|
||||||
]),
|
]),
|
||||||
Capability::Auth(vec![
|
Capability::Auth(vec![
|
||||||
AuthMechanism::Login,
|
AuthMechanism::Login,
|
||||||
AuthMechanism::CramMD5,
|
AuthMechanism::CramMd5,
|
||||||
AuthMechanism::Plain
|
AuthMechanism::Plain
|
||||||
]),
|
]),
|
||||||
Capability::StartTLS,
|
Capability::StartTls,
|
||||||
Capability::Size(12345),
|
Capability::Size(12345),
|
||||||
Capability::EightBitMIME,
|
Capability::EightBitMime,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
86
src/types.rs
86
src/types.rs
|
@ -89,7 +89,7 @@ pub enum Command {
|
||||||
/// mail transaction will be aborted.
|
/// mail transaction will be aborted.
|
||||||
Quit,
|
Quit,
|
||||||
// Extensions
|
// Extensions
|
||||||
StartTLS,
|
StartTls,
|
||||||
// AUTH LOGIN
|
// AUTH LOGIN
|
||||||
AuthLogin(Option<String>),
|
AuthLogin(Option<String>),
|
||||||
// AUTH PLAIN
|
// AUTH PLAIN
|
||||||
|
@ -149,7 +149,7 @@ impl Command {
|
||||||
Command::Noop { .. } => "NOOP",
|
Command::Noop { .. } => "NOOP",
|
||||||
Command::Quit => "QUIT",
|
Command::Quit => "QUIT",
|
||||||
// Extensions
|
// Extensions
|
||||||
Command::StartTLS => "STARTTLS",
|
Command::StartTls => "STARTTLS",
|
||||||
// TODO: SMTP AUTH LOGIN
|
// TODO: SMTP AUTH LOGIN
|
||||||
Command::AuthLogin(_) => "AUTHLOGIN",
|
Command::AuthLogin(_) => "AUTHLOGIN",
|
||||||
// TODO: SMTP AUTH PLAIN
|
// TODO: SMTP AUTH PLAIN
|
||||||
|
@ -233,7 +233,7 @@ impl Command {
|
||||||
Quit => writer.write_all(b"QUIT")?,
|
Quit => writer.write_all(b"QUIT")?,
|
||||||
// ----- Extensions -----
|
// ----- Extensions -----
|
||||||
// starttls = "STARTTLS" CRLF
|
// starttls = "STARTTLS" CRLF
|
||||||
StartTLS => writer.write_all(b"STARTTLS")?,
|
StartTls => writer.write_all(b"STARTTLS")?,
|
||||||
// auth_login_command = "AUTH LOGIN" [SP username] CRLF
|
// auth_login_command = "AUTH LOGIN" [SP username] CRLF
|
||||||
AuthLogin(None) => {
|
AuthLogin(None) => {
|
||||||
writer.write_all(b"AUTH LOGIN")?;
|
writer.write_all(b"AUTH LOGIN")?;
|
||||||
|
@ -316,7 +316,7 @@ pub enum Response {
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn parse_greeting(input: &[u8]) -> IResult<&[u8], Self> {
|
pub fn parse_greeting(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
crate::parse::response::Greeting(input)
|
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
|
||||||
|
@ -335,7 +335,7 @@ impl Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_other(input: &[u8]) -> IResult<&[u8], Self> {
|
pub fn parse_other(input: &[u8]) -> IResult<&[u8], Self> {
|
||||||
crate::parse::response::Reply_lines(input)
|
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
|
||||||
|
@ -465,13 +465,13 @@ pub enum Capability {
|
||||||
|
|
||||||
/// Expand the mailing list [RFC821]
|
/// Expand the mailing list [RFC821]
|
||||||
/// Command description updated by [RFC5321]
|
/// Command description updated by [RFC5321]
|
||||||
EXPN,
|
Expn,
|
||||||
/// Supply helpful information [RFC821]
|
/// Supply helpful information [RFC821]
|
||||||
/// Command description updated by [RFC5321]
|
/// Command description updated by [RFC5321]
|
||||||
Help,
|
Help,
|
||||||
|
|
||||||
/// SMTP and Submit transport of 8bit MIME content [RFC6152]
|
/// SMTP and Submit transport of 8bit MIME content [RFC6152]
|
||||||
EightBitMIME,
|
EightBitMime,
|
||||||
|
|
||||||
/// Message size declaration [RFC1870]
|
/// Message size declaration [RFC1870]
|
||||||
Size(u32),
|
Size(u32),
|
||||||
|
@ -480,7 +480,7 @@ pub enum Capability {
|
||||||
Chunking,
|
Chunking,
|
||||||
|
|
||||||
/// Binary MIME [RFC3030]
|
/// Binary MIME [RFC3030]
|
||||||
BinaryMIME,
|
BinaryMime,
|
||||||
|
|
||||||
/// Checkpoint/Restart [RFC1845]
|
/// Checkpoint/Restart [RFC1845]
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
|
@ -492,34 +492,34 @@ pub enum Capability {
|
||||||
Pipelining,
|
Pipelining,
|
||||||
|
|
||||||
/// Delivery Status Notification [RFC3461]
|
/// Delivery Status Notification [RFC3461]
|
||||||
DSN,
|
Dsn,
|
||||||
|
|
||||||
/// Extended Turn [RFC1985]
|
/// Extended Turn [RFC1985]
|
||||||
/// SMTP [RFC5321] only. Not for use on Submit port 587.
|
/// SMTP [RFC5321] only. Not for use on Submit port 587.
|
||||||
ETRN,
|
Etrn,
|
||||||
|
|
||||||
/// Enhanced Status Codes [RFC2034]
|
/// Enhanced Status Codes [RFC2034]
|
||||||
EnhancedStatusCodes,
|
EnhancedStatusCodes,
|
||||||
|
|
||||||
/// Start TLS [RFC3207]
|
/// Start TLS [RFC3207]
|
||||||
StartTLS,
|
StartTls,
|
||||||
|
|
||||||
/// Notification of no soliciting [RFC3865]
|
/// Notification of no soliciting [RFC3865]
|
||||||
// NoSoliciting,
|
// NoSoliciting,
|
||||||
|
|
||||||
/// Message Tracking [RFC3885]
|
/// Message Tracking [RFC3885]
|
||||||
MTRK,
|
Mtrk,
|
||||||
|
|
||||||
/// Authenticated TURN [RFC2645]
|
/// Authenticated TURN [RFC2645]
|
||||||
/// SMTP [RFC5321] only. Not for use on Submit port 587.
|
/// SMTP [RFC5321] only. Not for use on Submit port 587.
|
||||||
ATRN,
|
Atrn,
|
||||||
|
|
||||||
/// Authentication [RFC4954]
|
/// Authentication [RFC4954]
|
||||||
Auth(Vec<AuthMechanism>),
|
Auth(Vec<AuthMechanism>),
|
||||||
|
|
||||||
/// Remote Content [RFC4468]
|
/// Remote Content [RFC4468]
|
||||||
/// Submit [RFC6409] only. Not for use with SMTP on port 25.
|
/// Submit [RFC6409] only. Not for use with SMTP on port 25.
|
||||||
BURL,
|
Burl,
|
||||||
|
|
||||||
/// Future Message Release [RFC4865]
|
/// Future Message Release [RFC4865]
|
||||||
// FutureRelease,
|
// FutureRelease,
|
||||||
|
@ -531,16 +531,16 @@ pub enum Capability {
|
||||||
// ConNeg,
|
// ConNeg,
|
||||||
|
|
||||||
/// Internationalized email address [RFC6531]
|
/// Internationalized email address [RFC6531]
|
||||||
SMTPUTF8,
|
SmtpUtf8,
|
||||||
|
|
||||||
/// Priority Message Handling [RFC6710]
|
/// Priority Message Handling [RFC6710]
|
||||||
// MTPRIORITY,
|
// MTPRIORITY,
|
||||||
|
|
||||||
/// Require Recipient Valid Since [RFC7293]
|
/// Require Recipient Valid Since [RFC7293]
|
||||||
RRVS,
|
Rrvs,
|
||||||
|
|
||||||
/// Require TLS [RFC8689]
|
/// Require TLS [RFC8689]
|
||||||
RequireTLS,
|
RequireTls,
|
||||||
|
|
||||||
// Observed ...
|
// Observed ...
|
||||||
// TIME,
|
// TIME,
|
||||||
|
@ -557,21 +557,21 @@ pub enum Capability {
|
||||||
impl Capability {
|
impl Capability {
|
||||||
pub fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
|
pub fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Capability::EXPN => writer.write_all(b"EXPN"),
|
Capability::Expn => writer.write_all(b"EXPN"),
|
||||||
Capability::Help => writer.write_all(b"HELP"),
|
Capability::Help => writer.write_all(b"HELP"),
|
||||||
Capability::EightBitMIME => writer.write_all(b"8BITMIME"),
|
Capability::EightBitMime => writer.write_all(b"8BITMIME"),
|
||||||
Capability::Size(number) => writer.write_all(format!("SIZE {}", number).as_bytes()),
|
Capability::Size(number) => writer.write_all(format!("SIZE {}", number).as_bytes()),
|
||||||
Capability::Chunking => writer.write_all(b"CHUNKING"),
|
Capability::Chunking => writer.write_all(b"CHUNKING"),
|
||||||
Capability::BinaryMIME => writer.write_all(b"BINARYMIME"),
|
Capability::BinaryMime => writer.write_all(b"BINARYMIME"),
|
||||||
Capability::Checkpoint => writer.write_all(b"CHECKPOINT"),
|
Capability::Checkpoint => writer.write_all(b"CHECKPOINT"),
|
||||||
Capability::DeliverBy => writer.write_all(b"DELIVERBY"),
|
Capability::DeliverBy => writer.write_all(b"DELIVERBY"),
|
||||||
Capability::Pipelining => writer.write_all(b"PIPELINING"),
|
Capability::Pipelining => writer.write_all(b"PIPELINING"),
|
||||||
Capability::DSN => writer.write_all(b"DSN"),
|
Capability::Dsn => writer.write_all(b"DSN"),
|
||||||
Capability::ETRN => writer.write_all(b"ETRN"),
|
Capability::Etrn => writer.write_all(b"ETRN"),
|
||||||
Capability::EnhancedStatusCodes => writer.write_all(b"ENHANCEDSTATUSCODES"),
|
Capability::EnhancedStatusCodes => writer.write_all(b"ENHANCEDSTATUSCODES"),
|
||||||
Capability::StartTLS => writer.write_all(b"STARTTLS"),
|
Capability::StartTls => writer.write_all(b"STARTTLS"),
|
||||||
Capability::MTRK => writer.write_all(b"MTRK"),
|
Capability::Mtrk => writer.write_all(b"MTRK"),
|
||||||
Capability::ATRN => writer.write_all(b"ATRN"),
|
Capability::Atrn => writer.write_all(b"ATRN"),
|
||||||
Capability::Auth(mechanisms) => {
|
Capability::Auth(mechanisms) => {
|
||||||
if let Some((tail, head)) = mechanisms.split_last() {
|
if let Some((tail, head)) = mechanisms.split_last() {
|
||||||
writer.write_all(b"AUTH ")?;
|
writer.write_all(b"AUTH ")?;
|
||||||
|
@ -586,10 +586,10 @@ impl Capability {
|
||||||
writer.write_all(b"AUTH")
|
writer.write_all(b"AUTH")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Capability::BURL => writer.write_all(b"BURL"),
|
Capability::Burl => writer.write_all(b"BURL"),
|
||||||
Capability::SMTPUTF8 => writer.write_all(b"SMTPUTF8"),
|
Capability::SmtpUtf8 => writer.write_all(b"SMTPUTF8"),
|
||||||
Capability::RRVS => writer.write_all(b"RRVS"),
|
Capability::Rrvs => writer.write_all(b"RRVS"),
|
||||||
Capability::RequireTLS => writer.write_all(b"REQUIRETLS"),
|
Capability::RequireTls => writer.write_all(b"REQUIRETLS"),
|
||||||
Capability::Other { keyword, params } => {
|
Capability::Other { keyword, params } => {
|
||||||
if let Some((tail, head)) = params.split_last() {
|
if let Some((tail, head)) = params.split_last() {
|
||||||
writer.write_all(keyword.as_bytes())?;
|
writer.write_all(keyword.as_bytes())?;
|
||||||
|
@ -773,13 +773,13 @@ impl From<ReplyCode> for u16 {
|
||||||
pub enum AuthMechanism {
|
pub enum AuthMechanism {
|
||||||
Plain,
|
Plain,
|
||||||
Login,
|
Login,
|
||||||
GSSAPI,
|
GssApi,
|
||||||
|
|
||||||
CramMD5,
|
CramMd5,
|
||||||
CramSHA1,
|
CramSha1,
|
||||||
ScramMD5,
|
ScramMd5,
|
||||||
DigestMD5,
|
DigestMd5,
|
||||||
NTLM,
|
Ntlm,
|
||||||
|
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
@ -789,13 +789,13 @@ impl AuthMechanism {
|
||||||
match self {
|
match self {
|
||||||
AuthMechanism::Plain => writer.write_all(b"PLAIN"),
|
AuthMechanism::Plain => writer.write_all(b"PLAIN"),
|
||||||
AuthMechanism::Login => writer.write_all(b"LOGIN"),
|
AuthMechanism::Login => writer.write_all(b"LOGIN"),
|
||||||
AuthMechanism::GSSAPI => writer.write_all(b"GSSAPI"),
|
AuthMechanism::GssApi => writer.write_all(b"GSSAPI"),
|
||||||
|
|
||||||
AuthMechanism::CramMD5 => writer.write_all(b"CRAM-MD5"),
|
AuthMechanism::CramMd5 => writer.write_all(b"CRAM-MD5"),
|
||||||
AuthMechanism::CramSHA1 => writer.write_all(b"CRAM-SHA1"),
|
AuthMechanism::CramSha1 => writer.write_all(b"CRAM-SHA1"),
|
||||||
AuthMechanism::ScramMD5 => writer.write_all(b"SCRAM-MD5"),
|
AuthMechanism::ScramMd5 => writer.write_all(b"SCRAM-MD5"),
|
||||||
AuthMechanism::DigestMD5 => writer.write_all(b"DIGEST-MD5"),
|
AuthMechanism::DigestMd5 => writer.write_all(b"DIGEST-MD5"),
|
||||||
AuthMechanism::NTLM => writer.write_all(b"NTLM"),
|
AuthMechanism::Ntlm => writer.write_all(b"NTLM"),
|
||||||
|
|
||||||
AuthMechanism::Other(other) => writer.write_all(other.as_bytes()),
|
AuthMechanism::Other(other) => writer.write_all(other.as_bytes()),
|
||||||
}
|
}
|
||||||
|
@ -912,7 +912,7 @@ mod tests {
|
||||||
Response::Ehlo {
|
Response::Ehlo {
|
||||||
domain: "example.org".into(),
|
domain: "example.org".into(),
|
||||||
greet: Some("...".into()),
|
greet: Some("...".into()),
|
||||||
capabilities: vec![Capability::StartTLS],
|
capabilities: vec![Capability::StartTls],
|
||||||
},
|
},
|
||||||
b"250-example.org ...\r\n250 STARTTLS\r\n".as_ref(),
|
b"250-example.org ...\r\n250 STARTTLS\r\n".as_ref(),
|
||||||
),
|
),
|
||||||
|
@ -920,7 +920,7 @@ mod tests {
|
||||||
Response::Ehlo {
|
Response::Ehlo {
|
||||||
domain: "example.org".into(),
|
domain: "example.org".into(),
|
||||||
greet: Some("...".into()),
|
greet: Some("...".into()),
|
||||||
capabilities: vec![Capability::StartTLS, Capability::Size(12345)],
|
capabilities: vec![Capability::StartTls, Capability::Size(12345)],
|
||||||
},
|
},
|
||||||
b"250-example.org ...\r\n250-STARTTLS\r\n250 SIZE 12345\r\n".as_ref(),
|
b"250-example.org ...\r\n250-STARTTLS\r\n250 SIZE 12345\r\n".as_ref(),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue