some refactor

This commit is contained in:
Quentin 2023-07-23 09:46:57 +02:00
parent 00d36fd498
commit 18b081cb9a
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 100 additions and 50 deletions

View file

@ -3,13 +3,12 @@ use nom::{
branch::alt, branch::alt,
bytes::complete::{tag_no_case, tag, take_while1}, bytes::complete::{tag_no_case, tag, take_while1},
character::complete::space0, character::complete::space0,
combinator::{not, map}, combinator::{map},
multi::many0, multi::many0,
sequence::{pair, preceded, terminated, tuple}, sequence::{pair, terminated, tuple},
}; };
use crate::text::whitespace::{foldable_line, obs_crlf}; use crate::text::whitespace::{foldable_line, obs_crlf};
use crate::text::misc_token::{Unstructured, unstructured}; use crate::text::misc_token::{Unstructured, unstructured};
use crate::text::boundary::boundary;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum CompField<'a, T> { pub enum CompField<'a, T> {
@ -39,6 +38,7 @@ pub fn header<'a, T>(fx: impl Fn(&'a [u8]) -> IResult<&[u8], T> + Copy)
))), obs_crlf), CompFieldList)(input) ))), obs_crlf), CompFieldList)(input)
} }
/*
pub fn header_in_boundaries<'a, T>(bound: &'a [u8], fx: impl Fn(&'a [u8]) -> IResult<&[u8], T> + Copy) pub fn header_in_boundaries<'a, T>(bound: &'a [u8], fx: impl Fn(&'a [u8]) -> IResult<&[u8], T> + Copy)
-> impl Fn(&'a [u8]) -> IResult<&[u8], CompFieldList<T>> -> impl Fn(&'a [u8]) -> IResult<&[u8], CompFieldList<T>>
{ {
@ -50,6 +50,7 @@ pub fn header_in_boundaries<'a, T>(bound: &'a [u8], fx: impl Fn(&'a [u8]) -> IRe
map(foldable_line, CompField::Bad), map(foldable_line, CompField::Bad),
)))), obs_crlf), CompFieldList)(input) )))), obs_crlf), CompFieldList)(input)
} }
*/
pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> { pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
move |input| { move |input| {

View file

@ -2,21 +2,28 @@ use crate::mime::mechanism::Mechanism;
use crate::rfc5322::identification::MessageID; use crate::rfc5322::identification::MessageID;
use crate::text::misc_token::Unstructured; use crate::text::misc_token::Unstructured;
use crate::mime::field::Content; use crate::mime::field::Content;
use crate::mime::r#type::{AnyType, Multipart, Message, Text, Binary}; use crate::mime::r#type::{AnyType, self as ctype}; //Multipart, Message, Text, Binary};
//
pub struct Multipart<'a>(pub ctype::Multipart, Generic<'a>);
pub struct Message<'a>(pub ctype::Message, Generic<'a>);
pub struct Text<'a>(pub ctype::Text, Generic<'a>);
pub struct Binary<'a>(pub ctype::Binary, Generic<'a>);
pub enum AnyMIME<'a> { pub enum AnyMIME<'a> {
Multipart(Multipart, Generic<'a>), Mult(Multipart<'a>),
Message(Message, Generic<'a>), Msg(Message<'a>),
Text(Text, Generic<'a>), Txt(Text<'a>),
Binary(Binary, Generic<'a>), Bin(Binary<'a>),
} }
impl<'a> AnyMIME<'a> { impl<'a> AnyMIME<'a> {
pub fn from_pair(at: AnyType, gen: Generic<'a>) -> Self { pub fn from_pair(at: AnyType, gen: Generic<'a>) -> Self {
match at { match at {
AnyType::Multipart(m) => AnyMIME::Multipart(m, gen), AnyType::Multipart(m) => AnyMIME::Mult(Multipart(m, gen)),
AnyType::Message(m) => AnyMIME::Message(m, gen), AnyType::Message(m) => AnyMIME::Msg(Message(m, gen)),
AnyType::Text(m) => AnyMIME::Text(m, gen), AnyType::Text(m) => AnyMIME::Txt(Text(m, gen)),
AnyType::Binary(m) => AnyMIME::Binary(m, gen), AnyType::Binary(m) => AnyMIME::Bin(Binary(m, gen)),
} }
} }
} }

1
src/part/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod part;

View file

@ -7,65 +7,105 @@ use nom::{
combinator::{not, opt, recognize}, combinator::{not, opt, recognize},
}; };
use crate::mime::r#type; use crate::mime::r#type as ctype;
use crate::mime::mime;
use crate::rfc5322::{self as imf};
pub struct Part<'a> { pub struct Multipart(pub mime::Multipart, pub Vec<Part<'a>>);
Multipart(Multipart<MIME>, Vec<Part<'a>>), pub struct Message(pub mime::Message, pub imf::message::Message, pub Part<'a>);
Message(MIME<Message>, Message, Part<'a>), pub struct Text(pub mime::Text, pub &'a [u8]);
Text(MIME<Text>, &'a [u8]), pub struct Binary(pub mime::Binary, pub &'a [u8]);
Binary(MIME<Binary>, &'a [u8]),
pub struct AnyPart<'a> {
Mult(Multipart<'a>),
Msg(Message<'a>),
Txt(Text<'a>),
Bin(Binary<'a>),
} }
pub struct Part<'a> { pub enum MixedField<'a> {
List(Vec<Part<'a>>), MIME(mime::fields::Content<'a>),
Single(Part<'a>), IMF(rfc5322::fields::Field<'a>),
Leaf(&'a [u8]), }
impl<'a> MixedField<'a> {
pub fn mime(&self) -> Option<&mime::fields::Content<'a>> {
match self {
MIME(v) => Some(v),
_ => None,
}
}
pub fn imf(&self) -> Option<&rfc5322::fields::Field<'a>> {
match self {
IMF(v) => Some(v),
_ => None,
}
}
}
impl<'a, MixedField> CompFieldList<'a, MixedField> {
pub fn sections(self) -> (mime::mime::AnyMIME<'a>, imf::message::Message<'a>) {
let k = self.known();
let mime = k.iter().map(MixedField::mime).flatten().collect::<mime::mime::AnyMIME>();
let imf = k.iter().map(MixedField::imf).flatten().collect::<imf::message::Message>();
(mime, imf)
}
}
pub fn mixed_field(input: &[u8]) -> IResult<&[u8], MixedField> {
alt((
map(mime::fields::content, MixedField::MIME),
map(rfc5322::fields::field, MixedField::IMF),
))(input)
} }
pub fn message() -> IResult<&[u8], Part> { pub fn message<'a>(m: mime::Message<'a>) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Message<'a>> {
}
pub fn multipart<'a>(m: Multipart<MIME>) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Part<'a>> {
move |input: &[u8]| { move |input: &[u8]| {
let (mut input_loop, _) = preamble(m.ctype.boundary)(input)?; let (input, fields) = header(mixed_field)(input)?;
let mut parts: Vec<Part> = vec![]; let (in_mime, imf) = fields.sections();
let part = to_anypart(in_mime, input);
Ok((&b[], Message(m, imf, part)))
}
}
pub fn multipart<'a>(m: mime::Multipart<'a>) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Multipart<'a>> {
move |input: &[u8]| {
let (mut input_loop, _) = part_raw(m.ctype.boundary)(input)?;
let mut mparts: Vec<AnyPart> = vec![];
loop { loop {
let input = match boundary(m.ctype.boundary)(input_loop) { let input = match boundary(m.ctype.boundary)(input_loop) {
Err(_) => return Ok((input_loop, parts)), Err(_) => return Ok((input_loop, Multipart(m, mparts))),
Ok((inp, Delimiter::Last)) => return Ok((inp, Part::List(parts))), Ok((inp, Delimiter::Last)) => return Ok((inp, Multipart(m, mparts))),
Ok((inp, Delimiter::Next)) => inp, Ok((inp, Delimiter::Next)) => inp,
}; };
// parse mime headers // parse mime headers
let (input, fields) = header_in_boundaries(ctype.boundary, content)(input)?; let (input, fields) = header(content)(input)?;
let mime = fields.to_mime(); let mime = fields.to_mime();
// parse raw part
let (input, rpart) = part_raw(ctype.boundary.as_bytes())(input)?;
// parse mime body // parse mime body
match mime.part_type { mparts.push(to_anypart(mime, rpart);
Type::Multipart(m) => multipart(m),
Type::Message(m) => message(m),
Type::Text(t) | Type::Binary
}
// based on headers, parse part
let input = match part(bound)(input) {
Err(_) => return Ok((input, parts)),
Ok((inp, part)) => {
parts.push(part);
inp
}
};
input_loop = input; input_loop = input;
} }
} }
} }
pub fn discrete() -> IResult<&[u8], Part> { pub fn to_anypart(m: AnyMIME<'a>, rpart: &[u8]) -> AnyPart<'a> {
match mime {
AnyMIME::Mult(a) => map(multipart(a), AnyPart::Mult)(rpart)
.unwrap_or(AnyPart::Text(Text::default(), rpart)),
AnyMIME::Msg(a) => map(message(a), AnyPart::Msg)(rpart)
.unwrap_or(AnyPart::Text(Text::default(), rpart)),
AnyMIME::Txt(a) => AnyPart::Txt(Text(a, rpart)),
AnyMIME::Bin(a) => AnyPart::Bin(Binary(a, rpart)),
}
} }
pub fn part<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
pub fn part_raw<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
move |input: &[u8]| { move |input: &[u8]| {
recognize(many0(pair( recognize(many0(pair(
not(boundary(bound)), not(boundary(bound)),
@ -74,6 +114,7 @@ pub fn part<'a>(bound: &'a [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]> { pub fn preamble<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
move |input: &[u8]| { move |input: &[u8]| {
recognize(many0(tuple(( recognize(many0(tuple((
@ -81,7 +122,7 @@ pub fn preamble<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &
many0(pair(not(boundary(bound)), obs_crlf)), many0(pair(not(boundary(bound)), obs_crlf)),
))))(input) ))))(input)
} }
} }*/
// FIXME parse email here // FIXME parse email here
@ -111,7 +152,7 @@ Field: Body
} }
#[test] #[test]
fn test_part() { fn test_part_raw() {
assert_eq!( assert_eq!(
part(b"simple boundary")(b"Content-type: text/plain; charset=us-ascii part(b"simple boundary")(b"Content-type: text/plain; charset=us-ascii