From 4baa97628353e18ab6469d76c871d4b4953e85ed Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Sat, 22 Jul 2023 12:55:27 +0200 Subject: [PATCH] parse mime fields --- src/mime/field.rs | 66 +++++++++++++++++++++++--------- src/mime/{section.rs => mime.rs} | 0 src/mime/mod.rs | 2 +- src/part/field.rs | 0 src/{mime => part}/part.rs | 0 5 files changed, 49 insertions(+), 19 deletions(-) rename src/mime/{section.rs => mime.rs} (100%) create mode 100644 src/part/field.rs rename src/{mime => part}/part.rs (100%) diff --git a/src/mime/field.rs b/src/mime/field.rs index 043e229..9d39ef3 100644 --- a/src/mime/field.rs +++ b/src/mime/field.rs @@ -1,25 +1,55 @@ +use nom::{ + IResult, + branch::alt, + combinator::map, + sequence::{preceded, terminated}, +}; + +use crate::text::whitespace::obs_crlf; +use crate::text::misc_token::{Unstructured, unstructured}; +use crate::rfc5322::identification::{MessageID, msg_id}; +use crate::header::field_name; +use crate::mime::r#type::{NaiveType, naive_type}; +use crate::mime::mechanism::{Mechanism, mechanism}; + #[derive(Debug, PartialEq)] pub enum Content<'a> { - Type(Type<'a>), + Type(NaiveType<'a>), TransferEncoding(Mechanism<'a>), - ID(MessageId<'a>), - Description(Unstructured), + ID(MessageID<'a>), + Description(Unstructured<'a>), } -fn field(input: &str) -> IResult<&str, Content> { +fn field(input: &[u8]) -> IResult<&[u8], Content> { terminated(alt(( - preceded(field_name(b"content-type"), map(date, Field::Date)), - - field_name(input).map(|(rest, name)| { - ( - "", - match name.to_lowercase().as_ref() { - "" => ContentType(Type(rest)), - "content-transfer-encoding" => ContentTransferEncoding(Mechanism(rest)), - "content-id" => ContentID(Identifier(rest)), - "content-description" => ContentDescription(Unstructured(rest)), - _ => Optional(name, Unstructured(rest)), - } - ) - }) + preceded(field_name(b"content-type"), map(naive_type, Content::Type)), + preceded(field_name(b"content-transfer-encoding"), map(mechanism, Content::TransferEncoding)), + preceded(field_name(b"content-id"), map(msg_id, Content::ID)), + preceded(field_name(b"content-description"), map(unstructured, Content::Description)), + )), obs_crlf)(input) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mime::r#type::*; + use crate::mime::charset::EmailCharset; + + #[test] + fn test_content_type() { + let (rest, content) = field(b"Content-Type: text/plain; charset=UTF-8; format=flowed\r\n").unwrap(); + assert_eq!(&b""[..], rest); + + if let Content::Type(nt) = content { + assert_eq!( + nt.to_type(), + Type::Text(TextDesc { + charset: EmailCharset::UTF_8, + subtype: TextSubtype::Plain, + }), + ); + } else { + panic!("Expected Content::Type, got {:?}", content); + } + } } diff --git a/src/mime/section.rs b/src/mime/mime.rs similarity index 100% rename from src/mime/section.rs rename to src/mime/mime.rs diff --git a/src/mime/mod.rs b/src/mime/mod.rs index 7f7117a..a128165 100644 --- a/src/mime/mod.rs +++ b/src/mime/mod.rs @@ -1,4 +1,4 @@ pub mod charset; pub mod mechanism; pub mod r#type; -//pub mod field; +pub mod field; diff --git a/src/part/field.rs b/src/part/field.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/mime/part.rs b/src/part/part.rs similarity index 100% rename from src/mime/part.rs rename to src/part/part.rs