diff --git a/melib/src/collection.rs b/melib/src/collection.rs index 95ee89db2..a64d820bf 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -21,12 +21,13 @@ use super::*; use crate::backends::FolderHash; +use core::ops::{Index, IndexMut}; use smallvec::SmallVec; use std::collections::BTreeMap; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use fnv::FnvHashMap; +use fnv::{FnvHashMap, FnvHashSet}; pub struct EnvelopeRef<'g> { guard: RwLockReadGuard<'g, FnvHashMap>, @@ -68,6 +69,7 @@ pub struct Collection { subject_index: Option>, pub threads: FnvHashMap, sent_folder: Option, + pub mailboxes: FnvHashMap>, } impl Drop for Collection { @@ -101,6 +103,7 @@ impl Collection { * /cur, or it was deleted). */ let threads = FnvHashMap::with_capacity_and_hasher(16, Default::default()); + let mailboxes = FnvHashMap::with_capacity_and_hasher(16, Default::default()); Collection { envelopes: Arc::new(RwLock::new(envelopes)), @@ -108,6 +111,7 @@ impl Collection { message_ids, subject_index, threads, + mailboxes, sent_folder: None, } } @@ -123,6 +127,9 @@ impl Collection { pub fn remove(&mut self, envelope_hash: EnvelopeHash, folder_hash: FolderHash) { debug!("DEBUG: Removing {}", envelope_hash); self.envelopes.write().unwrap().remove(&envelope_hash); + self.mailboxes.entry(folder_hash).and_modify(|m| { + m.remove(&envelope_hash); + }); self.threads .entry(folder_hash) .or_default() @@ -144,11 +151,15 @@ impl Collection { if !self.envelopes.write().unwrap().contains_key(&old_hash) { return; } - let mut env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); - env.set_hash(new_hash); + let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); + self.mailboxes.entry(folder_hash).and_modify(|m| { + m.remove(&old_hash); + m.insert(new_hash); + }); + envelope.set_hash(new_hash); self.message_ids - .insert(env.message_id().raw().to_vec(), new_hash); - self.envelopes.write().unwrap().insert(new_hash, env); + .insert(envelope.message_id().raw().to_vec(), new_hash); + self.envelopes.write().unwrap().insert(new_hash, envelope); { if self .threads @@ -175,7 +186,7 @@ impl Collection { } } - /// Merge new Mailbox to collection and update threads. + /// Merge new mailbox to collection and update threads. /// Returns a list of already existing folders whose threads were updated pub fn merge( &mut self, @@ -191,16 +202,21 @@ impl Collection { let &mut Collection { ref mut threads, ref mut envelopes, + ref mut mailboxes, ref sent_folder, .. } = self; if !threads.contains_key(&folder_hash) { threads.insert(folder_hash, Threads::new(new_envelopes.len())); + mailboxes.insert(folder_hash, new_envelopes.keys().cloned().collect()); for (h, e) in new_envelopes { envelopes.write().unwrap().insert(h, e); } } else { + mailboxes.entry(folder_hash).and_modify(|m| { + m.extend(new_envelopes.keys().cloned()); + }); threads.entry(folder_hash).and_modify(|t| { let mut ordered_hash_set = new_envelopes.keys().cloned().collect::>(); @@ -291,6 +307,10 @@ impl Collection { let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); envelope.set_thread(old_env.thread()); let new_hash = envelope.hash(); + self.mailboxes.entry(folder_hash).and_modify(|m| { + m.remove(&old_hash); + m.insert(new_hash); + }); self.message_ids .insert(envelope.message_id().raw().to_vec(), new_hash); self.envelopes.write().unwrap().insert(new_hash, envelope); @@ -328,6 +348,9 @@ impl Collection { pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) { let hash = envelope.hash(); + self.mailboxes.entry(folder_hash).and_modify(|m| { + m.insert(hash); + }); self.message_ids .insert(envelope.message_id().raw().to_vec(), hash); self.envelopes.write().unwrap().insert(hash, envelope); @@ -365,3 +388,16 @@ impl Collection { self.envelopes.read().unwrap().contains_key(env_hash) } } + +impl Index<&FolderHash> for Collection { + type Output = FnvHashSet; + fn index(&self, index: &FolderHash) -> &FnvHashSet { + &self.mailboxes[index] + } +} + +impl IndexMut<&FolderHash> for Collection { + fn index_mut(&mut self, index: &FolderHash) -> &mut FnvHashSet { + self.mailboxes.get_mut(index).unwrap() + } +} diff --git a/melib/src/lib.rs b/melib/src/lib.rs index d7bd908fe..bae5b70a8 100644 --- a/melib/src/lib.rs +++ b/melib/src/lib.rs @@ -119,7 +119,6 @@ mod collection; pub mod conf; pub mod email; pub mod error; -pub mod mailbox; pub mod thread; pub use crate::email::*; pub use crate::thread::*; @@ -138,11 +137,10 @@ extern crate bitflags; extern crate fnv; extern crate uuid; -pub use crate::conf::*; -pub use crate::mailbox::*; - pub use crate::backends::{Backends, RefreshEvent, RefreshEventConsumer, SpecialUsageMailbox}; -pub use crate::email::{Envelope, Flag}; +pub use crate::collection::*; +pub use crate::conf::*; +pub use crate::email::{Envelope, EnvelopeHash, Flag}; pub use crate::error::{MeliError, Result}; pub use crate::addressbook::*; diff --git a/melib/src/mailbox.rs b/melib/src/mailbox.rs deleted file mode 100644 index f32d706fc..000000000 --- a/melib/src/mailbox.rs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * meli - mailbox module. - * - * Copyright 2017 Manos Pitsidianakis - * - * This file is part of meli. - * - * meli is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * meli is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with meli. If not, see . - */ - -/*! - * Mail related code. - * - * This module handles reading emails from various backends, handling account data etc - */ - -use crate::backends::Folder; -pub use crate::collection::*; -pub use crate::email::*; -use fnv::{FnvHashMap, FnvHashSet}; - -/// `Mailbox` represents a folder of mail. -#[derive(Debug, Deserialize, Serialize, Clone, Default)] -pub struct Mailbox { - #[serde(skip_serializing, skip_deserializing)] - pub folder: Folder, - name: String, - pub envelopes: FnvHashSet, - has_sent: bool, -} - -impl Mailbox { - pub fn new(folder: Folder, envelopes: &FnvHashMap) -> Mailbox { - let name = folder.name().into(); - let envelopes = envelopes.keys().cloned().collect(); - Mailbox { - folder, - name, - envelopes, - ..Default::default() - } - } - - pub fn merge(&mut self, envelopes: &FnvHashMap) { - self.envelopes.extend(envelopes.keys().cloned()); - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn is_empty(&self) -> bool { - self.envelopes.is_empty() - } - pub fn len(&self) -> usize { - self.envelopes.len() - } - pub fn insert(&mut self, h: EnvelopeHash) { - self.envelopes.insert(h); - } - pub fn rename(&mut self, old_hash: EnvelopeHash, new_hash: EnvelopeHash) { - self.envelopes.remove(&old_hash); - - self.envelopes.insert(new_hash); - } - pub fn remove(&mut self, h: EnvelopeHash) { - self.envelopes.remove(&h); - } -} diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index c2bc68c57..48d08d45a 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -137,7 +137,7 @@ pub trait MailListingTrait: ListingTrait { ) { let account = &mut context.accounts[self.coordinates().0]; let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new(); - let folder_hash = account[self.coordinates().1].unwrap().folder.hash(); + let folder_hash = self.coordinates().1; for (_, h) in account.collection.threads[&folder_hash].thread_group_iter(thread_hash) { envs_to_set.push( account.collection.threads[&folder_hash].thread_nodes()[&h] @@ -449,7 +449,8 @@ impl Component for Listing { .list_folders() .into_iter() .filter(|folder_node| { - context.accounts[*account_index].ref_folders()[&folder_node.hash] + context.accounts[*account_index][&folder_node.hash] + .ref_folder .is_subscribed() }) .map(|f| (f.depth, f.hash)) @@ -464,7 +465,8 @@ impl Component for Listing { .list_folders() .into_iter() .filter(|folder_node| { - context.accounts[*account_index].ref_folders()[&folder_node.hash] + context.accounts[*account_index][&folder_node.hash] + .ref_folder .is_subscribed() }) .map(|f| (f.depth, f.hash)) @@ -550,10 +552,10 @@ impl Component for Listing { { /* Account might have no folders yet if it's offline */ /* Check if per-folder configuration overrides general configuration */ - if let Some(index_style) = - context.accounts.get(self.cursor_pos.0).and_then(|account| { - account.folder_confs(*folder_hash).conf_override.index_style - }) + if let Some(index_style) = context + .accounts + .get(self.cursor_pos.0) + .and_then(|account| account[folder_hash].conf.conf_override.index_style) { self.component.set_style(index_style); } else if let Some(index_style) = context @@ -870,15 +872,20 @@ impl Component for Listing { }; let account = &context.accounts[self.cursor_pos.0]; - if let Ok(m) = account[folder_hash].as_result() { - format!( + use crate::conf::accounts::MailboxStatus; + match account[&folder_hash].status { + MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!( "Mailbox: {}, Messages: {}, New: {}", - m.folder.name(), - m.envelopes.len(), - m.folder.count().ok().map(|(v, _)| v).unwrap_or(0), - ) - } else { - account[folder_hash].to_string() + account[&folder_hash].ref_folder.name(), + account.collection[&folder_hash].len(), + account[&folder_hash] + .ref_folder + .count() + .ok() + .map(|(v, _)| v) + .unwrap_or(0), + ), + MailboxStatus::Failed(_) | MailboxStatus::None => account[&folder_hash].status(), } } } @@ -905,7 +912,7 @@ impl Listing { let entries: SmallVec<[(usize, FolderHash); 16]> = a .list_folders() .into_iter() - .filter(|folder_node| a.ref_folders()[&folder_node.hash].is_subscribed()) + .filter(|folder_node| a[&folder_node.hash].ref_folder.is_subscribed()) .map(|f| (f.depth, f.hash)) .collect::<_>(); @@ -974,8 +981,11 @@ impl Listing { debug!("BUG: invalid area in print_account"); } // Each entry and its index in the account - let folders: FnvHashMap = - context.accounts[a.index].ref_folders().clone(); + let folders: FnvHashMap = context.accounts[a.index] + .folder_entries + .iter() + .map(|(&hash, entry)| (hash, entry.ref_folder.clone())) + .collect(); let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); @@ -1160,7 +1170,9 @@ impl Listing { .list_folders() .into_iter() .filter(|folder_node| { - context.accounts[self.cursor_pos.0].ref_folders()[&folder_node.hash].is_subscribed() + context.accounts[self.cursor_pos.0][&folder_node.hash] + .ref_folder + .is_subscribed() }) .map(|f| (f.depth, f.hash)) .collect::<_>(); @@ -1175,7 +1187,7 @@ impl Listing { if let Some(index_style) = context .accounts .get(self.cursor_pos.0) - .and_then(|account| account.folder_confs(*folder_hash).conf_override.index_style) + .and_then(|account| account[folder_hash].conf.conf_override.index_style) { self.component.set_style(index_style); } else if let Some(index_style) = context diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index 66d5b0c65..c6839de23 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -142,7 +142,7 @@ impl MailListingTrait for CompactListing { ret }; let message: String = - context.accounts[self.cursor_pos.0][self.cursor_pos.1].to_string(); + context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status(); self.data_columns.columns[0] = CellBuffer::new_with_context(message.len(), 1, default_cell, context); self.length = 0; @@ -650,7 +650,7 @@ impl CompactListing { hash: ThreadHash, ) -> EntryStrings { let thread = threads.thread_ref(hash); - let folder = &context.accounts[self.cursor_pos.0].folder_confs[&self.cursor_pos.1]; + let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mut tags = String::new(); let mut colors: SmallVec<[_; 8]> = SmallVec::new(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); @@ -716,9 +716,8 @@ impl CompactListing { fn redraw_list(&mut self, context: &Context, items: Box>) { let account = &context.accounts[self.cursor_pos.0]; - let mailbox = &account[self.cursor_pos.1].unwrap(); - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.cursor_pos.1]; self.order.clear(); self.selection.clear(); self.length = 0; @@ -752,7 +751,7 @@ impl CompactListing { debug!("key = {}", root_env_hash); debug!( "name = {} {}", - mailbox.name(), + account[&self.cursor_pos.1].name(), context.accounts[self.cursor_pos.0].name() ); debug!("{:#?}", context.accounts); @@ -837,7 +836,7 @@ impl CompactListing { //debug!("key = {}", root_env_hash); //debug!( // "name = {} {}", - // mailbox.name(), + // account[&self.cursor_pos.1].name(), // context.accounts[self.cursor_pos.0].name() //); //debug!("{:#?}", context.accounts); @@ -968,8 +967,7 @@ impl CompactListing { } } if self.length == 0 && self.filter_term.is_empty() { - let mailbox = &account[self.cursor_pos.1]; - let message = mailbox.to_string(); + let message = format!("{} is empty", account[&self.cursor_pos.1].name()); self.data_columns.columns[0] = CellBuffer::new_with_context(message.len(), self.length + 1, default_cell, context); write_string_to_grid( diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index c7758e8c6..b1825bce0 100644 --- a/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -128,7 +128,7 @@ impl MailListingTrait for ConversationsListing { ret }; let message: String = - context.accounts[self.cursor_pos.0][self.cursor_pos.1].to_string(); + context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status(); self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context); self.length = 0; @@ -592,7 +592,7 @@ impl ConversationsListing { hash: ThreadHash, ) -> EntryStrings { let thread = threads.thread_ref(hash); - let folder = &context.accounts[self.cursor_pos.0].folder_confs[&self.cursor_pos.1]; + let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mut tags = String::new(); let mut colors = SmallVec::new(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); @@ -658,9 +658,8 @@ impl ConversationsListing { fn redraw_list(&mut self, context: &Context, items: Box>) { let account = &context.accounts[self.cursor_pos.0]; - let mailbox = &account[self.cursor_pos.1].unwrap(); - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.cursor_pos.1]; self.order.clear(); self.selection.clear(); self.length = 0; @@ -684,7 +683,7 @@ impl ConversationsListing { debug!("key = {}", root_env_hash); debug!( "name = {} {}", - mailbox.name(), + account[&self.cursor_pos.1].name(), context.accounts[self.cursor_pos.0].name() ); debug!("{:#?}", context.accounts); @@ -852,8 +851,7 @@ impl ConversationsListing { .set_attrs(self.color_cache.theme_default.attrs); ret }; - let mailbox = &account[self.cursor_pos.1]; - let message = mailbox.to_string(); + let message = format!("{} is empty", account[&self.cursor_pos.1].name()); self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context); write_string_to_grid( &message, diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index 203a8a8de..e0cf94a64 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -142,7 +142,7 @@ impl MailListingTrait for PlainListing { ret }; let message: String = - context.accounts[self.cursor_pos.0][self.cursor_pos.1].to_string(); + context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status(); self.data_columns.columns[0] = CellBuffer::new_with_context(message.len(), 1, default_cell, context); self.length = 0; @@ -158,9 +158,7 @@ impl MailListingTrait for PlainListing { return; } } - self.local_collection = context.accounts[self.cursor_pos.0][self.cursor_pos.1] - .unwrap() - .envelopes + self.local_collection = context.accounts[self.cursor_pos.0].collection[&self.cursor_pos.1] .iter() .cloned() .collect(); @@ -169,9 +167,8 @@ impl MailListingTrait for PlainListing { .envelopes .read() .unwrap(); - self.thread_node_hashes = context.accounts[self.cursor_pos.0][self.cursor_pos.1] - .unwrap() - .envelopes + self.thread_node_hashes = context.accounts[self.cursor_pos.0].collection + [&self.cursor_pos.1] .iter() .map(|h| (*h, env_lck[h].thread())) .collect(); @@ -616,7 +613,7 @@ impl PlainListing { } } fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings { - let folder = &context.accounts[self.cursor_pos.0].folder_confs[&self.cursor_pos.1]; + let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mut tags = String::new(); let mut colors = SmallVec::new(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); @@ -664,7 +661,7 @@ impl PlainListing { fn redraw_list(&mut self, context: &Context) { let account = &context.accounts[self.cursor_pos.0]; - let mailbox = &account[self.cursor_pos.1].unwrap(); + let mailbox = &account[&self.cursor_pos.1]; self.order.clear(); self.selection.clear(); @@ -890,8 +887,7 @@ impl PlainListing { } } if self.length == 0 && self.filter_term.is_empty() { - let mailbox = &account[self.cursor_pos.1]; - let message = mailbox.to_string(); + let message = format!("{} is empty", account[&self.cursor_pos.1].name()); self.data_columns.columns[0] = CellBuffer::new_with_context(message.len(), self.length + 1, default_cell, context); write_string_to_grid( @@ -1139,10 +1135,7 @@ impl Component for PlainListing { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { let account = &context.accounts[self.cursor_pos.0]; if !account.collection.contains_key(new_hash) - || !account[self.cursor_pos.1] - .unwrap() - .envelopes - .contains(new_hash) + || !account.collection[&self.cursor_pos.1].contains(new_hash) { return false; } diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index c6bf32168..27ca503d0 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -99,7 +99,7 @@ impl MailListingTrait for ThreadListing { ret }; let message: String = - context.accounts[self.cursor_pos.0][self.cursor_pos.1].to_string(); + context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status(); self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context); self.length = 0; @@ -116,9 +116,7 @@ impl MailListingTrait for ThreadListing { } } let account = &context.accounts[self.cursor_pos.0]; - let mailbox = account[self.cursor_pos.1].unwrap(); - - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.cursor_pos.1]; self.length = threads.len(); self.locations.clear(); let default_cell = { @@ -129,7 +127,7 @@ impl MailListingTrait for ThreadListing { ret }; if self.length == 0 { - let message = format!("Folder `{}` is empty.", mailbox.folder.name()); + let message = format!("Folder `{}` is empty.", account[&self.cursor_pos.1].name()); self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context); write_string_to_grid( &message, @@ -348,12 +346,7 @@ impl ListingTrait for ThreadListing { } fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { - let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() { - context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap() - } else { - return; - }; - if mailbox.is_empty() || mailbox.len() <= idx { + if context.accounts[self.cursor_pos.0].collection[&self.cursor_pos.1].is_empty() { return; } @@ -414,12 +407,7 @@ impl ThreadListing { } fn highlight_line_self(&mut self, idx: usize, context: &Context) { - let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() { - context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap() - } else { - return; - }; - if mailbox.is_empty() { + if context.accounts[self.cursor_pos.0].collection[&self.cursor_pos.1].is_empty() { return; } if self.locations[idx] != 0 { diff --git a/src/components/mail/status.rs b/src/components/mail/status.rs index 188850720..f475557a7 100644 --- a/src/components/mail/status.rs +++ b/src/components/mail/status.rs @@ -307,10 +307,14 @@ impl StatusPanel { self.content[(2, h + y + 1)].set_ch(' '); } } - let count = a.ref_folders.values().fold((0, 0), |acc, f| { - let count = f.count().unwrap_or((0, 0)); - (acc.0 + count.0, acc.1 + count.1) - }); + let count = a + .folder_entries + .values() + .map(|entry| &entry.ref_folder) + .fold((0, 0), |acc, f| { + let count = f.count().unwrap_or((0, 0)); + (acc.0 + count.0, acc.1 + count.1) + }); let (mut column_width, _) = write_string_to_grid( &format!("Messages total {}, unseen {}", count.1, count.0), &mut self.content, @@ -357,8 +361,9 @@ impl StatusPanel { None, ); for (i, f) in a - .ref_folders + .folder_entries .values() + .map(|entry| &entry.ref_folder) .filter(|f| f.special_usage() != SpecialUsageMailbox::Normal) .enumerate() { @@ -474,8 +479,9 @@ impl Component for AccountStatus { None, ); for f in a - .ref_folders + .folder_entries .values() + .map(|entry| &entry.ref_folder) .filter(|f| f.special_usage() != SpecialUsageMailbox::Normal) { line += 1; @@ -501,7 +507,7 @@ impl Component for AccountStatus { ); line += 2; for folder_node in a.list_folders() { - let f: &Folder = &a.ref_folders()[&folder_node.hash]; + let f: &Folder = &a[&folder_node.hash].ref_folder; if f.is_subscribed() { write_string_to_grid( f.path(), diff --git a/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs index b0bf8fb6f..edd252480 100644 --- a/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -69,7 +69,7 @@ pub struct ThreadView { impl ThreadView { const DESCRIPTION: &'static str = "thread view"; /* - * coordinates: (account index, mailbox index, root set thread_node index) + * coordinates: (account index, folder_hash, root set thread_node index) * expanded_hash: optional position of expanded entry when we render the threadview. Default * expanded message is the last one. * context: current context @@ -163,8 +163,7 @@ impl ThreadView { fn initiate(&mut self, expanded_hash: Option, context: &Context) { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].unwrap(); - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.coordinates.1]; if !threads.groups.contains_key(&self.thread_group) { return; @@ -649,8 +648,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = if self.dirty { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].unwrap(); - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.coordinates.1]; let thread_root = threads .thread_group_iter(self.thread_group) .next() @@ -752,8 +750,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].unwrap(); - let threads = &account.collection.threads[&mailbox.folder.hash()]; + let threads = &account.collection.threads[&self.coordinates.1]; let thread_root = threads .thread_group_iter(self.thread_group) .next() diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index 13eebc929..0091b999f 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -30,11 +30,12 @@ use melib::backends::{ BackendOp, Backends, Folder, FolderHash, MailBackend, NotifyFn, ReadOnlyOp, RefreshEvent, RefreshEventConsumer, RefreshEventKind, SpecialUsageMailbox, }; +use melib::email::*; use melib::error::{MeliError, Result}; -use melib::mailbox::*; use melib::text_processing::GlobMatch; use melib::thread::{SortField, SortOrder, ThreadNode, ThreadNodeHash, Threads}; use melib::AddressBook; +use melib::Collection; use smallvec::SmallVec; use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification}; @@ -50,97 +51,61 @@ use std::sync::{Arc, RwLock}; pub type Worker = Option>>>; -macro_rules! mailbox { - ($idx:expr, $folders:expr) => { - $folders.get_mut(&$idx).unwrap().unwrap_mut() - }; -} - #[derive(Serialize, Debug)] -pub enum MailboxEntry { - Available(Mailbox), +pub enum MailboxStatus { + Available, Failed(MeliError), /// first argument is done work, and second is total work - Parsing(Mailbox, usize, usize), + Parsing(usize, usize), None, } -impl Default for MailboxEntry { +impl Default for MailboxStatus { fn default() -> Self { - MailboxEntry::Parsing(Mailbox::default(), 0, 0) + MailboxStatus::Parsing(0, 0) } } -impl std::fmt::Display for MailboxEntry { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{}", - match self { - MailboxEntry::Available(ref m) => m.name().to_string(), - MailboxEntry::Failed(ref e) => e.to_string(), - MailboxEntry::None => "Not subscribed, is this a bug?".to_string(), - MailboxEntry::Parsing(_, done, total) => { - format!("Parsing messages. [{}/{}]", done, total) - } - } - ) - } -} -impl MailboxEntry { +impl MailboxStatus { pub fn is_available(&self) -> bool { - if let MailboxEntry::Available(_) = self { + if let MailboxStatus::Available = self { true } else { false } } pub fn is_parsing(&self) -> bool { - if let MailboxEntry::Parsing(_, _, _) = self { + if let MailboxStatus::Parsing(_, _) = self { true } else { false } } +} - pub fn as_result(&self) -> Result<&Mailbox> { - match self { - MailboxEntry::Available(ref m) => Ok(m), - MailboxEntry::Parsing(ref m, _, _) => Ok(m), - MailboxEntry::Failed(ref e) => Err(MeliError::new(format!( - "Mailbox is not available: {}", - e.to_string() - ))), - MailboxEntry::None => Err(MeliError::new("Mailbox is not subscribed.")), +#[derive(Debug)] +pub struct FolderEntry { + pub status: MailboxStatus, + pub name: String, + pub ref_folder: Folder, + pub conf: FileFolderConf, + pub worker: Worker, +} + +impl FolderEntry { + pub fn status(&self) -> String { + match self.status { + MailboxStatus::Available => self.name().to_string(), + MailboxStatus::Failed(ref e) => e.to_string(), + MailboxStatus::None => "Not subscribed, is this a bug?".to_string(), + MailboxStatus::Parsing(done, total) => { + format!("Parsing messages. [{}/{}]", done, total) + } } } - pub fn as_mut_result(&mut self) -> Result<&mut Mailbox> { - match self { - MailboxEntry::Available(ref mut m) => Ok(m), - MailboxEntry::Parsing(ref mut m, _, _) => Ok(m), - MailboxEntry::Failed(ref e) => Err(MeliError::new(format!( - "Mailbox is not available: {}", - e.to_string() - ))), - MailboxEntry::None => Err(MeliError::new("Mailbox is not subscribed.")), - } - } - - pub fn unwrap_mut(&mut self) -> &mut Mailbox { - match self { - MailboxEntry::Available(ref mut m) => m, - MailboxEntry::Parsing(ref mut m, _, _) => m, - e => panic!(format!("mailbox is not available! {:#}", e)), - } - } - - pub fn unwrap(&self) -> &Mailbox { - match self { - MailboxEntry::Available(ref m) => m, - MailboxEntry::Parsing(ref m, _, _) => m, - e => panic!(format!("mailbox is not available! {:#}", e)), - } + pub fn name(&self) -> &str { + &self.name } } @@ -149,20 +114,13 @@ pub struct Account { pub index: usize, name: String, pub is_online: bool, - pub(crate) folders: FnvHashMap, - pub(crate) ref_folders: FnvHashMap, - pub(crate) folder_confs: FnvHashMap, + pub(crate) folder_entries: FnvHashMap, pub(crate) folders_order: Vec, - pub(crate) folder_names: FnvHashMap, tree: Vec, sent_folder: Option, pub(crate) collection: Collection, - pub(crate) address_book: AddressBook, - - pub(crate) workers: FnvHashMap, pub(crate) work_context: WorkContext, - pub(crate) settings: AccountConf, pub(crate) runtime_settings: AccountConf, pub(crate) backend: Arc>>, @@ -210,7 +168,7 @@ impl Drop for Account { permissions.set_mode(0o600); // Read/write for owner only. f.set_permissions(permissions).unwrap(); let writer = io::BufWriter::new(f); - if let Err(err) = bincode::serialize_into(writer, &self.folders) { + if let Err(err) = bincode::serialize_into(writer, &self.collection) { eprintln!("{}", err); }; }; @@ -218,26 +176,6 @@ impl Drop for Account { } } -pub struct MailboxIterator<'a> { - folders_order: &'a [FolderHash], - folders: &'a FnvHashMap, - pos: usize, -} - -impl<'a> Iterator for MailboxIterator<'a> { - type Item = &'a MailboxEntry; - - fn next(&mut self) -> Option<&'a MailboxEntry> { - if self.pos == self.folders.len() { - return None; - } - let fh = &self.folders_order[self.pos]; - - self.pos += 1; - Some(&self.folders[&fh]) - } -} - #[derive(Serialize, Debug, Clone, Default)] pub struct FolderNode { pub hash: FolderHash, @@ -295,16 +233,12 @@ impl Account { index, name, is_online: false, - folders: Default::default(), - ref_folders: Default::default(), - folder_confs: Default::default(), + folder_entries: Default::default(), folders_order: Default::default(), - folder_names: Default::default(), tree: Default::default(), address_book, sent_folder: Default::default(), collection: Default::default(), - workers: Default::default(), work_context, runtime_settings: settings.clone(), settings, @@ -325,12 +259,9 @@ impl Account { return; } }; - let mut folders: FnvHashMap = + let mut folder_entries: FnvHashMap = FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default()); let mut folders_order: Vec = Vec::with_capacity(ref_folders.len()); - let mut workers: FnvHashMap = FnvHashMap::default(); - let mut folder_names = FnvHashMap::default(); - let mut folder_confs = FnvHashMap::default(); let mut sent_folder = None; for f in ref_folders.values_mut() { @@ -355,7 +286,16 @@ impl Account { } _ => {} } - folder_confs.insert(f.hash(), conf.clone()); + folder_entries.insert( + f.hash(), + FolderEntry { + ref_folder: f.clone(), + name: f.path().to_string(), + status: MailboxStatus::None, + conf: conf.clone(), + worker: None, + }, + ); } else { let mut new = FileFolderConf::default(); new.folder_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal { @@ -368,9 +308,17 @@ impl Account { tmp }; - folder_confs.insert(f.hash(), new); + folder_entries.insert( + f.hash(), + FolderEntry { + ref_folder: f.clone(), + name: f.path().to_string(), + status: MailboxStatus::None, + conf: new, + worker: None, + }, + ); } - folder_names.insert(f.hash(), f.path().to_string()); } let mut tree: Vec = Vec::new(); @@ -378,36 +326,27 @@ impl Account { for (h, f) in ref_folders.iter() { if !f.is_subscribed() { /* Skip unsubscribed folder */ - folders.insert(*h, MailboxEntry::None); - workers.insert(*h, None); continue; } - folders.insert( - *h, - MailboxEntry::Parsing(Mailbox::new(f.clone(), &FnvHashMap::default()), 0, 0), - ); - workers.insert( - *h, - Account::new_worker( + folder_entries.entry(*h).and_modify(|entry| { + entry.status = MailboxStatus::Parsing(0, 0); + entry.worker = Account::new_worker( f.clone(), &mut self.backend, &self.work_context, self.notify_fn.clone(), - ), - ); + ); + }); + collection.mailboxes.insert(*h, Default::default()); collection.threads.insert(*h, Threads::default()); } - build_folders_order(&mut tree, &ref_folders, &mut folders_order); - self.folders = folders; - self.ref_folders = ref_folders; - self.folder_confs = folder_confs; + build_folders_order(&mut tree, &folder_entries, &mut folders_order); self.folders_order = folders_order; - self.folder_names = folder_names; + self.folder_entries = folder_entries; self.tree = tree; self.sent_folder = sent_folder; self.collection = collection; - self.workers = workers; } fn new_worker( @@ -483,7 +422,7 @@ impl Account { Some(w) } pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option { - if !self.folders[&folder_hash].is_available() { + if !self.folder_entries[&folder_hash].status.is_available() { self.event_queue.push_back((folder_hash, event)); return None; } @@ -493,7 +432,6 @@ impl Account { //let mailbox: &mut Mailbox = self.folders[idx].as_mut().unwrap().as_mut().unwrap(); match kind { RefreshEventKind::Update(old_hash, envelope) => { - mailbox!(&folder_hash, self.folders).rename(old_hash, envelope.hash()); #[cfg(feature = "sqlite3")] { if let Err(err) = crate::sqlite3::remove(old_hash).and_then(|_| { @@ -514,7 +452,6 @@ impl Account { } RefreshEventKind::Rename(old_hash, new_hash) => { debug!("rename {} to {}", old_hash, new_hash); - mailbox!(&folder_hash, self.folders).rename(old_hash, new_hash); self.collection.rename(old_hash, new_hash, folder_hash); #[cfg(feature = "sqlite3")] { @@ -538,13 +475,10 @@ impl Account { RefreshEventKind::Create(envelope) => { let env_hash = envelope.hash(); if self.collection.contains_key(&env_hash) - && mailbox!(&folder_hash, self.folders) - .envelopes - .contains(&env_hash) + && self.collection[&folder_hash].contains(&env_hash) { return None; } - mailbox!(&folder_hash, self.folders).insert(env_hash); let (is_seen, is_draft) = { (envelope.is_seen(), envelope.flags().contains(Flag::DRAFT)) }; let (subject, from) = { @@ -578,10 +512,12 @@ impl Account { self.collection.insert_reply(env_hash); } - let ref_folders: FnvHashMap = - self.backend.read().unwrap().folders().unwrap(); - let folder_conf = &self.folder_confs[&folder_hash]; - if folder_conf.folder_conf().ignore.is_true() { + if self.folder_entries[&folder_hash] + .conf + .folder_conf + .ignore + .is_true() + { return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); } @@ -606,13 +542,12 @@ impl Account { "{}\n{} {}", subject, self.name, - ref_folders[&folder_hash].name(), + self.folder_entries[&folder_hash].name() ), Some(crate::types::NotificationType::NewMail), )); } RefreshEventKind::Remove(envelope_hash) => { - mailbox!(&folder_hash, self.folders).remove(envelope_hash); #[cfg(feature = "sqlite3")] { let envelopes = self.collection.envelopes.read(); @@ -633,15 +568,15 @@ impl Account { return Some(EnvelopeRemove(envelope_hash)); } RefreshEventKind::Rescan => { - let ref_folders: FnvHashMap = - self.backend.read().unwrap().folders().unwrap(); let handle = Account::new_worker( - ref_folders[&folder_hash].clone(), + self.folder_entries[&folder_hash].ref_folder.clone(), &mut self.backend, &self.work_context, self.notify_fn.clone(), ); - self.workers.insert(folder_hash, handle); + self.folder_entries.entry(folder_hash).and_modify(|entry| { + entry.worker = handle; + }); } RefreshEventKind::Failure(e) => { debug!("RefreshEvent Failure: {}", e.to_string()); @@ -717,18 +652,14 @@ impl Account { } pub fn len(&self) -> usize { - self.folders.len() + self.tree.len() } pub fn is_empty(&self) -> bool { - self.folders.is_empty() - } - - pub fn ref_folders(&self) -> &FnvHashMap { - &self.ref_folders + self.tree.is_empty() } pub fn list_folders(&self) -> Vec { - let mut ret = Vec::with_capacity(self.folders.len()); + let mut ret = Vec::with_capacity(self.folder_entries.len()); fn rec(node: &FolderNode, ret: &mut Vec) { ret.push(node.clone()); for c in node.children.iter() { @@ -747,14 +678,12 @@ impl Account { pub fn name(&self) -> &str { &self.name } - pub fn workers(&mut self) -> &mut FnvHashMap { - &mut self.workers - } fn load_mailbox(&mut self, folder_hash: FolderHash, payload: Result>) { if payload.is_err() { - self.folders - .insert(folder_hash, MailboxEntry::Failed(payload.unwrap_err())); + self.folder_entries.entry(folder_hash).and_modify(|entry| { + entry.status = MailboxStatus::Failed(payload.unwrap_err()); + }); self.sender .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(folder_hash))) .unwrap(); @@ -765,20 +694,14 @@ impl Account { .into_iter() .map(|e| (e.hash(), e)) .collect::>(); - match self.folders.entry(folder_hash).or_default() { - MailboxEntry::Failed(_) | MailboxEntry::None => {} - MailboxEntry::Parsing(ref mut m, _, _) | MailboxEntry::Available(ref mut m) => { - m.merge(&envelopes); - if let Some(updated_folders) = - self.collection - .merge(envelopes, folder_hash, self.sent_folder) - { - for f in updated_folders { - self.sender - .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f))) - .unwrap(); - } - } + if let Some(updated_folders) = + self.collection + .merge(envelopes, folder_hash, self.sent_folder) + { + for f in updated_folders { + self.sender + .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f))) + .unwrap(); } } self.sender @@ -791,11 +714,17 @@ impl Account { return Err(0); } loop { - match self.workers.get_mut(&folder_hash).unwrap() { + match self + .folder_entries + .get_mut(&folder_hash) + .unwrap() + .worker + .as_mut() + { None => { - return if self.folders[&folder_hash].is_available() - || (self.folders[&folder_hash].is_parsing() - && self.collection.threads.contains_key(&folder_hash)) + return if self.folder_entries[&folder_hash].status.is_available() + || (self.folder_entries[&folder_hash].status.is_parsing() + && self.collection.mailboxes.contains_key(&folder_hash)) { Ok(()) } else { @@ -812,13 +741,9 @@ impl Account { } Ok(AsyncStatus::Finished) => { debug!("got finished in status for {}", folder_hash); - self.folders.entry(folder_hash).and_modify(|f| { - let m = if let MailboxEntry::Parsing(m, _, _) = f { - std::mem::replace(m, Mailbox::default()) - } else { - return; - }; - *f = MailboxEntry::Available(m); + self.folder_entries.entry(folder_hash).and_modify(|entry| { + entry.status = MailboxStatus::Available; + entry.worker = None; }); self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( @@ -826,13 +751,14 @@ impl Account { folder_hash, )))) .unwrap(); - - self.workers.insert(folder_hash, None); } Ok(AsyncStatus::ProgressReport(n)) => { - self.folders.entry(folder_hash).and_modify(|f| { - if let MailboxEntry::Parsing(_, ref mut d, _) = f { - *d += n; + self.folder_entries.entry(folder_hash).and_modify(|entry| { + match entry.status { + MailboxStatus::Parsing(ref mut d, _) => { + *d += n; + } + _ => {} } }); //return Err(n); @@ -843,9 +769,9 @@ impl Account { }, }; } - if self.folders[&folder_hash].is_available() - || (self.folders[&folder_hash].is_parsing() - && self.collection.threads.contains_key(&folder_hash)) + if self.folder_entries[&folder_hash].status.is_available() + || (self.folder_entries[&folder_hash].status.is_parsing() + && self.collection.mailboxes.contains_key(&folder_hash)) { Ok(()) } else { @@ -909,13 +835,6 @@ impl Account { } self.backend.write().unwrap().save(bytes, folder, flags) } - pub fn iter_mailboxes(&self) -> MailboxIterator { - MailboxIterator { - folders_order: &self.folders_order, - folders: &self.folders, - pos: 0, - } - } pub fn contains_key(&self, h: EnvelopeHash) -> bool { self.collection.contains_key(&h) @@ -966,39 +885,40 @@ impl Account { tmp }; - self.folder_confs.insert(folder.hash(), new); - self.folder_names - .insert(folder.hash(), folder.path().to_string()); - self.folders.insert( - folder.hash(), - MailboxEntry::Parsing( - Mailbox::new(folder.clone(), &FnvHashMap::default()), - 0, - 0, - ), - ); - self.workers.insert( - folder.hash(), - Account::new_worker( - folder.clone(), - &mut self.backend, - &self.work_context, - self.notify_fn.clone(), - ), + let folder_hash = folder.hash(); + self.folder_entries.insert( + folder_hash, + FolderEntry { + name: folder.path().to_string(), + status: MailboxStatus::Parsing(0, 0), + conf: new, + worker: Account::new_worker( + folder.clone(), + &mut self.backend, + &self.work_context, + self.notify_fn.clone(), + ), + ref_folder: folder, + }, ); self.collection .threads - .insert(folder.hash(), Threads::default()); - self.ref_folders = self.backend.read().unwrap().folders()?; - build_folders_order(&mut self.tree, &self.ref_folders, &mut self.folders_order); + .insert(folder_hash, Threads::default()); + build_folders_order( + &mut self.tree, + &self.folder_entries, + &mut self.folders_order, + ); Ok(format!("`{}` successfully created.", &path)) } FolderOperation::Delete(path) => { - if self.ref_folders.len() == 1 { + if self.folder_entries.len() == 1 { return Err(MeliError::new("Cannot delete only mailbox.")); } - let folder_hash = if let Some((folder_hash, _)) = - self.ref_folders.iter().find(|(_, f)| f.path() == path) + let folder_hash = if let Some((folder_hash, _)) = self + .folder_entries + .iter() + .find(|(_, f)| f.ref_folder.path() == path) { *folder_hash } else { @@ -1011,13 +931,9 @@ impl Account { folder_hash, )))) .unwrap(); - self.folders.remove(&folder_hash); - self.ref_folders = self.backend.read().unwrap().folders()?; - self.folder_confs.remove(&folder_hash); if let Some(pos) = self.folders_order.iter().position(|&h| h == folder_hash) { self.folders_order.remove(pos); } - self.folder_names.remove(&folder_hash); if let Some(pos) = self.tree.iter().position(|n| n.hash == folder_hash) { self.tree.remove(pos); } @@ -1025,7 +941,9 @@ impl Account { self.sent_folder = None; } self.collection.threads.remove(&folder_hash); - self.workers.remove(&folder_hash); // FIXME Kill worker as well + self.collection.mailboxes.remove(&folder_hash); + self.folder_entries.remove(&folder_hash); + // FIXME Kill worker as well // FIXME remove from settings as well @@ -1038,29 +956,13 @@ impl Account { } } - pub fn folder_confs(&self, folder_hash: FolderHash) -> &FileFolderConf { - &self.folder_confs[&folder_hash] - } - - pub fn sent_folder(&self) -> &str { - let sent_folder = self - .folder_confs - .iter() - .find(|(_, f)| f.folder_conf().usage == Some(SpecialUsageMailbox::Sent)); - if let Some(sent_folder) = sent_folder.as_ref() { - &self.folder_names[&sent_folder.0] - } else { - "" - } - } - pub fn special_use_folder(&self, special_use: SpecialUsageMailbox) -> Option<&str> { let ret = self - .folder_confs + .folder_entries .iter() - .find(|(_, f)| f.folder_conf().usage == Some(special_use)); + .find(|(_, f)| f.conf.folder_conf().usage == Some(special_use)); if let Some(ret) = ret.as_ref() { - Some(&self.folder_names[&ret.0]) + Some(ret.1.name()) } else { None } @@ -1117,7 +1019,7 @@ impl Account { let mut ret = SmallVec::new(); let envelopes = self.collection.envelopes.read().unwrap(); - for &env_hash in &self.folders[&folder_hash].as_result()?.envelopes { + for &env_hash in &self.collection[&folder_hash].iter() { let envelope = &envelopes[&env_hash]; if envelope.subject().contains(&search_term) { ret.push(env_hash); @@ -1140,32 +1042,32 @@ impl Account { } } -impl Index for Account { - type Output = MailboxEntry; - fn index(&self, index: FolderHash) -> &MailboxEntry { - &self.folders[&index] +impl Index<&FolderHash> for Account { + type Output = FolderEntry; + fn index(&self, index: &FolderHash) -> &FolderEntry { + &self.folder_entries[index] } } -impl IndexMut for Account { - fn index_mut(&mut self, index: FolderHash) -> &mut MailboxEntry { - self.folders.get_mut(&index).unwrap() +impl IndexMut<&FolderHash> for Account { + fn index_mut(&mut self, index: &FolderHash) -> &mut FolderEntry { + self.folder_entries.get_mut(index).unwrap() } } fn build_folders_order( tree: &mut Vec, - ref_folders: &FnvHashMap, + folder_entries: &FnvHashMap, folders_order: &mut Vec, ) { let mut stack: SmallVec<[FolderHash; 8]> = SmallVec::new(); tree.clear(); folders_order.clear(); - for (h, f) in ref_folders.iter() { - if f.parent().is_none() { + for (h, f) in folder_entries.iter() { + if f.ref_folder.parent().is_none() { fn rec( h: FolderHash, - ref_folders: &FnvHashMap, + folder_entries: &FnvHashMap, depth: usize, ) -> FolderNode { let mut node = FolderNode { @@ -1173,18 +1075,18 @@ fn build_folders_order( children: Vec::new(), depth, }; - for &c in ref_folders[&h].children() { - node.children.push(rec(c, ref_folders, depth + 1)); + for &c in folder_entries[&h].ref_folder.children() { + node.children.push(rec(c, folder_entries, depth + 1)); } node }; - tree.push(rec(*h, &ref_folders, 0)); - for &c in f.children() { + tree.push(rec(*h, &folder_entries, 0)); + for &c in f.ref_folder.children() { stack.push(c); } while let Some(next) = stack.pop() { - for c in ref_folders[&next].children() { + for c in folder_entries[&next].ref_folder.children() { stack.push(*c); } } @@ -1192,14 +1094,23 @@ fn build_folders_order( } tree.sort_unstable_by(|a, b| { - if ref_folders[&b.hash].path().eq_ignore_ascii_case("INBOX") { + if folder_entries[&b.hash] + .ref_folder + .path() + .eq_ignore_ascii_case("INBOX") + { std::cmp::Ordering::Greater - } else if ref_folders[&a.hash].path().eq_ignore_ascii_case("INBOX") { + } else if folder_entries[&a.hash] + .ref_folder + .path() + .eq_ignore_ascii_case("INBOX") + { std::cmp::Ordering::Less } else { - ref_folders[&a.hash] + folder_entries[&a.hash] + .ref_folder .path() - .cmp(&ref_folders[&b.hash].path()) + .cmp(&folder_entries[&b.hash].ref_folder.path()) } }); @@ -1207,14 +1118,23 @@ fn build_folders_order( for n in tree.iter_mut() { folders_order.push(n.hash); n.children.sort_unstable_by(|a, b| { - if ref_folders[&b.hash].path().eq_ignore_ascii_case("INBOX") { + if folder_entries[&b.hash] + .ref_folder + .path() + .eq_ignore_ascii_case("INBOX") + { std::cmp::Ordering::Greater - } else if ref_folders[&a.hash].path().eq_ignore_ascii_case("INBOX") { + } else if folder_entries[&a.hash] + .ref_folder + .path() + .eq_ignore_ascii_case("INBOX") + { std::cmp::Ordering::Less } else { - ref_folders[&a.hash] + folder_entries[&a.hash] + .ref_folder .path() - .cmp(&ref_folders[&b.hash].path()) + .cmp(&folder_entries[&b.hash].ref_folder.path()) } }); stack.extend(n.children.iter().rev().map(Some)); diff --git a/src/state.rs b/src/state.rs index 656ef13fb..433637231 100644 --- a/src/state.rs +++ b/src/state.rs @@ -153,7 +153,7 @@ impl Context { debug!( "hash & folder: {:?} {}", folder_node.hash, - accounts[account_pos].ref_folders()[&folder_node.hash].name() + accounts[account_pos][&folder_node.hash].name() ); mailbox_hashes.insert(folder_node.hash, account_pos); }