melib/maildir: impl copy_messages for Maildir

memfd
Manos Pitsidianakis 2020-09-11 16:58:56 +03:00
parent a1585d4006
commit 4829e13c47
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
10 changed files with 238 additions and 57 deletions

View File

@ -318,24 +318,22 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
mailbox_hash: MailboxHash,
flags: Option<Flag>,
) -> ResultFuture<()>;
fn copy_messages(
&mut self,
_env_hashes: EnvelopeHashBatch,
_source_mailbox_hash: MailboxHash,
_destination_mailbox_hash: MailboxHash,
_move_: bool,
_destination_flags: Option<Flag>,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}
env_hashes: EnvelopeHashBatch,
source_mailbox_hash: MailboxHash,
destination_mailbox_hash: MailboxHash,
move_: bool,
) -> ResultFuture<()>;
fn set_flags(
&mut self,
_env_hashes: EnvelopeHashBatch,
_mailbox_hash: MailboxHash,
_flags: SmallVec<[(std::result::Result<Flag, String>, bool); 8]>,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}
env_hashes: EnvelopeHashBatch,
mailbox_hash: MailboxHash,
flags: SmallVec<[(std::result::Result<Flag, String>, bool); 8]>,
) -> ResultFuture<()>;
fn delete_messages(
&self,
_env_hashes: EnvelopeHashBatch,

View File

@ -533,7 +533,6 @@ impl MailBackend for ImapType {
source_mailbox_hash: MailboxHash,
destination_mailbox_hash: MailboxHash,
move_: bool,
destination_flags: Option<Flag>,
) -> ResultFuture<()> {
let uid_store = self.uid_store.clone();
let connection = self.connection.clone();
@ -607,9 +606,6 @@ impl MailBackend for ImapType {
conn.send_command(command.as_bytes()).await?;
conn.read_response(&mut response, RequiredResponses::empty())
.await?;
if let Some(_flags) = destination_flags {
//FIXME
}
if move_ {
let command = {
let mut cmd = format!("UID STORE {}", uids[0]);

View File

@ -380,7 +380,6 @@ impl MailBackend for JmapType {
_source_mailbox_hash: MailboxHash,
_destination_mailbox_hash: MailboxHash,
_move_: bool,
_destination_flags: Option<Flag>,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}

View File

@ -23,7 +23,7 @@ use super::{MaildirMailbox, MaildirOp, MaildirPathTrait};
use crate::backends::{RefreshEventKind::*, *};
use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result};
use crate::error::{ErrorKind, MeliError, Result};
use crate::shellexpand::ShellExpandTrait;
use futures::prelude::Stream;
@ -565,6 +565,14 @@ impl MailBackend for MaildirType {
DebouncedEvent::Rename(src, dest) => {
debug!("DebouncedEvent::Rename(src = {:?}, dest = {:?})", src, dest);
let mailbox_hash = get_path_hash!(src);
let dest_mailbox = {
let dest_mailbox = get_path_hash!(dest);
if dest_mailbox == mailbox_hash {
None
} else {
Some(dest_mailbox)
}
};
let old_hash: EnvelopeHash = get_file_hash(src.as_path());
let new_hash: EnvelopeHash = get_file_hash(dest.as_path());
@ -578,39 +586,88 @@ impl MailBackend for MaildirType {
if index_lock.contains_key(&old_hash) && !index_lock[&old_hash].removed
{
debug!("contains_old_key");
index_lock.entry(old_hash).and_modify(|e| {
debug!(&e.modified);
e.modified = Some(PathMod::Hash(new_hash));
});
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: get_path_hash!(dest),
kind: Rename(old_hash, new_hash),
}),
);
if !was_seen && is_seen {
let mut lck = mailbox_counts[&mailbox_hash].0.lock().unwrap();
*lck = lck.saturating_sub(1);
} else if was_seen && !is_seen {
*mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
}
if old_flags != new_flags {
if let Some(dest_mailbox) = dest_mailbox {
index_lock.entry(old_hash).and_modify(|e| {
e.removed = true;
});
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: get_path_hash!(dest),
kind: NewFlags(new_hash, (new_flags, vec![])),
mailbox_hash,
kind: Remove(old_hash),
}),
);
let file_name = dest
.as_path()
.strip_prefix(&root_path)
.unwrap()
.to_path_buf();
drop(hash_indexes_lock);
if let Ok(env) = add_path_to_index(
&hash_indexes,
dest_mailbox,
dest.as_path(),
&cache_dir,
file_name,
) {
mailbox_index
.lock()
.unwrap()
.insert(env.hash(), dest_mailbox);
debug!(
"Create event {} {} {}",
env.hash(),
env.subject(),
dest.display()
);
if !env.is_seen() {
*mailbox_counts[&dest_mailbox].0.lock().unwrap() += 1;
}
*mailbox_counts[&dest_mailbox].1.lock().unwrap() += 1;
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: dest_mailbox,
kind: Create(Box::new(env)),
}),
);
}
} else {
index_lock.entry(old_hash).and_modify(|e| {
debug!(&e.modified);
e.modified = Some(PathMod::Hash(new_hash));
});
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: Rename(old_hash, new_hash),
}),
);
if !was_seen && is_seen {
let mut lck =
mailbox_counts[&mailbox_hash].0.lock().unwrap();
*lck = lck.saturating_sub(1);
} else if was_seen && !is_seen {
*mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
}
if old_flags != new_flags {
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
kind: NewFlags(new_hash, (new_flags, vec![])),
}),
);
}
mailbox_index.lock().unwrap().insert(new_hash, mailbox_hash);
index_lock.insert(new_hash, dest.into());
}
mailbox_index
.lock()
.unwrap()
.insert(new_hash, get_path_hash!(dest));
index_lock.insert(new_hash, dest.into());
continue;
} else if !index_lock.contains_key(&new_hash)
&& index_lock
@ -640,7 +697,7 @@ impl MailBackend for MaildirType {
drop(hash_indexes_lock);
if let Ok(env) = add_path_to_index(
&hash_indexes,
mailbox_hash,
dest_mailbox.unwrap_or(mailbox_hash),
dest.as_path(),
&cache_dir,
file_name,
@ -648,7 +705,7 @@ impl MailBackend for MaildirType {
mailbox_index
.lock()
.unwrap()
.insert(env.hash(), mailbox_hash);
.insert(env.hash(), dest_mailbox.unwrap_or(mailbox_hash));
debug!(
"Create event {} {} {}",
env.hash(),
@ -656,14 +713,20 @@ impl MailBackend for MaildirType {
dest.display()
);
if !env.is_seen() {
*mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
*mailbox_counts[&dest_mailbox.unwrap_or(mailbox_hash)]
.0
.lock()
.unwrap() += 1;
}
*mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
*mailbox_counts[&dest_mailbox.unwrap_or(mailbox_hash)]
.1
.lock()
.unwrap() += 1;
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash,
mailbox_hash: dest_mailbox.unwrap_or(mailbox_hash),
kind: Create(Box::new(env)),
}),
);
@ -671,6 +734,43 @@ impl MailBackend for MaildirType {
} else {
debug!("not valid email");
}
} else if let Some(dest_mailbox) = dest_mailbox {
drop(hash_indexes_lock);
let file_name = dest
.as_path()
.strip_prefix(&root_path)
.unwrap()
.to_path_buf();
if let Ok(env) = add_path_to_index(
&hash_indexes,
dest_mailbox,
dest.as_path(),
&cache_dir,
file_name,
) {
mailbox_index
.lock()
.unwrap()
.insert(env.hash(), dest_mailbox);
debug!(
"Create event {} {} {}",
env.hash(),
env.subject(),
dest.display()
);
if !env.is_seen() {
*mailbox_counts[&dest_mailbox].0.lock().unwrap() += 1;
}
*mailbox_counts[&dest_mailbox].1.lock().unwrap() += 1;
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: dest_mailbox,
kind: Create(Box::new(env)),
}),
);
}
} else {
if was_seen && !is_seen {
*mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
@ -679,7 +779,7 @@ impl MailBackend for MaildirType {
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: get_path_hash!(dest),
mailbox_hash,
kind: Rename(old_hash, new_hash),
}),
);
@ -689,7 +789,7 @@ impl MailBackend for MaildirType {
account_hash,
BackendEvent::Refresh(RefreshEvent {
account_hash,
mailbox_hash: get_path_hash!(dest),
mailbox_hash,
kind: NewFlags(new_hash, (new_flags, vec![])),
}),
);
@ -813,6 +913,60 @@ impl MailBackend for MaildirType {
}))
}
fn copy_messages(
&mut self,
env_hashes: EnvelopeHashBatch,
source_mailbox_hash: MailboxHash,
destination_mailbox_hash: MailboxHash,
move_: bool,
) -> ResultFuture<()> {
let hash_index = self.hash_indexes.clone();
if !self.mailboxes.contains_key(&source_mailbox_hash) {
return Err(MeliError::new("Invalid source mailbox hash").set_kind(ErrorKind::Bug));
} else if !self.mailboxes.contains_key(&destination_mailbox_hash) {
return Err(MeliError::new("Invalid destination mailbox hash").set_kind(ErrorKind::Bug));
}
let mut dest_path: PathBuf = self.mailboxes[&destination_mailbox_hash].fs_path().into();
dest_path.push("cur");
Ok(Box::pin(async move {
let mut hash_indexes_lck = hash_index.lock().unwrap();
let hash_index = hash_indexes_lck.entry(source_mailbox_hash).or_default();
for env_hash in env_hashes.iter() {
let path_src = {
if !hash_index.contains_key(&env_hash) {
continue;
}
if let Some(modif) = &hash_index[&env_hash].modified {
match modif {
PathMod::Path(ref path) => path.clone(),
PathMod::Hash(hash) => hash_index[&hash].to_path_buf(),
}
} else {
hash_index[&env_hash].to_path_buf()
}
};
let filename = path_src
.file_name()
.expect(&format!("Could not get filename of {}", path_src.display()));
dest_path.push(filename);
hash_index.entry(env_hash).or_default().modified =
Some(PathMod::Path(dest_path.clone()));
if move_ {
debug!("renaming {:?} to {:?}", path_src, dest_path);
fs::rename(&path_src, &dest_path)?;
debug!("success in rename");
} else {
debug!("copying {:?} to {:?}", path_src, dest_path);
fs::copy(&path_src, &dest_path)?;
debug!("success in copy");
}
dest_path.pop();
}
Ok(())
}))
}
fn create_mailbox(
&mut self,
new_path: String,

View File

@ -993,6 +993,25 @@ impl MailBackend for MboxType {
)))
}
fn copy_messages(
&mut self,
_env_hashes: EnvelopeHashBatch,
_source_mailbox_hash: MailboxHash,
_destination_mailbox_hash: MailboxHash,
_move_: bool,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}
fn set_flags(
&mut self,
_env_hashes: EnvelopeHashBatch,
_mailbox_hash: MailboxHash,
_flags: SmallVec<[(std::result::Result<Flag, String>, bool); 8]>,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}
fn save(
&self,
_bytes: Vec<u8>,

View File

@ -287,7 +287,6 @@ impl MailBackend for NntpType {
_source_mailbox_hash: MailboxHash,
_destination_mailbox_hash: MailboxHash,
_move_: bool,
_destination_flags: Option<Flag>,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}

View File

@ -684,6 +684,16 @@ impl MailBackend for NotmuchDb {
Ok(Box::pin(async { Ok(()) }))
}
fn copy_messages(
&mut self,
_env_hashes: EnvelopeHashBatch,
_source_mailbox_hash: MailboxHash,
_destination_mailbox_hash: MailboxHash,
_move_: bool,
) -> ResultFuture<()> {
Err(MeliError::new("Unimplemented."))
}
fn set_flags(
&mut self,
env_hashes: EnvelopeHashBatch,

View File

@ -270,7 +270,6 @@ pub trait MailListingTrait: ListingTrait {
mailbox_hash,
destination_mailbox_hash,
/* move? */ false,
/* flags */ None,
)
}) {
Err(err) => {
@ -309,7 +308,6 @@ pub trait MailListingTrait: ListingTrait {
mailbox_hash,
destination_mailbox_hash,
/* move? */ true,
/* flags */ None,
)
}) {
Err(err) => {

View File

@ -1437,6 +1437,12 @@ impl Component for ConversationsListing {
);
}
}
UIEvent::EnvelopeRemove(ref _env_hash, ref thread_hash) => {
if self.order.contains_key(thread_hash) {
self.refresh_mailbox(context, false);
self.set_dirty(true);
}
}
UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);

View File

@ -605,7 +605,9 @@ impl Account {
}
pub fn reload(&mut self, event: RefreshEvent, mailbox_hash: MailboxHash) -> Option<UIEvent> {
if !self.mailbox_entries[&mailbox_hash].status.is_available() {
if !self.mailbox_entries[&mailbox_hash].status.is_available()
&& !self.mailbox_entries[&mailbox_hash].status.is_parsing()
{
self.event_queue.push_back((mailbox_hash, event));
return None;
}