Set flags in backends and mark as read when read in maillisting

embed
Manos Pitsidianakis 2018-08-06 11:05:09 +03:00
parent b21d30c2ef
commit f2a646158d
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
7 changed files with 135 additions and 11 deletions

View File

@ -68,3 +68,11 @@ impl From<nom::IError> for MeliError {
MeliError::new(format!("{:?}", kind))
}
}
//use std::option;
//impl From<option::NoneError> for MeliError {
// #[inline]
// fn from(kind: option::NoneError) -> MeliError {
// MeliError::new(format!("{:?}", kind))
// }
//}

View File

@ -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)]

View File

@ -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<Result<Vec<Envelope>>> {
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 || {

View File

@ -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)]

View File

@ -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

View File

@ -253,6 +253,9 @@ impl Envelope {
e.flags = operation.fetch_flags();
Some(e)
}
pub fn set_operation_token(&mut self, operation_token: Box<BackendOpGenerator>) {
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()
}

View File

@ -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) {