diff --git a/Cargo.toml b/Cargo.toml index 1796653..0d6b830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,16 @@ [package] -name = "buzz" -version = "1.1.10" +name = "buzz-ed" +version = "1.1.11" -description = "A simple system tray application for notifying about unseen e-mail" +description = "A simple application for notifying about unseen e-mail" readme = "README.md" authors = ["Jon Gjengset "] -homepage = "https://github.com/jonhoo/buzz" -repository = "https://github.com/jonhoo/buzz.git" +homepage = "https://github.com/teldra/buzz-ed" +repository = "https://github.com/teldra/buzz-ed.git" -keywords = ["email","cli","systray","notification"] +keywords = ["email","cli"] categories = ["command-line-utilities", "email"] license = "MIT/Apache-2.0" diff --git a/README.md b/README.md index a2179f3..168dfdb 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,21 @@ # Introduction Using mutt (or pine), but annoyed that it doesn't give you any -notifications when you've received new emails? buzz is a simple tray +notifications when you've received new emails? buzz-ed is a simple application that detects new emails on IMAP servers using IDLE (push -rather than pull). When it detects unseen messages, it shows a OSD style -notification and changes the tray icon to indicate that you have new -mail. +rather than pull). When it detects unseen messages, it shows writes +the amount of new messages to a defined file and runs a defined command. This project is a Rust fork of [hasmail](https://github.com/jonhoo/hasmail), which provides basically the same features, and is written in Go. -## What does it look like: - -![no new e-mail](assets/no-email.png?raw=true) -![new e-mail](assets/new-email.png?raw=true) - -![new e-mail notification](assets/notification.png?raw=true) # Configuration -buzz looks for a +buzz-ed looks for a [TOML](https://github.com/toml-lang/toml#user-content-example) -configuration file in `~/.config/buzz.toml` on startup. The +configuration file in `~/.config/buzz/buzz.toml` on startup. The configuration file consists of a number of sections, each corresponding to one account: @@ -34,11 +27,20 @@ username = "jon@gmail.com" pwcmd = "gnome-keyring-query get gmail_pw" ``` +## Running buzz-ed + +``` +buzz /tmp/mails "pkill -RTMIN+2 i3blocks" +``` + +The first argument is the file, where it stores the amount of unread messages. +The second argument is the script or programm it starts after the amount has changed. + + ## Account fields The value in `[]` can be anything (though avoid `.` as it will be parsed -as a new TOML section), and is shown in the tooltip when new e-mails -arrive for an account. The options for an account are as follows: +as a new TOML section). The options for an account are as follows: - `server`: The address to connect to. MUST currently be SSL/TLS enabled. @@ -46,8 +48,4 @@ arrive for an account. The options for an account are as follows: - `username`: Username for authentication. - `pwcmd`: Command to execute to get password for authentication. -# TODOs - - [ ] `click` command - - [ ] hover tooltip - - [ ] customizeable folder diff --git a/src/main.rs b/src/main.rs index 063917d..c25b681 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,6 @@ 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,56 +103,6 @@ impl Connection { } last_notified = std::cmp::max(last_notified, uids.iter().cloned().max().unwrap_or(0)); - let mut subjects = BTreeMap::new(); - if !uids.is_empty() { - let uids: Vec<_> = uids.into_iter().map(|v: u32| format!("{}", v)).collect(); - for msg in self.socket - .uid_fetch(&uids.join(","), "RFC822.HEADER")? - .iter() - { - let msg = msg.header(); - if msg.is_none() { - continue; - } - - match mailparse::parse_headers(msg.unwrap()) { - Ok((headers, _)) => { - use mailparse::MailHeaderMap; - - 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), - } - } - } - - tx.send((account, num_unseen)).unwrap(); // IDLE until we see changes @@ -296,14 +244,14 @@ fn main() { for (i, num_unseen) in rx { unseen[i] = num_unseen; - let mut file = std::fs::File::create("/tmp/mails").expect("create failed"); + let output_path = ::std::env::args().nth(1).unwrap(); + let commands = ::std::env::args().nth(2).unwrap(); + let mut file = std::fs::File::create(&output_path).expect("create failed"); file.write_all(num_unseen.to_string().as_bytes()).expect( "write failed", ); - Command::new("pkill") - .arg("-RTMIN+2") - .arg("i3blocks") - .spawn() - .expect("pkill command failed to start"); + Command::new("sh").arg("-c").arg(&commands).spawn().expect( + "command failed to start", + ); } }