From e963965e770843475fc41a34053c6d91e7227db9 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Sun, 23 Jul 2023 16:20:38 +0200 Subject: [PATCH] working message parsing! --- src/mime/mime.rs | 2 +- src/mime/type.rs | 3 +- src/part/part.rs | 180 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 171 insertions(+), 14 deletions(-) diff --git a/src/mime/mime.rs b/src/mime/mime.rs index 97d5fe4..152b493 100644 --- a/src/mime/mime.rs +++ b/src/mime/mime.rs @@ -7,7 +7,7 @@ use crate::mime::r#type::{AnyType, self as ctype}; //Multipart, Message, Text, B #[derive(Debug, PartialEq, Clone)] pub struct Multipart<'a>(pub ctype::Multipart, pub Generic<'a>); -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct Message<'a>(pub ctype::Message, pub Generic<'a>); #[derive(Debug, PartialEq, Clone, Default)] diff --git a/src/mime/type.rs b/src/mime/type.rs index e038a17..5cef456 100644 --- a/src/mime/type.rs +++ b/src/mime/type.rs @@ -109,8 +109,9 @@ impl<'a> From<&NaiveType<'a>> for MultipartSubtype { } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Default, Clone)] pub enum Message { + #[default] RFC822, Partial, External, diff --git a/src/part/part.rs b/src/part/part.rs index a0e3828..c2ea11d 100644 --- a/src/part/part.rs +++ b/src/part/part.rs @@ -144,21 +144,12 @@ pub fn part_raw<'a>(bound: &[u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a } } -/* -pub fn preamble<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> { - move |input: &[u8]| { - recognize(many0(tuple(( - is_not(CRLF), - many0(pair(not(boundary(bound)), obs_crlf)), - ))))(input) - } -}*/ - -// FIXME parse email here - #[cfg(test)] mod tests { use super::*; + use chrono::{FixedOffset, TimeZone}; + use crate::text::misc_token::{Word, Phrase, Unstructured, UnstrToken}; + use crate::text::encoding::{EncodedWord, QuotedChunk, Base64Word, QuotedWord}; #[test] fn test_preamble() { @@ -256,4 +247,169 @@ This is the epilogue. It is also to be ignored. )) ); } + + #[test] + fn test_message() { + let fullmail: &[u8] = r#"Date: Sat, 8 Jul 2023 07:14:29 +0200 +From: Grrrnd Zero +To: John Doe +CC: =?ISO-8859-1?Q?Andr=E9?= Pirard +Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= + =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?= +X-Unknown: something something +Bad entry + on multiple lines +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="b1_e376dc71bafc953c0b0fdeb9983a9956" +Content-Transfer-Encoding: 7bit + +This is a multi-part message in MIME format. + +--b1_e376dc71bafc953c0b0fdeb9983a9956 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +GZ +OoOoO +oOoOoOoOo +oOoOoOoOoOoOoOoOo +oOoOoOoOoOoOoOoOoOoOoOo +oOoOoOoOoOoOoOoOoOoOoOoOoOoOo +OoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO + +--b1_e376dc71bafc953c0b0fdeb9983a9956 +Content-Type: text/html; charset=us-ascii + +
GZ
+OoOoO
+oOoOoOoOo
+oOoOoOoOoOoOoOoOo
+oOoOoOoOoOoOoOoOoOoOoOo
+oOoOoOoOoOoOoOoOoOoOoOoOoOoOo
+OoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO
+
+ +--b1_e376dc71bafc953c0b0fdeb9983a9956-- +"#.as_bytes(); + + let base_mime = mime::mime::Message::default(); + assert_eq!( + message(base_mime.clone())(fullmail), + Ok(( + &[][..], + Message ( + base_mime, + imf::message::Message { + date: Some(FixedOffset::east_opt(2 * 3600) + .unwrap() + .with_ymd_and_hms(2023, 07, 8, 7, 14, 29) + .unwrap()), + from: vec![ + imf::mailbox::MailboxRef { + name: Some(Phrase(vec![Word::Atom(&b"Grrrnd"[..]), Word::Atom(&b"Zero"[..])])), + addrspec: imf::mailbox::AddrSpec { + local_part: imf::mailbox::LocalPart(vec![ + imf::mailbox::LocalPartToken::Word(Word::Atom(&b"grrrndzero"[..])) + ]), + domain: imf::mailbox::Domain::Atoms(vec![&b"example"[..], &b"org"[..]]), + } + }, + ], + + to: vec![imf::address::AddressRef::Single(imf::mailbox::MailboxRef { + name: Some(Phrase(vec![Word::Atom(&b"John"[..]), Word::Atom(&b"Doe"[..])])), + addrspec: imf::mailbox::AddrSpec { + local_part: imf::mailbox::LocalPart(vec![ + imf::mailbox::LocalPartToken::Word(Word::Atom(&b"jdoe"[..])) + ]), + domain: imf::mailbox::Domain::Atoms(vec![&b"machine"[..], &b"example"[..]]), + } + })], + + cc: vec![imf::address::AddressRef::Single(imf::mailbox::MailboxRef { + name: Some(Phrase(vec![ + Word::Encoded(EncodedWord::Quoted(QuotedWord { + enc: encoding_rs::WINDOWS_1252, + chunks: vec![ + QuotedChunk::Safe(&b"Andr"[..]), + QuotedChunk::Encoded(0xE9), + ], + })), + Word::Atom(&b"Pirard"[..]) + ])), + addrspec: imf::mailbox::AddrSpec { + local_part: imf::mailbox::LocalPart(vec![ + imf::mailbox::LocalPartToken::Word(Word::Atom(&b"PIRARD"[..])) + ]), + domain: imf::mailbox::Domain::Atoms(vec![ + &b"vm1"[..], &b"ulg"[..], &b"ac"[..], &b"be"[..], + ]), + } + })], + + subject: Some(Unstructured(vec![ + UnstrToken::Encoded(EncodedWord::Base64(Base64Word{ + enc: encoding_rs::WINDOWS_1252, + content: &b"SWYgeW91IGNhbiByZWFkIHRoaXMgeW8"[..], + })), + UnstrToken::Encoded(EncodedWord::Base64(Base64Word{ + enc: encoding_rs::ISO_8859_2, + content: &b"dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg"[..], + })), + ])), + msg_id: Some(imf::identification::MessageID { + left: &b"NTAxNzA2AC47634Y366BAMTY4ODc5MzQyODY0ODY5"[..], + right: &b"www.grrrndzero.org"[..], + }), + mime_version: Some(imf::mime::Version { major: 1, minor: 0}), + ..imf::message::Message::default() + }, + Box::new(AnyPart::Mult(Multipart ( + mime::mime::Multipart( + mime::r#type::Multipart { + subtype: mime::r#type::MultipartSubtype::Alternative, + boundary: "b1_e376dc71bafc953c0b0fdeb9983a9956".to_string(), + }, + mime::mime::Generic::default(), + ), + vec![ + AnyPart::Txt(Text( + mime::mime::Text( + mime::r#type::Text { + subtype: mime::r#type::TextSubtype::Plain, + charset: mime::charset::EmailCharset::UTF_8, + }, + mime::mime::Generic { + transfer_encoding: mime::mechanism::Mechanism::QuotedPrintable, + ..mime::mime::Generic::default() + } + ), + &b"GZ\nOoOoO\noOoOoOoOo\noOoOoOoOoOoOoOoOo\noOoOoOoOoOoOoOoOoOoOoOo\noOoOoOoOoOoOoOoOoOoOoOoOoOoOo\nOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO\n"[..], + )), + AnyPart::Txt(Text( + mime::mime::Text( + mime::r#type::Text { + subtype: mime::r#type::TextSubtype::Html, + charset: mime::charset::EmailCharset::US_ASCII, + }, + mime::mime::Generic::default(), + ), + &br#"
GZ
+OoOoO
+oOoOoOoOo
+oOoOoOoOoOoOoOoOo
+oOoOoOoOoOoOoOoOoOoOoOo
+oOoOoOoOoOoOoOoOoOoOoOoOoOoOo
+OoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO
+
+"#[..], + )), + ], + ))), + ), + )) + ); + } }