diff --git a/Cargo.toml b/Cargo.toml index 04a495a4..c079f777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ memmap = "*" base64 = "*" crossbeam = "^0.3.0" fnv = "1.0.3" +encoding = "0.2.33" [dependencies.ncurses] features = ["wide"] diff --git a/src/lib.rs b/src/lib.rs index dbf636b5..4674e990 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,3 +31,4 @@ extern crate nom; extern crate chrono; extern crate base64; extern crate memmap; +extern crate encoding; diff --git a/src/mailbox/backends/mod.rs b/src/mailbox/backends/mod.rs index 6326eb44..1dbc11f5 100644 --- a/src/mailbox/backends/mod.rs +++ b/src/mailbox/backends/mod.rs @@ -30,8 +30,42 @@ pub trait MailBackend { } -/* A BackendOp manages common operations for the various mail backends. They should be created when - * needed */ +/// A BackendOp manages common operations for the various mail backends. They only live for the +/// duration of the operation. They are generated by BackendOpGenerator on demand. +/// +/// # Motivation +/// +/// We need a way to do various operations on individual mails regardless of what backend they come +/// from (eg local or imap). +/// +/// # Example +/// ``` +/// use melib::mailbox::backends::{BackendOp, BackendOpGenerator}; +/// use melib::error::Result; +/// +/// #[derive(Debug)] +/// struct FooOp {} +/// +/// impl BackendOp for FooOp { +/// fn description(&self) -> String { +/// "Foobar".to_string() +/// } +/// fn as_bytes(&mut self) -> Result<&[u8]> { +/// unimplemented!() +/// } +/// fn fetch_headers(&mut self) -> Result<&[u8]> { +/// unimplemented!() +/// } +/// fn fetch_body(&mut self) -> Result<&[u8]> { +/// unimplemented!() +/// } +/// } +/// +/// let foogen = BackendOpGenerator::new(Box::new(|| Box::new(FooOp {}))); +/// let operation = foogen.generate(); +/// assert_eq!("Foobar", &operation.description()); +/// +/// ``` pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { fn description(&self) -> String; fn as_bytes(&mut self) -> Result<&[u8]>; @@ -41,7 +75,11 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { fn fetch_body(&mut self) -> Result<&[u8]>; } -/* BackendOpGenerator is a wrapper for a closure that returns a BackendOp object */ +/// BackendOpGenerator is a wrapper for a closure that returns a BackendOp object +/// See BackendOp for details. + /* + * I know this sucks, but that's the best way I found that rustc deems safe. + * */ pub struct BackendOpGenerator(Box Box>); impl BackendOpGenerator { pub fn new(b: Box Box>) -> Self { @@ -55,7 +93,8 @@ unsafe impl Send for BackendOpGenerator {} unsafe impl Sync for BackendOpGenerator {} impl fmt::Debug for BackendOpGenerator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "BackendOpGenerator") + let op = self.generate(); + write!(f, "BackendOpGenerator: {}", op.description()) } } diff --git a/src/mailbox/email/attachments.rs b/src/mailbox/email/attachments.rs index f4b9b02f..4efcaa0e 100644 --- a/src/mailbox/email/attachments.rs +++ b/src/mailbox/email/attachments.rs @@ -91,6 +91,8 @@ pub enum ContentTransferEncoding { Other { tag: String }, } +/// TODO: Add example. +/// pub struct AttachmentBuilder { content_type: (ContentType, ContentSubType), content_transfer_encoding: ContentTransferEncoding, @@ -156,7 +158,12 @@ self ContentTransferEncoding::Base64 => { match ::base64::decode(&::std::str::from_utf8(&self.raw).unwrap().trim().lines().fold(String::with_capacity(self.raw.len()), |mut acc, x| { acc.push_str(x); acc })) { Ok( ref v ) => { - String::from_utf8_lossy(v).into_owned() + let s = String::from_utf8_lossy(v); + if s.find("\r\n").is_some() { + s.replace("\r\n","\n") + } else { + s.into_owned() + } }, _ => { String::from_utf8_lossy(&self.raw).into_owned() diff --git a/src/mailbox/email/mod.rs b/src/mailbox/email/mod.rs index 06b17381..0764238b 100644 --- a/src/mailbox/email/mod.rs +++ b/src/mailbox/email/mod.rs @@ -231,8 +231,16 @@ impl Mail let new_ref = MessageID::new(new_val, slice); match self.references { Some(ref mut s) => { - if s.refs.contains(&new_ref) { - return; + if s.refs.contains(&new_ref) { + if s.refs[s.refs.len() - 1] != new_ref { + if let Some(index) = s.refs.iter().position(|ref x| **x == new_ref) { + s.refs.remove(index); + } else { + panic!(); + } + } else { + return; + } } s.refs.push(new_ref); }, diff --git a/src/mailbox/mod.rs b/src/mailbox/mod.rs index 4cbfb67c..6c2ba1ed 100644 --- a/src/mailbox/mod.rs +++ b/src/mailbox/mod.rs @@ -183,7 +183,12 @@ fn build_collection(threads: &mut Vec, id_table: &mut FnvHashMapB, search down the children of B to see if A is reachable, and also search down the children of A to see if B is reachable. If either is already reachable as a child of the other, don't add the link. */ let mut curr_ref = x_index; + let mut iasf = 0; for &r in x.get_references().iter().rev() { + if iasf == 1 { + continue; + } + iasf += 1; let parent_id = if id_table.contains_key(r.get_raw()) { let p = id_table[r.get_raw()]; @@ -216,6 +221,9 @@ fn build_collection(threads: &mut Vec, id_table: &mut FnvHashMap