eml_codec/message/
field.rs1use bounded_static::ToStatic;
2#[cfg(feature = "tracing")]
3use tracing::warn;
4
5#[cfg(feature = "arbitrary")]
6use crate::fuzz_eq::FuzzEq;
7use crate::print::{Formatter, Print};
8use crate::raw_input::RawInput;
9use crate::{header, imf, mime};
10
11#[derive(Clone, Debug, PartialEq, ToStatic)]
16#[cfg_attr(feature = "arbitrary", derive(FuzzEq))]
17pub enum MessageField<'a> {
18 MIME {
19 f: mime::field::Field<'a>,
20 raw_body: RawInput<'a>,
21 },
22 Imf {
23 f: imf::field::Field<'a>,
24 raw_body: RawInput<'a>,
25 },
26 Unstructured(header::Unstructured<'a>),
28}
29
30impl<'a> MessageField<'a> {
31 pub fn raw_name(&self) -> header::FieldName<'a> {
32 match self {
33 MessageField::MIME { f, .. } => f.raw_name(),
34 MessageField::Imf { f, .. } => f.raw_name(),
35 MessageField::Unstructured(u) => u.name.clone(),
36 }
37 }
38
39 pub fn raw_body(&self) -> RawInput<'a> {
40 match self {
41 MessageField::MIME { raw_body, .. } => raw_body.clone(),
42 MessageField::Imf { raw_body, .. } => raw_body.clone(),
43 MessageField::Unstructured(u) => u.raw_body.clone(),
44 }
45 }
46}
47
48impl<'a> Print for MessageField<'a> {
49 fn print(&self, fmt: &mut impl Formatter) {
50 match self {
51 MessageField::MIME { f, .. } => f.print(fmt),
52 MessageField::Imf { f, .. } => f.print(fmt),
53 MessageField::Unstructured(u) => u.print(fmt),
54 }
55 }
56}
57
58#[derive(Clone, Debug, PartialEq, ToStatic)]
60#[cfg_attr(feature = "arbitrary", derive(FuzzEq))]
61pub enum MessageEntry<'a> {
62 MIME {
63 e: mime::field::Entry,
64 raw_body: RawInput<'a>,
65 },
66 Imf {
67 e: imf::field::Entry,
68 raw_body: RawInput<'a>,
69 },
70 Unstructured(header::Unstructured<'a>),
72}
73
74#[derive(Debug, PartialEq, ToStatic)]
77pub(crate) struct NaiveMessageFields<'a> {
78 pub mime: mime::NaiveMIME<'a>,
79 pub imf: imf::Imf<'a>,
80 pub entries: Vec<MessageEntry<'a>>,
81}
82
83impl<'a> FromIterator<header::FieldRaw<'a>> for NaiveMessageFields<'a> {
84 #[cfg_attr(
85 feature = "tracing",
86 tracing::instrument(name = "MessageFields::from_iter", skip(it))
87 )]
88 fn from_iter<I: IntoIterator<Item = header::FieldRaw<'a>>>(it: I) -> Self {
89 let mut mime = mime::NaiveMIME::default();
90 let mut imf = imf::PartialImf::default();
91 let mut entries = vec![];
92 for f in it {
93 match mime::field::NaiveField::try_from(&f) {
94 Ok(mimef) => {
95 if let Some(entry) = mime.add_field(mimef) {
96 entries.push(MessageEntry::MIME {
97 e: entry,
98 raw_body: f.body.into(),
99 })
100 } else {
101 #[cfg(feature = "tracing-recover")]
103 warn!(field = ?f, "dropping conflicting MIME field")
104 }
105 continue;
106 }
107 Err(mime::field::InvalidField::Body) => {
108 #[cfg(feature = "tracing-unsupported")]
110 warn!(field = ?f, "dropping MIME field with an invalid body");
111 continue;
112 }
113 Err(mime::field::InvalidField::Name) => {
114 }
116 };
117
118 match imf::field::Field::try_from(&f) {
119 Ok(imff) => {
120 match imf.add_field(imff) {
121 Ok(entry) => entries.push(MessageEntry::Imf {
122 e: entry,
123 raw_body: f.body.into(),
124 }),
125 Err(imf::AddFieldErr::NoEntry) => {
126 #[cfg(feature = "tracing-recover")]
127 warn!(field = ?f, "no new entry for IMF field");
128 }
129 Err(imf::AddFieldErr::Conflict) => {
130 #[cfg(feature = "tracing-recover")]
131 warn!(field = ?f, "discarding conflicting IMF field");
132 }
133 }
134 continue;
135 }
136 Err(imf::field::InvalidField::NeedsDiscard) => {
137 #[cfg(feature = "tracing-recover")]
140 warn!(field = ?f, "dropping IMF field with a body to be discarded");
141 continue;
142 }
143 Err(imf::field::InvalidField::Body) => {
144 #[cfg(feature = "tracing-unsupported")]
146 warn!(field = ?f, "dropping IMF field with an invalid body");
147 continue;
148 }
149 Err(imf::field::InvalidField::Name) => {
150 }
152 }
153
154 if let Some(u) = header::Unstructured::from_raw(&f) {
155 entries.push(MessageEntry::Unstructured(u));
156 } else {
157 #[cfg(feature = "tracing-unsupported")]
159 warn!(field = ?f, "dropping field that cannot be parsed as unstructured")
160 }
161 }
162
163 NaiveMessageFields {
164 mime,
165 imf: imf.to_imf(),
166 entries,
167 }
168 }
169}