From 94f345d731329e029016495f1c674b6a9b17401a Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sat, 3 Aug 2024 14:06:47 +0300 Subject: [PATCH] Implement mailbox renaming command Signed-off-by: Manos Pitsidianakis --- meli/src/accounts.rs | 2 +- meli/src/accounts/jobs.rs | 13 + meli/src/accounts/mailbox_ops.rs | 427 ++++++++++++++++--------------- 3 files changed, 234 insertions(+), 208 deletions(-) diff --git a/meli/src/accounts.rs b/meli/src/accounts.rs index b1f73fd7..8be85c77 100644 --- a/meli/src/accounts.rs +++ b/meli/src/accounts.rs @@ -1325,7 +1325,7 @@ impl Account { if let Some(mut job) = self.active_jobs.remove(job_id) { let job_id = *job_id; match job { - JobRequest::Mailbox(ref mut inner) => { + JobRequest::Mailbox(inner) => { self.process_mailbox_event(job_id, inner); return true; } diff --git a/meli/src/accounts/jobs.rs b/meli/src/accounts/jobs.rs index 564a721b..425631e8 100644 --- a/meli/src/accounts/jobs.rs +++ b/meli/src/accounts/jobs.rs @@ -40,6 +40,11 @@ pub enum MailboxJobRequest { mailbox_hash: MailboxHash, handle: JoinHandle>>, }, + RenameMailbox { + mailbox_hash: MailboxHash, + new_path: String, + handle: JoinHandle>, + }, SetMailboxPermissions { mailbox_hash: MailboxHash, handle: JoinHandle>, @@ -58,6 +63,13 @@ impl std::fmt::Debug for MailboxJobRequest { Self::DeleteMailbox { mailbox_hash, .. } => { write!(f, "JobRequest::DeleteMailbox({})", mailbox_hash) } + Self::RenameMailbox { + mailbox_hash, + new_path, + .. + } => { + write!(f, "JobRequest::RenameMailbox {mailbox_hash} to {new_path} ") + } Self::SetMailboxPermissions { .. } => { write!(f, "JobRequest::SetMailboxPermissions") } @@ -75,6 +87,7 @@ impl std::fmt::Display for MailboxJobRequest { Self::Mailboxes { .. } => write!(f, "Get mailbox list"), Self::CreateMailbox { path, .. } => write!(f, "Create mailbox {}", path), Self::DeleteMailbox { .. } => write!(f, "Delete mailbox"), + Self::RenameMailbox { new_path, .. } => write!(f, "Rename mailbox to {new_path}"), Self::SetMailboxPermissions { .. } => write!(f, "Set mailbox permissions"), Self::SetMailboxSubscription { .. } => write!(f, "Set mailbox subscription"), } diff --git a/meli/src/accounts/mailbox_ops.rs b/meli/src/accounts/mailbox_ops.rs index e584160f..15928cfb 100644 --- a/meli/src/accounts/mailbox_ops.rs +++ b/meli/src/accounts/mailbox_ops.rs @@ -113,12 +113,71 @@ impl Account { ); Ok(()) } - MailboxOperation::Rename(_, _) => Err(Error::new("Not implemented.")), + MailboxOperation::Rename(path, new_path) => { + let mailbox_hash = self.mailbox_by_path(&path)?; + let job = self + .backend + .write() + .unwrap() + .rename_mailbox(mailbox_hash, new_path.clone())?; + let handle = self.main_loop_handler.job_executor.spawn( + format!("rename-mailbox {path} to {new_path}").into(), + job, + self.is_async(), + ); + self.insert_job( + handle.job_id, + JobRequest::Mailbox(MailboxJobRequest::RenameMailbox { + handle, + mailbox_hash, + new_path, + }), + ); + Ok(()) + } MailboxOperation::SetPermissions(_) => Err(Error::new("Not implemented.")), } } - pub fn process_mailbox_event(&mut self, job_id: JobId, job: &mut MailboxJobRequest) { + pub fn process_mailbox_event(&mut self, job_id: JobId, mut job: MailboxJobRequest) { + macro_rules! try_handle { + ($handle:ident, $binding:pat => $then:block) => {{ + try_handle! { $handle, Err(err) => { + self.main_loop_handler + .job_executor + .set_job_success(job_id, false); + self.main_loop_handler + .send(ThreadEvent::UIEvent(UIEvent::Notification { + title: None, + body: format!("{}: {} failed", &self.name, job).into(), + kind: Some(NotificationType::Error(err.kind)), + source: Some(err), + })); + return; + }, + $binding => $then + } + }}; + ($handle:ident, Err($err:pat) => $then_err: block, $binding:pat => $then:block) => {{ + match $handle.chan.try_recv() { + _err @ Ok(None) | _err @ Err(_) => { + /* canceled */ + #[cfg(debug_assertions)] + log::trace!( + "handle.chan.try_recv() for job {} returned {:?}", + job_id, + _err + ); + self.main_loop_handler + .job_executor + .set_job_success(job_id, false); + } + Ok(Some(Err($err))) => $then_err, + Ok(Some(Ok($binding))) => $then, + } + }}; + } + match job { MailboxJobRequest::Mailboxes { ref mut handle } => { if let Ok(Some(mailboxes)) = handle.chan.try_recv() { @@ -166,229 +225,184 @@ impl Account { } } } - MailboxJobRequest::CreateMailbox { - ref path, - ref mut handle, - .. - } => { - if let Ok(Some(r)) = handle.chan.try_recv() { - match r { - Err(err) => { - self.main_loop_handler - .job_executor - .set_job_success(job_id, false); - self.main_loop_handler.send(ThreadEvent::UIEvent( - UIEvent::Notification { - title: Some( - format!( - "{}: could not create mailbox {}", - &self.name, path - ) - .into(), - ), - source: None, - body: err.to_string().into(), - kind: Some(NotificationType::Error(err.kind)), - }, - )); - } - Ok((mailbox_hash, mut mailboxes)) => { - self.main_loop_handler.send(ThreadEvent::UIEvent( - UIEvent::MailboxCreate((self.hash, mailbox_hash)), - )); - let mut new = FileMailboxConf::default(); - new.mailbox_conf.subscribe = ToggleFlag::InternalVal(true); - new.mailbox_conf.usage = if mailboxes[&mailbox_hash].special_usage() - != SpecialUsageMailbox::Normal - { - Some(mailboxes[&mailbox_hash].special_usage()) - } else { - let tmp = SpecialUsageMailbox::detect_usage( - mailboxes[&mailbox_hash].name(), - ); - if let Some(tmp) = tmp.filter(|&v| v != SpecialUsageMailbox::Normal) - { - mailboxes.entry(mailbox_hash).and_modify(|entry| { - let _ = entry.set_special_usage(tmp); - }); - } - tmp - }; - // if new mailbox has parent, we need to update its children field - if let Some(parent_hash) = mailboxes[&mailbox_hash].parent() { - self.mailbox_entries - .entry(parent_hash) - .and_modify(|parent| { - parent.ref_mailbox = - mailboxes.remove(&parent_hash).unwrap(); - }); - } - let status = MailboxStatus::default(); - - self.mailbox_entries.insert( - mailbox_hash, - MailboxEntry::new( - status, - mailboxes[&mailbox_hash].path().to_string(), - mailboxes.remove(&mailbox_hash).unwrap(), - new, - ), - ); - self.collection - .threads - .write() - .unwrap() - .insert(mailbox_hash, Threads::default()); - self.collection - .mailboxes - .write() - .unwrap() - .insert(mailbox_hash, Default::default()); - build_mailboxes_order( - &mut self.tree, - &self.mailbox_entries, - &mut self.mailboxes_order, - ); + MailboxJobRequest::CreateMailbox { ref mut handle, .. } => { + try_handle! { handle, (mailbox_hash, mut mailboxes) => { + self.main_loop_handler.send(ThreadEvent::UIEvent( + UIEvent::MailboxCreate((self.hash, mailbox_hash)), + )); + let mut new = FileMailboxConf::default(); + new.mailbox_conf.subscribe = ToggleFlag::InternalVal(true); + new.mailbox_conf.usage = if mailboxes[&mailbox_hash].special_usage() + != SpecialUsageMailbox::Normal + { + Some(mailboxes[&mailbox_hash].special_usage()) + } else { + let tmp = SpecialUsageMailbox::detect_usage( + mailboxes[&mailbox_hash].name(), + ); + if let Some(tmp) = tmp.filter(|&v| v != SpecialUsageMailbox::Normal) + { + mailboxes.entry(mailbox_hash).and_modify(|entry| { + let _ = entry.set_special_usage(tmp); + }); } + tmp + }; + // if new mailbox has parent, we need to update its children field + if let Some(parent_hash) = mailboxes[&mailbox_hash].parent() { + self.mailbox_entries + .entry(parent_hash) + .and_modify(|parent| { + parent.ref_mailbox = + mailboxes.remove(&parent_hash).unwrap(); + }); } - } + let status = MailboxStatus::default(); + + self.mailbox_entries.insert( + mailbox_hash, + MailboxEntry::new( + status, + mailboxes[&mailbox_hash].path().to_string(), + mailboxes.remove(&mailbox_hash).unwrap(), + new, + ), + ); + self.collection + .threads + .write() + .unwrap() + .insert(mailbox_hash, Threads::default()); + self.collection + .mailboxes + .write() + .unwrap() + .insert(mailbox_hash, Default::default()); + build_mailboxes_order( + &mut self.tree, + &self.mailbox_entries, + &mut self.mailboxes_order, + ); + }} } MailboxJobRequest::DeleteMailbox { mailbox_hash, ref mut handle, .. } => { - match handle.chan.try_recv() { - Err(_) => { /* canceled */ } - Ok(None) => {} - Ok(Some(Err(err))) => { - self.main_loop_handler - .job_executor - .set_job_success(job_id, false); - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::Notification { - title: Some( - format!("{}: could not delete mailbox", &self.name).into(), - ), - source: None, - body: err.to_string().into(), - kind: Some(NotificationType::Error(err.kind)), - })); + try_handle! { handle, mut mailboxes => { + self.main_loop_handler + .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( + self.hash, + mailbox_hash, + )))); + if let Some(pos) = + self.mailboxes_order.iter().position(|&h| h == mailbox_hash) + { + self.mailboxes_order.remove(pos); } - Ok(Some(Ok(mut mailboxes))) => { - let mailbox_hash = *mailbox_hash; - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( - self.hash, - mailbox_hash, - )))); - if let Some(pos) = - self.mailboxes_order.iter().position(|&h| h == mailbox_hash) - { - self.mailboxes_order.remove(pos); - } - if let Some(pos) = self.tree.iter().position(|n| n.hash == mailbox_hash) { - self.tree.remove(pos); - } - if self.settings.sent_mailbox == Some(mailbox_hash) { - self.settings.sent_mailbox = None; + if let Some(pos) = self.tree.iter().position(|n| n.hash == mailbox_hash) { + self.tree.remove(pos); + } + if self.settings.sent_mailbox == Some(mailbox_hash) { + self.settings.sent_mailbox = None; + } + self.collection + .threads + .write() + .unwrap() + .remove(&mailbox_hash); + let deleted_mailbox = + self.mailbox_entries.shift_remove(&mailbox_hash).unwrap(); + // if deleted mailbox had parent, we need to update its children field + if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() { + self.mailbox_entries + .entry(parent_hash) + .and_modify(|parent| { + parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap(); + }); + } + self.collection + .mailboxes + .write() + .unwrap() + .remove(&mailbox_hash); + build_mailboxes_order( + &mut self.tree, + &self.mailbox_entries, + &mut self.mailboxes_order, + ); + // [ref:FIXME] remove from settings as well + + self.main_loop_handler + .send(ThreadEvent::UIEvent(UIEvent::Notification { + title: Some( + format!("{}: mailbox deleted successfully", &self.name).into(), + ), + source: None, + body: "".into(), + kind: Some(NotificationType::Info), + })); + }} + } + MailboxJobRequest::RenameMailbox { + ref mut handle, + mailbox_hash, + ref mut new_path, + } => { + use indexmap::map::MutableKeys; + try_handle! { handle, mailbox => { + let new_hash = mailbox.hash(); + if let Some((_, key, entry)) = self.mailbox_entries.get_full_mut2(&mailbox_hash) { + *key = new_hash; + *entry = MailboxEntry::new(entry.status.clone(), std::mem::take(new_path), mailbox, entry.conf.clone()); + } + if let Some(key) = self.mailboxes_order.iter_mut().find(|k| **k == mailbox_hash) { + *key = new_hash; + } + if let Some((_, key, _)) = self.event_queue.get_full_mut2(&mailbox_hash) { + *key = new_hash; + } + { + let mut threads = self.collection.threads.write().unwrap(); + if let Some(entry) = threads.remove(&mailbox_hash) { + threads.insert(new_hash, entry); } - self.collection - .threads - .write() - .unwrap() - .remove(&mailbox_hash); - let deleted_mailbox = - self.mailbox_entries.shift_remove(&mailbox_hash).unwrap(); - // if deleted mailbox had parent, we need to update its children field - if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() { - self.mailbox_entries - .entry(parent_hash) - .and_modify(|parent| { - parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap(); - }); + } + { + let mut mailboxes = self.collection.mailboxes.write().unwrap(); + if let Some(entry) = mailboxes.remove(&mailbox_hash) { + mailboxes.insert(new_hash, entry); } - self.collection - .mailboxes - .write() - .unwrap() - .remove(&mailbox_hash); - build_mailboxes_order( - &mut self.tree, - &self.mailbox_entries, - &mut self.mailboxes_order, - ); - // [ref:FIXME] remove from settings as well - - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::Notification { - title: Some( - format!("{}: mailbox deleted successfully", &self.name).into(), - ), - source: None, - body: "".into(), - kind: Some(NotificationType::Info), - })); } - } + build_mailboxes_order( + &mut self.tree, + &self.mailbox_entries, + &mut self.mailboxes_order, + ); + }} } MailboxJobRequest::SetMailboxPermissions { ref mut handle, .. } => { - match handle.chan.try_recv() { - Err(_) => { /* canceled */ } - Ok(None) => {} - Ok(Some(Err(err))) => { - self.main_loop_handler - .job_executor - .set_job_success(job_id, false); - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::Notification { - title: Some( - format!("{}: could not set mailbox permissions", &self.name) - .into(), - ), - source: None, - body: err.to_string().into(), - kind: Some(NotificationType::Error(err.kind)), - })); - } - Ok(Some(Ok(_))) => { - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::Notification { - title: Some( - format!("{}: mailbox permissions set successfully", &self.name) - .into(), - ), - source: None, - body: "".into(), - kind: Some(NotificationType::Info), - })); - } - } + try_handle! { handle, _ => { + self.main_loop_handler + .send(ThreadEvent::UIEvent(UIEvent::Notification { + title: Some( + format!("{}: mailbox permissions set successfully", &self.name) + .into(), + ), + source: None, + body: "".into(), + kind: Some(NotificationType::Info), + })); + }} } MailboxJobRequest::SetMailboxSubscription { ref mut handle, ref mailbox_hash, ref new_value, } => { - match handle.chan.try_recv() { - Err(_) => { /* canceled */ } - Ok(None) => {} - Ok(Some(Err(err))) => { - self.main_loop_handler - .job_executor - .set_job_success(job_id, false); - self.main_loop_handler - .send(ThreadEvent::UIEvent(UIEvent::Notification { - title: Some( - format!("{}: could not set mailbox subscription", &self.name) - .into(), - ), - source: None, - body: err.to_string().into(), - kind: Some(NotificationType::Error(err.kind)), - })); - } - Ok(Some(Ok(()))) if self.mailbox_entries.contains_key(mailbox_hash) => { + try_handle! { handle, () => { + if self.mailbox_entries.contains_key(mailbox_hash) { self.mailbox_entries.entry(*mailbox_hash).and_modify(|m| { m.conf.mailbox_conf.subscribe = if *new_value { ToggleFlag::True @@ -413,8 +427,7 @@ impl Account { kind: Some(NotificationType::Info), })); } - Ok(Some(Ok(()))) => {} - } + }} } } }