BackendOp: Change set_{flag,tag} methods

async
Manos Pitsidianakis 2020-06-28 19:16:13 +03:00
parent 8c1fc031e5
commit c82367e00d
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
10 changed files with 257 additions and 187 deletions

View File

@ -68,9 +68,9 @@ use std::fmt::Debug;
use std::ops::Deref; use std::ops::Deref;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use core::pin::Pin;
pub use futures::stream::Stream; pub use futures::stream::Stream;
use std::future::Future; use std::future::Future;
pub use std::pin::Pin;
use std; use std;
use std::collections::HashMap; use std::collections::HashMap;
@ -330,6 +330,11 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
work_context: WorkContext, work_context: WorkContext,
) -> Result<std::thread::ThreadId>; ) -> Result<std::thread::ThreadId>;
fn mailboxes(&self) -> Result<HashMap<MailboxHash, Mailbox>>; fn mailboxes(&self) -> Result<HashMap<MailboxHash, Mailbox>>;
fn mailboxes_async(
&self,
) -> Result<Pin<Box<dyn Future<Output = Result<HashMap<MailboxHash, Mailbox>>> + Send>>> {
Err(MeliError::new("Unimplemented."))
}
fn operation(&self, hash: EnvelopeHash) -> Result<Box<dyn BackendOp>>; fn operation(&self, hash: EnvelopeHash) -> Result<Box<dyn BackendOp>>;
fn save(&self, bytes: &[u8], mailbox_hash: MailboxHash, flags: Option<Flag>) -> Result<()>; fn save(&self, bytes: &[u8], mailbox_hash: MailboxHash, flags: Option<Flag>) -> Result<()>;
@ -427,8 +432,16 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
fn description(&self) -> String; fn description(&self) -> String;
fn as_bytes(&mut self) -> Result<&[u8]>; fn as_bytes(&mut self) -> Result<&[u8]>;
fn fetch_flags(&self) -> Result<Flag>; fn fetch_flags(&self) -> Result<Flag>;
fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag, value: bool) -> Result<()>; fn set_flag(
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()>; &mut self,
flag: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>>;
fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>>;
} }
/// Wrapper for BackendOps that are to be set read-only. /// Wrapper for BackendOps that are to be set read-only.
@ -456,10 +469,18 @@ impl BackendOp for ReadOnlyOp {
fn fetch_flags(&self) -> Result<Flag> { fn fetch_flags(&self) -> Result<Flag> {
self.op.fetch_flags() self.op.fetch_flags()
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> { fn set_flag(
&mut self,
_flag: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("read-only set.")) Err(MeliError::new("read-only set."))
} }
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("read-only set.")) Err(MeliError::new("read-only set."))
} }
} }

View File

@ -21,7 +21,7 @@
use super::*; use super::*;
use crate::backends::BackendOp; use crate::backends::*;
use crate::email::*; use crate::email::*;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
use std::cell::Cell; use std::cell::Cell;
@ -98,7 +98,6 @@ impl BackendOp for ImapOp {
let mut bytes_cache = self.uid_store.byte_cache.lock()?; let mut bytes_cache = self.uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(self.uid).or_default(); let cache = bytes_cache.entry(self.uid).or_default();
if let Some((flags, _)) = flags { if let Some((flags, _)) = flags {
self.flags.set(Some(flags));
cache.flags = Some(flags); cache.flags = Some(flags);
} }
cache.bytes = cache.bytes =
@ -149,77 +148,87 @@ impl BackendOp for ImapOp {
Ok(self.flags.get().unwrap()) Ok(self.flags.get().unwrap())
} }
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(
&mut self,
f: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut flags = self.fetch_flags()?; let mut flags = self.fetch_flags()?;
flags.set(f, value); flags.set(f, value);
let connection = self.connection.clone();
let mailbox_hash = self.mailbox_hash;
let uid = self.uid;
let uid_store = self.uid_store.clone();
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?; Ok(Box::pin(async move {
conn.select_mailbox(self.mailbox_hash, &mut response, false)?; let mut conn = try_lock(&connection, Some(std::time::Duration::new(2, 0)))?;
debug!(&response); conn.select_mailbox(mailbox_hash, &mut response, false)?;
conn.send_command( debug!(&response);
format!( conn.send_command(
"UID STORE {} FLAGS.SILENT ({})", format!(
self.uid, "UID STORE {} FLAGS.SILENT ({})",
flags_to_imap_list!(flags) uid,
) flags_to_imap_list!(flags)
.as_bytes(), )
)?; .as_bytes(),
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?; )?;
debug!(&response); conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
match protocol_parser::uid_fetch_flags_response(response.as_bytes()) debug!(&response);
.map(|(_, v)| v) match protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map_err(MeliError::from) .map(|(_, v)| v)
{ .map_err(MeliError::from)
Ok(v) => { {
if v.len() == 1 { Ok(v) => {
debug!("responses len is {}", v.len()); if v.len() == 1 {
let (uid, (flags, _)) = v[0]; debug!("responses len is {}", v.len());
assert_eq!(uid, self.uid); let (uid, (flags, _)) = v[0];
self.flags.set(Some(flags)); assert_eq!(uid, uid);
}
} }
Err(e) => Err(e)?,
} }
Err(e) => Err(e)?, let mut bytes_cache = uid_store.byte_cache.lock()?;
} let cache = bytes_cache.entry(uid).or_default();
let mut bytes_cache = self.uid_store.byte_cache.lock()?; cache.flags = Some(flags);
let cache = bytes_cache.entry(self.uid).or_default(); Ok(())
cache.flags = Some(flags); }))
Ok(())
} }
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> { fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?; let connection = self.connection.clone();
conn.select_mailbox(self.mailbox_hash, &mut response, false)?; let mailbox_hash = self.mailbox_hash;
conn.send_command( let uid = self.uid;
format!( let uid_store = self.uid_store.clone();
"UID STORE {} {}FLAGS.SILENT ({})",
self.uid, Ok(Box::pin(async move {
if value { "+" } else { "-" }, let mut conn = try_lock(&connection, Some(std::time::Duration::new(2, 0)))?;
&tag conn.select_mailbox(mailbox_hash, &mut response, false)?;
) conn.send_command(
.as_bytes(), format!(
)?; "UID STORE {} {}FLAGS.SILENT ({})",
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?; uid,
protocol_parser::uid_fetch_flags_response(response.as_bytes()) if value { "+" } else { "-" },
.map(|(_, v)| v) &tag
.map_err(MeliError::from)?; )
let hash = tag_hash!(tag); .as_bytes(),
if value { )?;
self.uid_store.tag_index.write().unwrap().insert(hash, tag); conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
} else { protocol_parser::uid_fetch_flags_response(response.as_bytes())
self.uid_store.tag_index.write().unwrap().remove(&hash); .map(|(_, v)| v)
} .map_err(MeliError::from)?;
if !envelope.labels().iter().any(|&h_| h_ == hash) { let hash = tag_hash!(tag);
if value { if value {
envelope.labels_mut().push(hash); uid_store.tag_index.write().unwrap().insert(hash, tag);
} else {
uid_store.tag_index.write().unwrap().remove(&hash);
} }
} Ok(())
if !value { }))
if let Some(pos) = envelope.labels().iter().position(|&h_| h_ == hash) {
envelope.labels_mut().remove(pos);
}
}
Ok(())
} }
} }

View File

@ -164,7 +164,7 @@ impl BackendOp for ImapOp {
self.flags.get().unwrap() self.flags.get().unwrap()
} }
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(&mut self, f: Flag, value: bool) -> Result<()> {
let mut flags = self.fetch_flags(); let mut flags = self.fetch_flags();
flags.set(f, value); flags.set(f, value);
@ -202,7 +202,7 @@ impl BackendOp for ImapOp {
Ok(()) Ok(())
} }
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> { fn set_tag(&mut self, tag: String, value: bool) -> Result<()> {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?; let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(self.mailbox_hash, &mut response)?; conn.select_mailbox(self.mailbox_hash, &mut response)?;

View File

@ -21,7 +21,7 @@
use super::*; use super::*;
use crate::backends::BackendOp; use crate::backends::*;
use crate::error::Result; use crate::error::Result;
use std::cell::Cell; use std::cell::Cell;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -101,11 +101,19 @@ impl BackendOp for JmapOp {
Ok(Flag::default()) Ok(Flag::default())
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { fn set_flag(
Ok(()) &mut self,
_f: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented"))
} }
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { fn set_tag(
Ok(()) &mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented"))
} }
} }

View File

@ -26,11 +26,11 @@ pub use self::backend::*;
mod stream; mod stream;
pub use stream::*; pub use stream::*;
pub use futures::stream::Stream;
use crate::backends::*; use crate::backends::*;
use crate::email::{Envelope, Flag}; use crate::email::Flag;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait; use crate::shellexpand::ShellExpandTrait;
pub use futures::stream::Stream;
use memmap::{Mmap, Protection}; use memmap::{Mmap, Protection};
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
@ -106,49 +106,61 @@ impl<'a> BackendOp for MaildirOp {
Ok(path.flags()) Ok(path.flags())
} }
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(
let path = self.path(); &mut self,
let path = path.to_str().unwrap(); // Assume UTF-8 validity f: Flag,
let idx: usize = path value: bool,
.rfind(":2,") ) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
.ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", self)))?
+ 3;
let mut new_name: String = path[..idx].to_string();
let mut flags = self.fetch_flags()?; let mut flags = self.fetch_flags()?;
flags.set(f, value); let old_hash = self.hash;
let mailbox_hash = self.mailbox_hash;
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');
}
let old_hash = envelope.hash();
let new_name: PathBuf = new_name.into();
let hash_index = self.hash_index.clone(); let hash_index = self.hash_index.clone();
let mut map = hash_index.lock().unwrap(); let path = self.path();
let map = map.entry(self.mailbox_hash).or_default(); Ok(Box::pin(async move {
map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone())); let path = path;
let path = path.to_str().unwrap(); // Assume UTF-8 validity
let idx: usize = path
.rfind(":2,")
.ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", path)))?
+ 3;
let mut new_name: String = path[..idx].to_string();
flags.set(f, value);
debug!("renaming {:?} to {:?}", path, new_name); if !(flags & Flag::DRAFT).is_empty() {
fs::rename(&path, &new_name)?; new_name.push('D');
debug!("success in rename"); }
Ok(()) 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');
}
let new_name: PathBuf = new_name.into();
let mut map = hash_index.lock().unwrap();
let map = map.entry(mailbox_hash).or_default();
map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone()));
debug!("renaming {:?} to {:?}", path, new_name);
fs::rename(&path, &new_name)?;
debug!("success in rename");
Ok(())
}))
} }
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Maildir doesn't support tags.")) Err(MeliError::new("Maildir doesn't support tags."))
} }
} }

View File

@ -24,12 +24,7 @@
*/ */
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp; use crate::backends::*;
use crate::backends::MailboxHash;
use crate::backends::{
BackendMailbox, MailBackend, Mailbox, MailboxPermissions, RefreshEvent, RefreshEventConsumer,
RefreshEventKind, SpecialUsageMailbox,
};
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::parser::BytesExt; use crate::email::parser::BytesExt;
use crate::email::*; use crate::email::*;
@ -257,11 +252,19 @@ impl BackendOp for MboxOp {
Ok(flags) Ok(flags)
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> { fn set_flag(
Ok(()) &mut self,
_flag: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented."))
} }
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("mbox doesn't support tags.")) Err(MeliError::new("mbox doesn't support tags."))
} }
} }

View File

@ -20,11 +20,7 @@
*/ */
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::MailboxHash; use crate::backends::*;
use crate::backends::{
BackendMailbox, BackendOp, MailBackend, Mailbox, MailboxPermissions, RefreshEventConsumer,
SpecialUsageMailbox,
};
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag}; use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
@ -407,7 +403,7 @@ impl MailBackend for NotmuchDb {
_work_context: WorkContext, _work_context: WorkContext,
) -> Result<std::thread::ThreadId> { ) -> Result<std::thread::ThreadId> {
extern crate notify; extern crate notify;
use crate::backends::{RefreshEvent, RefreshEventKind::*}; use crate::backends::RefreshEventKind::*;
use notify::{watcher, RecursiveMode, Watcher}; use notify::{watcher, RecursiveMode, Watcher};
let (tx, rx) = std::sync::mpsc::channel(); let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = watcher(tx, std::time::Duration::from_secs(2)).unwrap(); let mut watcher = watcher(tx, std::time::Duration::from_secs(2)).unwrap();
@ -621,7 +617,7 @@ impl MailBackend for NotmuchDb {
.as_ref() .as_ref()
.unwrap_or(&self.path) .unwrap_or(&self.path)
.to_path_buf(); .to_path_buf();
crate::backends::MaildirType::save_to_mailbox(path, bytes, flags) MaildirType::save_to_mailbox(path, bytes, flags)
} }
fn as_any(&self) -> &dyn ::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
@ -681,10 +677,13 @@ impl BackendOp for NotmuchOp {
Ok(flags) Ok(flags)
} }
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> { fn set_flag(
&mut self,
f: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut flags = self.fetch_flags()?; let mut flags = self.fetch_flags()?;
flags.set(f, value); flags.set(f, value);
envelope.set_flags(flags);
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let mut index_lck = self.index.write().unwrap(); let mut index_lck = self.index.write().unwrap();
unsafe { unsafe {
@ -713,7 +712,7 @@ impl BackendOp for NotmuchOp {
macro_rules! add_tag { macro_rules! add_tag {
($l:literal) => {{ ($l:literal) => {{
if tags.contains(unsafe { &cstr!($l) }) { if tags.contains(unsafe { &cstr!($l) }) {
return Ok(()); return Ok(Box::pin(async { Ok(()) }));
} }
if let Err(err) = try_call!( if let Err(err) = try_call!(
self.lib, self.lib,
@ -728,7 +727,7 @@ impl BackendOp for NotmuchOp {
macro_rules! remove_tag { macro_rules! remove_tag {
($l:literal) => {{ ($l:literal) => {{
if !tags.contains(unsafe { &cstr!($l) }) { if !tags.contains(unsafe { &cstr!($l) }) {
return Ok(()); return Ok(Box::pin(async { Ok(()) }));
} }
if let Err(err) = try_call!( if let Err(err) = try_call!(
self.lib, self.lib,
@ -771,10 +770,14 @@ impl BackendOp for NotmuchOp {
*p = c_str.into(); *p = c_str.into();
} }
Ok(()) Ok(Box::pin(async { Ok(()) }))
} }
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> { fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut message: *mut notmuch_message_t = std::ptr::null_mut(); let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let index_lck = self.index.read().unwrap(); let index_lck = self.index.read().unwrap();
unsafe { unsafe {
@ -817,17 +820,7 @@ impl BackendOp for NotmuchOp {
if value { if value {
self.tag_index.write().unwrap().insert(hash, tag); self.tag_index.write().unwrap().insert(hash, tag);
} }
if !envelope.labels().iter().any(|&h_| h_ == hash) { Ok(Box::pin(async { Ok(()) }))
if value {
envelope.labels_mut().push(hash);
}
}
if !value {
if let Some(pos) = envelope.labels().iter().position(|&h_| h_ == hash) {
envelope.labels_mut().remove(pos);
}
}
Ok(())
} }
} }

View File

@ -49,8 +49,10 @@ use std::borrow::Cow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::fmt; use std::fmt;
use std::future::Future;
use std::hash::Hasher; use std::hash::Hasher;
use std::option::Option; use std::option::Option;
use std::pin::Pin;
use std::str; use std::str;
use std::string::String; use std::string::String;
@ -605,9 +607,9 @@ impl Envelope {
f: Flag, f: Flag,
value: bool, value: bool,
mut operation: Box<dyn BackendOp>, mut operation: Box<dyn BackendOp>,
) -> Result<()> { ) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
self.flags.set(f, value); self.flags.set(f, value);
operation.set_flag(self, f, value) operation.set_flag(f, value)
} }
pub fn set_flags(&mut self, f: Flag) { pub fn set_flags(&mut self, f: Flag) {
self.flags = f; self.flags = f;
@ -615,18 +617,24 @@ impl Envelope {
pub fn flags(&self) -> Flag { pub fn flags(&self) -> Flag {
self.flags self.flags
} }
pub fn set_seen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> { pub fn set_seen(
&mut self,
operation: Box<dyn BackendOp>,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
if !self.flags.contains(Flag::SEEN) { if !self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, true, operation) self.set_flag(Flag::SEEN, true, operation)
} else { } else {
Ok(()) Ok(Box::pin(async { Ok(()) }))
} }
} }
pub fn set_unseen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> { pub fn set_unseen(
&mut self,
operation: Box<dyn BackendOp>,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
if self.flags.contains(Flag::SEEN) { if self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, false, operation) self.set_flag(Flag::SEEN, false, operation)
} else { } else {
Ok(()) Ok(Box::pin(async { Ok(()) }))
} }
} }
pub fn is_seen(&self) -> bool { pub fn is_seen(&self) -> bool {

View File

@ -168,48 +168,56 @@ pub trait MailListingTrait: ListingTrait {
}; };
let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash); let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash);
match a { match a {
ListingAction::SetSeen => { ListingAction::SetSeen => match envelope.set_seen(op) {
if let Err(e) = envelope.set_seen(op) { Err(e) => {
context.replies.push_back(UIEvent::StatusEvent( context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(e.to_string()), StatusEvent::DisplayMessage(e.to_string()),
)); ));
} }
} Ok(fut) => {
ListingAction::SetUnseen => { //accout.job_executor.spawn_specialized(fut);
if let Err(e) = envelope.set_unseen(op) { }
},
ListingAction::SetUnseen => match envelope.set_unseen(op) {
Err(e) => {
context.replies.push_back(UIEvent::StatusEvent( context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(e.to_string()), StatusEvent::DisplayMessage(e.to_string()),
)); ));
} }
} Ok(fut) => {}
},
ListingAction::Delete => { ListingAction::Delete => {
drop(envelope); drop(envelope);
if let Err(err) = account.delete(env_hash, mailbox_hash) { match account.delete(env_hash, mailbox_hash) {
context.replies.push_back(UIEvent::Notification( Err(err) => {
Some("Could not delete.".to_string()), context.replies.push_back(UIEvent::Notification(
err.to_string(), Some("Could not delete.".to_string()),
Some(NotificationType::ERROR), err.to_string(),
)); Some(NotificationType::ERROR),
return; ));
return;
}
Ok(fut) => {}
} }
continue; continue;
} }
ListingAction::CopyTo(ref mailbox_path) => { ListingAction::CopyTo(ref mailbox_path) => {
drop(envelope); drop(envelope);
if let Err(err) = match account
account .mailbox_by_path(mailbox_path)
.mailbox_by_path(mailbox_path) .and_then(|mailbox_hash| {
.and_then(|mailbox_hash| { op.as_bytes()
op.as_bytes() .and_then(|bytes| account.save(bytes, mailbox_hash, None))
.and_then(|bytes| account.save(bytes, mailbox_hash, None)) }) {
}) Err(err) => {
{ context.replies.push_back(UIEvent::Notification(
context.replies.push_back(UIEvent::Notification( Some("Could not copy.".to_string()),
Some("Could not copy.".to_string()), err.to_string(),
err.to_string(), Some(NotificationType::ERROR),
Some(NotificationType::ERROR), ));
)); return;
return; }
Ok(fut) => {}
} }
continue; continue;
} }
@ -297,7 +305,7 @@ pub trait MailListingTrait: ListingTrait {
continue; continue;
} }
ListingAction::Tag(Remove(ref tag_str)) => { ListingAction::Tag(Remove(ref tag_str)) => {
if let Err(err) = op.set_tag(&mut envelope, tag_str.to_string(), false) { if let Err(err) = op.set_tag(tag_str.to_string(), false) {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not set tag.".to_string()), Some("Could not set tag.".to_string()),
err.to_string(), err.to_string(),
@ -307,7 +315,7 @@ pub trait MailListingTrait: ListingTrait {
} }
} }
ListingAction::Tag(Add(ref tag_str)) => { ListingAction::Tag(Add(ref tag_str)) => {
if let Err(err) = op.set_tag(&mut envelope, tag_str.to_string(), true) { if let Err(err) = op.set_tag(tag_str.to_string(), true) {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not set tag.".to_string()), Some("Could not set tag.".to_string()),
err.to_string(), err.to_string(),

View File

@ -21,13 +21,13 @@
use super::*; use super::*;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::MailboxHash; use melib::backends::*;
use melib::backends::{Backend, BackendOp, Backends, MailBackend, Mailbox, RefreshEventConsumer};
use melib::conf::AccountSettings; use melib::conf::AccountSettings;
use melib::email::{Envelope, EnvelopeHash, Flag}; use melib::email::{Envelope, EnvelopeHash, Flag};
use melib::error::{MeliError, Result}; use melib::error::{MeliError, Result};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::future::Future;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
// TODO replace with melib::Envelope after simplifying melib::Envelope's // TODO replace with melib::Envelope after simplifying melib::Envelope's
@ -318,11 +318,19 @@ impl BackendOp for PluginOp {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_flag(&mut self, __envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { fn set_flag(
&mut self,
_f: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> { fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
} }