Set flags in backends and mark as read when read in maillisting
parent
b21d30c2ef
commit
f2a646158d
|
@ -68,3 +68,11 @@ impl From<nom::IError> for MeliError {
|
||||||
MeliError::new(format!("{:?}", kind))
|
MeliError::new(format!("{:?}", kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//use std::option;
|
||||||
|
//impl From<option::NoneError> for MeliError {
|
||||||
|
// #[inline]
|
||||||
|
// fn from(kind: option::NoneError) -> MeliError {
|
||||||
|
// MeliError::new(format!("{:?}", kind))
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
use conf::Folder;
|
use conf::Folder;
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use async::*;
|
use async::*;
|
||||||
use mailbox::backends::{BackendOp, MailBackend, RefreshEventConsumer};
|
use mailbox::backends::{MailBackend, RefreshEventConsumer};
|
||||||
use mailbox::email::{Envelope, Flag};
|
use mailbox::email::{Envelope, };
|
||||||
|
|
||||||
/// `BackendOp` implementor for Imap
|
/// `BackendOp` implementor for Imap
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
@ -35,6 +35,9 @@ impl ImapOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
impl BackendOp for ImapOp {
|
impl BackendOp for ImapOp {
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
@ -51,7 +54,7 @@ impl BackendOp for ImapOp {
|
||||||
fn fetch_flags(&self) -> Flag {
|
fn fetch_flags(&self) -> Flag {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/// Imap backend
|
/// Imap backend
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -43,6 +43,7 @@ use memmap::{Mmap, Protection};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
/// `BackendOp` implementor for Maildir
|
/// `BackendOp` implementor for Maildir
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -101,18 +102,53 @@ impl BackendOp for MaildirOp {
|
||||||
for f in filename.chars().rev() {
|
for f in filename.chars().rev() {
|
||||||
match f {
|
match f {
|
||||||
',' => break,
|
',' => break,
|
||||||
|
'D' => flag |= Flag::DRAFT,
|
||||||
|
'F' => flag |= Flag::FLAGGED,
|
||||||
'P' => flag |= Flag::PASSED,
|
'P' => flag |= Flag::PASSED,
|
||||||
'R' => flag |= Flag::REPLIED,
|
'R' => flag |= Flag::REPLIED,
|
||||||
'S' => flag |= Flag::SEEN,
|
'S' => flag |= Flag::SEEN,
|
||||||
'T' => flag |= Flag::TRASHED,
|
'T' => flag |= Flag::TRASHED,
|
||||||
'D' => flag |= Flag::DRAFT,
|
|
||||||
'F' => flag |= Flag::FLAGGED,
|
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flag
|
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
|
/// Maildir backend https://cr.yp.to/proto/maildir.html
|
||||||
|
@ -193,14 +229,12 @@ impl MaildirType {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn multicore(&self, cores: usize, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
pub fn multicore(&self, cores: usize, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
|
|
||||||
let mut w = AsyncBuilder::new();
|
let mut w = AsyncBuilder::new();
|
||||||
let handle = {
|
let handle = {
|
||||||
let tx = w.tx();
|
let tx = w.tx();
|
||||||
// TODO: Avoid clone
|
// TODO: Avoid clone
|
||||||
let folder = folder.clone();
|
let folder = folder.clone();
|
||||||
|
|
||||||
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name(format!("parsing {:?}", folder))
|
.name(format!("parsing {:?}", folder))
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
use conf::Folder;
|
use conf::Folder;
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use async::*;
|
use async::*;
|
||||||
use mailbox::backends::{BackendOp, MailBackend, RefreshEventConsumer};
|
use mailbox::backends::{MailBackend, RefreshEventConsumer};
|
||||||
use mailbox::email::{Envelope, Flag};
|
use mailbox::email::{Envelope, };
|
||||||
|
|
||||||
/// `BackendOp` implementor for Mbox
|
/// `BackendOp` implementor for Mbox
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
@ -35,6 +35,7 @@ impl MboxOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl BackendOp for MboxOp {
|
impl BackendOp for MboxOp {
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
@ -51,7 +52,11 @@ impl BackendOp for MboxOp {
|
||||||
fn fetch_flags(&self) -> Flag {
|
fn fetch_flags(&self) -> Flag {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
fn set_flags(&self, f: Flag) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Mbox backend
|
/// Mbox backend
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -143,6 +143,7 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
|
||||||
fn fetch_headers(&mut self) -> Result<&[u8]>;
|
fn fetch_headers(&mut self) -> Result<&[u8]>;
|
||||||
fn fetch_body(&mut self) -> Result<&[u8]>;
|
fn fetch_body(&mut self) -> Result<&[u8]>;
|
||||||
fn fetch_flags(&self) -> Flag;
|
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
|
/// `BackendOpGenerator` is a wrapper for a closure that returns a `BackendOp` object
|
||||||
|
|
|
@ -253,6 +253,9 @@ impl Envelope {
|
||||||
e.flags = operation.fetch_flags();
|
e.flags = operation.fetch_flags();
|
||||||
Some(e)
|
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<()> {
|
pub fn populate_headers(&mut self) -> Result<()> {
|
||||||
let mut operation = self.operation_token.generate();
|
let mut operation = self.operation_token.generate();
|
||||||
|
@ -529,13 +532,18 @@ impl Envelope {
|
||||||
self.datetime = Some(new_val);
|
self.datetime = Some(new_val);
|
||||||
self.timestamp = new_val.timestamp() as u64;
|
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;
|
self.flags |= f;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn flags(&self) -> Flag {
|
pub fn flags(&self) -> Flag {
|
||||||
self.flags
|
self.flags
|
||||||
}
|
}
|
||||||
|
pub fn set_seen(&mut self) -> Result<()> {
|
||||||
|
self.set_flag(Flag::SEEN)
|
||||||
|
}
|
||||||
pub fn is_seen(&self) -> bool {
|
pub fn is_seen(&self) -> bool {
|
||||||
!(self.flags & Flag::SEEN).is_empty()
|
!(self.flags & Flag::SEEN).is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,37 @@ impl MailListing {
|
||||||
|
|
||||||
self.content = content;
|
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) {
|
fn highlight_line(&self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
|
||||||
let threaded = context.accounts[self.cursor_pos.0]
|
let threaded = context.accounts[self.cursor_pos.0]
|
||||||
.runtime_settings
|
.runtime_settings
|
||||||
|
@ -311,6 +342,8 @@ impl MailListing {
|
||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
context.dirty_areas.push_back(area);
|
context.dirty_areas.push_back(area);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_thread_entry(
|
fn make_thread_entry(
|
||||||
|
@ -403,6 +436,37 @@ impl Component for MailListing {
|
||||||
context.dirty_areas.push_back(area);
|
context.dirty_areas.push_back(area);
|
||||||
return;
|
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;
|
let mid = get_y(upper_left) + total_rows - bottom_entity_rows;
|
||||||
self.draw_list(
|
self.draw_list(
|
||||||
grid,
|
grid,
|
||||||
|
@ -444,6 +508,7 @@ impl Component for MailListing {
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|v| v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context));
|
.map(|v| v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context));
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn process_event(&mut self, event: &UIEvent, context: &mut Context) {
|
fn process_event(&mut self, event: &UIEvent, context: &mut Context) {
|
||||||
|
|
Loading…
Reference in New Issue