From f2a646158dd1284f048c426caa344af340a61624 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 6 Aug 2018 11:05:09 +0300 Subject: [PATCH] Set flags in backends and mark as read when read in maillisting --- melib/src/error.rs | 8 ++++ melib/src/mailbox/backends/imap.rs | 9 ++-- melib/src/mailbox/backends/maildir.rs | 42 +++++++++++++++-- melib/src/mailbox/backends/mbox.rs | 9 +++- melib/src/mailbox/backends/mod.rs | 1 + melib/src/mailbox/email/mod.rs | 12 ++++- ui/src/components/mail/listing.rs | 65 +++++++++++++++++++++++++++ 7 files changed, 135 insertions(+), 11 deletions(-) diff --git a/melib/src/error.rs b/melib/src/error.rs index 3391875c..2aaec9e1 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -68,3 +68,11 @@ impl From for MeliError { MeliError::new(format!("{:?}", kind)) } } + +//use std::option; +//impl From for MeliError { +// #[inline] +// fn from(kind: option::NoneError) -> MeliError { +// MeliError::new(format!("{:?}", kind)) +// } +//} diff --git a/melib/src/mailbox/backends/imap.rs b/melib/src/mailbox/backends/imap.rs index dc6193c7..d33be68b 100644 --- a/melib/src/mailbox/backends/imap.rs +++ b/melib/src/mailbox/backends/imap.rs @@ -22,8 +22,8 @@ use conf::Folder; use error::Result; use async::*; -use mailbox::backends::{BackendOp, MailBackend, RefreshEventConsumer}; -use mailbox::email::{Envelope, Flag}; +use mailbox::backends::{MailBackend, RefreshEventConsumer}; +use mailbox::email::{Envelope, }; /// `BackendOp` implementor for Imap #[derive(Debug, Default, Clone)] @@ -35,6 +35,9 @@ impl ImapOp { } } + +/* + impl BackendOp for ImapOp { fn description(&self) -> String { unimplemented!(); @@ -51,7 +54,7 @@ impl BackendOp for ImapOp { fn fetch_flags(&self) -> Flag { unimplemented!(); } -} +}*/ /// Imap backend #[derive(Debug)] diff --git a/melib/src/mailbox/backends/maildir.rs b/melib/src/mailbox/backends/maildir.rs index 2235895e..4167b19c 100644 --- a/melib/src/mailbox/backends/maildir.rs +++ b/melib/src/mailbox/backends/maildir.rs @@ -43,6 +43,7 @@ use memmap::{Mmap, Protection}; use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; use std::hash::Hasher; +use std::fs; /// `BackendOp` implementor for Maildir #[derive(Debug, Default)] @@ -101,18 +102,53 @@ impl BackendOp for MaildirOp { for f in filename.chars().rev() { match f { ',' => break, + 'D' => flag |= Flag::DRAFT, + 'F' => flag |= Flag::FLAGGED, '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 } + fn set_flag(&mut self, envelope: &mut Envelope, f: &Flag) -> Result<()> { + let idx: usize = self.path.rfind(":2,").ok_or(MeliError::new(format!("Invalid email filename: {:?}", self)))? + 3; + let mut new_name: String = self.path[..idx].to_string(); + let mut flags = self.fetch_flags(); + flags.toggle(*f); + if !(flags & Flag::DRAFT).is_empty() { + new_name.push('D'); + } + if !(flags & Flag::FLAGGED).is_empty() { + new_name.push('F'); + } + if !(flags & Flag::PASSED).is_empty() { + new_name.push('P'); + } + if !(flags & Flag::REPLIED).is_empty() { + new_name.push('R'); + } + if !(flags & Flag::SEEN).is_empty() { + new_name.push('S'); + } + if !(flags & Flag::TRASHED).is_empty() { + new_name.push('T'); + } + eprintln!("new name is {}", new_name); + + fs::rename(&self.path, &new_name)?; + envelope.set_operation_token( + Box::new( + BackendOpGenerator::new( + Box::new( move || Box::new(MaildirOp::new(new_name.clone()))) + ) + ) + ); + Ok(()) + } } /// Maildir backend https://cr.yp.to/proto/maildir.html @@ -193,14 +229,12 @@ impl MaildirType { Ok(()) } pub fn multicore(&self, cores: usize, folder: &Folder) -> Async>> { - let mut w = AsyncBuilder::new(); let handle = { let tx = w.tx(); // TODO: Avoid clone let folder = folder.clone(); - thread::Builder::new() .name(format!("parsing {:?}", folder)) .spawn(move || { diff --git a/melib/src/mailbox/backends/mbox.rs b/melib/src/mailbox/backends/mbox.rs index cb28dba7..3d218548 100644 --- a/melib/src/mailbox/backends/mbox.rs +++ b/melib/src/mailbox/backends/mbox.rs @@ -22,8 +22,8 @@ use conf::Folder; use error::Result; use async::*; -use mailbox::backends::{BackendOp, MailBackend, RefreshEventConsumer}; -use mailbox::email::{Envelope, Flag}; +use mailbox::backends::{MailBackend, RefreshEventConsumer}; +use mailbox::email::{Envelope, }; /// `BackendOp` implementor for Mbox #[derive(Debug, Default, Clone)] @@ -35,6 +35,7 @@ impl MboxOp { } } +/* impl BackendOp for MboxOp { fn description(&self) -> String { unimplemented!(); @@ -51,7 +52,11 @@ impl BackendOp for MboxOp { fn fetch_flags(&self) -> Flag { unimplemented!(); } + fn set_flags(&self, f: Flag) -> Result<()> { + unimplemented!() + } } +*/ /// Mbox backend #[derive(Debug)] diff --git a/melib/src/mailbox/backends/mod.rs b/melib/src/mailbox/backends/mod.rs index cbaee595..6d75644a 100644 --- a/melib/src/mailbox/backends/mod.rs +++ b/melib/src/mailbox/backends/mod.rs @@ -143,6 +143,7 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { fn fetch_headers(&mut self) -> Result<&[u8]>; fn fetch_body(&mut self) -> Result<&[u8]>; fn fetch_flags(&self) -> Flag; + fn set_flag(&mut self, &mut Envelope, &Flag) -> Result<()>; } /// `BackendOpGenerator` is a wrapper for a closure that returns a `BackendOp` object diff --git a/melib/src/mailbox/email/mod.rs b/melib/src/mailbox/email/mod.rs index 2148682d..d300a691 100644 --- a/melib/src/mailbox/email/mod.rs +++ b/melib/src/mailbox/email/mod.rs @@ -253,6 +253,9 @@ impl Envelope { e.flags = operation.fetch_flags(); Some(e) } + pub fn set_operation_token(&mut self, operation_token: Box) { + self.operation_token= Arc::new(operation_token); + } pub fn populate_headers(&mut self) -> Result<()> { let mut operation = self.operation_token.generate(); @@ -529,13 +532,18 @@ impl Envelope { self.datetime = Some(new_val); self.timestamp = new_val.timestamp() as u64; } - pub fn set_flag(&mut self, f: Flag) -> () { + pub fn set_flag(&mut self, f: Flag) -> Result<()> { + let mut operation = self.operation_token.generate(); + operation.set_flag(self, &f)?; self.flags |= f; - + Ok(()) } pub fn flags(&self) -> Flag { self.flags } + pub fn set_seen(&mut self) -> Result<()> { + self.set_flag(Flag::SEEN) + } pub fn is_seen(&self) -> bool { !(self.flags & Flag::SEEN).is_empty() } diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs index dca64a7a..5ed00b69 100644 --- a/ui/src/components/mail/listing.rs +++ b/ui/src/components/mail/listing.rs @@ -221,6 +221,37 @@ impl MailListing { self.content = content; } + + fn highlight_line_self(&mut self, idx: usize, context: &Context) { + let threaded = context.accounts[self.cursor_pos.0] + .runtime_settings + .threaded; + let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] + .as_ref() + .unwrap(); + let envelope: &Envelope = if threaded { + let i = mailbox.threaded_mail(idx); + &mailbox.collection[i] + } else { + &mailbox.collection[idx] + }; + + let fg_color = if !envelope.is_seen() { + Color::Byte(0) + } else { + Color::Default + }; + let bg_color = + if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + }; + change_colors(&mut self.content, ((0, idx), (MAX_COLS-1, idx)), fg_color, bg_color); + } + fn highlight_line(&self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { let threaded = context.accounts[self.cursor_pos.0] .runtime_settings @@ -311,6 +342,8 @@ impl MailListing { context, ); context.dirty_areas.push_back(area); + + } fn make_thread_entry( @@ -403,6 +436,37 @@ impl Component for MailListing { context.dirty_areas.push_back(area); return; } + /* Mark message as read */ + let idx = self.cursor_pos.2; + let must_highlight = { + if self.length == 0 { + false + } else { + let threaded = context.accounts[self.cursor_pos.0] + .runtime_settings + .threaded; + let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1] + .as_mut() + .unwrap(); + let envelope: &mut Envelope = if threaded { + let i = mailbox.threaded_mail(idx); + &mut mailbox.collection[i] + } else { + &mut mailbox.collection[idx] + }; + if !envelope.is_seen() { + eprintln!("setting seen"); + envelope.set_seen(); + true + } else { + false + } + } + }; + if must_highlight { + eprintln!("must highlight"); + self.highlight_line_self(idx, context); + } let mid = get_y(upper_left) + total_rows - bottom_entity_rows; self.draw_list( grid, @@ -444,6 +508,7 @@ impl Component for MailListing { .as_mut() .map(|v| v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context)); self.dirty = false; + } } fn process_event(&mut self, event: &UIEvent, context: &mut Context) {