summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/add_folder.rs53
-rw-r--r--src/cmd/count.rs27
-rw-r--r--src/cmd/folders.rs35
-rw-r--r--src/cmd/init.rs35
-rw-r--r--src/cmd/list.rs158
-rw-r--r--src/cmd/move.rs19
-rw-r--r--src/cmd/move_mail.rs18
-rw-r--r--src/cmd/raw.rs185
-rw-r--r--src/cmd/read.rs24
-rw-r--r--src/cmd/remove.rs29
-rw-r--r--src/cmd/search.rs17
-rw-r--r--src/cmd/show.rs26
-rw-r--r--src/cmd/stats.rs25
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()
+ }
+}