diff --git a/Cargo.lock b/Cargo.lock index 228d73c..6dd39d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,7 +131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "buzz" version = "1.0.7" dependencies = [ - "imap 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "imap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "mailparse 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "notify-rust 3.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -568,14 +568,24 @@ dependencies = [ [[package]] name = "imap" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "imap-proto 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "imap-proto" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.3.4" @@ -1349,7 +1359,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gobject-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70409d6405db8b1591602fcd0cbe8af52cd9976dd39194442b4c149ba343f86d" "checksum gtk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "414f3522f550a0b4f65e089f00ffcd3987dab8b0be284cb979aa7f6a03d60516" "checksum gtk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9554cf5b3a85a13fb39258c65b04b262989c1d7a758f8f555b77a478621a91" -"checksum imap 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01150a9ea6b0ff4c7135c04090bfe2e5e073b90263208b08a7d4bfff0b5f47e2" +"checksum imap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3072853e727ec65d846008463e37265d8fe4917ed68765ae7dda2d1f5e65860b" +"checksum imap-proto 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8733e1ad1058e09532090e95b1debda73cc25ea4d1ba53bf4a60870c19865952" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" diff --git a/Cargo.toml b/Cargo.toml index dd4bbac..97977e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ license = "MIT/Apache-2.0" debug=true [dependencies] -imap = "0.6.0" +imap = "0.8.1" native-tls = "0.1" systray = "0.3.0" mailparse = "0.6.0" diff --git a/src/main.rs b/src/main.rs index 3a8cc3b..cafcee7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,17 +7,17 @@ extern crate systray; extern crate toml; extern crate xdg; -use native_tls::{TlsConnector, TlsStream}; use imap::client::Client; +use native_tls::{TlsConnector, TlsStream}; use rayon::prelude::*; -use std::process::Command; +use std::fs::File; use std::io::prelude::*; use std::net::TcpStream; -use std::time::Duration; +use std::process::Command; use std::sync::mpsc; -use std::fs::File; use std::thread; +use std::time::Duration; #[derive(Clone)] struct Account { @@ -30,12 +30,14 @@ struct Account { impl Account { pub fn connect(&self) -> Result>, imap::error::Error> { let tls = TlsConnector::builder()?.build()?; - Client::secure_connect((&*self.server.0, self.server.1), &self.server.0, tls).and_then( + Client::secure_connect((&*self.server.0, self.server.1), &self.server.0, &tls).and_then( |mut c| { - try!(c.login(&self.username, &self.password)); - let cap = try!(c.capability()); - if !cap.iter().any(|c| c == "IDLE") { - return Err(imap::error::Error::BadResponse(cap)); + try!(c.login(self.username.trim(), self.password.trim())); + let cap = try!(c.capabilities()); + if !cap.iter().any(|&c| c == "IDLE") { + return Err(imap::error::Error::BadResponse( + cap.iter().cloned().collect(), + )); } try!(c.select("INBOX")); Ok(Connection { @@ -103,7 +105,7 @@ impl Connection { let mut num_unseen = 0; let mut uids = Vec::new(); - let unseen = unseen.join(" "); + let unseen = ::std::str::from_utf8(&unseen[..]).unwrap(); let unseen = unseen.split_whitespace().skip(2); for uid in unseen.take_while(|&e| e != "" && e != "Completed") { if let Ok(uid) = usize::from_str_radix(uid, 10) { @@ -117,18 +119,24 @@ impl Connection { let mut subjects = Vec::new(); if !uids.is_empty() { - let mut finish = |message: &[u8]| -> bool { - match mailparse::parse_headers(message) { + for msg in self.socket + .uid_fetch(&uids.join(","), "RFC822.HEADER")? + .iter() + { + let msg = msg.rfc822_header(); + if msg.is_none() { + continue; + } + + match mailparse::parse_headers(msg.unwrap()) { Ok((headers, _)) => { use mailparse::MailHeaderMap; match headers.get_first_value("Subject") { Ok(Some(subject)) => { subjects.push(subject); - return true; } Ok(None) => { subjects.push(String::from("")); - return true; } Err(e) => { println!("failed to get message subject: {:?}", e); @@ -137,30 +145,14 @@ impl Connection { } Err(e) => println!("failed to parse headers of message: {:?}", e), } - false - }; - - let lines = self.socket.uid_fetch(&uids.join(","), "RFC822.HEADER")?; - let mut message = Vec::new(); - for line in &lines { - if line.starts_with("* ") { - if !message.is_empty() { - finish(&message[..]); - message.clear(); - } - continue; - } - message.extend(line.as_bytes()); } - finish(&message[..]); } if !subjects.is_empty() { use notify_rust::{Notification, NotificationHint}; let title = format!( "@{} has new mail ({} unseen)", - self.account.name, - num_unseen + self.account.name, num_unseen ); let notification = format!("> {}", subjects.join("\n> ")); println!("! {}", title); @@ -274,8 +266,8 @@ fn main() { return; } }; - if let Err(e) = app.set_icon_from_file(&"/usr/share/icons/Faenza/stock/24/stock_disconnect.png" - .to_string()) + if let Err(e) = + app.set_icon_from_file(&"/usr/share/icons/Faenza/stock/24/stock_disconnect.png".to_string()) { println!("Could not set application icon: {}", e); } @@ -298,14 +290,12 @@ fn main() { Err(imap::error::Error::Io(e)) => { println!( "Failed to connect account {}: {}; retrying in {}s", - account.name, - e, - wait + account.name, e, wait ); thread::sleep(Duration::from_secs(wait)); } Err(e) => { - println!("{} host produced bad IMAP tunnel: {}", account.name, e); + println!("{} host produced bad IMAP tunnel: {:?}", account.name, e); break; } } @@ -323,8 +313,7 @@ fn main() { } // We have now connected - app.set_icon_from_file(&"/usr/share/icons/Faenza/stock/24/stock_connect.png" - .to_string()) + app.set_icon_from_file(&"/usr/share/icons/Faenza/stock/24/stock_connect.png".to_string()) .ok(); let (tx, rx) = mpsc::channel(); @@ -339,8 +328,7 @@ fn main() { for (i, num_unseen) in rx { unseen[i] = num_unseen; if unseen.iter().sum::() == 0 { - app.set_icon_from_file(&"/usr/share/icons/oxygen/base/32x32/status/mail-unread.png" - .to_string()) + app.set_icon_from_file(&"/usr/share/icons/oxygen/base/32x32/status/mail-unread.png".to_string()) .unwrap(); } else { app.set_icon_from_file(