melib,ui: add MailboxEntry enum

Use an enum to describe a mailbox's state in ui::conf::Account instead
of Result.
embed
Manos Pitsidianakis 2019-07-28 18:52:45 +03:00
parent 5b679be782
commit 8a0e702127
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
12 changed files with 176 additions and 144 deletions

View File

@ -106,13 +106,10 @@ impl Collection {
} }
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
let env = self.envelopes.entry(new_hash).or_default() as *mut Envelope; self.threads
unsafe { .entry(folder_hash)
self.threads .or_default()
.entry(folder_hash) .insert(&mut self.envelopes, new_hash);
.or_default()
.insert(&mut (*env), &self.envelopes);
}
for (h, t) in self.threads.iter_mut() { for (h, t) in self.threads.iter_mut() {
if *h == folder_hash { if *h == folder_hash {
continue; continue;
@ -127,7 +124,7 @@ impl Collection {
&mut self, &mut self,
mut envelopes: FnvHashMap<EnvelopeHash, Envelope>, mut envelopes: FnvHashMap<EnvelopeHash, Envelope>,
folder_hash: FolderHash, folder_hash: FolderHash,
mailbox: &mut Result<Mailbox>, mailbox: &mut Mailbox,
sent_folder: Option<FolderHash>, sent_folder: Option<FolderHash>,
) { ) {
self.sent_folder = sent_folder; self.sent_folder = sent_folder;
@ -135,9 +132,7 @@ impl Collection {
if self.message_ids.contains_key(e.message_id().raw()) { if self.message_ids.contains_key(e.message_id().raw()) {
/* skip duplicates until a better way to handle them is found. */ /* skip duplicates until a better way to handle them is found. */
//FIXME //FIXME
if let Ok(mailbox) = mailbox.as_mut() { mailbox.remove(h);
mailbox.remove(h);
}
false false
} else { } else {
self.message_ids.insert(e.message_id().raw().to_vec(), h); self.message_ids.insert(e.message_id().raw().to_vec(), h);
@ -214,13 +209,10 @@ impl Collection {
} }
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
let env = self.envelopes.entry(new_hash).or_default() as *mut Envelope; self.threads
unsafe { .entry(folder_hash)
self.threads .or_default()
.entry(folder_hash) .insert(&mut self.envelopes, new_hash);
.or_default()
.insert(&mut (*env), &self.envelopes);
}
for (h, t) in self.threads.iter_mut() { for (h, t) in self.threads.iter_mut() {
if *h == folder_hash { if *h == folder_hash {
continue; continue;
@ -236,10 +228,17 @@ impl Collection {
self.message_ids self.message_ids
.insert(envelope.message_id().raw().to_vec(), hash); .insert(envelope.message_id().raw().to_vec(), hash);
self.envelopes.insert(hash, envelope); self.envelopes.insert(hash, envelope);
self.threads if !self
.threads
.entry(folder_hash) .entry(folder_hash)
.or_default() .or_default()
.insert_reply(&mut self.envelopes, hash); .insert_reply(&mut self.envelopes, hash)
{
self.threads
.entry(folder_hash)
.or_default()
.insert(&mut self.envelopes, hash);
}
&self.envelopes[&hash] &self.envelopes[&hash]
} }
pub fn insert_reply(&mut self, env_hash: EnvelopeHash) { pub fn insert_reply(&mut self, env_hash: EnvelopeHash) {

View File

@ -27,7 +27,6 @@
use crate::backends::Folder; use crate::backends::Folder;
pub use crate::email::*; pub use crate::email::*;
use crate::error::Result;
use crate::thread::ThreadHash; use crate::thread::ThreadHash;
pub use crate::thread::{SortField, SortOrder, ThreadNode, Threads}; pub use crate::thread::{SortField, SortOrder, ThreadNode, Threads};
@ -47,19 +46,15 @@ pub struct Mailbox {
} }
impl Mailbox { impl Mailbox {
pub fn new( pub fn new(folder: Folder, envelopes: &FnvHashMap<EnvelopeHash, Envelope>) -> Mailbox {
folder: Folder,
envelopes: Result<&FnvHashMap<EnvelopeHash, Envelope>>,
) -> Result<Mailbox> {
let envelopes = envelopes?;
let name = folder.name().into(); let name = folder.name().into();
let envelopes = envelopes.keys().cloned().collect(); let envelopes = envelopes.keys().cloned().collect();
Ok(Mailbox { Mailbox {
folder, folder,
name, name,
envelopes, envelopes,
..Default::default() ..Default::default()
}) }
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {

View File

@ -938,12 +938,7 @@ impl Threads {
new_hash_set.difference(&self.hash_set).cloned().collect(); new_hash_set.difference(&self.hash_set).cloned().collect();
for h in difference { for h in difference {
debug!("inserting {}", envelopes[&h].subject()); debug!("inserting {}", envelopes[&h].subject());
let env = envelopes.entry(h).or_default() as *mut Envelope; self.insert(envelopes, h);
unsafe {
// `envelopes` is borrowed immutably and `insert` only changes the envelope's
// `thread` field.
self.insert(&mut (*env), envelopes);
}
} }
self.create_root_set(envelopes); self.create_root_set(envelopes);
@ -953,10 +948,10 @@ impl Threads {
tree.retain(|t| root_set.contains(&t.id)); tree.retain(|t| root_set.contains(&t.id));
} }
pub fn insert(&mut self, envelope: &mut Envelope, envelopes: &Envelopes) { pub fn insert(&mut self, envelopes: &mut Envelopes, env_hash: EnvelopeHash) {
self.link_envelope(envelope); self.link_envelope(envelopes.get_mut(&env_hash).unwrap());
{ {
let id = self.message_ids[envelope.message_id().raw()]; let id = self.message_ids[envelopes[&env_hash].message_id().raw()];
self.rebuild_thread(id, envelopes); self.rebuild_thread(id, envelopes);
} }
} }

View File

@ -143,7 +143,7 @@ impl Composer {
context: &Context, context: &Context,
) -> Self { ) -> Self {
let account = &context.accounts[coordinates.0]; let account = &context.accounts[coordinates.0];
let mailbox = &account[coordinates.1].as_ref().unwrap(); let mailbox = &account[coordinates.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
let thread_nodes = &threads.thread_nodes(); let thread_nodes = &threads.thread_nodes();
let mut ret = Composer::default(); let mut ret = Composer::default();

View File

@ -532,12 +532,16 @@ impl Listing {
Ok(_) => { Ok(_) => {
let account = &context.accounts[index]; let account = &context.accounts[index];
let count = account[entries[&folder_idx].hash()] let count = account[entries[&folder_idx].hash()]
.as_ref()
.unwrap() .unwrap()
.envelopes .envelopes
.iter() .iter()
.map(|h| &account.collection[&h]) .filter_map(|h| {
.filter(|e| !e.is_seen()) if account.collection[&h].is_seen() {
None
} else {
Some(())
}
})
.count(); .count();
let len = s.len(); let len = s.len();
s.insert_str( s.insert_str(

View File

@ -539,13 +539,14 @@ impl CompactListing {
// Get mailbox as a reference. // Get mailbox as a reference.
// //
match context.accounts[self.cursor_pos.0].status(folder_hash) { match context.accounts[self.cursor_pos.0].status(folder_hash) {
Ok(_) => {} Ok(()) => {}
Err(_) => { Err(_) => {
let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string();
self.data_columns.columns[0] = self.data_columns.columns[0] =
CellBuffer::new("Loading.".len(), 1, Cell::with_char(' ')); CellBuffer::new(message.len(), 1, Cell::with_char(' '));
self.length = 0; self.length = 0;
write_string_to_grid( write_string_to_grid(
"Loading.", message.as_str(),
&mut self.data_columns.columns[0], &mut self.data_columns.columns[0],
Color::Default, Color::Default,
Color::Default, Color::Default,
@ -562,7 +563,7 @@ impl CompactListing {
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); let mailbox = &account[self.cursor_pos.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
self.order.clear(); self.order.clear();
@ -778,7 +779,11 @@ impl CompactListing {
return; return;
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); let mailbox = if account[self.cursor_pos.1].is_available() {
account[self.cursor_pos.1].unwrap()
} else {
return;
};
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
self.length = 0; self.length = 0;
@ -913,10 +918,7 @@ impl CompactListing {
} }
fn get_envelope_under_cursor(&self, cursor: usize, context: &Context) -> EnvelopeHash { fn get_envelope_under_cursor(&self, cursor: usize, context: &Context) -> EnvelopeHash {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let folder_hash = account[self.cursor_pos.1] let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
.as_ref()
.map(|m| m.folder.hash())
.unwrap();
let threads = &account.collection.threads[&folder_hash]; let threads = &account.collection.threads[&folder_hash];
if self.filtered_selection.is_empty() { if self.filtered_selection.is_empty() {
let thread_node = threads.root_set(cursor); let thread_node = threads.root_set(cursor);
@ -1035,10 +1037,7 @@ impl Component for CompactListing {
.thread() .thread()
.clone() .clone()
}; };
let folder_hash = account[self.cursor_pos.1] let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
.as_ref()
.map(|m| m.folder.hash())
.unwrap();
let threads = &account.collection.threads[&folder_hash]; let threads = &account.collection.threads[&folder_hash];
let root_thread_index = threads.root_iter().position(|t| t == thread_hash); let root_thread_index = threads.root_iter().position(|t| t == thread_hash);
if let Some(pos) = root_thread_index { if let Some(pos) = root_thread_index {
@ -1168,10 +1167,7 @@ impl Component for CompactListing {
let i = self.get_envelope_under_cursor(self.cursor_pos.2, context); let i = self.get_envelope_under_cursor(self.cursor_pos.2, context);
let account = &mut context.accounts[self.cursor_pos.0]; let account = &mut context.accounts[self.cursor_pos.0];
let thread_hash = account.get_env(&i).thread(); let thread_hash = account.get_env(&i).thread();
let folder_hash = account[self.cursor_pos.1] let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash();
.as_ref()
.map(|m| m.folder.hash())
.unwrap();
let threads = account.collection.threads.entry(folder_hash).or_default(); let threads = account.collection.threads.entry(folder_hash).or_default();
let thread_group = threads.thread_nodes()[&thread_hash].thread_group(); let thread_group = threads.thread_nodes()[&thread_hash].thread_group();
let thread_group = threads.find(thread_group); let thread_group = threads.find(thread_group);

View File

@ -266,10 +266,11 @@ impl PlainListing {
match context.accounts[self.cursor_pos.0].status(folder_hash) { match context.accounts[self.cursor_pos.0].status(folder_hash) {
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' ')); let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string();
self.content = CellBuffer::new(message.len(), 1, Cell::with_char(' '));
self.length = 0; self.length = 0;
write_string_to_grid( write_string_to_grid(
"Loading.", message.as_str(),
&mut self.content, &mut self.content,
Color::Default, Color::Default,
Color::Default, Color::Default,
@ -280,7 +281,7 @@ impl PlainListing {
} }
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let mailbox = &account[self.cursor_pos.1].as_ref().unwrap(); let mailbox = &account[self.cursor_pos.1].unwrap();
self.length = mailbox.len(); self.length = mailbox.len();
self.content = CellBuffer::new(MAX_COLS, self.length + 1, Cell::with_char(' ')); self.content = CellBuffer::new(MAX_COLS, self.length + 1, Cell::with_char(' '));

View File

@ -137,9 +137,11 @@ impl ListingTrait for ThreadListing {
} }
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() {
.as_ref() context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap()
.unwrap(); } else {
return;
};
if mailbox.is_empty() || mailbox.len() <= idx { if mailbox.is_empty() || mailbox.len() <= idx {
return; return;
} }
@ -222,10 +224,11 @@ impl ThreadListing {
match context.accounts[self.cursor_pos.0].status(folder_hash) { match context.accounts[self.cursor_pos.0].status(folder_hash) {
Ok(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' ')); let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string();
self.content = CellBuffer::new(message.len(), 1, Cell::with_char(' '));
self.length = 0; self.length = 0;
write_string_to_grid( write_string_to_grid(
"Loading.", message.as_str(),
&mut self.content, &mut self.content,
Color::Default, Color::Default,
Color::Default, Color::Default,
@ -236,7 +239,7 @@ impl ThreadListing {
} }
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); let mailbox = account[self.cursor_pos.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
self.length = threads.len(); self.length = threads.len();
@ -328,9 +331,11 @@ impl ThreadListing {
} }
fn highlight_line_self(&mut self, idx: usize, context: &Context) { fn highlight_line_self(&mut self, idx: usize, context: &Context) {
let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() {
.as_ref() context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap()
.unwrap(); } else {
return;
};
if mailbox.is_empty() { if mailbox.is_empty() {
return; return;
} }

View File

@ -158,7 +158,7 @@ impl ThreadView {
fn initiate(&mut self, expanded_hash: Option<ThreadHash>, context: &Context) { fn initiate(&mut self, expanded_hash: Option<ThreadHash>, context: &Context) {
/* stack to push thread messages in order in order to pop and print them later */ /* stack to push thread messages in order in order to pop and print them later */
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let mailbox = &account[self.coordinates.1].as_ref().unwrap(); let mailbox = &account[self.coordinates.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
let thread_iter = threads.thread_iter(self.coordinates.2); let thread_iter = threads.thread_iter(self.coordinates.2);
@ -607,7 +607,7 @@ impl ThreadView {
/* First draw the thread subject on the first row */ /* First draw the thread subject on the first row */
let y = if self.dirty { let y = if self.dirty {
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let mailbox = &account[self.coordinates.1].as_ref().unwrap(); let mailbox = &account[self.coordinates.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)];
let i = if let Some(i) = thread_node.message() { let i = if let Some(i) = thread_node.message() {
@ -688,7 +688,7 @@ impl ThreadView {
/* First draw the thread subject on the first row */ /* First draw the thread subject on the first row */
let y = { let y = {
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let mailbox = &account[self.coordinates.1].as_ref().unwrap(); let mailbox = &account[self.coordinates.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)];
let i = if let Some(i) = thread_node.message() { let i = if let Some(i) = thread_node.message() {
@ -904,7 +904,7 @@ impl Component for ThreadView {
UIEvent::Input(Key::Char('e')) => { UIEvent::Input(Key::Char('e')) => {
{ {
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let mailbox = &account[self.coordinates.1].as_ref().unwrap(); let mailbox = &account[self.coordinates.1].unwrap();
let threads = &account.collection.threads[&mailbox.folder.hash()]; let threads = &account.collection.threads[&mailbox.folder.hash()];
let thread_node = let thread_node =
&threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; &threads.thread_nodes()[&threads.root_set(self.coordinates.2)];

View File

@ -921,7 +921,7 @@ impl Component for StatusBar {
} }
} }
let account = &context.accounts[*idx_a]; let account = &context.accounts[*idx_a];
let m = &account[*idx_f].as_ref().unwrap(); let m = &account[*idx_f].unwrap();
self.status = format!( self.status = format!(
"{} | Mailbox: {}, Messages: {}, New: {}", "{} | Mailbox: {}, Messages: {}, New: {}",
self.mode, self.mode,

View File

@ -46,24 +46,75 @@ use std::ops::{Index, IndexMut};
use std::result; use std::result;
use std::sync::Arc; use std::sync::Arc;
pub type Worker = Option<Async<(Result<FnvHashMap<EnvelopeHash, Envelope>>, Result<Mailbox>)>>; pub type Worker = Option<Async<Result<(FnvHashMap<EnvelopeHash, Envelope>, Mailbox)>>>;
macro_rules! mailbox { macro_rules! mailbox {
($idx:expr, $folders:expr) => { ($idx:expr, $folders:expr) => {
$folders $folders.get_mut(&$idx).unwrap().unwrap_mut()
.get_mut(&$idx)
.unwrap()
.as_mut()
.unwrap()
.as_mut()
.unwrap()
}; };
} }
#[derive(Serialize, Debug)]
pub enum MailboxEntry {
Available(Mailbox),
Failed(MeliError),
/// first argument is done work, and second is total work
Parsing(usize, usize),
/// first argument is done work, and second is total work
Threading(usize, usize),
}
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::Parsing(done, total) => {
format!("Parsing messages. [{}/{}]", done, total)
}
MailboxEntry::Threading(done, total) => {
format!("Calculating threads. [{}/{}]", done, total)
}
}
)
}
}
impl MailboxEntry {
pub fn is_available(&self) -> bool {
if let MailboxEntry::Available(_) = self {
true
} else {
false
}
}
pub fn is_parsing(&self) -> bool {
if let MailboxEntry::Parsing(_, _) = self {
true
} else {
false
}
}
pub fn unwrap_mut(&mut self) -> &mut Mailbox {
match self {
MailboxEntry::Available(ref mut m) => m,
e => panic!(format!("mailbox is not available! {:#}", e)),
}
}
pub fn unwrap(&self) -> &Mailbox {
match self {
MailboxEntry::Available(ref m) => m,
e => panic!(format!("mailbox is not available! {:#}", e)),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Account { pub struct Account {
name: String, name: String,
pub(crate) folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>>, pub(crate) folders: FnvHashMap<FolderHash, MailboxEntry>,
pub(crate) folders_order: Vec<FolderHash>, pub(crate) folders_order: Vec<FolderHash>,
folder_names: FnvHashMap<FolderHash, String>, folder_names: FnvHashMap<FolderHash, String>,
tree: Vec<FolderNode>, tree: Vec<FolderNode>,
@ -113,31 +164,21 @@ impl Drop for Account {
pub struct MailboxIterator<'a> { pub struct MailboxIterator<'a> {
folders_order: &'a [FolderHash], folders_order: &'a [FolderHash],
folders: &'a FnvHashMap<FolderHash, Option<Result<Mailbox>>>, folders: &'a FnvHashMap<FolderHash, MailboxEntry>,
pos: usize, pos: usize,
} }
impl<'a> Iterator for MailboxIterator<'a> { impl<'a> Iterator for MailboxIterator<'a> {
type Item = Option<&'a Mailbox>; type Item = &'a MailboxEntry;
fn next(&mut self) -> Option<Option<&'a Mailbox>> { fn next(&mut self) -> Option<&'a MailboxEntry> {
if self.pos == self.folders.len() { if self.pos == self.folders.len() {
return None; return None;
} }
let fh = &self.folders_order[self.pos]; let fh = &self.folders_order[self.pos];
if self.pos == self.folders.len() {
return None;
}
self.pos += 1; self.pos += 1;
if self.folders[&fh].is_none() { Some(&self.folders[&fh])
return Some(None);
}
if let Some(Err(_)) = self.folders[&fh] {
return Some(None);
}
Some(Some(self.folders[&fh].as_ref().unwrap().as_ref().unwrap()))
} }
} }
@ -156,7 +197,7 @@ impl Account {
) -> Self { ) -> Self {
let mut backend = map.get(settings.account().format())(settings.account()); let mut backend = map.get(settings.account().format())(settings.account());
let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders(); let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders();
let mut folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>> = let mut folders: FnvHashMap<FolderHash, MailboxEntry> =
FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default()); FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default());
let mut folders_order: Vec<FolderHash> = Vec::with_capacity(ref_folders.len()); let mut folders_order: Vec<FolderHash> = Vec::with_capacity(ref_folders.len());
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default(); let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
@ -208,7 +249,7 @@ impl Account {
} }
} }
} }
folders.insert(*h, None); folders.insert(*h, MailboxEntry::Parsing(0, 0));
workers.insert( workers.insert(
*h, *h,
Account::new_worker(f.clone(), &mut backend, notify_fn.clone()), Account::new_worker(f.clone(), &mut backend, notify_fn.clone()),
@ -282,15 +323,19 @@ impl Account {
.collect::<FnvHashMap<EnvelopeHash, Envelope>>() .collect::<FnvHashMap<EnvelopeHash, Envelope>>()
}); });
let hash = folder.hash(); let hash = folder.hash();
let m = Mailbox::new(folder, envelopes.as_ref().map_err(Clone::clone)); if envelopes.is_err() {
tx.send(AsyncStatus::Payload((envelopes, m))); tx.send(AsyncStatus::Payload(Err(envelopes.unwrap_err())));
notify_fn.notify(hash);
return;
}
let envelopes = envelopes.unwrap();
let m = Mailbox::new(folder, &envelopes);
tx.send(AsyncStatus::Payload(Ok((envelopes, m))));
notify_fn.notify(hash); notify_fn.notify(hash);
}))) })))
} }
pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> { pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> {
if self.folders[&folder_hash].is_none() if !self.folders[&folder_hash].is_available() {
|| self.folders[&folder_hash].as_ref().unwrap().is_err()
{
self.event_queue.push_back((folder_hash, event)); self.event_queue.push_back((folder_hash, event));
return None; return None;
} }
@ -306,15 +351,13 @@ impl Account {
} }
RefreshEventKind::Rename(old_hash, new_hash) => { RefreshEventKind::Rename(old_hash, new_hash) => {
debug!("rename {} to {}", old_hash, new_hash); debug!("rename {} to {}", old_hash, new_hash);
let mailbox = mailbox!(&folder_hash, self.folders); mailbox!(&folder_hash, self.folders).rename(old_hash, new_hash);
mailbox.rename(old_hash, new_hash);
self.collection.rename(old_hash, new_hash, folder_hash); self.collection.rename(old_hash, new_hash, folder_hash);
return Some(EnvelopeRename(old_hash, new_hash)); return Some(EnvelopeRename(old_hash, new_hash));
} }
RefreshEventKind::Create(envelope) => { RefreshEventKind::Create(envelope) => {
let env_hash = envelope.hash(); let env_hash = envelope.hash();
let mailbox = mailbox!(&folder_hash, self.folders); mailbox!(&folder_hash, self.folders).insert(env_hash);
mailbox.insert(env_hash);
self.collection.insert(*envelope, folder_hash); self.collection.insert(*envelope, folder_hash);
if self if self
.sent_folder .sent_folder
@ -367,7 +410,7 @@ impl Account {
pub fn watch(&self, r: RefreshEventConsumer) { pub fn watch(&self, r: RefreshEventConsumer) {
self.backend.watch(r).unwrap(); self.backend.watch(r).unwrap();
} }
/* This doesn't represent the number of correctly parsed mailboxes though */
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.folders.len() self.folders.len()
} }
@ -417,17 +460,18 @@ impl Account {
fn load_mailbox( fn load_mailbox(
&mut self, &mut self,
folder_hash: FolderHash, folder_hash: FolderHash,
mailbox: (Result<FnvHashMap<EnvelopeHash, Envelope>>, Result<Mailbox>), payload: (Result<(FnvHashMap<EnvelopeHash, Envelope>, Mailbox)>),
) { ) {
let (envs, mut mailbox) = mailbox; if payload.is_err() {
if envs.is_err() { self.folders
self.folders.insert(folder_hash, None); .insert(folder_hash, MailboxEntry::Failed(payload.unwrap_err()));
return; return;
} }
let envs = envs.unwrap(); let (envelopes, mut mailbox) = payload.unwrap();
self.collection self.collection
.merge(envs, folder_hash, &mut mailbox, self.sent_folder); .merge(envelopes, folder_hash, &mut mailbox, self.sent_folder);
self.folders.insert(folder_hash, Some(mailbox)); self.folders
.insert(folder_hash, MailboxEntry::Available(mailbox));
} }
pub fn status(&mut self, folder_hash: FolderHash) -> result::Result<(), usize> { pub fn status(&mut self, folder_hash: FolderHash) -> result::Result<(), usize> {
@ -435,12 +479,17 @@ impl Account {
None => { None => {
return Ok(()); return Ok(());
} }
Some(ref mut w) if self.folders[&folder_hash].is_none() => match w.poll() { Some(ref mut w) if self.folders[&folder_hash].is_parsing() => match w.poll() {
Ok(AsyncStatus::NoUpdate) => { Ok(AsyncStatus::NoUpdate) => {
return Err(0); return Err(0);
} }
Ok(AsyncStatus::Finished) => {} Ok(AsyncStatus::Finished) => {}
Ok(AsyncStatus::ProgressReport(n)) => { Ok(AsyncStatus::ProgressReport(n)) => {
self.folders.entry(folder_hash).and_modify(|f| {
if let MailboxEntry::Parsing(ref mut d, _) = f {
*d += n;
}
});
return Err(n); return Err(n);
} }
_ => { _ => {
@ -496,7 +545,7 @@ impl Account {
} }
pub fn operation(&self, h: EnvelopeHash) -> Box<BackendOp> { pub fn operation(&self, h: EnvelopeHash) -> Box<BackendOp> {
for mailbox in self.folders.values() { for mailbox in self.folders.values() {
if let Some(Ok(m)) = mailbox { if let MailboxEntry::Available(ref m) = mailbox {
if m.envelopes.contains(&h) { if m.envelopes.contains(&h) {
let operation = self.backend.operation(h, m.folder.hash()); let operation = self.backend.operation(h, m.folder.hash());
if self.settings.account.read_only() { if self.settings.account.read_only() {
@ -542,41 +591,28 @@ impl Account {
} }
impl Index<FolderHash> for Account { impl Index<FolderHash> for Account {
type Output = Result<Mailbox>; type Output = MailboxEntry;
fn index(&self, index: FolderHash) -> &Result<Mailbox> { fn index(&self, index: FolderHash) -> &MailboxEntry {
&self.folders[&index] &self.folders[&index]
.as_ref()
.expect("BUG: Requested mailbox that is not yet available.")
} }
} }
/// Will panic if mailbox hasn't loaded, ask `status()` first.
impl IndexMut<FolderHash> for Account { impl IndexMut<FolderHash> for Account {
fn index_mut(&mut self, index: FolderHash) -> &mut Result<Mailbox> { fn index_mut(&mut self, index: FolderHash) -> &mut MailboxEntry {
self.folders self.folders.get_mut(&index).unwrap()
.get_mut(&index)
.unwrap()
.as_mut()
.expect("BUG: Requested mailbox that is not yet available.")
} }
} }
impl Index<usize> for Account { impl Index<usize> for Account {
type Output = Result<Mailbox>; type Output = MailboxEntry;
fn index(&self, index: usize) -> &Result<Mailbox> { fn index(&self, index: usize) -> &MailboxEntry {
&self.folders[&self.folders_order[index]] &self.folders[&self.folders_order[index]]
.as_ref()
.expect("BUG: Requested mailbox that is not yet available.")
} }
} }
/// Will panic if mailbox hasn't loaded, ask `status()` first. /// Will panic if mailbox hasn't loaded, ask `status()` first.
impl IndexMut<usize> for Account { impl IndexMut<usize> for Account {
fn index_mut(&mut self, index: usize) -> &mut Result<Mailbox> { fn index_mut(&mut self, index: usize) -> &mut MailboxEntry {
self.folders self.folders.get_mut(&self.folders_order[index]).unwrap()
.get_mut(&self.folders_order[index])
.unwrap()
.as_mut()
.expect("BUG: Requested mailbox that is not yet available.")
} }
} }

View File

@ -276,11 +276,12 @@ impl State {
return; return;
} }
if let Some(notification) = self.context.accounts[idxa].reload(event, hash) { if let Some(notification) = self.context.accounts[idxa].reload(event, hash) {
if let UIEvent::Notification(_, _) = notification {
self.context
.replies
.push_back(UIEvent::MailboxUpdate((idxa, hash)));
}
self.rcv_event(notification); self.rcv_event(notification);
} else {
self.context
.replies
.push_back(UIEvent::MailboxUpdate((idxa, hash)));
} }
} else { } else {
debug!( debug!(