diff options
Diffstat (limited to 'src/cmd/list.rs')
-rw-r--r-- | src/cmd/list.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/cmd/list.rs b/src/cmd/list.rs new file mode 100644 index 0000000..0ec0389 --- /dev/null +++ b/src/cmd/list.rs @@ -0,0 +1,116 @@ +use std::cmp::Reverse; + +use log::warn; +use maildir::Maildir; + +use crate::arguments::{SortInfo, SortKey, SortOrder}; +use crate::error::Result; +use crate::rfc822::{MailHeader, TopMailHeader}; + +fn from_or_sender<'a>(mh: &'a MailHeader) -> &'a str { + if mh.from.len() == 0 { + warn!("mail without from"); + panic!() + } + if mh.from.len() == 1 { + &mh.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().unwrap() +} + +fn sort_by_and_take( + mut entries: Vec<maildir::MailEntry>, + sortby: &SortInfo, + s: usize, + e: usize, +) -> Vec<TopMailHeader> { + match sortby.key { + SortKey::Date => { + match sortby.order { + SortOrder::Ascending => entries.sort_by(|a, b| { + mid_to_rec_time(a.id()) + .partial_cmp(&mid_to_rec_time(b.id())) + .unwrap() + }), + SortOrder::Descending => 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.try_into().map_err(|e| warn!("{}", e)).ok()) + .collect() + } + SortKey::Size => { + match sortby.order { + SortOrder::Ascending => { + entries.sort_by_cached_key(|a| a.path().metadata().map_or(0, |m| m.len())) + } + SortOrder::Descending => entries + .sort_by_cached_key(|a| Reverse(a.path().metadata().map_or(0, |m| m.len()))), + } + entries + .drain(s..e) + .filter_map(|me| me.try_into().map_err(|e| warn!("{}", e)).ok()) + .collect() + } + SortKey::Subject => { + let mut x: Vec<TopMailHeader> = entries + .drain(..) + .filter_map(|me| me.try_into().map_err(|e| warn!("{}", e)).ok()) + .collect(); + match sortby.order { + SortOrder::Ascending => x.sort_by(|a, b| a.head.subject.cmp(&b.head.subject)), + SortOrder::Descending => x.sort_by(|b, a| a.head.subject.cmp(&b.head.subject)), + } + x.drain(s..e).collect() + } + SortKey::Sender => { + let mut x: Vec<TopMailHeader> = entries + .drain(..) + .filter_map(|me| me.try_into().map_err(|e| warn!("{}", e)).ok()) + .collect(); + match sortby.order { + SortOrder::Ascending => { + x.sort_by(|a, b| from_or_sender(&a.head).cmp(from_or_sender(&b.head))) + } + SortOrder::Descending => { + x.sort_by(|b, a| from_or_sender(&a.head).cmp(from_or_sender(&b.head))) + } + } + x.drain(s..e).collect() + } + } +} + +pub fn list(md: &Maildir, i: usize, j: usize, sortby: &SortInfo) -> Result<Vec<TopMailHeader>> { + 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(), i); + let end = std::cmp::min(a.len(), j); + Ok(sort_by_and_take(a, sortby, start, end)) +} |