BackendOp: Change set_{flag,tag} methods
parent
8c1fc031e5
commit
c82367e00d
|
@ -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."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue