diff --git a/Cargo.toml b/Cargo.toml
index c079f777..e70c542f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,6 +23,7 @@ base64 = "*"
crossbeam = "^0.3.0"
fnv = "1.0.3"
encoding = "0.2.33"
+bitflags = "1.0"
[dependencies.ncurses]
features = ["wide"]
diff --git a/src/lib.rs b/src/lib.rs
index 4674e990..1bd073b6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,3 +32,6 @@ extern crate chrono;
extern crate base64;
extern crate memmap;
extern crate encoding;
+
+#[macro_use]
+extern crate bitflags;
diff --git a/src/mailbox/backends/maildir.rs b/src/mailbox/backends/maildir.rs
index aa417ee2..2bd7c29d 100644
--- a/src/mailbox/backends/maildir.rs
+++ b/src/mailbox/backends/maildir.rs
@@ -19,7 +19,7 @@
* along with meli. If not, see .
*/
-use mailbox::email::Envelope;
+use mailbox::email::{Envelope, Flag};
use error::{MeliError, Result};
use mailbox::backends::{BackendOp, BackendOpGenerator, MailBackend};
use mailbox::email::parser;
@@ -79,6 +79,31 @@ impl BackendOp for MaildirOp {
let result = parser::headers_raw(raw).to_full_result()?;
Ok(result)
}
+ fn fetch_flags(&self) -> Flag {
+ let mut flag = Flag::default();
+ let path = PathBuf::from(&self.path);
+ let filename = path.file_name().unwrap().to_str().unwrap();
+ if !filename.contains(":2,") {
+ return flag;
+ }
+
+ for f in filename.chars().rev() {
+ match f {
+ ',' => break,
+ 'P' => flag |= Flag::PASSED,
+ 'R' => flag |= Flag::REPLIED,
+ 'S' => flag |= Flag::SEEN,
+ 'T' => flag |= Flag::TRASHED,
+ 'D' => flag |= Flag::DRAFT,
+ 'F' => flag |= Flag::FLAGGED,
+ _ => panic!(),
+ }
+
+ }
+
+
+ flag
+ }
}
diff --git a/src/mailbox/backends/mod.rs b/src/mailbox/backends/mod.rs
index 8bf987d5..7705af04 100644
--- a/src/mailbox/backends/mod.rs
+++ b/src/mailbox/backends/mod.rs
@@ -20,7 +20,7 @@
*/
pub mod maildir;
-use mailbox::email::Envelope;
+use mailbox::email::{Envelope, Flag};
use error::Result;
use std::fmt;
@@ -59,6 +59,9 @@ pub trait MailBackend {
/// fn fetch_body(&mut self) -> Result<&[u8]> {
/// unimplemented!()
/// }
+/// fn fetch_flags((&self) -> Flag {
+/// unimplemented!()
+/// }
/// }
///
/// let foogen = BackendOpGenerator::new(Box::new(|| Box::new(FooOp {})));
@@ -73,6 +76,7 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
//fn copy(&self
fn fetch_headers(&mut self) -> Result<&[u8]>;
fn fetch_body(&mut self) -> Result<&[u8]>;
+ fn fetch_flags(&self) -> Flag;
}
/// `BackendOpGenerator` is a wrapper for a closure that returns a `BackendOp` object
diff --git a/src/mailbox/email/mod.rs b/src/mailbox/email/mod.rs
index 075fdbd5..9a8e6333 100644
--- a/src/mailbox/email/mod.rs
+++ b/src/mailbox/email/mod.rs
@@ -106,6 +106,19 @@ struct References {
refs: Vec,
}
+
+bitflags! {
+ #[derive(Default)]
+ pub struct Flag: u8 {
+ const PASSED = 0b00000001;
+ const REPLIED = 0b00000010;
+ const SEEN = 0b00000100;
+ const TRASHED = 0b00001000;
+ const DRAFT = 0b00010000;
+ const FLAGGED = 0b00100000;
+ }
+}
+
/* A very primitive mail object */
#[derive(Debug, Clone)]
pub struct Envelope {
@@ -123,6 +136,8 @@ pub struct Envelope {
thread: usize,
operation_token: Arc>,
+
+ flags: Flag,
}
@@ -314,6 +329,12 @@ impl Envelope {
self.timestamp = v.timestamp();
}
}
+ pub fn get_flags(&self) -> Flag {
+ self.flags
+ }
+ pub fn is_seen(&self) -> bool {
+ !(self.flags & Flag::SEEN).is_empty()
+ }
pub fn new(token: Box) -> Self {
Envelope {
date: "".to_string(),
@@ -331,20 +352,27 @@ impl Envelope {
thread: 0,
operation_token: Arc::new(token),
+ flags: Flag::default(),
}
}
pub fn from(operation_token: Box) -> Option {
- let mut operation = operation_token.generate();
+ let operation = operation_token.generate();
+ let mut e = Envelope::new(operation_token);
+ e.flags = operation.fetch_flags();
+ Some(e)
+ }
+
+ pub fn populate_headers(&mut self) -> () {
+ let mut operation = self.operation_token.generate();
let headers = match parser::headers(operation.fetch_headers().unwrap()).to_full_result() {
Ok(v) => v,
_ => {
- let operation = operation_token.generate();
+ let operation = self.operation_token.generate();
eprintln!("error in parsing mail\n{}", operation.description());
- return None;
+ return;
}
};
- let mut mail = Envelope::new(operation_token);
let mut in_reply_to = None;
let mut datetime = None;
@@ -359,7 +387,7 @@ impl Envelope {
} else {
"".to_string()
};
- mail.set_to(value);
+ self.set_to(value);
} else if name.eq_ignore_ascii_case("from") {
let parse_result = parser::subject(value.as_bytes());
let value = if parse_result.is_done() {
@@ -367,7 +395,7 @@ impl Envelope {
} else {
"".to_string()
};
- mail.set_from(value);
+ self.set_from(value);
} else if name.eq_ignore_ascii_case("subject") {
let parse_result = parser::subject(value.trim().as_bytes());
let value = if parse_result.is_done() {
@@ -375,35 +403,33 @@ impl Envelope {
} else {
"".to_string()
};
- mail.set_subject(value);
+ self.set_subject(value);
} else if name.eq_ignore_ascii_case("message-id") {
- mail.set_message_id(value);
+ self.set_message_id(value);
} else if name.eq_ignore_ascii_case("references") {
{
let parse_result = parser::references(value.as_bytes());
if parse_result.is_done() {
for v in parse_result.to_full_result().unwrap() {
- mail.push_references(v);
+ self.push_references(v);
}
}
}
- mail.set_references(value.to_string());
+ self.set_references(value.to_string());
} else if name.eq_ignore_ascii_case("in-reply-to") {
- mail.set_in_reply_to(value);
+ self.set_in_reply_to(value);
in_reply_to = Some(value);
} else if name.eq_ignore_ascii_case("date") {
- mail.set_date(value.to_string());
+ self.set_date(value.to_string());
datetime = Some(value.to_string());
}
}
if let Some(ref mut x) = in_reply_to {
- mail.push_references(x);
+ self.push_references(x);
}
if let Some(ref mut d) = datetime {
- mail.set_datetime(parser::date(d));
+ self.set_datetime(parser::date(d));
}
-
- Some(mail)
}
}
diff --git a/src/mailbox/mod.rs b/src/mailbox/mod.rs
index 37f46055..c380fcb8 100644
--- a/src/mailbox/mod.rs
+++ b/src/mailbox/mod.rs
@@ -34,7 +34,7 @@ use mailbox::thread::{build_threads, Container};
use std::option::Option;
-/*a Mailbox represents a folder of mail. Currently only Maildir is supported.*/
+/// `Mailbox` represents a folder of mail. Currently only `Maildir` is supported.
#[derive(Debug, Clone)]
pub struct Mailbox {
pub path: String,
@@ -48,6 +48,9 @@ pub struct Mailbox {
impl Mailbox {
pub fn new(path: &str, sent_folder: &Option>) -> Result {
let mut collection: Vec = maildir::MaildirType::new(path).get()?;
+ for e in &mut collection {
+ e.populate_headers();
+ }
collection.sort_by(|a, b| a.get_date().cmp(&b.get_date()));
let (threads, threaded_collection) = build_threads(&mut collection, sent_folder);
diff --git a/src/mailbox/thread.rs b/src/mailbox/thread.rs
index bb8021a9..891cda72 100644
--- a/src/mailbox/thread.rs
+++ b/src/mailbox/thread.rs
@@ -19,15 +19,6 @@
* along with meli. If not, see .
*/
-/* a Container struct is needed to describe the Thread tree forest during creation
- * of threads. Because of Rust's memory model, we store indexes of other node
- * instead of references and every reference is passed through the Container owner
- * (a Vec).
- *
- * message refers to a Envelope entry in a Vec. If it's empty, the Container is
- * nonexistent in our Mailbox but we know it exists (for example we have a copy
- * of a reply to a mail but we don't have its copy.
- */
use mailbox::email::*;
use mailbox::Mailbox;
use error::Result;
@@ -40,6 +31,13 @@ use std;
type UnixTimestamp = i64;
+/// A `Container` struct is needed to describe the thread tree forest during creation of threads.
+/// Because of Rust's memory model, we store indexes of Envelopes inside a collection instead of
+/// references and every reference is passed through the `Container` owner (a `Vec`).
+//
+/// `message` refers to a `Envelope` entry in a `Vec`. If it's empty, the `Container` is
+/// nonexistent in our `Mailbox` but we know it exists (for example we have a copy
+/// of a reply to a mail but we don't have its copy.
#[derive(Clone, Copy, Debug)]
pub struct Container {
id: usize,
@@ -230,6 +228,7 @@ fn build_collection(
}
+/// Builds threads from a collection.
pub fn build_threads(
collection: &mut Vec,
sent_folder: &Option>,
diff --git a/src/ui/index.rs b/src/ui/index.rs
index 456b65e1..e1b24f0b 100644
--- a/src/ui/index.rs
+++ b/src/ui/index.rs
@@ -338,7 +338,14 @@ impl Window for Index {
}
impl Index {
pub fn new(mailbox: &Mailbox) -> Index {
- let mailbox = (*mailbox).clone();
+ let mailbox = mailbox.clone();
+ let mut unread_count = 0;
+ for e in &mailbox.collection {
+ if !e.is_seen() {
+ unread_count += 1;
+ }
+ }
+ eprintln!("unread count {}", unread_count);
let mut screen_height = 0;
let mut screen_width = 0;
/* Get the screen bounds. */