use std::cmp::Reverse; use log::warn; 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 { if mh.written_from.is_empty() { warn!("mail without from"); panic!() } if mh.written_from.len() == 1 { &mh.written_from[0].address } else { &mh.sender.as_ref().unwrap().address } } fn mid_to_rec_time(mid: &str) -> f64 { let Some(dec) = mid.find('.') else { warn!("Invaild mail-id {}", mid); return 0.0; }; let Some(sep) = mid[dec + 1..].find('.') else { return 0.0; }; mid[..dec + 1 + sep] .parse() .or_else(|_| mid[..dec].parse()) .unwrap_or(0.0) } fn sort_by_and_take( mut entries: Vec, sortby: Sort, s: usize, e: usize, ) -> Vec { 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 = entries .drain(..) .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) .collect(); 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() } Sort_parameter::sender => { let mut x: Vec = entries .drain(..) .filter_map(|me| me_to_lmh(me).map_err(|e| warn!("{}", e)).ok()) .collect(); 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() } } } 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); } } }; } 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 mail_heads = sort_by_and_take(a, sort, start, end); call.reply(mail_heads) } else { call.reply_not_initialized() } }