summaryrefslogtreecommitdiff
path: root/src/cmd/list.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/list.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/list.rs')
-rw-r--r--src/cmd/list.rs158
1 files changed, 86 insertions, 72 deletions
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()
+ }
}