use nom::combinator::map;
use crate::header;
use crate::imf::identification::{msg_id, MessageID};
use crate::mime::mechanism::{mechanism, Mechanism};
use crate::mime::r#type::{naive_type, NaiveType};
use crate::text::misc_token::{unstructured, Unstructured};
#[derive(Debug, PartialEq)]
pub enum Content<'a> {
Type(NaiveType<'a>),
TransferEncoding(Mechanism<'a>),
ID(MessageID<'a>),
Description(Unstructured<'a>),
}
#[allow(dead_code)]
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> TryFrom<&header::Field<'a>> for Content<'a> {
type Error = ();
fn try_from(f: &header::Field<'a>) -> Result<Self, Self::Error> {
let content = match f {
header::Field::Good(header::Kv2(key, value)) => match key
.to_ascii_lowercase()
.as_slice()
{
b"content-type" => map(naive_type, Content::Type)(value),
b"content-transfer-encoding" => map(mechanism, Content::TransferEncoding)(value),
b"content-id" => map(msg_id, Content::ID)(value),
b"content-description" => map(unstructured, Content::Description)(value),
_ => return Err(()),
},
_ => return Err(()),
};
content.map(|(_, content)| content).or(Err(()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::header;
use crate::mime::r#type::*;
use crate::text::misc_token::MIMEWord;
use crate::text::quoted::QuotedString;
#[test]
fn test_header() {
let fullmail: &[u8] = r#"Date: Sat, 8 Jul 2023 07:14:29 +0200
From: Grrrnd Zero <grrrndzero@example.org>
To: John Doe <jdoe@machine.example>
Subject: Re: Saying Hello
Message-ID: <NTAxNzA2AC47634Y366BAMTY4ODc5MzQyODY0ODY5@www.grrrndzero.org>
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="b1_e376dc71bafc953c0b0fdeb9983a9956"
Content-Transfer-Encoding: 7bit
This is a multipart message.
"#
.as_bytes();
assert_eq!(
map(header::header_kv, |k| k
.iter()
.flat_map(Content::try_from)
.collect())(fullmail),
Ok((
&b"This is a multipart message.\n\n"[..],
vec![
Content::Type(NaiveType {
main: &b"multipart"[..],
sub: &b"alternative"[..],
params: vec![Parameter {
name: &b"boundary"[..],
value: MIMEWord::Quoted(QuotedString(vec![
&b"b1_e376dc71bafc953c0b0fdeb9983a9956"[..]
])),
}]
}),
Content::TransferEncoding(Mechanism::_7Bit),
],
)),
);
}
}