melib/ui: refer to Folders by FolderHash
parent
04eb8d926f
commit
87adc6dd19
|
@ -147,7 +147,7 @@ impl NotifyFn {
|
|||
pub trait MailBackend: ::std::fmt::Debug {
|
||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>;
|
||||
fn watch(&self, sender: RefreshEventConsumer) -> Result<()>;
|
||||
fn folders(&self) -> Vec<Folder>;
|
||||
fn folders(&self) -> FnvHashMap<FolderHash, Folder>;
|
||||
fn operation(&self, hash: EnvelopeHash, folder_hash: FolderHash) -> Box<BackendOp>;
|
||||
|
||||
fn save(&self, bytes: &[u8], folder: &str) -> Result<()>;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#[macro_use]
|
||||
mod backend;
|
||||
pub use self::backend::*;
|
||||
|
||||
|
@ -165,14 +166,24 @@ impl<'a> BackendOp for MaildirOp {
|
|||
new_name.push('T');
|
||||
}
|
||||
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("renaming {:?} to {:?}", path, new_name);
|
||||
if cfg!(debug_assertions) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("renaming {:?} to {:?}", path, new_name);
|
||||
}
|
||||
fs::rename(&path, &new_name)?;
|
||||
let hash = envelope.hash();
|
||||
if cfg!(debug_assertions) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("success in rename");
|
||||
}
|
||||
let old_hash = envelope.hash();
|
||||
let new_name: PathBuf = new_name.into();
|
||||
let new_hash = get_file_hash(&new_name);
|
||||
envelope.set_hash(new_hash);
|
||||
let hash_index = self.hash_index.clone();
|
||||
let mut map = hash_index.lock().unwrap();
|
||||
let map = map.entry(self.folder_hash).or_default();
|
||||
*map.get_mut(&hash).unwrap() = PathBuf::from(new_name);
|
||||
map.remove(&old_hash);
|
||||
map.insert(new_hash, new_name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ macro_rules! path_is_new {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_path_hash {
|
||||
($path:expr) => {{
|
||||
let mut path = $path.clone();
|
||||
|
@ -109,7 +110,7 @@ macro_rules! get_path_hash {
|
|||
}};
|
||||
}
|
||||
|
||||
fn get_file_hash(file: &Path) -> EnvelopeHash {
|
||||
pub(super) fn get_file_hash(file: &Path) -> EnvelopeHash {
|
||||
/*
|
||||
let mut buf = Vec::with_capacity(2048);
|
||||
let mut f = fs::File::open(&file).unwrap_or_else(|_| panic!("Can't open {}", file.display()));
|
||||
|
@ -126,15 +127,13 @@ fn get_file_hash(file: &Path) -> EnvelopeHash {
|
|||
|
||||
fn move_to_cur(p: PathBuf) -> PathBuf {
|
||||
let mut new = p.clone();
|
||||
{
|
||||
let file_name = p.file_name().unwrap();
|
||||
new.pop();
|
||||
new.pop();
|
||||
let file_name = p.file_name().unwrap();
|
||||
new.pop();
|
||||
new.pop();
|
||||
|
||||
new.push("cur");
|
||||
new.push(file_name);
|
||||
new.set_extension(":2,");
|
||||
}
|
||||
new.push("cur");
|
||||
new.push(file_name);
|
||||
new.set_extension(":2,");
|
||||
if cfg!(debug_assertions) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("moved to cur: {}", new.display());
|
||||
|
@ -144,15 +143,15 @@ fn move_to_cur(p: PathBuf) -> PathBuf {
|
|||
}
|
||||
|
||||
impl MailBackend for MaildirType {
|
||||
fn folders(&self) -> Vec<Folder> {
|
||||
self.folders.iter().map(|f| f.clone()).collect()
|
||||
fn folders(&self) -> FnvHashMap<FolderHash, Folder> {
|
||||
self.folders.iter().map(|f| (f.hash(), f.clone())).collect()
|
||||
}
|
||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||
self.multicore(4, folder)
|
||||
}
|
||||
fn watch(&self, sender: RefreshEventConsumer) -> Result<()> {
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
|
||||
let root_path = self.path.to_path_buf();
|
||||
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
|
||||
for f in &self.folders {
|
||||
|
@ -315,7 +314,7 @@ eprintln!("removed but not contained in index");
|
|||
kind: Remove(hash),
|
||||
});
|
||||
}
|
||||
/* Envelope hasn't changed, so handle this here */
|
||||
/* Envelope hasn't changed */
|
||||
DebouncedEvent::Rename(src, dest) => {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("DebouncedEvent::Rename(src = {:?}, dest = {:?})", src, dest);
|
||||
|
@ -335,13 +334,43 @@ eprintln!("contains_key");
|
|||
});
|
||||
index_lock.remove(&old_hash);
|
||||
index_lock.insert(new_hash, dest);
|
||||
} else {
|
||||
/* Maybe a re-read should be triggered here just to be safe. */
|
||||
sender.send(RefreshEvent {
|
||||
hash: get_path_hash!(dest),
|
||||
kind: Rescan,
|
||||
});
|
||||
continue;
|
||||
} else if !index_lock.contains_key(&new_hash) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("not contains_key");
|
||||
let file_name = dest
|
||||
.as_path()
|
||||
.strip_prefix(&root_path)
|
||||
.unwrap()
|
||||
.to_path_buf();
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("filename = {:?}", file_name);
|
||||
if let Some(env) = add_path_to_index(
|
||||
&hash_indexes,
|
||||
folder_hash,
|
||||
dest.as_path(),
|
||||
&cache_dir,
|
||||
file_name,
|
||||
) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("Create event {} {} {}", env.hash(), env.subject(), dest.display());
|
||||
if cfg!(debug_assertions) {
|
||||
}
|
||||
sender.send(RefreshEvent {
|
||||
hash: folder_hash,
|
||||
kind: Create(Box::new(env)),
|
||||
});
|
||||
continue;
|
||||
} else {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("not valid email");
|
||||
}
|
||||
}
|
||||
/* Maybe a re-read should be triggered here just to be safe. */
|
||||
sender.send(RefreshEvent {
|
||||
hash: get_path_hash!(dest),
|
||||
kind: Rescan,
|
||||
});
|
||||
}
|
||||
/* Trigger rescan of folder */
|
||||
DebouncedEvent::Rescan => {
|
||||
|
|
|
@ -101,6 +101,9 @@ eprintln!("DEBUG: Removing {}", envelope_hash);
|
|||
}
|
||||
|
||||
pub fn rename(&mut self, old_hash: EnvelopeHash, new_hash: EnvelopeHash) {
|
||||
if !self.envelopes.contains_key(&old_hash) {
|
||||
return;
|
||||
}
|
||||
let mut env = self.envelopes.remove(&old_hash).unwrap();
|
||||
env.set_hash(new_hash);
|
||||
self.envelopes.insert(new_hash, env);
|
||||
|
|
|
@ -146,7 +146,7 @@ impl AccountMenu {
|
|||
return;
|
||||
}
|
||||
let len = s.len();
|
||||
match context.accounts[index].status(root) {
|
||||
match context.accounts[index].status(entries[root].1.hash()) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
return;
|
||||
|
@ -263,10 +263,17 @@ impl Component for AccountMenu {
|
|||
|
||||
context.dirty_areas.push_back(area);
|
||||
}
|
||||
fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool {
|
||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
match *event {
|
||||
UIEvent::RefreshMailbox(c) => {
|
||||
self.cursor = Some(c);
|
||||
UIEvent::RefreshMailbox((idxa, folder_hash)) => {
|
||||
self.cursor = Some((
|
||||
idxa,
|
||||
context.accounts[idxa]
|
||||
.folders_order
|
||||
.iter()
|
||||
.position(|&h| h == folder_hash)
|
||||
.unwrap_or(0),
|
||||
));
|
||||
self.dirty = true;
|
||||
}
|
||||
UIEvent::ChangeMode(UIMode::Normal) => {
|
||||
|
|
|
@ -104,15 +104,15 @@ impl MailboxView {
|
|||
}
|
||||
self.cursor_pos.1 = self.new_cursor_pos.1;
|
||||
self.cursor_pos.0 = self.new_cursor_pos.0;
|
||||
let folder_hash = context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
|
||||
|
||||
// Inform State that we changed the current folder view.
|
||||
context.replies.push_back(UIEvent::RefreshMailbox((
|
||||
self.cursor_pos.0,
|
||||
self.cursor_pos.1,
|
||||
)));
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::RefreshMailbox((self.cursor_pos.0, folder_hash)));
|
||||
// Get mailbox as a reference.
|
||||
//
|
||||
match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) {
|
||||
match context.accounts[self.cursor_pos.0].status(folder_hash) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' '));
|
||||
|
@ -442,17 +442,32 @@ impl Component for MailboxView {
|
|||
self.dirty = true;
|
||||
}
|
||||
UIEvent::MailboxUpdate((ref idxa, ref idxf))
|
||||
if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 =>
|
||||
if (*idxa, *idxf)
|
||||
== (
|
||||
self.new_cursor_pos.0,
|
||||
context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1],
|
||||
) =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
}
|
||||
UIEvent::StartupCheck(ref f)
|
||||
if context.mailbox_hashes[f] == (self.new_cursor_pos.0, self.new_cursor_pos.1) =>
|
||||
if *f
|
||||
== context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1] =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
}
|
||||
UIEvent::EnvelopeRename(ref folder_hash, _, _) => {
|
||||
if *folder_hash
|
||||
== context.accounts[self.cursor_pos.0].folders_order[self.new_cursor_pos.1]
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
}
|
||||
}
|
||||
UIEvent::ChangeMode(UIMode::Normal) => {
|
||||
self.dirty = true;
|
||||
}
|
||||
|
@ -649,6 +664,7 @@ impl CompactListing {
|
|||
impl Component for CompactListing {
|
||||
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||
if !self.populated {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("populating");
|
||||
for (idx, a) in context.accounts.iter().enumerate() {
|
||||
for (fidx, _) in a.iter_mailboxes().enumerate() {
|
||||
|
|
|
@ -105,17 +105,15 @@ impl PlainListing {
|
|||
}
|
||||
self.cursor_pos.0 = self.new_cursor_pos.0;
|
||||
self.cursor_pos.1 = self.new_cursor_pos.1;
|
||||
let folder_hash = context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
|
||||
|
||||
// Inform State that we changed the current folder view.
|
||||
context.replies.push_back(UIEvent::RefreshMailbox((
|
||||
self.cursor_pos.0,
|
||||
self.cursor_pos.1,
|
||||
)));
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::RefreshMailbox((self.cursor_pos.0, folder_hash)));
|
||||
// Get mailbox as a reference.
|
||||
//
|
||||
// Get mailbox as a reference.
|
||||
//
|
||||
match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) {
|
||||
match context.accounts[self.cursor_pos.0].status(folder_hash) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' '));
|
||||
|
@ -505,13 +503,20 @@ impl Component for PlainListing {
|
|||
self.view = None;
|
||||
}
|
||||
UIEvent::MailboxUpdate((ref idxa, ref idxf))
|
||||
if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 =>
|
||||
if (*idxa, *idxf)
|
||||
== (
|
||||
self.new_cursor_pos.0,
|
||||
context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1],
|
||||
) =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
}
|
||||
UIEvent::StartupCheck(ref f)
|
||||
if context.mailbox_hashes[f] == (self.new_cursor_pos.0, self.new_cursor_pos.1) =>
|
||||
if *f
|
||||
== context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1] =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
|
|
|
@ -103,15 +103,15 @@ impl ThreadListing {
|
|||
}
|
||||
self.cursor_pos.1 = self.new_cursor_pos.1;
|
||||
self.cursor_pos.0 = self.new_cursor_pos.0;
|
||||
let folder_hash = context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
|
||||
|
||||
// Inform State that we changed the current folder view.
|
||||
context.replies.push_back(UIEvent::RefreshMailbox((
|
||||
self.cursor_pos.0,
|
||||
self.cursor_pos.1,
|
||||
)));
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::RefreshMailbox((self.cursor_pos.0, folder_hash)));
|
||||
// Get mailbox as a reference.
|
||||
//
|
||||
match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) {
|
||||
match context.accounts[self.cursor_pos.0].status(folder_hash) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' '));
|
||||
|
@ -668,13 +668,20 @@ impl Component for ThreadListing {
|
|||
self.view = None;
|
||||
}
|
||||
UIEvent::MailboxUpdate((ref idxa, ref idxf))
|
||||
if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 =>
|
||||
if (*idxa, *idxf)
|
||||
== (
|
||||
self.new_cursor_pos.0,
|
||||
context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1],
|
||||
) =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
}
|
||||
UIEvent::StartupCheck(ref f)
|
||||
if context.mailbox_hashes[f] == (self.new_cursor_pos.0, self.new_cursor_pos.1) =>
|
||||
if *f
|
||||
== context.accounts[self.new_cursor_pos.0].folders_order
|
||||
[self.new_cursor_pos.1] =>
|
||||
{
|
||||
self.refresh_mailbox(context);
|
||||
self.set_dirty();
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
*/
|
||||
|
||||
use super::AccountConf;
|
||||
use fnv::FnvHashMap;
|
||||
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus};
|
||||
use melib::backends::FolderHash;
|
||||
use melib::error::Result;
|
||||
use melib::mailbox::backends::{
|
||||
Backends, Folder, MailBackend, NotifyFn, RefreshEvent, RefreshEventConsumer, RefreshEventKind,
|
||||
|
@ -44,19 +46,26 @@ pub type Worker = Option<Async<Result<Mailbox>>>;
|
|||
|
||||
macro_rules! mailbox {
|
||||
($idx:expr, $folders:expr) => {
|
||||
$folders[$idx].as_mut().unwrap().as_mut().unwrap()
|
||||
$folders
|
||||
.get_mut(&$idx)
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Account {
|
||||
name: String,
|
||||
folders: Vec<Option<Result<Mailbox>>>,
|
||||
pub(crate) folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>>,
|
||||
pub(crate) folders_order: Vec<FolderHash>,
|
||||
sent_folder: Option<usize>,
|
||||
|
||||
pub(crate) address_book: AddressBook,
|
||||
|
||||
pub(crate) workers: Vec<Worker>,
|
||||
pub(crate) workers: FnvHashMap<FolderHash, Worker>,
|
||||
|
||||
pub(crate) settings: AccountConf,
|
||||
pub(crate) runtime_settings: AccountConf,
|
||||
|
@ -83,7 +92,8 @@ impl Drop for Account {
|
|||
}
|
||||
|
||||
pub struct MailboxIterator<'a> {
|
||||
folders: &'a [Option<Result<Mailbox>>],
|
||||
folders_order: &'a [FolderHash],
|
||||
folders: &'a FnvHashMap<FolderHash, Option<Result<Mailbox>>>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
|
@ -94,19 +104,19 @@ impl<'a> Iterator for MailboxIterator<'a> {
|
|||
if self.pos == self.folders.len() {
|
||||
return None;
|
||||
}
|
||||
for f in self.folders[self.pos..].iter() {
|
||||
for fh in self.folders_order[self.pos..].iter() {
|
||||
if self.pos == self.folders.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pos += 1;
|
||||
if let Some(Err(_)) = f {
|
||||
if self.folders[&fh].is_none() {
|
||||
return Some(None);
|
||||
}
|
||||
if let None = f {
|
||||
if let Some(Err(_)) = self.folders[&fh] {
|
||||
return Some(None);
|
||||
}
|
||||
return Some(Some(f.as_ref().unwrap().as_ref().unwrap()));
|
||||
return Some(Some(self.folders[&fh].as_ref().unwrap().as_ref().unwrap()));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
@ -115,26 +125,28 @@ impl<'a> Iterator for MailboxIterator<'a> {
|
|||
impl Account {
|
||||
pub fn new(name: String, settings: AccountConf, map: &Backends, notify_fn: NotifyFn) -> Self {
|
||||
let mut backend = map.get(settings.account().format())(settings.account());
|
||||
let mut ref_folders: Vec<Folder> = backend.folders();
|
||||
let mut folders: Vec<Option<Result<Mailbox>>> = Vec::with_capacity(ref_folders.len());
|
||||
let mut workers: Vec<Worker> = Vec::new();
|
||||
let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders();
|
||||
let mut folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>> =
|
||||
FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default());
|
||||
let mut folders_order: Vec<FolderHash> = ref_folders.values().map(|f| f.hash()).collect();
|
||||
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
|
||||
let notify_fn = Arc::new(notify_fn);
|
||||
|
||||
if let Some(pos) = ref_folders
|
||||
.iter()
|
||||
.values()
|
||||
.position(|f| f.name().eq_ignore_ascii_case("INBOX"))
|
||||
{
|
||||
ref_folders.swap(pos, 0);
|
||||
folders_order.swap(pos, 0);
|
||||
}
|
||||
let sent_folder = ref_folders
|
||||
.iter()
|
||||
.values()
|
||||
.position(|x: &Folder| x.name() == settings.account().sent_folder);
|
||||
if let Some(folder_confs) = settings.conf().folders() {
|
||||
//if cfg!(debug_assertions) {
|
||||
//eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
//eprintln!("folder renames: {:?}", folder_renames);
|
||||
//}
|
||||
for f in &mut ref_folders {
|
||||
for f in ref_folders.values_mut() {
|
||||
if let Some(r) = folder_confs.get(&f.name().to_ascii_lowercase()) {
|
||||
if let Some(rename) = r.rename() {
|
||||
f.change_name(rename);
|
||||
|
@ -142,9 +154,9 @@ impl Account {
|
|||
}
|
||||
}
|
||||
}
|
||||
for f in ref_folders {
|
||||
folders.push(None);
|
||||
workers.push(Account::new_worker(f, &mut backend, notify_fn.clone()));
|
||||
for (h, f) in ref_folders.into_iter() {
|
||||
folders.insert(h, None);
|
||||
workers.insert(h, Account::new_worker(f, &mut backend, notify_fn.clone()));
|
||||
}
|
||||
let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
|
||||
let address_book = if let Ok(data) = data_dir.place_data_file("addressbook") {
|
||||
|
@ -166,6 +178,7 @@ impl Account {
|
|||
Account {
|
||||
name,
|
||||
folders,
|
||||
folders_order,
|
||||
address_book,
|
||||
sent_folder,
|
||||
workers,
|
||||
|
@ -196,13 +209,13 @@ impl Account {
|
|||
notify_fn.notify(hash);
|
||||
})))
|
||||
}
|
||||
pub fn reload(&mut self, event: RefreshEvent, idx: usize) -> Option<UIEvent> {
|
||||
pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> {
|
||||
let kind = event.kind();
|
||||
{
|
||||
//let mailbox: &mut Mailbox = self.folders[idx].as_mut().unwrap().as_mut().unwrap();
|
||||
match kind {
|
||||
RefreshEventKind::Update(old_hash, envelope) => {
|
||||
mailbox!(idx, self.folders).update(old_hash, *envelope);
|
||||
mailbox!(&folder_hash, self.folders).update(old_hash, *envelope);
|
||||
return Some(EnvelopeUpdate(old_hash));
|
||||
}
|
||||
RefreshEventKind::Rename(old_hash, new_hash) => {
|
||||
|
@ -210,39 +223,40 @@ impl Account {
|
|||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("rename {} to {}", old_hash, new_hash);
|
||||
}
|
||||
mailbox!(idx, self.folders).rename(old_hash, new_hash);
|
||||
return Some(EnvelopeRename(idx, old_hash, new_hash));
|
||||
let mailbox = mailbox!(&folder_hash, self.folders);
|
||||
mailbox.rename(old_hash, new_hash);
|
||||
return Some(EnvelopeRename(mailbox.folder.hash(), old_hash, new_hash));
|
||||
}
|
||||
RefreshEventKind::Create(envelope) => {
|
||||
if cfg!(debug_assertions) {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("create {}", envelope.hash());
|
||||
}
|
||||
let env: &Envelope = mailbox!(idx, self.folders).insert(*envelope);
|
||||
let ref_folders: Vec<Folder> = self.backend.folders();
|
||||
let env: &Envelope = mailbox!(&folder_hash, self.folders).insert(*envelope);
|
||||
let ref_folders: FnvHashMap<FolderHash, Folder> = self.backend.folders();
|
||||
return Some(Notification(
|
||||
Some("new mail".into()),
|
||||
format!(
|
||||
"{} {:.15}:\n\nFrom: {:.15}\nSubject: {:.15}",
|
||||
self.name,
|
||||
ref_folders[idx].name(),
|
||||
ref_folders[&folder_hash].name(),
|
||||
env.subject(),
|
||||
env.field_from_to_string(),
|
||||
),
|
||||
));
|
||||
}
|
||||
RefreshEventKind::Remove(envelope_hash) => {
|
||||
mailbox!(idx, self.folders).remove(envelope_hash);
|
||||
mailbox!(&folder_hash, self.folders).remove(envelope_hash);
|
||||
return Some(EnvelopeRemove(envelope_hash));
|
||||
}
|
||||
RefreshEventKind::Rescan => {
|
||||
let ref_folders: Vec<Folder> = self.backend.folders();
|
||||
let ref_folders: FnvHashMap<FolderHash, Folder> = self.backend.folders();
|
||||
let handle = Account::new_worker(
|
||||
ref_folders[idx].clone(),
|
||||
ref_folders[&folder_hash].clone(),
|
||||
&mut self.backend,
|
||||
self.notify_fn.clone(),
|
||||
);
|
||||
self.workers[idx] = handle;
|
||||
self.workers.insert(folder_hash, handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +279,7 @@ impl Account {
|
|||
//eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
//eprintln!("folder renames: {:?}", folder_renames);
|
||||
//}
|
||||
for f in &mut folders {
|
||||
for f in folders.values_mut() {
|
||||
if let Some(r) = folder_confs.get(&f.name().to_ascii_lowercase()) {
|
||||
if let Some(rename) = r.rename() {
|
||||
f.change_name(rename);
|
||||
|
@ -273,23 +287,28 @@ impl Account {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if let Some(pos) = folders
|
||||
.iter()
|
||||
.position(|f| f.name().eq_ignore_ascii_case("INBOX"))
|
||||
{
|
||||
folders.swap(pos, 0);
|
||||
}
|
||||
folders
|
||||
*/
|
||||
self.folders_order
|
||||
.iter()
|
||||
.map(|ref h| folders.remove(&h).unwrap())
|
||||
.collect()
|
||||
}
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
pub fn workers(&mut self) -> &mut Vec<Worker> {
|
||||
pub fn workers(&mut self) -> &mut FnvHashMap<FolderHash, Worker> {
|
||||
&mut self.workers
|
||||
}
|
||||
|
||||
fn load_mailbox(&mut self, index: usize, mailbox: Result<Mailbox>) {
|
||||
self.folders[index] = Some(mailbox);
|
||||
fn load_mailbox(&mut self, folder_hash: FolderHash, mailbox: Result<Mailbox>) {
|
||||
self.folders.insert(folder_hash, Some(mailbox));
|
||||
/*
|
||||
if self.sent_folder.is_some() && self.sent_folder.unwrap() == index {
|
||||
self.folders[index] = Some(mailbox);
|
||||
|
@ -340,12 +359,12 @@ impl Account {
|
|||
}
|
||||
*/
|
||||
|
||||
pub fn status(&mut self, index: usize) -> result::Result<(), usize> {
|
||||
match self.workers[index].as_mut() {
|
||||
pub fn status(&mut self, folder_hash: FolderHash) -> result::Result<(), usize> {
|
||||
match self.workers.get_mut(&folder_hash).unwrap() {
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
Some(ref mut w) if self.folders[index].is_none() => match w.poll() {
|
||||
Some(ref mut w) if self.folders[&folder_hash].is_none() => match w.poll() {
|
||||
Ok(AsyncStatus::NoUpdate) => {
|
||||
return Err(0);
|
||||
}
|
||||
|
@ -359,11 +378,11 @@ impl Account {
|
|||
},
|
||||
Some(_) => return Ok(()),
|
||||
};
|
||||
let m = mem::replace(&mut self.workers[index], None)
|
||||
let m = mem::replace(self.workers.get_mut(&folder_hash).unwrap(), None)
|
||||
.unwrap()
|
||||
.extract();
|
||||
self.workers[index] = None;
|
||||
self.load_mailbox(index, m);
|
||||
self.workers.insert(folder_hash, None);
|
||||
self.load_mailbox(folder_hash, m);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -377,16 +396,36 @@ impl Account {
|
|||
}
|
||||
pub fn iter_mailboxes<'a>(&'a self) -> MailboxIterator<'a> {
|
||||
MailboxIterator {
|
||||
folders_order: &self.folders_order,
|
||||
folders: &self.folders,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Index<FolderHash> for Account {
|
||||
type Output = Result<Mailbox>;
|
||||
fn index(&self, index: FolderHash) -> &Result<Mailbox> {
|
||||
&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 {
|
||||
fn index_mut(&mut self, index: FolderHash) -> &mut Result<Mailbox> {
|
||||
self.folders
|
||||
.get_mut(&index)
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.expect("BUG: Requested mailbox that is not yet available.")
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Account {
|
||||
type Output = Result<Mailbox>;
|
||||
fn index(&self, index: usize) -> &Result<Mailbox> {
|
||||
&self.folders[index]
|
||||
&self.folders[&self.folders_order[index]]
|
||||
.as_ref()
|
||||
.expect("BUG: Requested mailbox that is not yet available.")
|
||||
}
|
||||
|
@ -395,7 +434,9 @@ impl Index<usize> for Account {
|
|||
/// Will panic if mailbox hasn't loaded, ask `status()` first.
|
||||
impl IndexMut<usize> for Account {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Result<Mailbox> {
|
||||
self.folders[index]
|
||||
self.folders
|
||||
.get_mut(&self.folders_order[index])
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.expect("BUG: Requested mailbox that is not yet available.")
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ impl InputHandler {
|
|||
/// A context container for loaded settings, accounts, UI changes, etc.
|
||||
pub struct Context {
|
||||
pub accounts: Vec<Account>,
|
||||
pub mailbox_hashes: FnvHashMap<FolderHash, (usize, usize)>,
|
||||
pub mailbox_hashes: FnvHashMap<FolderHash, usize>,
|
||||
pub settings: Settings,
|
||||
|
||||
pub runtime_settings: Settings,
|
||||
|
@ -101,11 +101,15 @@ impl Context {
|
|||
pub fn restore_input(&self) {
|
||||
self.input.restore(self.sender.clone());
|
||||
}
|
||||
pub fn account_status(&mut self, idx_a: usize, idx_m: usize) -> result::Result<(), usize> {
|
||||
match self.accounts[idx_a].status(idx_m) {
|
||||
pub fn account_status(
|
||||
&mut self,
|
||||
idx_a: usize,
|
||||
folder_hash: FolderHash,
|
||||
) -> result::Result<(), usize> {
|
||||
match self.accounts[idx_a].status(folder_hash) {
|
||||
Ok(()) => {
|
||||
self.replies
|
||||
.push_back(UIEvent::MailboxUpdate((idx_a, idx_m)));
|
||||
.push_back(UIEvent::MailboxUpdate((idx_a, folder_hash)));
|
||||
Ok(())
|
||||
}
|
||||
Err(n) => Err(n),
|
||||
|
@ -220,7 +224,7 @@ impl State {
|
|||
work_controller: WorkController::new(),
|
||||
};
|
||||
for a in s.context.accounts.iter_mut() {
|
||||
for worker in a.workers.iter_mut() {
|
||||
for worker in a.workers.values_mut() {
|
||||
if let Some(worker) = worker.as_mut() {
|
||||
if let Some(w) = worker.work() {
|
||||
s.work_controller.queue.add_work(w);
|
||||
|
@ -249,7 +253,7 @@ impl State {
|
|||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!("hash & folder: {:?} {}", folder.hash(), folder.name());
|
||||
}
|
||||
s.context.mailbox_hashes.insert(folder.hash(), (x, y));
|
||||
s.context.mailbox_hashes.insert(folder.hash(), x);
|
||||
}
|
||||
let sender = s.context.sender.clone();
|
||||
account.watch(RefreshEventConsumer::new(Box::new(move |r| {
|
||||
|
@ -271,24 +275,25 @@ impl State {
|
|||
*/
|
||||
pub fn refresh_event(&mut self, event: RefreshEvent) {
|
||||
let hash = event.hash();
|
||||
if let Some(&(idxa, idxm)) = self.context.mailbox_hashes.get(&hash) {
|
||||
if self.context.accounts[idxa].status(idxm).is_err() {
|
||||
if let Some(&idxa) = self.context.mailbox_hashes.get(&hash) {
|
||||
if self.context.accounts[idxa].status(hash).is_err() {
|
||||
self.context.replies.push_back(UIEvent::from(event));
|
||||
return;
|
||||
}
|
||||
if let Some(notification) = self.context.accounts[idxa].reload(event, idxm) {
|
||||
if let Some(notification) = self.context.accounts[idxa].reload(event, hash) {
|
||||
self.context
|
||||
.sender
|
||||
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(hash)));
|
||||
self.context
|
||||
.sender
|
||||
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((idxa, idxm))));
|
||||
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((idxa, hash))));
|
||||
self.context.replies.push_back(notification);
|
||||
}
|
||||
self.context
|
||||
.replies
|
||||
.push_back(UIEvent::MailboxUpdate((idxa, idxm)));
|
||||
.push_back(UIEvent::MailboxUpdate((idxa, hash)));
|
||||
} else {
|
||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||
eprintln!(
|
||||
"BUG: mailbox with hash {} not found in mailbox_hashes.",
|
||||
hash
|
||||
|
|
|
@ -72,7 +72,7 @@ pub enum UIEvent {
|
|||
Input(Key),
|
||||
ExInput(Key),
|
||||
InsertInput(Key),
|
||||
RefreshMailbox((usize, usize)),
|
||||
RefreshMailbox((usize, FolderHash)), //view has changed to FolderHash mailbox
|
||||
//Quit?
|
||||
Resize,
|
||||
/// Force redraw.
|
||||
|
@ -83,12 +83,12 @@ pub enum UIEvent {
|
|||
Notification(Option<String>, String),
|
||||
Action(Action),
|
||||
StatusEvent(StatusEvent),
|
||||
MailboxUpdate((usize, usize)), // (account_idx, mailbox_idx)
|
||||
MailboxUpdate((usize, FolderHash)), // (account_idx, mailbox_idx)
|
||||
ComponentKill(Uuid),
|
||||
StartupCheck(FolderHash),
|
||||
RefreshEvent(Box<RefreshEvent>),
|
||||
EnvelopeUpdate(EnvelopeHash),
|
||||
EnvelopeRename(usize, EnvelopeHash, EnvelopeHash),
|
||||
EnvelopeRename(FolderHash, EnvelopeHash, EnvelopeHash),
|
||||
EnvelopeRemove(EnvelopeHash),
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue