use std::fs::read; use std::io::ErrorKind as IOErrKind; use std::path::PathBuf; use protobuf::Message as _; use crate::cmd::open_submaildir; use crate::error::{Error, Result}; use crate::pb3::jwebmail::mimeheader::ContentDisposition::*; use crate::pb3::jwebmail::{MIMEHeader, RawReq, RawResp}; use crate::rfc822::parse_mail_content; pub fn raw(md_path: PathBuf, req: &[u8]) -> Result> { let r = RawReq::parse_from_bytes(req)?; let md = open_submaildir(md_path, &r.folder); let mut mail = md.find(&r.mid).ok_or_else(|| { std::io::Error::new(IOErrKind::NotFound, format!("mail {} not found", &r.mid)) })?; match r.path.as_deref() { Some("") | None => { let mut mh = MIMEHeader::new(); mh.maintype = "message".to_owned(); mh.subtype = "rfc822".to_owned(); mh.file_name = Some(mail.id().to_owned()); mh.contentdispo = CONTENT_DISPOSITION_NONE.into(); let mut resp = RawResp::new(); resp.header = Some(mh).into(); resp.body = read(mail.path())?; resp.write_to_bytes().map_err(|e| e.into()) } Some(mime_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()? }; let mut resp = RawResp::new(); resp.header = Some(mime_part).into(); resp.body = content; resp.write_to_bytes().map_err(|e| e.into()) } } }