diff --git a/Cargo.lock b/Cargo.lock index 9cdd249..ac8ecf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,9 +151,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "buzz" -version = "1.1.3" +version = "1.1.4" dependencies = [ "askama_escape 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "imap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "mailparse 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 6571442..59a70fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "buzz" -version = "1.1.3" +version = "1.1.4" description = "A simple system tray application for notifying about unseen e-mail" readme = "README.md" @@ -31,3 +31,4 @@ xdg = "2.1.0" notify-rust = "3.4.0" rayon = "1.0.0" askama_escape = "0.1" +chrono = "0.4" diff --git a/src/main.rs b/src/main.rs index af40e86..f052e8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ extern crate askama_escape; +extern crate chrono; extern crate imap; extern crate mailparse; extern crate native_tls; @@ -11,6 +12,8 @@ extern crate xdg; use native_tls::{TlsConnector, TlsStream}; use rayon::prelude::*; +use std::borrow::Cow; +use std::collections::BTreeMap; use std::fs::File; use std::io::prelude::*; use std::net::TcpStream; @@ -105,7 +108,7 @@ impl Connection { } let uids: Vec<_> = uids.into_iter().map(|v: u32| format!("{}", v)).collect(); - let mut subjects = Vec::new(); + let mut subjects = BTreeMap::new(); if !uids.is_empty() { for msg in self .socket @@ -120,17 +123,34 @@ impl Connection { match mailparse::parse_headers(msg.unwrap()) { Ok((headers, _)) => { use mailparse::MailHeaderMap; - match headers.get_first_value("Subject") { - Ok(Some(subject)) => { - subjects.push(subject); - } - Ok(None) => { - subjects.push(String::from("")); - } + + let subject = match headers.get_first_value("Subject") { + Ok(Some(subject)) => Cow::from(subject), + Ok(None) => Cow::from(""), Err(e) => { println!("failed to get message subject: {:?}", e); + continue; } - } + }; + + let date = match headers.get_first_value("Date") { + Ok(Some(date)) => { + match chrono::DateTime::parse_from_rfc2822(&date) { + Ok(date) => date.with_timezone(&chrono::Local), + Err(e) => { + println!("failed to parse message date: {:?}", e); + chrono::Local::now() + } + } + } + Ok(None) => chrono::Local::now(), + Err(e) => { + println!("failed to get message date: {:?}", e); + continue; + } + }; + + subjects.insert(date, subject); } Err(e) => println!("failed to parse headers of message: {:?}", e), } @@ -143,12 +163,21 @@ impl Connection { "@{} has new mail ({} unseen)", self.account.name, num_unseen ); - let notification = format!("> {}", subjects.join("\n> ")); + + // we want the n newest e-mail in reverse chronological order + let mut notification = String::new(); + for subject in subjects.values().rev() { + notification.push_str("> "); + notification.push_str(subject); + notification.push_str("\n"); + } + let notification = notification.trim_end(); + println!("! {}", title); println!("{}", notification); Notification::new() .summary(&title) - .body(&format!("{}", askama_escape::escape(¬ification))) + .body(&format!("{}", askama_escape::escape(notification))) .icon("notification-message-email") .hint(NotificationHint::Category("email".to_owned())) .timeout(-1)