diff options
author | Jannis M. Hoffmann <jannis@fehcom.de> | 2024-11-21 21:14:40 +0100 |
---|---|---|
committer | Jannis M. Hoffmann <jannis@fehcom.de> | 2024-11-21 21:14:40 +0100 |
commit | 48c2945172b88c35c187d298a35bf26716af4e91 (patch) | |
tree | 2af21ddb4dcacd191e07fef156609b7c1488ebaf /src/cmd/raw.rs | |
parent | 6ed535387df0dffa72a10e601b8ea37c99345d84 (diff) |
Switch to varlink as IPC protocol
This is a lot! Whole new design on top of a statefult varlink interface.
You can now handle multiple request response cycles over a single
connection.
The error responses are lot more refined than just status codes with
optional messages and finally part of the protocol.
TODO: A lot of error handling needs to be improved.
Diffstat (limited to 'src/cmd/raw.rs')
-rw-r--r-- | src/cmd/raw.rs | 185 |
1 files changed, 94 insertions, 91 deletions
diff --git a/src/cmd/raw.rs b/src/cmd/raw.rs index 9fe7620..a20eded 100644 --- a/src/cmd/raw.rs +++ b/src/cmd/raw.rs @@ -1,106 +1,109 @@ -use std::fs::read; -use std::io::ErrorKind as IOErrKind; -use std::path::PathBuf; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; -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::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::MIMEHeader_content_dispo as CD; +use crate::de_jmhoffmann_jwebmail_mailstorage::{Call_Raw, MIMEHeader, MIMEHeader_mime_type}; use crate::rfc822::parse_mail_content; -pub fn raw(md_path: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = RawReq::parse_from_bytes(req)?; - - let md = open_submaildir(md_path, &r.folder); +pub fn raw( + ms: &MailStorage, + call: &mut dyn Call_Raw, + folder: String, + mid: String, + path: Option<String>, +) -> varlink::Result<()> { + if let Some(p) = ms.maildir_path.read().unwrap().clone() { + let md = open_submaildir(p, &folder); - let mut mail = md.find(&r.mid).ok_or_else(|| { - std::io::Error::new(IOErrKind::NotFound, format!("mail {} not found", &r.mid)) - })?; + if let Some(mut mail) = md.find(&mid) { + match path.as_deref() { + Some("") | None => call.reply( + MIMEHeader { + mime_type: MIMEHeader_mime_type { + main_type: "message".to_owned(), + sub_type: "rfc822".to_owned(), + }, + file_name: Some(mail.id().to_owned()), + content_dispo: CD::none, + }, + BASE64_STANDARD + .encode(std::fs::read(mail.path()).map_err(varlink::map_context!())?), + ), + Some(mime_path) => { + if let Ok(path) = mime_path + .split('.') + .map(|x| x.parse()) + .collect::<std::result::Result<Vec<usize>, std::num::ParseIntError>>() + { + let mut m = mail.parsed().unwrap(); - match r.path.as_deref() { - Some("") | None => { - let mut mh = MIMEHeader::new(); + if path[0] != 0 { + return call.reply_invalid_path_in_mail( + folder, + mid, + mime_path.to_owned(), + ); + } - mh.maintype = "message".to_owned(); - mh.subtype = "rfc822".to_owned(); - mh.file_name = Some(mail.id().to_owned()); - mh.contentdispo = CONTENT_DISPOSITION_NONE.into(); + for i in &path[1..] { + match &m.ctype.mimetype { + x if x.starts_with("message/") => { + if *i != 0 { + return call.reply_invalid_path_in_mail( + folder, + mid, + mime_path.to_owned(), + ); + } + let s: &'static _ = m.get_body_raw().unwrap().leak(); + m = mailparse::parse_mail(s).unwrap(); + } + x if x.starts_with("multipart/") => { + if *i >= m.subparts.len() { + return call.reply_invalid_path_in_mail( + folder, + mid, + mime_path.to_owned(), + ); + } + m = m.subparts.swap_remove(*i); + } + _ => { + return call.reply_invalid_path_in_mail( + folder, + mid, + mime_path.to_owned(), + ); + } + } + } - 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::<Result<Vec<_>>>()?; - let mut m = mail.parsed()?; + if m.ctype.mimetype.starts_with("multipart/") { + return call.reply_invalid_path_in_mail( + folder, + mid, + mime_path.to_owned(), + ); + } - if path[0] != 0 { - return Err(Error::PathError { - msg: "Message must be accessed by a 0".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().unwrap().into_bytes() + } else { + m.get_body_raw().unwrap() + }; - 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(), - }) + call.reply(mime_part, BASE64_STANDARD.encode(content)) + } else { + call.reply_invalid_path_in_mail(folder, mid, 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()) + } else { + call.reply_invalid_mid(folder, mid) } + } else { + call.reply_not_initialized() } } |