diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/add_folder.rs | 53 | ||||
-rw-r--r-- | src/cmd/count.rs | 27 | ||||
-rw-r--r-- | src/cmd/folders.rs | 35 | ||||
-rw-r--r-- | src/cmd/init.rs | 35 | ||||
-rw-r--r-- | src/cmd/list.rs | 158 | ||||
-rw-r--r-- | src/cmd/move.rs | 19 | ||||
-rw-r--r-- | src/cmd/move_mail.rs | 18 | ||||
-rw-r--r-- | src/cmd/raw.rs | 185 | ||||
-rw-r--r-- | src/cmd/read.rs | 24 | ||||
-rw-r--r-- | src/cmd/remove.rs | 29 | ||||
-rw-r--r-- | src/cmd/search.rs | 17 | ||||
-rw-r--r-- | src/cmd/show.rs | 26 | ||||
-rw-r--r-- | src/cmd/stats.rs | 25 |
13 files changed, 362 insertions, 289 deletions
diff --git a/src/cmd/add_folder.rs b/src/cmd/add_folder.rs index 82df1f9..07ad455 100644 --- a/src/cmd/add_folder.rs +++ b/src/cmd/add_folder.rs @@ -1,37 +1,40 @@ use std::fs::create_dir; -use std::path::PathBuf; -use protobuf::Message as _; +use varlink; -use crate::error::Result; -use crate::pb3::jwebmail::{AddFolderReq, AddFolderResp}; +use crate::cmd::MailStorage; +use crate::de_jmhoffmann_jwebmail_mailstorage::{AddFolder_Reply_status, Call_AddFolder}; -pub fn add_folder(mut p: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = AddFolderReq::parse_from_bytes(req)?; - let mut resp = AddFolderResp::new(); +pub fn add_folder( + ms: &MailStorage, + call: &mut dyn Call_AddFolder, + name: String, +) -> varlink::Result<()> { + if let Some(mut p) = ms.maildir_path.read().unwrap().clone() { + let mut folder = ".".to_owned(); + folder.push_str(&name); - let mut folder = ".".to_owned(); - folder.push_str(&r.name); - p.push(folder); + p.push(folder); - if p.is_dir() { - resp.status = 1; - return resp.write_to_bytes().map_err(|e| e.into()); - } + if p.is_dir() { + return call.reply(AddFolder_Reply_status::skiped); + } - create_dir(&p)?; + create_dir(&p).map_err(varlink::map_context!())?; - p.push("tmp"); - create_dir(&p)?; + p.push("tmp"); + create_dir(&p).map_err(varlink::map_context!())?; - p.pop(); - p.push("new"); - create_dir(&p)?; + p.pop(); + p.push("new"); + create_dir(&p).map_err(varlink::map_context!())?; - p.pop(); - p.push("cur"); - create_dir(p)?; + p.pop(); + p.push("cur"); + create_dir(p).map_err(varlink::map_context!())?; - resp.status = 0; - resp.write_to_bytes().map_err(|e| e.into()) + call.reply(AddFolder_Reply_status::created) + } else { + call.reply_not_initialized() + } } diff --git a/src/cmd/count.rs b/src/cmd/count.rs deleted file mode 100644 index 5de542b..0000000 --- a/src/cmd/count.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::path::PathBuf; - -use protobuf::Message; - -use crate::cmd::open_submaildir; -use crate::error::Result; -use crate::pb3::jwebmail::{StatsReq, StatsResp}; - -pub fn count(path: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = StatsReq::parse_from_bytes(req)?; - - let md = open_submaildir(path, &r.folder); - - let mut resp = StatsResp::new(); - resp.mail_count = md.count_cur() as u32; - resp.unread_count = md - .list_cur() - .filter(|x| x.as_ref().map_or(false, |z| !z.is_seen())) - .count() as u32; - resp.byte_size = md - .path() - .join("cur") - .read_dir()? - .map(|x| x.map_or(0, |z| z.metadata().map_or(0, |y| y.len()))) - .sum(); - resp.write_to_bytes().map_err(|e| e.into()) -} diff --git a/src/cmd/folders.rs b/src/cmd/folders.rs index 417203c..8bf9a30 100644 --- a/src/cmd/folders.rs +++ b/src/cmd/folders.rs @@ -1,9 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; -use protobuf::Message as _; - -use crate::error::Result; -use crate::pb3::jwebmail::{FoldersReq, FoldersResp}; +use crate::cmd::MailStorage; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Folders; fn is_mailsubdir(p: &Path) -> bool { if !p.is_dir() { @@ -32,19 +30,20 @@ fn is_mailsubdir(p: &Path) -> bool { true } -pub fn folders(path: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let _ = FoldersReq::parse_from_bytes(req)?; - - let mut subdirs: Vec<_> = path - .read_dir()? - .filter_map(|d| d.ok()) - .filter(|d| is_mailsubdir(&d.path())) - .filter_map(|d| Some(d.path().file_name()?.to_string_lossy()[1..].to_owned())) - .collect(); +pub fn folders(ms: &MailStorage, call: &mut dyn Call_Folders) -> varlink::Result<()> { + if let Some(path) = &*ms.maildir_path.read().unwrap() { + let mut subdirs: Vec<_> = path + .read_dir() + .map_err(varlink::map_context!())? + .filter_map(|d| d.ok()) + .filter(|d| is_mailsubdir(&d.path())) + .filter_map(|d| Some(d.path().file_name()?.to_string_lossy()[1..].to_owned())) + .collect(); - subdirs.sort(); + subdirs.sort(); - let mut res = FoldersResp::new(); - res.folders = subdirs; - res.write_to_bytes().map_err(|e| e.into()) + call.reply(subdirs) + } else { + call.reply_not_initialized() + } } diff --git a/src/cmd/init.rs b/src/cmd/init.rs new file mode 100644 index 0000000..167d028 --- /dev/null +++ b/src/cmd/init.rs @@ -0,0 +1,35 @@ +use std::ffi::CString; + +use crate::cmd::MailStorage; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Init; + +pub fn init( + ms: &MailStorage, + call: &mut dyn Call_Init, + unix_user: String, + mailbox_path: String, +) -> varlink::Result<()> { + unsafe { + *libc::__errno_location() = 0; + } + if let Ok(c_sys_user) = CString::new(unix_user.clone()) { + let user_info: *const libc::passwd = unsafe { libc::getpwnam(c_sys_user.as_ptr()) }; + let err = unsafe { *libc::__errno_location() }; + if err != 0 { + return call.reply_invalid_user(unix_user); + } + if user_info.is_null() { + return call.reply_invalid_user(unix_user); + } + let rc = unsafe { libc::setuid((*user_info).pw_uid) }; + if rc != 0 { + return call.reply_invalid_user(unix_user); + } + + *ms.maildir_path.write().unwrap() = Some(mailbox_path.into()); + + call.reply() + } else { + call.reply_invalid_user(unix_user) + } +} diff --git a/src/cmd/list.rs b/src/cmd/list.rs index 3c2d42a..8aeaf97 100644 --- a/src/cmd/list.rs +++ b/src/cmd/list.rs @@ -1,12 +1,11 @@ use std::cmp::Reverse; -use std::path::PathBuf; use log::warn; -use protobuf::Message as _; -use crate::cmd::open_submaildir; -use crate::error::Result; -use crate::pb3::jwebmail::{ListMailHeader, ListReq, ListResp, MailHeader}; +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::{ + Call_List, ListMailHeader, MailHeader, Sort, Sort_direction, Sort_parameter, +}; use crate::rfc822::me_to_lmh; fn from_or_sender(mh: &MailHeader) -> &str { @@ -37,95 +36,110 @@ fn mid_to_rec_time(mid: &str) -> f64 { fn sort_by_and_take( mut entries: Vec<maildir::MailEntry>, - sortby: &str, + sortby: Sort, s: usize, e: usize, ) -> Vec<ListMailHeader> { - match sortby { - "date" => { - entries.sort_by(|a, b| { - mid_to_rec_time(a.id()) - .partial_cmp(&mid_to_rec_time(b.id())) - .unwrap() - }); - entries - .drain(s..e) - .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) - .collect() - } - "!date" => { - entries.sort_by(|b, a| { - mid_to_rec_time(a.id()) - .partial_cmp(&mid_to_rec_time(b.id())) - .unwrap() - }); - entries - .drain(s..e) - .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) - .collect() - } - "size" => { - entries.sort_by_cached_key(|a| a.path().metadata().map_or(0, |m| m.len())); - entries - .drain(s..e) - .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) - .collect() - } - "!size" => { - entries.sort_by_cached_key(|a| Reverse(a.path().metadata().map_or(0, |m| m.len()))); - entries - .drain(s..e) - .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) - .collect() - } - "subject" | "!subject" => { + match sortby.parameter { + Sort_parameter::date => match sortby.direction { + Sort_direction::asc => { + entries.sort_by(|a, b| { + mid_to_rec_time(a.id()) + .partial_cmp(&mid_to_rec_time(b.id())) + .unwrap() + }); + entries + .drain(s..e) + .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) + .collect() + } + Sort_direction::desc => { + entries.sort_by(|b, a| { + mid_to_rec_time(a.id()) + .partial_cmp(&mid_to_rec_time(b.id())) + .unwrap() + }); + entries + .drain(s..e) + .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) + .collect() + } + }, + Sort_parameter::size => match sortby.direction { + Sort_direction::asc => { + entries.sort_by_cached_key(|a| a.path().metadata().map_or(0, |m| m.len())); + entries + .drain(s..e) + .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) + .collect() + } + Sort_direction::desc => { + entries.sort_by_cached_key(|a| Reverse(a.path().metadata().map_or(0, |m| m.len()))); + entries + .drain(s..e) + .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) + .collect() + } + }, + Sort_parameter::subject => { let mut x: Vec<ListMailHeader> = entries .drain(..) .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) .collect(); - if sortby.as_bytes().first().copied() == Some(b'!') { - x.sort_by(|a, b| a.header.subject.cmp(&b.header.subject)) - } else { - x.sort_by(|b, a| a.header.subject.cmp(&b.header.subject)) + match sortby.direction { + Sort_direction::asc => x.sort_by(|a, b| a.header.subject.cmp(&b.header.subject)), + Sort_direction::desc => x.sort_by(|b, a| a.header.subject.cmp(&b.header.subject)), } x.drain(s..e).collect() } - "sender" | "!sender" => { + Sort_parameter::sender => { let mut x: Vec<ListMailHeader> = entries .drain(..) .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) .collect(); - if sortby.as_bytes().first().copied() != Some(b'!') { - x.sort_by(|a, b| from_or_sender(&a.header).cmp(from_or_sender(&b.header))) - } else { - x.sort_by(|b, a| from_or_sender(&a.header).cmp(from_or_sender(&b.header))) + match sortby.direction { + Sort_direction::asc => { + x.sort_by(|a, b| from_or_sender(&a.header).cmp(from_or_sender(&b.header))) + } + Sort_direction::desc => { + x.sort_by(|b, a| from_or_sender(&a.header).cmp(from_or_sender(&b.header))) + } } x.drain(s..e).collect() } - _ => todo!(), } } -pub fn list(path: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = ListReq::parse_from_bytes(req)?; - let md = open_submaildir(path, &r.folder); +pub fn list( + ms: &MailStorage, + call: &mut dyn Call_List, + folder: String, + start: i64, + end: i64, + sort: Sort, +) -> varlink::Result<()> { + if let Some(path) = ms.maildir_path.read().unwrap().clone() { + let md = open_submaildir(path, &folder); - for r in md.list_new() { - match r { - Err(e) => warn!("{}", e), - Ok(me) => { - if let Err(e) = md.move_new_to_cur(me.id()) { - warn!("{}", e); + for r in md.list_new() { + match r { + Err(e) => warn!("{}", e), + Ok(me) => { + if let Err(e) = md.move_new_to_cur(me.id()) { + warn!("{}", e); + } } - } - }; - } + }; + } + + let a: Vec<_> = md.list_cur().filter_map(std::result::Result::ok).collect(); + let start = std::cmp::min(a.len(), start as usize); + let end = std::cmp::min(a.len(), end as usize); - let a: Vec<_> = md.list_cur().filter_map(std::result::Result::ok).collect(); - let start = std::cmp::min(a.len(), r.start as usize); - let end = std::cmp::min(a.len(), r.end as usize); + let mail_heads = sort_by_and_take(a, sort, start, end); - let mut resp = ListResp::new(); - resp.mail_heads = sort_by_and_take(a, &r.sort, start, end); - resp.write_to_bytes().map_err(|e| e.into()) + call.reply(mail_heads) + } else { + call.reply_not_initialized() + } } diff --git a/src/cmd/move.rs b/src/cmd/move.rs new file mode 100644 index 0000000..c852d6c --- /dev/null +++ b/src/cmd/move.rs @@ -0,0 +1,19 @@ +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Move; + +pub fn r#move( + ms: &MailStorage, + call: &mut dyn Call_Move, + mid: String, + from_folder: String, + to_folder: String, +) -> varlink::Result<()> { + if let Some(p) = ms.maildir_path.read().unwrap().clone() { + let from = open_submaildir(p.clone(), &from_folder); + let to = open_submaildir(p, &to_folder); + from.move_to(&mid, &to).unwrap(); + call.reply() + } else { + call.reply_not_initialized() + } +} diff --git a/src/cmd/move_mail.rs b/src/cmd/move_mail.rs deleted file mode 100644 index 146e906..0000000 --- a/src/cmd/move_mail.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::path::PathBuf; - -use protobuf::Message as _; - -use crate::cmd::open_submaildir; -use crate::error::Result; -use crate::pb3::jwebmail::{MoveReq, MoveResp}; - -pub fn move_mail(p: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = MoveReq::parse_from_bytes(req)?; - - let from = open_submaildir(p.clone(), &r.from_f); - let to = open_submaildir(p, &r.to_f); - from.move_to(&r.mid, &to)?; - - let resp = MoveResp::new(); - resp.write_to_bytes().map_err(|e| e.into()) -} 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() } } diff --git a/src/cmd/read.rs b/src/cmd/read.rs deleted file mode 100644 index 797f4d6..0000000 --- a/src/cmd/read.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::io::ErrorKind as IOErrKind; -use std::path::PathBuf; - -use protobuf::Message as _; - -use crate::cmd::open_submaildir; -use crate::error::Result; -use crate::pb3::jwebmail::{ShowReq, ShowResp}; -use crate::rfc822::parsed_mail_to_mail; - -pub fn read(path: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = ShowReq::parse_from_bytes(req)?; - let md = open_submaildir(path, &r.folder); - - md.add_flags(&r.mid, "S")?; - - let mut mail = md.find(&r.mid).ok_or_else(|| { - std::io::Error::new(IOErrKind::NotFound, format!("mail {} not found", &r.mid)) - })?; - - let mut resp = ShowResp::new(); - resp.mail = Some(parsed_mail_to_mail(mail.parsed()?)?).into(); - resp.write_to_bytes().map_err(|e| e.into()) -} diff --git a/src/cmd/remove.rs b/src/cmd/remove.rs index 8d26e68..73328a5 100644 --- a/src/cmd/remove.rs +++ b/src/cmd/remove.rs @@ -1,17 +1,18 @@ -use std::path::PathBuf; +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Remove; -use protobuf::Message as _; +pub fn remove( + ms: &MailStorage, + call: &mut dyn Call_Remove, + folder: String, + mid: String, +) -> varlink::Result<()> { + if let Some(p) = ms.maildir_path.read().unwrap().clone() { + let md = open_submaildir(p, &folder); + md.add_flags(&mid, "T").map_err(varlink::map_context!())?; -use crate::cmd::open_submaildir; -use crate::error::Result; -use crate::pb3::jwebmail::{RemoveReq, RemoveResp}; - -pub fn remove(p: PathBuf, req: &[u8]) -> Result<Vec<u8>> { - let r = RemoveReq::parse_from_bytes(req)?; - - let md = open_submaildir(p, &r.folder); - md.add_flags(&r.mid, "T")?; - - let resp = RemoveResp::new(); - resp.write_to_bytes().map_err(|e| e.into()) + call.reply() + } else { + call.reply_not_initialized() + } } diff --git a/src/cmd/search.rs b/src/cmd/search.rs new file mode 100644 index 0000000..7cf0fb0 --- /dev/null +++ b/src/cmd/search.rs @@ -0,0 +1,17 @@ +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Search; + +pub fn search( + ms: &MailStorage, + call: &mut dyn Call_Search, + folder: String, + _pattern: String, +) -> varlink::Result<()> { + if let Some(p) = ms.maildir_path.read().unwrap().clone() { + let md = open_submaildir(p, &folder); + + todo!(); + } else { + call.reply_not_initialized() + } +} diff --git a/src/cmd/show.rs b/src/cmd/show.rs new file mode 100644 index 0000000..442eb21 --- /dev/null +++ b/src/cmd/show.rs @@ -0,0 +1,26 @@ +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Show; +use crate::rfc822::parsed_mail_to_mail; + +pub fn show( + ms: &MailStorage, + call: &mut dyn Call_Show, + folder: String, + mid: String, +) -> varlink::Result<()> { + if let Some(path) = ms.maildir_path.read().unwrap().clone() { + let md = open_submaildir(path, &folder); + + md.add_flags(&mid, "S").map_err(varlink::map_context!())?; + + if let Some(mut mail) = md.find(&mid) { + let mail2 = parsed_mail_to_mail(mail.parsed().unwrap()).unwrap(); + + call.reply(mail2) + } else { + call.reply_invalid_mid(folder, mid) + } + } else { + call.reply_not_initialized() + } +} diff --git a/src/cmd/stats.rs b/src/cmd/stats.rs new file mode 100644 index 0000000..e8e8325 --- /dev/null +++ b/src/cmd/stats.rs @@ -0,0 +1,25 @@ +use crate::cmd::{open_submaildir, MailStorage}; +use crate::de_jmhoffmann_jwebmail_mailstorage::Call_Stats; + +pub fn stats(ms: &MailStorage, call: &mut dyn Call_Stats, folder: String) -> varlink::Result<()> { + if let Some(maildir_path) = ms.maildir_path.read().unwrap().clone() { + let maildir = open_submaildir(maildir_path, &folder); + + let mail_count = maildir.count_cur() as i64; + let unread_count = maildir + .list_cur() + .filter(|x| x.as_ref().map_or(false, |z| !z.is_seen())) + .count() as i64; + let byte_size: u64 = maildir + .path() + .join("cur") + .read_dir() + .map_err(varlink::map_context!())? + .map(|x| x.map_or(0, |z| z.metadata().map_or(0, |y| y.len()))) + .sum(); + + call.reply(mail_count, unread_count, byte_size as i64) + } else { + call.reply_not_initialized() + } +} |