new approach to build mimeheader
This commit is contained in:
parent
7195e5f661
commit
00d36fd498
4 changed files with 208 additions and 160 deletions
|
@ -11,7 +11,7 @@ use crate::rfc5322::identification::{MessageID, msg_id};
|
||||||
use crate::header::{field_name, CompFieldList};
|
use crate::header::{field_name, CompFieldList};
|
||||||
use crate::mime::r#type::{NaiveType, naive_type};
|
use crate::mime::r#type::{NaiveType, naive_type};
|
||||||
use crate::mime::mechanism::{Mechanism, mechanism};
|
use crate::mime::mechanism::{Mechanism, mechanism};
|
||||||
use crate::mime::mime::MIME;
|
use crate::mime::mime::AnyMIME;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Content<'a> {
|
pub enum Content<'a> {
|
||||||
|
@ -20,8 +20,25 @@ pub enum Content<'a> {
|
||||||
ID(MessageID<'a>),
|
ID(MessageID<'a>),
|
||||||
Description(Unstructured<'a>),
|
Description(Unstructured<'a>),
|
||||||
}
|
}
|
||||||
|
impl<'a> Content<'a> {
|
||||||
|
pub fn ctype(&'a self) -> Option<&'a NaiveType<'a>> {
|
||||||
|
match self { Content::Type(v) => Some(v), _ => None }
|
||||||
|
}
|
||||||
|
pub fn transfer_encoding(&'a self) -> Option<&'a Mechanism<'a>> {
|
||||||
|
match self { Content::TransferEncoding(v) => Some(v), _ => None }
|
||||||
|
}
|
||||||
|
pub fn id(&'a self) -> Option<&'a MessageID<'a>> {
|
||||||
|
match self { Content::ID(v) => Some(v), _ => None }
|
||||||
|
}
|
||||||
|
pub fn description(&'a self) -> Option<&'a Unstructured<'a>> {
|
||||||
|
match self { Content::Description(v) => Some(v), _ => None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> CompFieldList<'a, Content<'a>> {
|
impl<'a> CompFieldList<'a, Content<'a>> {
|
||||||
pub fn to_mime(self) -> MIME<'a> { self.known().into_iter().collect::<MIME>() }
|
pub fn to_mime(self) -> AnyMIME<'a> {
|
||||||
|
self.known().into_iter().collect::<AnyMIME>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(input: &[u8]) -> IResult<&[u8], Content> {
|
pub fn content(input: &[u8]) -> IResult<&[u8], Content> {
|
||||||
|
@ -37,7 +54,6 @@ pub fn content(input: &[u8]) -> IResult<&[u8], Content> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mime::r#type::*;
|
use crate::mime::r#type::*;
|
||||||
use crate::mime::mime::*;
|
|
||||||
use crate::mime::charset::EmailCharset;
|
use crate::mime::charset::EmailCharset;
|
||||||
use crate::text::misc_token::MIMEWord;
|
use crate::text::misc_token::MIMEWord;
|
||||||
use crate::text::quoted::QuotedString;
|
use crate::text::quoted::QuotedString;
|
||||||
|
@ -51,7 +67,7 @@ mod tests {
|
||||||
if let Content::Type(nt) = content {
|
if let Content::Type(nt) = content {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nt.to_type(),
|
nt.to_type(),
|
||||||
Type::Text(Text {
|
AnyType::Text(Text {
|
||||||
charset: EmailCharset::UTF_8,
|
charset: EmailCharset::UTF_8,
|
||||||
subtype: TextSubtype::Plain,
|
subtype: TextSubtype::Plain,
|
||||||
}),
|
}),
|
||||||
|
|
178
src/mime/mime.rs
178
src/mime/mime.rs
|
@ -1,151 +1,49 @@
|
||||||
use crate::mime::r#type::NaiveType;
|
|
||||||
use crate::mime::mechanism::Mechanism;
|
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::charset::EmailCharset;
|
use crate::mime::r#type::{AnyType, Multipart, Message, Text, Binary};
|
||||||
|
|
||||||
|
pub enum AnyMIME<'a> {
|
||||||
|
Multipart(Multipart, Generic<'a>),
|
||||||
|
Message(Message, Generic<'a>),
|
||||||
|
Text(Text, Generic<'a>),
|
||||||
|
Binary(Binary, Generic<'a>),
|
||||||
|
}
|
||||||
|
impl<'a> AnyMIME<'a> {
|
||||||
|
pub fn from_pair(at: AnyType, gen: Generic<'a>) -> Self {
|
||||||
|
match at {
|
||||||
|
AnyType::Multipart(m) => AnyMIME::Multipart(m, gen),
|
||||||
|
AnyType::Message(m) => AnyMIME::Message(m, gen),
|
||||||
|
AnyType::Text(m) => AnyMIME::Text(m, gen),
|
||||||
|
AnyType::Binary(m) => AnyMIME::Binary(m, gen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromIterator<Content<'a>> for AnyMIME<'a> {
|
||||||
|
fn from_iter<I: IntoIterator<Item = Content<'a>>>(it: I) -> Self {
|
||||||
|
let (at, gen) = it.into_iter().fold(
|
||||||
|
(AnyType::default(), Generic::default()),
|
||||||
|
|(mut at, mut section), field| {
|
||||||
|
match field {
|
||||||
|
Content::Type(v) => at = v.to_type(),
|
||||||
|
Content::TransferEncoding(v) => section.transfer_encoding = v,
|
||||||
|
Content::ID(v) => section.id = Some(v),
|
||||||
|
Content::Description(v) => section.description = Some(v),
|
||||||
|
};
|
||||||
|
(at, section)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::from_pair(at, gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
pub struct MIME<'a> {
|
pub struct Generic<'a> {
|
||||||
pub part_type: Type,
|
|
||||||
pub transfer_encoding: Mechanism<'a>,
|
pub transfer_encoding: Mechanism<'a>,
|
||||||
pub id: Option<MessageID<'a>>,
|
pub id: Option<MessageID<'a>>,
|
||||||
pub description: Option<Unstructured<'a>>,
|
pub description: Option<Unstructured<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromIterator<Content<'a>> for MIME<'a> {
|
|
||||||
fn from_iter<I: IntoIterator<Item = Content<'a>>>(source: I) -> Self {
|
|
||||||
source.into_iter().fold(
|
|
||||||
MIME::default(),
|
|
||||||
|mut section, field| {
|
|
||||||
match field {
|
|
||||||
Content::Type(v) => section.part_type = v.to_type(),
|
|
||||||
Content::TransferEncoding(v) => section.transfer_encoding = v,
|
|
||||||
Content::ID(v) => section.id = Some(v),
|
|
||||||
Content::Description(v) => section.description = Some(v),
|
|
||||||
};
|
|
||||||
section
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------- TYPE
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Type {
|
|
||||||
// Composite types
|
|
||||||
Multipart(Multipart),
|
|
||||||
Message(Message),
|
|
||||||
|
|
||||||
// Discrete types
|
|
||||||
Text(Text),
|
|
||||||
Binary,
|
|
||||||
}
|
|
||||||
impl Default for Type {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Text(Text::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> From<&'a NaiveType<'a>> for Type {
|
|
||||||
fn from(nt: &'a NaiveType<'a>) -> Self {
|
|
||||||
match nt.main.to_ascii_lowercase().as_slice() {
|
|
||||||
b"multipart" => Multipart::try_from(nt).map(Self::Multipart).unwrap_or(Self::default()),
|
|
||||||
b"message" => Self::Message(Message::from(nt)),
|
|
||||||
b"text" => Self::Text(Text::from(nt)),
|
|
||||||
_ => Self::Binary,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct Multipart {
|
|
||||||
pub subtype: MultipartSubtype,
|
|
||||||
pub boundary: String,
|
|
||||||
}
|
|
||||||
impl<'a> TryFrom<&'a NaiveType<'a>> for Multipart {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(nt: &'a NaiveType<'a>) -> Result<Self, Self::Error> {
|
|
||||||
nt.params.iter()
|
|
||||||
.find(|x| x.name.to_ascii_lowercase().as_slice() == b"boundary")
|
|
||||||
.map(|boundary| Multipart {
|
|
||||||
subtype: MultipartSubtype::from(nt),
|
|
||||||
boundary: boundary.value.to_string(),
|
|
||||||
})
|
|
||||||
.ok_or(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum MultipartSubtype {
|
|
||||||
Alternative,
|
|
||||||
Mixed,
|
|
||||||
Digest,
|
|
||||||
Parallel,
|
|
||||||
Report,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
impl<'a> From<&NaiveType<'a>> for MultipartSubtype {
|
|
||||||
fn from(nt: &NaiveType<'a>) -> Self {
|
|
||||||
match nt.sub.to_ascii_lowercase().as_slice() {
|
|
||||||
b"alternative" => Self::Alternative,
|
|
||||||
b"mixed" => Self::Mixed,
|
|
||||||
b"digest" => Self::Digest,
|
|
||||||
b"parallel" => Self::Parallel,
|
|
||||||
b"report" => Self::Report,
|
|
||||||
_ => Self::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Message {
|
|
||||||
RFC822,
|
|
||||||
Partial,
|
|
||||||
External,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
impl<'a> From<&NaiveType<'a>> for Message {
|
|
||||||
fn from(nt: &NaiveType<'a>) -> Self {
|
|
||||||
match nt.sub.to_ascii_lowercase().as_slice() {
|
|
||||||
b"rfc822" => Self::RFC822,
|
|
||||||
b"partial" => Self::Partial,
|
|
||||||
b"external" => Self::External,
|
|
||||||
_ => Self::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
|
||||||
pub struct Text {
|
|
||||||
pub subtype: TextSubtype,
|
|
||||||
pub charset: EmailCharset,
|
|
||||||
}
|
|
||||||
impl<'a> From<&NaiveType<'a>> for Text {
|
|
||||||
fn from(nt: &NaiveType<'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
subtype: TextSubtype::from(nt),
|
|
||||||
charset: nt.params.iter()
|
|
||||||
.find(|x| x.name.to_ascii_lowercase().as_slice() == b"charset")
|
|
||||||
.map(|x| EmailCharset::from(x.value.to_string().as_bytes()))
|
|
||||||
.unwrap_or(EmailCharset::US_ASCII),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
|
||||||
pub enum TextSubtype {
|
|
||||||
#[default]
|
|
||||||
Plain,
|
|
||||||
Html,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
impl<'a> From<&NaiveType<'a>> for TextSubtype {
|
|
||||||
fn from(nt: &NaiveType<'a>) -> Self {
|
|
||||||
match nt.sub.to_ascii_lowercase().as_slice() {
|
|
||||||
b"plain" => Self::Plain,
|
|
||||||
b"html" => Self::Html,
|
|
||||||
_ => Self::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
135
src/mime/type.rs
135
src/mime/type.rs
|
@ -8,7 +8,7 @@ use nom::{
|
||||||
|
|
||||||
use crate::text::misc_token::{MIMEWord, mime_word};
|
use crate::text::misc_token::{MIMEWord, mime_word};
|
||||||
use crate::text::words::{mime_atom};
|
use crate::text::words::{mime_atom};
|
||||||
use crate::mime::mime::{Type};
|
use crate::mime::charset::EmailCharset;
|
||||||
|
|
||||||
// --------- NAIVE TYPE
|
// --------- NAIVE TYPE
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -18,7 +18,7 @@ pub struct NaiveType<'a> {
|
||||||
pub params: Vec<Parameter<'a>>,
|
pub params: Vec<Parameter<'a>>,
|
||||||
}
|
}
|
||||||
impl<'a> NaiveType<'a> {
|
impl<'a> NaiveType<'a> {
|
||||||
pub fn to_type(&self) -> Type { self.into() }
|
pub fn to_type(&self) -> AnyType { self.into() }
|
||||||
}
|
}
|
||||||
pub fn naive_type(input: &[u8]) -> IResult<&[u8], NaiveType> {
|
pub fn naive_type(input: &[u8]) -> IResult<&[u8], NaiveType> {
|
||||||
map(
|
map(
|
||||||
|
@ -39,13 +39,136 @@ pub fn parameter_list(input: &[u8]) -> IResult<&[u8], Vec<Parameter>> {
|
||||||
many0(preceded(tag(";"), parameter))(input)
|
many0(preceded(tag(";"), parameter))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MIME TYPES TRANSLATED TO RUST TYPING SYSTEM
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum AnyType {
|
||||||
|
// Composite types
|
||||||
|
Multipart(Multipart),
|
||||||
|
Message(Message),
|
||||||
|
|
||||||
|
// Discrete types
|
||||||
|
Text(Text),
|
||||||
|
Binary(Binary),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AnyType {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Text(Text::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a NaiveType<'a>> for AnyType {
|
||||||
|
fn from(nt: &'a NaiveType<'a>) -> Self {
|
||||||
|
match nt.main.to_ascii_lowercase().as_slice() {
|
||||||
|
b"multipart" => Multipart::try_from(nt).map(Self::Multipart).unwrap_or(Self::default()),
|
||||||
|
b"message" => Self::Message(Message::from(nt)),
|
||||||
|
b"text" => Self::Text(Text::from(nt)),
|
||||||
|
_ => Self::Binary(Binary::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Multipart {
|
||||||
|
pub subtype: MultipartSubtype,
|
||||||
|
pub boundary: String,
|
||||||
|
}
|
||||||
|
impl<'a> TryFrom<&'a NaiveType<'a>> for Multipart {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(nt: &'a NaiveType<'a>) -> Result<Self, Self::Error> {
|
||||||
|
nt.params.iter()
|
||||||
|
.find(|x| x.name.to_ascii_lowercase().as_slice() == b"boundary")
|
||||||
|
.map(|boundary| Multipart {
|
||||||
|
subtype: MultipartSubtype::from(nt),
|
||||||
|
boundary: boundary.value.to_string(),
|
||||||
|
})
|
||||||
|
.ok_or(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum MultipartSubtype {
|
||||||
|
Alternative,
|
||||||
|
Mixed,
|
||||||
|
Digest,
|
||||||
|
Parallel,
|
||||||
|
Report,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
impl<'a> From<&NaiveType<'a>> for MultipartSubtype {
|
||||||
|
fn from(nt: &NaiveType<'a>) -> Self {
|
||||||
|
match nt.sub.to_ascii_lowercase().as_slice() {
|
||||||
|
b"alternative" => Self::Alternative,
|
||||||
|
b"mixed" => Self::Mixed,
|
||||||
|
b"digest" => Self::Digest,
|
||||||
|
b"parallel" => Self::Parallel,
|
||||||
|
b"report" => Self::Report,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Message {
|
||||||
|
RFC822,
|
||||||
|
Partial,
|
||||||
|
External,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
impl<'a> From<&NaiveType<'a>> for Message {
|
||||||
|
fn from(nt: &NaiveType<'a>) -> Self {
|
||||||
|
match nt.sub.to_ascii_lowercase().as_slice() {
|
||||||
|
b"rfc822" => Self::RFC822,
|
||||||
|
b"partial" => Self::Partial,
|
||||||
|
b"external" => Self::External,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Default)]
|
||||||
|
pub struct Text {
|
||||||
|
pub subtype: TextSubtype,
|
||||||
|
pub charset: EmailCharset,
|
||||||
|
}
|
||||||
|
impl<'a> From<&NaiveType<'a>> for Text {
|
||||||
|
fn from(nt: &NaiveType<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
subtype: TextSubtype::from(nt),
|
||||||
|
charset: nt.params.iter()
|
||||||
|
.find(|x| x.name.to_ascii_lowercase().as_slice() == b"charset")
|
||||||
|
.map(|x| EmailCharset::from(x.value.to_string().as_bytes()))
|
||||||
|
.unwrap_or(EmailCharset::US_ASCII),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Default)]
|
||||||
|
pub enum TextSubtype {
|
||||||
|
#[default]
|
||||||
|
Plain,
|
||||||
|
Html,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
impl<'a> From<&NaiveType<'a>> for TextSubtype {
|
||||||
|
fn from(nt: &NaiveType<'a>) -> Self {
|
||||||
|
match nt.sub.to_ascii_lowercase().as_slice() {
|
||||||
|
b"plain" => Self::Plain,
|
||||||
|
b"html" => Self::Html,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Default)]
|
||||||
|
pub struct Binary {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mime::charset::EmailCharset;
|
use crate::mime::charset::EmailCharset;
|
||||||
use crate::text::quoted::QuotedString;
|
use crate::text::quoted::QuotedString;
|
||||||
use crate::mime::mime::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parameter() {
|
fn test_parameter() {
|
||||||
|
@ -72,7 +195,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nt.to_type(),
|
nt.to_type(),
|
||||||
Type::Text(Text {
|
AnyType::Text(Text {
|
||||||
charset: EmailCharset::UTF_8,
|
charset: EmailCharset::UTF_8,
|
||||||
subtype: TextSubtype::Plain,
|
subtype: TextSubtype::Plain,
|
||||||
})
|
})
|
||||||
|
@ -86,7 +209,7 @@ mod tests {
|
||||||
assert_eq!(rest, &[]);
|
assert_eq!(rest, &[]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nt.to_type(),
|
nt.to_type(),
|
||||||
Type::Multipart(Multipart {
|
AnyType::Multipart(Multipart {
|
||||||
subtype: MultipartSubtype::Mixed,
|
subtype: MultipartSubtype::Mixed,
|
||||||
boundary: "--==_mimepart_64a3f2c69114f_2a13d020975fe".into(),
|
boundary: "--==_mimepart_64a3f2c69114f_2a13d020975fe".into(),
|
||||||
})
|
})
|
||||||
|
@ -100,7 +223,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nt.to_type(),
|
nt.to_type(),
|
||||||
Type::Message(Message::RFC822),
|
AnyType::Message(Message::RFC822),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,30 +10,42 @@ use nom::{
|
||||||
use crate::mime::r#type;
|
use crate::mime::r#type;
|
||||||
|
|
||||||
pub struct Part<'a> {
|
pub struct Part<'a> {
|
||||||
Multipart(r#type::Multipart, Vec<Part<'a>>),
|
Multipart(Multipart<MIME>, Vec<Part<'a>>),
|
||||||
Message(r#type::Message, Message, Part<'a>),
|
Message(MIME<Message>, Message, Part<'a>),
|
||||||
Text(r#type::Text, &'a [u8]),
|
Text(MIME<Text>, &'a [u8]),
|
||||||
Binary(&'a [u8]),
|
Binary(MIME<Binary>, &'a [u8]),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Part<'a> {
|
||||||
|
List(Vec<Part<'a>>),
|
||||||
|
Single(Part<'a>),
|
||||||
|
Leaf(&'a [u8]),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message() -> IResult<&[u8], Part> {
|
pub fn message() -> IResult<&[u8], Part> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn multipart<'a>(ctype: Multipart) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Part<'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(ctype.boundary)(input)?;
|
let (mut input_loop, _) = preamble(m.ctype.boundary)(input)?;
|
||||||
let mut parts: Vec<Part> = vec![];
|
let mut parts: Vec<Part> = vec![];
|
||||||
loop {
|
loop {
|
||||||
let input = match boundary(ctype.boundary)(input_loop) {
|
let input = match boundary(m.ctype.boundary)(input_loop) {
|
||||||
Err(_) => return Ok((input_loop, parts)),
|
Err(_) => return Ok((input_loop, parts)),
|
||||||
Ok((inp, Delimiter::Last)) => return Ok((inp, Part::Multipart(ctype, parts))),
|
Ok((inp, Delimiter::Last)) => return Ok((inp, Part::List(parts))),
|
||||||
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_in_boundaries(ctype.boundary, content)(input)?;
|
||||||
let mime = fields.to_mime();
|
let mime = fields.to_mime();
|
||||||
match mime.
|
|
||||||
|
// parse mime body
|
||||||
|
match mime.part_type {
|
||||||
|
Type::Multipart(m) => multipart(m),
|
||||||
|
Type::Message(m) => message(m),
|
||||||
|
Type::Text(t) | Type::Binary
|
||||||
|
}
|
||||||
|
|
||||||
// based on headers, parse part
|
// based on headers, parse part
|
||||||
|
|
||||||
|
@ -48,7 +60,6 @@ pub fn multipart<'a>(ctype: Multipart) -> impl Fn(&'a [u8]) -> IResult<&'a [u8],
|
||||||
input_loop = input;
|
input_loop = input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discrete() -> IResult<&[u8], Part> {
|
pub fn discrete() -> IResult<&[u8], Part> {
|
||||||
|
|
Loading…
Reference in a new issue