diff --git a/melib/src/backends.rs b/melib/src/backends.rs index f79e897f..12ee16a9 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -204,7 +204,7 @@ impl Backends { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RefreshEventKind { Update(EnvelopeHash, Box), /// Rename(old_hash, new_hash) @@ -216,16 +216,22 @@ pub enum RefreshEventKind { Failure(MeliError), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RefreshEvent { - hash: MailboxHash, + mailbox_hash: MailboxHash, + account_hash: AccountHash, kind: RefreshEventKind, } impl RefreshEvent { - pub fn hash(&self) -> MailboxHash { - self.hash + pub fn mailbox_hash(&self) -> MailboxHash { + self.mailbox_hash } + + pub fn account_hash(&self) -> AccountHash { + self.account_hash + } + pub fn kind(self) -> RefreshEventKind { /* consumes self! */ self.kind @@ -245,6 +251,12 @@ impl RefreshEventConsumer { } } +impl fmt::Debug for RefreshEventConsumer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RefreshEventConsumer") + } +} + pub struct NotifyFn(Box () + Send + Sync>); impl fmt::Debug for NotifyFn { @@ -555,6 +567,7 @@ pub fn mailbox_default() -> Mailbox { }) } +pub type AccountHash = u64; pub type MailboxHash = u64; pub type Mailbox = Box; diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index e9b0dea3..0218aa00 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -36,9 +36,9 @@ pub mod managesieve; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::backends::BackendOp; -use crate::backends::MailboxHash; use crate::backends::RefreshEvent; use crate::backends::RefreshEventKind::{self, *}; +use crate::backends::{AccountHash, MailboxHash}; use crate::backends::{BackendMailbox, MailBackend, Mailbox, RefreshEventConsumer}; use crate::conf::AccountSettings; use crate::email::*; @@ -120,12 +120,26 @@ macro_rules! get_conf_val { #[derive(Debug)] pub struct UIDStore { + account_hash: AccountHash, uidvalidity: Arc>>, hash_index: Arc>>, uid_index: Arc>>, byte_cache: Arc>>, } + +impl Default for UIDStore { + fn default() -> Self { + UIDStore { + account_hash: 0, + uidvalidity: Default::default(), + hash_index: Default::default(), + uid_index: Default::default(), + byte_cache: Default::default(), + } + } +} + #[derive(Debug)] pub struct ImapType { account_name: String, @@ -323,6 +337,11 @@ impl MailBackend for ImapType { let main_conn = self.connection.clone(); let uid_store = self.uid_store.clone(); let account_name = self.account_name.clone(); + let account_hash = { + let mut hasher = DefaultHasher::new(); + hasher.write(self.account_name.as_bytes()); + hasher.finish() + }; let w = AsyncBuilder::new(); let closure = move |work_context: WorkContext| { let thread = std::thread::current(); @@ -330,7 +349,8 @@ impl MailBackend for ImapType { Ok(conn) => conn, Err(err) => { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(err.clone()), }); @@ -350,6 +370,7 @@ impl MailBackend for ImapType { .send((thread.id(), "refresh".to_string())) .unwrap(); watch::examine_updates( + account_hash, &inbox, &sender, &mut conn, @@ -374,6 +395,11 @@ impl MailBackend for ImapType { let main_conn = self.connection.clone(); let is_online = self.online.clone(); let uid_store = self.uid_store.clone(); + let account_hash = { + let mut hasher = DefaultHasher::new(); + hasher.write(self.account_name.as_bytes()); + hasher.finish() + }; let handle = std::thread::Builder::new() .name(format!("{} imap connection", self.account_name.as_str(),)) .spawn(move || { @@ -397,6 +423,7 @@ impl MailBackend for ImapType { sender, work_context, tag_index, + account_hash, }; if has_idle { idle(kit).ok().take(); @@ -881,6 +908,15 @@ impl ImapType { Err(MeliError::new("Account is uninitialised.")), ))); let connection = ImapConnection::new_connection(&server_conf, online.clone()); + let account_hash = { + let mut hasher = DefaultHasher::new(); + hasher.write(s.name.as_bytes()); + hasher.finish() + }; + let uid_store: Arc = Arc::new(UIDStore { + account_hash, + ..UIDStore::default() + }); Ok(Box::new(ImapType { account_name: s.name().to_string(), @@ -892,12 +928,7 @@ impl ImapType { tag_index: Arc::new(RwLock::new(Default::default())), mailboxes: Arc::new(RwLock::new(Default::default())), connection: Arc::new(Mutex::new(connection)), - uid_store: Arc::new(UIDStore { - uidvalidity: Default::default(), - hash_index: Default::default(), - uid_index: Default::default(), - byte_cache: Default::default(), - }), + uid_store, })) } diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index 050b4fb8..f0b997fd 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -24,6 +24,7 @@ use std::sync::{Arc, Mutex, RwLock}; /// Arguments for IMAP watching functions pub struct ImapWatchKit { + pub account_hash: AccountHash, pub conn: ImapConnection, pub is_online: Arc)>>, pub main_conn: Arc>, @@ -35,13 +36,14 @@ pub struct ImapWatchKit { } macro_rules! exit_on_error { - ($sender:expr, $mailbox_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => { + ($sender:expr, $account_hash:ident, $mailbox_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => { $(if let Err(e) = $result { debug!("failure: {}", e.to_string()); $work_context.set_status.send(($thread_id, e.to_string())).unwrap(); $work_context.finished.send($thread_id).unwrap(); $sender.send(RefreshEvent { - hash: $mailbox_hash, + account_hash: $account_hash, + mailbox_hash: $mailbox_hash, kind: RefreshEventKind::Failure(e.clone()), }); Err(e) @@ -60,6 +62,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> { sender, work_context, tag_index, + account_hash, } = kit; loop { if super::try_lock(&is_online)?.1.is_ok() { @@ -86,6 +89,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> { )) .unwrap(); examine_updates( + account_hash, mailbox, &sender, &mut conn, @@ -113,6 +117,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { sender, work_context, tag_index, + account_hash, } = kit; loop { if super::try_lock(&is_online)?.1.is_ok() { @@ -138,7 +143,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { .send((thread_id, err.to_string())) .unwrap(); sender.send(RefreshEvent { - hash: 0, + account_hash, + mailbox_hash: 0, kind: RefreshEventKind::Failure(err.clone()), }); return Err(err); @@ -148,6 +154,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { let mut response = String::with_capacity(8 * 1024); exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -165,7 +172,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { if let Some(v) = uidvalidities.get_mut(&mailbox_hash) { if *v != ok.uidvalidity { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); *prev_exists = 0; @@ -178,11 +186,13 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { } } else { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(MeliError::new(format!( "Unknown mailbox: {} {}", mailbox.path(), @@ -202,6 +212,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { } exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -224,6 +235,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { let mut main_conn_lck = super::try_lock(&main_conn)?; exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -250,10 +262,12 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { .unwrap(); exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, examine_updates( + account_hash, mailbox, &sender, &mut conn, @@ -282,6 +296,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { /* UID SEARCH RECENT */ exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -300,6 +315,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { Ok(v) => { exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -358,7 +374,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { *mailbox.exists.lock().unwrap() += 1; sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } @@ -410,6 +427,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { if n > *prev_exists { exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -475,7 +493,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { *mailbox.unseen.lock().unwrap() += 1; } sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } @@ -503,6 +522,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { debug!("fetch {} {:?}", msg_seq, flags); exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -524,7 +544,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { if let Some(uid) = v.pop() { if let Some(env_hash) = uid_store.uid_index.lock().unwrap().get(&uid) { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: NewFlags(*env_hash, flags), }); } @@ -551,7 +572,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { .unwrap(); work_context.finished.send(thread_id).unwrap(); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(MeliError::new(format!( "IDLE connection dropped: {}", &err @@ -561,6 +583,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> { } pub fn examine_updates( + account_hash: AccountHash, mailbox: &ImapMailbox, sender: &RefreshEventConsumer, conn: &mut ImapConnection, @@ -574,6 +597,7 @@ pub fn examine_updates( let mut response = String::with_capacity(8 * 1024); exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -589,7 +613,8 @@ pub fn examine_updates( if let Some(v) = uidvalidities.get_mut(&mailbox_hash) { if *v != ok.uidvalidity { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); /* @@ -601,11 +626,13 @@ pub fn examine_updates( } } else { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(MeliError::new(format!( "Unknown mailbox: {} {}", mailbox.path(), @@ -621,6 +648,7 @@ pub fn examine_updates( /* UID SEARCH RECENT */ exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -637,6 +665,7 @@ pub fn examine_updates( Ok(v) => { exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -687,7 +716,8 @@ pub fn examine_updates( *mailbox.unseen.lock().unwrap() += 1; } sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } @@ -713,6 +743,7 @@ pub fn examine_updates( debug!("exists {}", n); exit_on_error!( sender, + account_hash, mailbox_hash, work_context, thread_id, @@ -761,7 +792,8 @@ pub fn examine_updates( *mailbox.unseen.lock().unwrap() += 1; } sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 894a7847..f48adece 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -199,6 +199,11 @@ impl MailBackend for MaildirType { ) -> Result> { let w = AsyncBuilder::new(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); + let account_hash = { + let mut hasher = DefaultHasher::default(); + hasher.write(self.name.as_bytes()); + hasher.finish() + }; let handle = { let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash]; @@ -277,7 +282,8 @@ impl MailBackend for MaildirType { bincode::serialize_into(writer, &e).unwrap(); } sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(e)), }); } else { @@ -290,7 +296,8 @@ impl MailBackend for MaildirType { } } for ev in current_hashes.into_iter().map(|h| RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Remove(h), }) { sender.send(ev); @@ -299,7 +306,8 @@ impl MailBackend for MaildirType { }; if let Err(err) = thunk(&sender) { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Failure(err), }); } @@ -314,6 +322,11 @@ impl MailBackend for MaildirType { ) -> Result { let (tx, rx) = channel(); let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); + let account_hash = { + let mut hasher = DefaultHasher::default(); + hasher.write(self.name.as_bytes()); + hasher.finish() + }; let root_path = self.path.to_path_buf(); watcher.watch(&root_path, RecursiveMode::Recursive).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); @@ -385,7 +398,8 @@ impl MailBackend for MaildirType { } *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } @@ -425,7 +439,8 @@ impl MailBackend for MaildirType { ) { mailbox_index.lock().unwrap().insert(env.hash(),mailbox_hash); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); } @@ -451,7 +466,8 @@ impl MailBackend for MaildirType { /* Send Write notice */ sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Update(old_hash, Box::new(env)), }); } @@ -500,7 +516,8 @@ impl MailBackend for MaildirType { }); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Remove(hash), }); } @@ -530,7 +547,8 @@ impl MailBackend for MaildirType { e.modified = Some(PathMod::Hash(new_hash)); }); sender.send(RefreshEvent { - hash: get_path_hash!(dest), + account_hash, + mailbox_hash: get_path_hash!(dest), kind: Rename(old_hash, new_hash), }); if !was_seen && is_seen { @@ -588,7 +606,8 @@ impl MailBackend for MaildirType { } *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: Create(Box::new(env)), }); continue; @@ -600,7 +619,8 @@ impl MailBackend for MaildirType { *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1; } sender.send(RefreshEvent { - hash: get_path_hash!(dest), + account_hash, + mailbox_hash: get_path_hash!(dest), kind: Rename(old_hash, new_hash), }); debug!("contains_new_key"); @@ -608,7 +628,8 @@ impl MailBackend for MaildirType { /* Maybe a re-read should be triggered here just to be safe. sender.send(RefreshEvent { - hash: get_path_hash!(dest), + account_hash, + mailbox_hash: get_path_hash!(dest), kind: Rescan, }); */ diff --git a/melib/src/backends/mbox.rs b/melib/src/backends/mbox.rs index 599b5a9f..4a4e5a2f 100644 --- a/melib/src/backends/mbox.rs +++ b/melib/src/backends/mbox.rs @@ -41,8 +41,9 @@ use memmap::{Mmap, Protection}; use nom::{IResult, Needed}; extern crate notify; use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; -use std::collections::HashMap; +use std::collections::hash_map::{DefaultHasher, HashMap}; use std::fs::File; +use std::hash::Hasher; use std::io::BufReader; use std::io::Read; use std::os::unix::io::AsRawFd; @@ -386,6 +387,7 @@ pub fn mbox_parse( /// Mbox backend #[derive(Debug, Default)] pub struct MboxType { + account_name: String, path: PathBuf, index: Arc>>, mailboxes: Arc>>, @@ -461,13 +463,15 @@ impl MailBackend for MboxType { .map_err(MeliError::new)?; debug!("watching {:?}", f.path.as_path()); } + let account_hash = { + let mut hasher = DefaultHasher::new(); + hasher.write(self.account_name.as_bytes()); + hasher.finish() + }; let index = self.index.clone(); let mailboxes = self.mailboxes.clone(); let handle = std::thread::Builder::new() - .name(format!( - "watching {}", - self.path.file_name().unwrap().to_str().unwrap() - )) + .name(format!("watching {}", self.account_name,)) .spawn(move || { // Move `watcher` in the closure's scope so that it doesn't get dropped. let _watcher = watcher; @@ -521,14 +525,16 @@ impl MailBackend for MboxType { { for env in envelopes { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Create(Box::new(env)), }); } } } else { sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); } @@ -547,7 +553,8 @@ impl MailBackend for MboxType { { let mailbox_hash = get_path_hash!(&pathbuf); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(MeliError::new(format!( "mbox mailbox {} was removed.", pathbuf.display() @@ -560,7 +567,8 @@ impl MailBackend for MboxType { if mailboxes.lock().unwrap().values().any(|f| &f.path == &src) { let mailbox_hash = get_path_hash!(&src); sender.send(RefreshEvent { - hash: mailbox_hash, + account_hash, + mailbox_hash, kind: RefreshEventKind::Failure(MeliError::new(format!( "mbox mailbox {} was renamed to {}.", src.display(), @@ -572,9 +580,10 @@ impl MailBackend for MboxType { } /* Trigger rescan of mailboxes */ DebouncedEvent::Rescan => { - for h in mailboxes.lock().unwrap().keys() { + for &mailbox_hash in mailboxes.lock().unwrap().keys() { sender.send(RefreshEvent { - hash: *h, + account_hash, + mailbox_hash, kind: RefreshEventKind::Rescan, }); } @@ -628,6 +637,7 @@ impl MboxType { ))); } let ret = MboxType { + account_name: s.name().to_string(), path, ..Default::default() }; diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs index 0d7513f3..549eb355 100644 --- a/melib/src/backends/notmuch.rs +++ b/melib/src/backends/notmuch.rs @@ -109,6 +109,7 @@ pub struct NotmuchDb { index: Arc>>, tag_index: Arc>>, path: PathBuf, + account_name: String, save_messages_to: Option, } @@ -238,6 +239,7 @@ impl NotmuchDb { mailboxes: Arc::new(RwLock::new(mailboxes)), save_messages_to: None, + account_name: s.name().to_string(), })) } @@ -435,6 +437,11 @@ impl MailBackend for NotmuchDb { watcher.watch(&self.path, RecursiveMode::Recursive).unwrap(); let path = self.path.clone(); let lib = self.lib.clone(); + let account_hash = { + let mut hasher = DefaultHasher::new(); + hasher.write(self.account_name.as_bytes()); + hasher.finish() + }; { let database = NotmuchDb::new_connection(path.as_path(), lib.clone(), false)?; let mut revision_uuid_lck = self.revision_uuid.write().unwrap(); @@ -450,10 +457,7 @@ impl MailBackend for NotmuchDb { let revision_uuid = self.revision_uuid.clone(); let handle = std::thread::Builder::new() - .name(format!( - "watching {}", - self.path.file_name().unwrap().to_str().unwrap() - )) + .name(format!("watching {}", self.account_name)) .spawn(move || { let _watcher = watcher; let c = move || -> std::result::Result<(), MeliError> { @@ -484,7 +488,8 @@ impl MailBackend for NotmuchDb { if let Err(err) = c() { sender.send(RefreshEvent { - hash: 0, + account_hash, + mailbox_hash: 0, kind: Failure(err.into()), }); } diff --git a/src/state.rs b/src/state.rs index ff434454..250c5ad3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -30,7 +30,7 @@ Input is received in the main loop from threads which listen on the stdin for us use super::*; use crate::plugins::PluginManager; -use melib::backends::{MailboxHash, NotifyFn}; +use melib::backends::{AccountHash, MailboxHash, NotifyFn}; use crossbeam::channel::{unbounded, Receiver, Sender}; use smallvec::SmallVec; @@ -89,7 +89,7 @@ impl InputHandler { /// A context container for loaded settings, accounts, UI changes, etc. pub struct Context { pub accounts: Vec, - pub mailbox_hashes: HashMap, + pub account_hashes: HashMap, pub settings: Settings, pub runtime_settings: Settings, @@ -132,7 +132,6 @@ impl Context { pub fn is_online(&mut self, account_pos: usize) -> Result<()> { let Context { ref mut accounts, - ref mut mailbox_hashes, ref mut replies, .. } = self; @@ -146,7 +145,6 @@ impl Context { mailbox_node.hash, accounts[account_pos][&mailbox_node.hash].name() ); - mailbox_hashes.insert(mailbox_node.hash, account_pos); } /* Account::watch() needs * - work_controller to pass `work_context` to the watcher threads and then add them @@ -246,6 +244,7 @@ impl State { let cols = termsize.0 as usize; let rows = termsize.1 as usize; + let mut account_hashes = HashMap::with_capacity_and_hasher(1, Default::default()); let work_controller = WorkController::new(sender.clone()); let accounts: Vec = { let mut file_accs = settings @@ -259,6 +258,14 @@ impl State { .enumerate() .map(|(index, (n, a_s))| { let sender = sender.clone(); + let account_hash = { + use std::collections::hash_map::DefaultHasher; + use std::hash::Hasher; + let mut hasher = DefaultHasher::new(); + hasher.write(n.as_bytes()); + hasher.finish() + }; + account_hashes.insert(account_hash, index); Account::new( index, n.to_string(), @@ -268,7 +275,10 @@ impl State { sender.clone(), NotifyFn::new(Box::new(move |f: MailboxHash| { sender - .send(ThreadEvent::UIEvent(UIEvent::WorkerProgress(f))) + .send(ThreadEvent::UIEvent(UIEvent::WorkerProgress( + account_hash, + f, + ))) .unwrap(); })), ) @@ -315,8 +325,7 @@ impl State { context: Context { accounts, - mailbox_hashes: HashMap::with_capacity_and_hasher(1, Default::default()), - + account_hashes, settings: settings.clone(), runtime_settings: settings, dirty_areas: VecDeque::with_capacity(5), @@ -362,25 +371,31 @@ impl State { * and startup a thread to remind us to poll it every now and then till it's finished. */ pub fn refresh_event(&mut self, event: RefreshEvent) { - let hash = event.hash(); - if let Some(&idxa) = self.context.mailbox_hashes.get(&hash) { - if self.context.accounts[idxa].load(hash).is_err() { - self.context.replies.push_back(UIEvent::from(event)); - return; - } - let Context { - ref mut accounts, .. - } = &mut self.context; - - if let Some(notification) = accounts[idxa].reload(event, hash) { - if let UIEvent::Notification(_, _, _) = notification { - self.rcv_event(UIEvent::MailboxUpdate((idxa, hash))); + let account_hash = event.account_hash(); + let mailbox_hash = event.mailbox_hash(); + if let Some(&idxa) = self.context.account_hashes.get(&account_hash) { + if self.context.accounts[idxa] + .mailbox_entries + .contains_key(&mailbox_hash) + { + if self.context.accounts[idxa].load(mailbox_hash).is_err() { + self.context.replies.push_back(UIEvent::from(event)); + return; + } + let Context { + ref mut accounts, .. + } = &mut self.context; + + if let Some(notification) = accounts[idxa].reload(event, mailbox_hash) { + if let UIEvent::Notification(_, _, _) = notification { + self.rcv_event(UIEvent::MailboxUpdate((idxa, mailbox_hash))); + } + self.rcv_event(notification); + } + } else { + if let melib::backends::RefreshEventKind::Failure(err) = event.kind() { + debug!(err); } - self.rcv_event(notification); - } - } else { - if let melib::backends::RefreshEventKind::Failure(err) = event.kind() { - debug!(err); } } } @@ -915,8 +930,8 @@ impl State { self.child = Some(child); return; } - UIEvent::WorkerProgress(mailbox_hash) => { - if let Some(&account_idx) = self.context.mailbox_hashes.get(&mailbox_hash) { + UIEvent::WorkerProgress(account_hash, mailbox_hash) => { + if let Some(&account_idx) = self.context.account_hashes.get(&account_hash) { let _ = self.context.accounts[account_idx].load(mailbox_hash); } return; diff --git a/src/types.rs b/src/types.rs index 4c7b8db7..deab6c3f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -38,7 +38,7 @@ pub use self::helpers::*; use super::execute::Action; use super::terminal::*; -use melib::backends::MailboxHash; +use melib::backends::{AccountHash, MailboxHash}; use melib::{EnvelopeHash, RefreshEvent}; use nix::unistd::Pid; use std; @@ -115,7 +115,7 @@ pub enum UIEvent { MailboxCreate((usize, MailboxHash)), AccountStatusChange(usize), ComponentKill(Uuid), - WorkerProgress(MailboxHash), + WorkerProgress(AccountHash, MailboxHash), StartupCheck(MailboxHash), RefreshEvent(Box), EnvelopeUpdate(EnvelopeHash),