some refactor
This commit is contained in:
parent
00d36fd498
commit
18b081cb9a
4 changed files with 100 additions and 50 deletions
|
@ -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| {
|
||||||
|
|
|
@ -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
1
src/part/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod part;
|
117
src/part/part.rs
117
src/part/part.rs
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue