mirror of
https://github.com/instant-labs/instant-smtp.git
synced 2025-02-16 15:02:03 +00:00
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]
|
||||
pub fn esmtp_param(input: &[u8]) -> IResult<&[u8], Parameter> {
|
||||
map(
|
||||
tuple((esmtp_keyword, opt(preceded(tag(b"="), esmtp_value)))),
|
||||
|(keyword, value)| Parameter::new(keyword, value),
|
||||
)(input)
|
||||
alt((
|
||||
map_res(tuple((tag_no_case(b"SIZE="), esmtp_value)), |(_, value)| {
|
||||
value.parse().map(Parameter::Size)
|
||||
}),
|
||||
map(
|
||||
tuple((esmtp_keyword, opt(preceded(tag(b"="), esmtp_value)))),
|
||||
|(keyword, value)| Parameter::Other {
|
||||
keyword: keyword.to_owned(),
|
||||
value: value.map(String::from),
|
||||
},
|
||||
),
|
||||
))(input)
|
||||
}
|
||||
|
||||
/// esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
|
||||
@ -353,7 +361,7 @@ pub fn Dot_string(input: &[u8]) -> IResult<&[u8], &str> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{ehlo, helo, mail};
|
||||
use super::{ehlo, helo, mail, Parameter};
|
||||
use crate::types::{Command, DomainOrAddress};
|
||||
|
||||
#[test]
|
||||
@ -382,12 +390,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
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!(
|
||||
parsed,
|
||||
Command::Mail {
|
||||
reverse_path: "userx@y.foo.org".into(),
|
||||
parameters: Vec::default(),
|
||||
parameters: vec![Parameter::Size(12345)],
|
||||
}
|
||||
);
|
||||
assert_eq!(rem, b"???");
|
||||
|
35
src/types.rs
35
src/types.rs
@ -110,9 +110,14 @@ impl DomainOrAddress {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Parameter {
|
||||
keyword: String,
|
||||
value: Option<String>,
|
||||
#[non_exhaustive]
|
||||
pub enum Parameter {
|
||||
/// Message size declaration [RFC1870]
|
||||
Size(u32),
|
||||
Other {
|
||||
keyword: String,
|
||||
value: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -244,20 +249,20 @@ impl Command {
|
||||
}
|
||||
|
||||
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<()> {
|
||||
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 {
|
||||
writer.write_all(b"=")?;
|
||||
writer.write_all(value.as_bytes())?;
|
||||
}
|
||||
if let Some(ref value) = value {
|
||||
writer.write_all(b"=")?;
|
||||
writer.write_all(value.as_bytes())?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user