summaryrefslogtreecommitdiff
path: root/src/cmd/raw.rs
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2024-11-21 21:14:40 +0100
committerJannis M. Hoffmann <jannis@fehcom.de>2024-11-21 21:14:40 +0100
commit48c2945172b88c35c187d298a35bf26716af4e91 (patch)
tree2af21ddb4dcacd191e07fef156609b7c1488ebaf /src/cmd/raw.rs
parent6ed535387df0dffa72a10e601b8ea37c99345d84 (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.rs185
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()
}
}