1use byteorder::{LE, ByteOrder};
27use chrono::naive::NaiveDateTime;
28
29mod error;
30mod attr_ids;
31
32use error::Error;
33pub use attr_ids::*;
34
35pub struct TnefReader<'a> {
39 src: &'a [u8],
40 code_page: u32,
41 msg_section: bool,
42 done: bool,
43}
44
45impl<'a> TnefReader<'a> {
46 pub fn new(src: &'a [u8]) -> Result<Self, Error> {
48 let mut ret = Self {
49 src, code_page: 0, msg_section: true, done: false,
50 };
51 ret.read_header()?;
52 ret.read_version()?;
53 ret.code_page = ret.read_oem_code_page()?;
54 Ok(ret)
55 }
56
57 pub fn get_code_page(&self) -> u32 {
59 self.code_page
60 }
61
62 fn read_attribute(&mut self)
63 -> Result<Option<(AttributeId, &'a [u8])>, Error>
64 {
65 if self.src.is_empty() { return Ok(None); }
66 let level = self.split_at(1)?[0];
67 match (level, self.msg_section) {
68 (0x01, true) | (0x02, false) => (),
69 (0x01, false) => return Err(Error::UnexpectedMessageAttribute),
70 (0x02, true) => self.msg_section = false,
71 _ => return Err(Error::InvalidAttributeLevel(level)),
72 }
73 let raw_id = self.read_u32()?;
74 let id = AttributeId::from_u32(self.msg_section, raw_id)?;
75 let len = self.read_u32()? as usize;
76 let msg = self.split_at(len)?;
77 self.verify_checksum(msg)?;
78 Ok(Some((id, msg)))
79 }
80
81 fn verify_checksum(&mut self, msg: &[u8]) -> Result<(), Error> {
82 let val = self.read_u16()?;
83 let sum: u16 = msg.iter()
84 .map(|b| u16::from(*b))
85 .fold(0, |sum, i| sum.wrapping_add(i));
86 if sum != val {
87 Err(Error::ChecksumMismatch)
88 } else {
89 Ok(())
90 }
91 }
92
93 fn read_u16(&mut self) -> Result<u16, Error> {
94 Ok(LE::read_u16(self.split_at(2)?))
95 }
96
97 fn read_u32(&mut self) -> Result<u32, Error> {
98 Ok(LE::read_u32(self.split_at(4)?))
99 }
100
101 fn split_at(&mut self, len: usize) -> Result<&'a [u8], Error> {
102 if self.src.len() < len { return Err(Error::UnexpectedEof); }
103 let (l, r) = {self.src}.split_at(len);
104 self.src = r;
105 Ok(l)
106 }
107
108 fn read_header(&mut self) -> Result<(), Error> {
109 let h = self.read_u32()?;
110 if h != 0x223e_9f78 {
111 return Err(Error::InvalidHeader);
112 }
113 let _ = self.read_u16()?;
115 Ok(())
116 }
117
118 fn read_version(&mut self) -> Result<(), Error> {
119 let level = self.split_at(1)?[0];
120 let id = self.read_u32()?;
121 let len = self.read_u32()?;
122 if level != 0x01 || id != 0x0008_9006 || len != 4 {
123 return Err(Error::InvalidVersion);
124 }
125 let msg = self.split_at(4)?;
126 if msg != b"\x00\x00\x01\x00" { return Err(Error::InvalidVersion); }
127 self.verify_checksum(msg)?;
128 Ok(())
129 }
130
131 fn read_oem_code_page(&mut self) -> Result<u32, Error> {
132 let level = self.split_at(1)?[0];
133 let id = self.read_u32()?;
134 let len = self.read_u32()?;
135 if level != 0x01 || id != 0x0006_9007 || len != 8 {
136 return Err(Error::InvalidVersion);
137 }
138 let msg = self.split_at(8)?;
139 self.verify_checksum(msg)?;
140 let code_page = LE::read_u32(&msg[..4]);
141 let sec_code_page = LE::read_u32(&msg[4..]);
142 if sec_code_page != 0 {
143 return Err(Error::InvalidOemCodePage);
144 }
145
146 codepage::to_encoding(code_page as u16)
147 .ok_or(Error::InvalidOemCodePage)?;
148
149 Ok(code_page)
150 }
151}
152
153impl<'a> std::iter::Iterator for TnefReader<'a> {
154 type Item = Result<(AttributeId, &'a [u8]), Error>;
155
156 fn next(&mut self) -> Option<Self::Item> {
157 if self.done { return None; }
158 match self.read_attribute() {
159 Ok(Some(val)) => Some(Ok(val)),
160 Ok(None) => {
161 self.done = true;
162 None
163 }
164 Err(err) => {
165 self.done = true;
166 Some(Err(err))
167 }
168 }
169 }
170}
171
172impl<'a> std::iter::FusedIterator for TnefReader<'a> {}
173
174fn parse_datetime(data: &[u8]) -> Result<NaiveDateTime, Error> {
175 use chrono::naive::{NaiveDate, NaiveTime};
176 if data.len() != 14 { return Err(Error::InvlidDateTime); }
177 let year = i32::from(LE::read_u16(&data[0..2]));
178 let month = u32::from(LE::read_u16(&data[2..4]));
179 let day = u32::from(LE::read_u16(&data[4..6]));
180 let hour = u32::from(LE::read_u16(&data[6..8]));
181 let minute = u32::from(LE::read_u16(&data[8..10]));
182 let second = u32::from(LE::read_u16(&data[10..12]));
183 let _day_of_week = LE::read_u16(&data[12..14]);
184
185 let date = NaiveDate::from_ymd_opt(year, month, day)
186 .ok_or(Error::InvlidDateTime)?;
187 let time = NaiveTime::from_hms_opt(hour, minute, second)
188 .ok_or(Error::InvlidDateTime)?;
189 Ok(NaiveDateTime::new(date, time))
190}
191
192#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
194pub enum AttachType {
195 File,
196 Ole,
197}
198
199#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
201pub enum AttachDataFlags {
202 FileDataDefault,
203 FileDataMacBinary,
204}
205
206#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
208pub struct RendData {
209 pub attach_type: AttachType,
210 pub attach_position: u32,
211 pub render_width: u16,
212 pub render_height: u16,
213 pub flags: AttachDataFlags,
214}
215
216impl RendData {
217 fn parse(data: &[u8]) -> Result<Self, Error> {
218 if data.len() != 14 { return Err(Error::InvalidRendData); }
219 let attach_type = match LE::read_u16(&data[0..2]) {
220 0x0001 => AttachType::File,
221 0x0002 => AttachType::Ole,
222 _ => return Err(Error::InvalidRendData),
223 };
224 let attach_position = LE::read_u32(&data[2..6]);
225 let render_width = LE::read_u16(&data[6..8]);
226 let render_height = LE::read_u16(&data[8..10]);
227 let flags = match LE::read_u32(&data[10..14]) {
228 0x0000_0000 => AttachDataFlags::FileDataDefault,
229 0x0000_0001 => AttachDataFlags::FileDataMacBinary,
230 _ => return Err(Error::InvalidRendData),
231 };
232 Ok(Self {
233 attach_type, attach_position, render_width, render_height, flags,
234 })
235 }
236}
237
238fn parse_string(data: &[u8], code_page: u32) -> Result<String, Error> {
239 let n = data.len();
240 if data.is_empty() || data[n-1] != 0x00 {
241 return Err(Error::InvalidString);
242 }
243 let (s, malformed) = codepage::to_encoding(code_page as u16)
244 .ok_or(Error::InvalidString)?
245 .decode_with_bom_removal(&data[..n-1]);
246 if malformed { return Err(Error::InvalidString); }
247 Ok(s.to_string())
248}
249
250#[derive(Default)]
252pub struct RawAttachment<'a> {
253 pub data: Option<&'a [u8]>,
254 pub title: Option<String>,
255 pub meta: Option<&'a [u8]>,
256 pub create_date: Option<NaiveDateTime>,
257 pub modify_date: Option<NaiveDateTime>,
258 pub transport_filename: Option<String>,
259 pub rend_data: Option<RendData>,
260 pub props: Option<&'a [u8]>,
261}
262
263impl<'a> RawAttachment<'a> {
264 fn is_default(&self) -> bool {
265 match self {
266 RawAttachment {
267 data: None, title: None, meta: None,
268 create_date: None, modify_date: None,
269 transport_filename: None, rend_data: None,
270 props: None,
271 } => true,
272 _ => false,
273 }
274 }
275}
276
277#[derive(Debug, Clone)]
279pub struct Attachment<'a> {
280 pub title: String,
281 pub data: &'a [u8],
282 pub create_date: NaiveDateTime,
283 pub modify_date: NaiveDateTime,
284 pub rend_data: RendData,
285 pub props: &'a [u8],
286 pub meta: Option<&'a [u8]>,
287 pub transport_filename: Option<String>,
288}
289
290impl<'a> Attachment<'a> {
291 fn from_raw(raw: RawAttachment<'a>) -> Option<Self> {
292 match raw {
293 RawAttachment {
294 title: Some(title),
295 data: Some(data),
296 create_date: Some(create_date),
297 modify_date: Some(modify_date),
298 rend_data: Some(rend_data),
299 props: Some(props),
300 meta,
301 transport_filename,
302 } => Some(Attachment {
303 title, data, create_date, modify_date, rend_data, props,
304 meta, transport_filename,
305 }),
306 _ => None,
307 }
308 }
309}
310
311pub fn read_attachments(buf: &[u8]) -> Result<Vec<Attachment>, Error> {
317 let r = TnefReader::new(&buf)?;
318 let code_page = r.get_code_page();
319 let mut buf = vec![];
320 let mut t = RawAttachment::default();
321 for attr in r {
322 let (id, data) = attr?;
323 let id = match id {
324 AttributeId::Message(_) => continue,
325 AttributeId::Attachment(v) => v,
326 };
327 if t.is_default() && id != AttachAttrId::AttachRendData {
329 return Err(Error::AttachmentParsingFailure);
330 }
331 match id {
332 AttachAttrId::AttachRendData => {
333 t.rend_data = Some(RendData::parse(data)?);
334 },
335 AttachAttrId::Data => {
336 if t.data.is_none() {
337 t.data = Some(data);
338 } else {
339 return Err(Error::AttachmentParsingFailure);
340 }
341 }
342 AttachAttrId::Title => {
343 if t.title.is_none() {
344 t.title = Some(parse_string(data, code_page)?);
345 } else {
346 return Err(Error::AttachmentParsingFailure);
347 }
348 }
349 AttachAttrId::MetaFile => {
350 if t.meta.is_none() {
351 t.meta = Some(data);
352 } else {
353 return Err(Error::AttachmentParsingFailure);
354 }
355 }
356 AttachAttrId::CreateDate => {
357 if t.create_date.is_none() {
358 t.create_date = Some(parse_datetime(data)?);
359 } else {
360 return Err(Error::AttachmentParsingFailure);
361 }
362 }
363 AttachAttrId::ModifyDate => {
364 if t.modify_date.is_none() {
365 t.modify_date = Some(parse_datetime(data)?);
366 } else {
367 return Err(Error::AttachmentParsingFailure);
368 }
369 }
370 AttachAttrId::TransportFilename => {
371 if t.transport_filename.is_none() {
372 t.transport_filename = Some(parse_string(data, code_page)?);
373 } else {
374 return Err(Error::AttachmentParsingFailure);
375 }
376 }
377 AttachAttrId::Attachment => {
379 if t.props.is_none() {
380 t.props = Some(data);
381 } else {
382 return Err(Error::AttachmentParsingFailure);
383 }
384 if let Some(att) = Attachment::from_raw(t) {
385 buf.push(att);
386 }
387 t = RawAttachment::default();
388 }
389 }
390 }
391 Ok(buf)
392}