use std::fs::read; use std::io::ErrorKind as IOErrKind; use maildir::Maildir; use crate::error::{Error, Result}; use crate::rfc822::{parse_mail_content, MIMEHeader}; pub fn raw(md: &Maildir, mid: &str, mime_path: &str) -> Result<(MIMEHeader, Vec)> { let mut mail = md.find(mid).ok_or_else(|| { std::io::Error::new(IOErrKind::NotFound, format!("mail {} not found", mid)) })?; if mime_path.is_empty() { let mh = MIMEHeader { maintype: "message".to_owned(), subtype: "rfc822".to_owned(), filename: mail.id().to_owned(), content_disposition: "".to_owned(), }; return Ok((mh, read(mail.path())?)); } let path = mime_path .split('.') .map(|x| { x.parse() .map_err(|pe: std::num::ParseIntError| Error::PathError { msg: pe.to_string(), path: mime_path.to_owned(), }) }) .collect::>>()?; let mut m = mail.parsed()?; if path[0] != 0 { return Err(Error::PathError { msg: "Message must be accessed by a 0".to_owned(), path: mime_path.to_owned(), }); } for i in &path[1..] { match &m.ctype.mimetype { x if x.starts_with("message/") => { if *i != 0 { return Err(Error::PathError { msg: "Message must be accessed by a 0".to_owned(), path: mime_path.to_owned(), }); } let s: &'static _ = m.get_body_raw()?.leak(); m = mailparse::parse_mail(s)?; } x if x.starts_with("multipart/") => { if *i >= m.subparts.len() { return Err(Error::PathError { msg: "Out of bounds access".to_owned(), path: mime_path.to_owned(), }); } m = m.subparts.swap_remove(*i); } _ => { return Err(Error::PathError { msg: "Unable to descent into leaf component".to_owned(), path: mime_path.to_owned(), }) } } } if m.ctype.mimetype.starts_with("multipart/") { return Err(Error::PathError { msg: "Can not show multipart component".to_owned(), path: mime_path.to_owned(), }); } let mime_part = parse_mail_content(&m)?; let content = if m.ctype.mimetype.starts_with("text/") { m.get_body()?.into_bytes() } else { m.get_body_raw()? }; Ok((mime_part, content)) }