Add typed support for `SIZE` parameter (RFC 1870)
This also makes `Parameter` type an enum so future type support for other parameters can be more easily added. Note that the enum is non-exhaustive so that future variant addtions would not cause API breaks.
This commit is contained in:
parent
1065b44eef
commit
6c6fa0f2ff
|
@ -88,10 +88,18 @@ pub fn Mail_parameters(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
||||||
|
|
||||||
/// esmtp-param = esmtp-keyword ["=" esmtp-value]
|
/// esmtp-param = esmtp-keyword ["=" esmtp-value]
|
||||||
pub fn esmtp_param(input: &[u8]) -> IResult<&[u8], Parameter> {
|
pub fn esmtp_param(input: &[u8]) -> IResult<&[u8], Parameter> {
|
||||||
|
alt((
|
||||||
|
map_res(tuple((tag_no_case(b"SIZE="), esmtp_value)), |(_, value)| {
|
||||||
|
value.parse().map(Parameter::Size)
|
||||||
|
}),
|
||||||
map(
|
map(
|
||||||
tuple((esmtp_keyword, opt(preceded(tag(b"="), esmtp_value)))),
|
tuple((esmtp_keyword, opt(preceded(tag(b"="), esmtp_value)))),
|
||||||
|(keyword, value)| Parameter::new(keyword, value),
|
|(keyword, value)| Parameter::Other {
|
||||||
)(input)
|
keyword: keyword.to_owned(),
|
||||||
|
value: value.map(String::from),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
|
/// esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
|
||||||
|
@ -353,7 +361,7 @@ pub fn Dot_string(input: &[u8]) -> IResult<&[u8], &str> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{ehlo, helo, mail};
|
use super::{ehlo, helo, mail, Parameter};
|
||||||
use crate::types::{Command, DomainOrAddress};
|
use crate::types::{Command, DomainOrAddress};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -382,12 +390,12 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mail() {
|
fn test_mail() {
|
||||||
let (rem, parsed) = mail(b"MAIL FROM:<userx@y.foo.org>\r\n???").unwrap();
|
let (rem, parsed) = mail(b"MAIL FROM:<userx@y.foo.org> size=12345\r\n???").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parsed,
|
parsed,
|
||||||
Command::Mail {
|
Command::Mail {
|
||||||
reverse_path: "userx@y.foo.org".into(),
|
reverse_path: "userx@y.foo.org".into(),
|
||||||
parameters: Vec::default(),
|
parameters: vec![Parameter::Size(12345)],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(rem, b"???");
|
assert_eq!(rem, b"???");
|
||||||
|
|
25
src/types.rs
25
src/types.rs
|
@ -110,9 +110,14 @@ impl DomainOrAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Parameter {
|
#[non_exhaustive]
|
||||||
|
pub enum Parameter {
|
||||||
|
/// Message size declaration [RFC1870]
|
||||||
|
Size(u32),
|
||||||
|
Other {
|
||||||
keyword: String,
|
keyword: String,
|
||||||
value: Option<String>,
|
value: Option<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -244,20 +249,20 @@ impl Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parameter {
|
impl Parameter {
|
||||||
pub fn new<K: Into<String>, V: Into<String>>(keyword: K, value: Option<V>) -> Parameter {
|
|
||||||
Parameter {
|
|
||||||
keyword: keyword.into(),
|
|
||||||
value: value.map(Into::into),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
|
pub fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
|
||||||
writer.write_all(self.keyword.as_bytes())?;
|
match self {
|
||||||
|
Parameter::Size(size) => {
|
||||||
|
write!(writer, "SIZE={}", size)?;
|
||||||
|
}
|
||||||
|
Parameter::Other { keyword, value } => {
|
||||||
|
writer.write_all(keyword.as_bytes())?;
|
||||||
|
|
||||||
if let Some(ref value) = self.value {
|
if let Some(ref value) = value {
|
||||||
writer.write_all(b"=")?;
|
writer.write_all(b"=")?;
|
||||||
writer.write_all(value.as_bytes())?;
|
writer.write_all(value.as_bytes())?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue