Replace every use of Folder with Mailbox

Use Mailbox for consistency.
memfd
Manos Pitsidianakis 2020-02-26 10:54:10 +02:00
parent 1245eae0be
commit 4ac52d9d5b
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
40 changed files with 1237 additions and 1205 deletions

30
meli.1
View File

@ -94,7 +94,7 @@ The menu's visibility may be toggled with
.Ic toggle_menu_visibility Ns .Ic toggle_menu_visibility Ns
). ).
.Pp .Pp
The view into each folder has 4 modes: plain, threaded, conversations and compact. The view into each mailbox has 4 modes: plain, threaded, conversations and compact.
Plain views each mail indvidually, threaded shows their thread relationship visually, and conversations includes one entry per thread of emails (compact is one row per thread). Plain views each mail indvidually, threaded shows their thread relationship visually, and conversations includes one entry per thread of emails (compact is one row per thread).
.Pp .Pp
If you're using a light color palette in your terminal, you may set If you're using a light color palette in your terminal, you may set
@ -224,9 +224,9 @@ To save your draft without sending it, issue command
.Cm close .Cm close
and select 'save as draft'. and select 'save as draft'.
.Pp .Pp
With no Draft or Sent folder, With no Draft or Sent mailbox,
.Nm .Nm
tries first saving mail in your INBOX and then at any other folder. tries first saving mail in your INBOX and then at any other mailbox.
On complete failure to save your draft or sent message it will be saved in your On complete failure to save your draft or sent message it will be saved in your
.Em tmp .Em tmp
directory instead and you will be notified of its location. directory instead and you will be notified of its location.
@ -307,17 +307,17 @@ filter mailbox with
key. key.
Escape exits filter results Escape exits filter results
.It Cm set read, set unread .It Cm set read, set unread
.It Cm create-folder Ar ACCOUNT Ar FOLDER_PATH .It Cm create-mailbox Ar ACCOUNT Ar MAILBOX_PATH
create folder with given path. create mailbox with given path.
Be careful with backends and separator sensitivity (eg IMAP) Be careful with backends and separator sensitivity (eg IMAP)
.It Cm subscribe-folder Ar ACCOUNT Ar FOLDER_PATH .It Cm subscribe-mailbox Ar ACCOUNT Ar MAILBOX_PATH
subscribe to folder with given path subscribe to mailbox with given path
.It Cm unsubscribe-folder Ar ACCOUNT Ar FOLDER_PATH .It Cm unsubscribe-mailbox Ar ACCOUNT Ar MAILBOX_PATH
unsubscribe to folder with given path unsubscribe to mailbox with given path
.It Cm rename-folder Ar ACCOUNT Ar FOLDER_PATH_SRC Ar FOLDER_PATH_DEST .It Cm rename-mailbox Ar ACCOUNT Ar MAILBOX_PATH_SRC Ar MAILBOX_PATH_DEST
rename folder rename mailbox
.It Cm delete-folder Ar ACCOUNT Ar FOLDER_PATH .It Cm delete-mailbox Ar ACCOUNT Ar MAILBOX_PATH
delete folder delete mailbox
.El .El
.Pp .Pp
envelope view commands: envelope view commands:
@ -376,9 +376,9 @@ Non-complete list of shortcuts and their default values.
PageUp, PageUp,
.It Ic next_page .It Ic next_page
PageDown PageDown
.It Ic prev_folder .It Ic prev_mailbox
\&'K' \&'K'
.It Ic next_folder .It Ic next_mailbox
\&'J' \&'J'
.It Ic prev_account .It Ic prev_account
\&'l' \&'l'

View File

@ -56,23 +56,23 @@ example configuration
.Bd -literal .Bd -literal
# Setting up a Maildir account # Setting up a Maildir account
[accounts.account-name] [accounts.account-name]
root_folder = "/path/to/root/folder" root_mailbox = "/path/to/root/folder"
format = "Maildir" format = "Maildir"
index_style = "Compact" index_style = "Compact"
identity="email@address.tld" identity="email@address.tld"
subscribed_folders = ["folder", "folder/Sent"] # or [ "*", ] for all folders subscribed_mailboxes = ["folder", "folder/Sent"] # or [ "*", ] for all mailboxes
display_name = "Name" display_name = "Name"
# Set folder-specific settings # Set mailbox-specific settings
[accounts.account-name.folders] [accounts.account-name.mailboxes]
"INBOX" = { alias="Inbox" } #inline table "INBOX" = { alias="Inbox" } #inline table
"drafts" = { alias="Drafts" } #inline table "drafts" = { alias="Drafts" } #inline table
[accounts.account-name.folders."foobar-devel"] # or a regular table [accounts.account-name.mailboxes."foobar-devel"] # or a regular table
ignore = true # don't show notifications for this folder ignore = true # don't show notifications for this mailbox
# Setting up an mbox account # Setting up an mbox account
[accounts.mbox] [accounts.mbox]
root_folder = "/var/mail/username" root_mailbox = "/var/mail/username"
format = "mbox" format = "mbox"
index_style = "Compact" index_style = "Compact"
identity="username@hostname.local" identity="username@hostname.local"
@ -105,16 +105,16 @@ available options are listed below.
.Sy default values are shown in parentheses. .Sy default values are shown in parentheses.
.Sh ACCOUNTS .Sh ACCOUNTS
.Bl -tag -width 36n .Bl -tag -width 36n
.It Ic root_folder Ar String .It Ic root_mailbox Ar String
the backend-specific path of the root_folder, usually INBOX. the backend-specific path of the root_mailbox, usually INBOX.
.It Ic format Ar String Op maildir mbox imap notmuch jmap .It Ic format Ar String Op maildir mbox imap notmuch jmap
the format of the mail backend. the format of the mail backend.
.It Ic subscribed_folders Ar [String,] .It Ic subscribed_mailboxes Ar [String,]
an array of folder paths to display in the UI. an array of mailbox paths to display in the UI.
Paths are relative to the root folder (eg "INBOX/Sent", not "Sent"). Paths are relative to the root mailbox (eg "INBOX/Sent", not "Sent").
The glob wildcard The glob wildcard
.Em \&* .Em \&*
can be used to match every folder name and path. can be used to match every mailbox name and path.
.It Ic identity Ar String .It Ic identity Ar String
your e-mail address that is inserted in the From: headers of outgoing mail your e-mail address that is inserted in the From: headers of outgoing mail
.It Ic index_style Ar String .It Ic index_style Ar String
@ -148,20 +148,20 @@ Available options are 'none' and 'sqlite3'
.It Ic vcard_folder Ar String .It Ic vcard_folder Ar String
(optional) Folder that contains .vcf files. (optional) Folder that contains .vcf files.
They are parsed and imported read-only. They are parsed and imported read-only.
.It Ic folders Ar folder_config .It Ic mailboxes Ar mailbox
(optional) configuration for each folder. (optional) configuration for each mailbox.
Its format is described below in Its format is described below in
.Sx FOLDERS Ns .Sx mailboxes Ns
\&. \&.
.El .El
.Sh notmuch only .Sh notmuch only
.Ic root_folder .Ic root_mailbox
points to the directory which contains the points to the directory which contains the
.Pa .notmuch/ .Pa .notmuch/
subdirectory. subdirectory.
notmuch folders are virtual, since they are defined by user-given notmuch queries. notmuch mailboxes are virtual, since they are defined by user-given notmuch queries.
Thus you have to explicitly state the folders you want in the Thus you have to explicitly state the mailboxes you want in the
.Ic folders .Ic mailboxes
field and set the field and set the
.Ar query .Ar query
property to each of them. property to each of them.
@ -170,7 +170,7 @@ Example:
[accounts.notmuch] [accounts.notmuch]
format = "notmuch" format = "notmuch"
\&... \&...
[accounts.notmuch.folders] [accounts.notmuch.mailboxes]
"INBOX" = { query="tag:inbox", subscribe = true } "INBOX" = { query="tag:inbox", subscribe = true }
"Drafts" = { query="tag:draft", subscribe = true } "Drafts" = { query="tag:draft", subscribe = true }
"Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true } "Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true }
@ -213,22 +213,22 @@ example:
.\" default value .\" default value
.Pq Em false .Pq Em false
.El .El
.Sh FOLDERS .Sh mailboxes
.Bl -tag -width 36n .Bl -tag -width 36n
.It Ic alias Ar String .It Ic alias Ar String
(optional) show a different name for this folder in the UI (optional) show a different name for this mailbox in the UI
.It Ic autoload Ar boolean .It Ic autoload Ar boolean
(optional) load this folder on startup (not functional yet) (optional) load this mailbox on startup (not functional yet)
.It Ic subscribe Ar boolean .It Ic subscribe Ar boolean
(optional) watch this folder for updates (optional) watch this mailbox for updates
.\" default value .\" default value
.Pq Em true .Pq Em true
.It Ic ignore Ar boolean .It Ic ignore Ar boolean
(optional) silently insert updates for this folder, if any (optional) silently insert updates for this mailbox, if any
.\" default value .\" default value
.Pq Em false .Pq Em false
.It Ic usage Ar boolean .It Ic usage Ar boolean
(optional) special usage of this folder. (optional) special usage of this mailbox.
Valid values are: Valid values are:
.Bl -bullet -compact .Bl -bullet -compact
.It .It
@ -248,9 +248,9 @@ Valid values are:
.It .It
.Ar Trash .Ar Trash
.El .El
otherwise usage is inferred from the folder title. otherwise usage is inferred from the mailbox title.
.It Ic conf_override Ar boolean .It Ic conf_override Ar boolean
(optional) override global settings for this folder. (optional) override global settings for this mailbox.
Available sections to override are Available sections to override are
.Em pager, notifications, shortcuts, composing .Em pager, notifications, shortcuts, composing
and the account options and the account options
@ -258,9 +258,9 @@ and the account options
\&. \&.
Example: Example:
.Bd -literal .Bd -literal
[accounts."imap.domain.tld".folders."INBOX"] [accounts."imap.domain.tld".mailboxes."INBOX"]
index_style = "plain" index_style = "plain"
[accounts."imap.domain.tld".folders."INBOX".pager] [accounts."imap.domain.tld".mailboxes."INBOX".pager]
filter = "" filter = ""
.Ed .Ed
.El .El
@ -347,12 +347,12 @@ Go to previous page.
Go to next page. Go to next page.
.\" default value .\" default value
.Pq Em PageDown .Pq Em PageDown
.It Ic prev_folder .It Ic prev_mailbox
Go to previous folder. Go to previous mailbox.
.\" default value .\" default value
.Pq Em K .Pq Em K
.It Ic next_folder .It Ic next_mailbox
Go to next folder. Go to next mailbox.
.\" default value .\" default value
.Pq Em J .Pq Em J
.It Ic prev_account .It Ic prev_account
@ -372,7 +372,7 @@ Set thread as seen.
.\" default value .\" default value
.Pq Em n .Pq Em n
.It Ic refresh .It Ic refresh
Manually request a folder refresh. Manually request a mailbox refresh.
.\" default value .\" default value
.Pq Em F5 .Pq Em F5
.It Ic search .It Ic search
@ -622,8 +622,8 @@ example configuration:
colors = { signed="#Ff6600", replied="DeepSkyBlue4", draft="#f00", replied="8" } colors = { signed="#Ff6600", replied="DeepSkyBlue4", draft="#f00", replied="8" }
[accounts.dummy] [accounts.dummy]
\&... \&...
[accounts.dummy.folders] [accounts.dummy.mailboxes]
# per folder override: # per mailbox override:
"INBOX" = { tags.ignore_tags=["inbox", ] } "INBOX" = { tags.ignore_tags=["inbox", ] }
.Ed .Ed
.Sh PGP .Sh PGP

View File

@ -193,12 +193,12 @@ pub enum RefreshEventKind {
#[derive(Debug)] #[derive(Debug)]
pub struct RefreshEvent { pub struct RefreshEvent {
hash: FolderHash, hash: MailboxHash,
kind: RefreshEventKind, kind: RefreshEventKind,
} }
impl RefreshEvent { impl RefreshEvent {
pub fn hash(&self) -> FolderHash { pub fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
pub fn kind(self) -> RefreshEventKind { pub fn kind(self) -> RefreshEventKind {
@ -220,7 +220,7 @@ impl RefreshEventConsumer {
} }
} }
pub struct NotifyFn(Box<dyn Fn(FolderHash) -> () + Send + Sync>); pub struct NotifyFn(Box<dyn Fn(MailboxHash) -> () + Send + Sync>);
impl fmt::Debug for NotifyFn { impl fmt::Debug for NotifyFn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -228,17 +228,17 @@ impl fmt::Debug for NotifyFn {
} }
} }
impl From<Box<dyn Fn(FolderHash) -> () + Send + Sync>> for NotifyFn { impl From<Box<dyn Fn(MailboxHash) -> () + Send + Sync>> for NotifyFn {
fn from(kind: Box<dyn Fn(FolderHash) -> () + Send + Sync>) -> Self { fn from(kind: Box<dyn Fn(MailboxHash) -> () + Send + Sync>) -> Self {
NotifyFn(kind) NotifyFn(kind)
} }
} }
impl NotifyFn { impl NotifyFn {
pub fn new(b: Box<dyn Fn(FolderHash) -> () + Send + Sync>) -> Self { pub fn new(b: Box<dyn Fn(MailboxHash) -> () + Send + Sync>) -> Self {
NotifyFn(b) NotifyFn(b)
} }
pub fn notify(&self, f: FolderHash) { pub fn notify(&self, f: MailboxHash) {
self.0(f); self.0(f);
} }
} }
@ -246,10 +246,10 @@ impl NotifyFn {
pub trait MailBackend: ::std::fmt::Debug + Send + Sync { pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
fn is_online(&self) -> Result<()>; fn is_online(&self) -> Result<()>;
fn connect(&mut self) {} fn connect(&mut self) {}
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>; fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>>;
fn refresh( fn refresh(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
_sender: RefreshEventConsumer, _sender: RefreshEventConsumer,
) -> Result<Async<()>> { ) -> Result<Async<()>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
@ -259,10 +259,10 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
sender: RefreshEventConsumer, sender: RefreshEventConsumer,
work_context: WorkContext, work_context: WorkContext,
) -> Result<std::thread::ThreadId>; ) -> Result<std::thread::ThreadId>;
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>>; fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>>;
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp>; fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp>;
fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()>; fn save(&self, bytes: &[u8], mailbox: &str, flags: Option<Flag>) -> Result<()>;
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {
None None
} }
@ -272,32 +272,32 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
unimplemented!() unimplemented!()
} }
fn create_folder( fn create_mailbox(
&mut self, &mut self,
_path: String, _path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> { ) -> Result<(MailboxHash, FnvHashMap<MailboxHash, Mailbox>)> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn delete_folder( fn delete_mailbox(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
) -> Result<FnvHashMap<FolderHash, Folder>> { ) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_folder_subscription(&mut self, _folder_hash: FolderHash, _val: bool) -> Result<()> { fn set_mailbox_subscription(&mut self, _mailbox_hash: MailboxHash, _val: bool) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn rename_folder(&mut self, _folder_hash: FolderHash, _new_path: String) -> Result<Folder> { fn rename_mailbox(&mut self, _mailbox_hash: MailboxHash, _new_path: String) -> Result<Mailbox> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_folder_permissions( fn set_mailbox_permissions(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
_val: FolderPermissions, _val: MailboxPermissions,
) -> Result<()> { ) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
@ -315,7 +315,7 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
/// ```ignore /// ```ignore
/// /* Create operation from Backend */ /// /* Create operation from Backend */
/// ///
/// let op = backend.operation(message.hash(), mailbox.folder.hash()); /// let op = backend.operation(message.hash(), mailbox.hash());
/// ``` /// ```
/// ///
/// # Example /// # Example
@ -443,30 +443,30 @@ impl SpecialUsageMailbox {
} }
} }
pub trait BackendFolder: Debug { pub trait BackendMailbox: Debug {
fn hash(&self) -> FolderHash; fn hash(&self) -> MailboxHash;
fn name(&self) -> &str; fn name(&self) -> &str;
/// Path of folder within the mailbox hierarchy, with `/` as separator. /// Path of mailbox within the mailbox hierarchy, with `/` as separator.
fn path(&self) -> &str; fn path(&self) -> &str;
fn change_name(&mut self, new_name: &str); fn change_name(&mut self, new_name: &str);
fn clone(&self) -> Folder; fn clone(&self) -> Mailbox;
fn children(&self) -> &[FolderHash]; fn children(&self) -> &[MailboxHash];
fn parent(&self) -> Option<FolderHash>; fn parent(&self) -> Option<MailboxHash>;
fn is_subscribed(&self) -> bool; fn is_subscribed(&self) -> bool;
fn set_is_subscribed(&mut self, new_val: bool) -> Result<()>; fn set_is_subscribed(&mut self, new_val: bool) -> Result<()>;
fn set_special_usage(&mut self, new_val: SpecialUsageMailbox) -> Result<()>; fn set_special_usage(&mut self, new_val: SpecialUsageMailbox) -> Result<()>;
fn special_usage(&self) -> SpecialUsageMailbox; fn special_usage(&self) -> SpecialUsageMailbox;
fn permissions(&self) -> FolderPermissions; fn permissions(&self) -> MailboxPermissions;
fn count(&self) -> Result<(usize, usize)>; fn count(&self) -> Result<(usize, usize)>;
} }
#[derive(Debug)] #[derive(Debug)]
struct DummyFolder { struct DummyMailbox {
v: Vec<FolderHash>, v: Vec<MailboxHash>,
} }
impl BackendFolder for DummyFolder { impl BackendMailbox for DummyMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
0 0
} }
@ -480,24 +480,24 @@ impl BackendFolder for DummyFolder {
fn change_name(&mut self, _s: &str) {} fn change_name(&mut self, _s: &str) {}
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
folder_default() mailbox_default()
} }
fn special_usage(&self) -> SpecialUsageMailbox { fn special_usage(&self) -> SpecialUsageMailbox {
SpecialUsageMailbox::Normal SpecialUsageMailbox::Normal
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.v &self.v
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
None None
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
FolderPermissions::default() MailboxPermissions::default()
} }
fn is_subscribed(&self) -> bool { fn is_subscribed(&self) -> bool {
true true
@ -513,29 +513,29 @@ impl BackendFolder for DummyFolder {
} }
} }
pub fn folder_default() -> Folder { pub fn mailbox_default() -> Mailbox {
Box::new(DummyFolder { Box::new(DummyMailbox {
v: Vec::with_capacity(0), v: Vec::with_capacity(0),
}) })
} }
pub type FolderHash = u64; pub type MailboxHash = u64;
pub type Folder = Box<dyn BackendFolder + Send + Sync>; pub type Mailbox = Box<dyn BackendMailbox + Send + Sync>;
impl Clone for Folder { impl Clone for Mailbox {
fn clone(&self) -> Self { fn clone(&self) -> Self {
BackendFolder::clone(self.deref()) BackendMailbox::clone(self.deref())
} }
} }
impl Default for Folder { impl Default for Mailbox {
fn default() -> Self { fn default() -> Self {
folder_default() mailbox_default()
} }
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct FolderPermissions { pub struct MailboxPermissions {
pub create_messages: bool, pub create_messages: bool,
pub remove_messages: bool, pub remove_messages: bool,
pub set_flags: bool, pub set_flags: bool,
@ -546,22 +546,22 @@ pub struct FolderPermissions {
pub change_permissions: bool, pub change_permissions: bool,
} }
impl Default for FolderPermissions { impl Default for MailboxPermissions {
fn default() -> Self { fn default() -> Self {
FolderPermissions { MailboxPermissions {
create_messages: false, create_messages: false,
remove_messages: false, remove_messages: false,
set_flags: false, set_flags: false,
create_child: false, create_child: false,
rename_messages: false, rename_messages: false,
delete_messages: false, delete_messages: false,
delete_mailbox: false, delete_mailbox: true,
change_permissions: false, change_permissions: false,
} }
} }
} }
impl std::fmt::Display for FolderPermissions { impl std::fmt::Display for MailboxPermissions {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{:#?}", self) write!(fmt, "{:#?}", self)
} }

View File

@ -24,8 +24,8 @@ use smallvec::SmallVec;
#[macro_use] #[macro_use]
mod protocol_parser; mod protocol_parser;
pub use protocol_parser::{UntaggedResponse::*, *}; pub use protocol_parser::{UntaggedResponse::*, *};
mod folder; mod mailbox;
pub use folder::*; pub use mailbox::*;
mod operations; mod operations;
pub use operations::*; pub use operations::*;
mod connection; mod connection;
@ -35,10 +35,10 @@ pub use watch::*;
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp; use crate::backends::BackendOp;
use crate::backends::FolderHash; use crate::backends::MailboxHash;
use crate::backends::RefreshEvent; use crate::backends::RefreshEvent;
use crate::backends::RefreshEventKind::{self, *}; use crate::backends::RefreshEventKind::{self, *};
use crate::backends::{BackendFolder, Folder, MailBackend, RefreshEventConsumer}; use crate::backends::{BackendMailbox, MailBackend, Mailbox, RefreshEventConsumer};
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::*; use crate::email::*;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
@ -117,8 +117,8 @@ macro_rules! get_conf_val {
#[derive(Debug)] #[derive(Debug)]
pub struct UIDStore { pub struct UIDStore {
uidvalidity: Arc<Mutex<FnvHashMap<FolderHash, UID>>>, uidvalidity: Arc<Mutex<FnvHashMap<MailboxHash, UID>>>,
hash_index: Arc<Mutex<FnvHashMap<EnvelopeHash, (UID, FolderHash)>>>, hash_index: Arc<Mutex<FnvHashMap<EnvelopeHash, (UID, MailboxHash)>>>,
uid_index: Arc<Mutex<FnvHashMap<UID, EnvelopeHash>>>, uid_index: Arc<Mutex<FnvHashMap<UID, EnvelopeHash>>>,
byte_cache: Arc<Mutex<FnvHashMap<UID, EnvelopeCache>>>, byte_cache: Arc<Mutex<FnvHashMap<UID, EnvelopeCache>>>,
@ -134,7 +134,7 @@ pub struct ImapType {
can_create_flags: Arc<Mutex<bool>>, can_create_flags: Arc<Mutex<bool>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>, mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, ImapMailbox>>>,
} }
impl MailBackend for ImapType { impl MailBackend for ImapType {
@ -152,16 +152,16 @@ impl MailBackend for ImapType {
} }
} }
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let uid_store = self.uid_store.clone(); let uid_store = self.uid_store.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
let can_create_flags = self.can_create_flags.clone(); let can_create_flags = self.can_create_flags.clone();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let (permissions, folder_path, folder_exists, no_select, unseen) = { let (permissions, mailbox_path, mailbox_exists, no_select, unseen) = {
let f = &self.folders.read().unwrap()[&folder_hash]; let f = &self.mailboxes.read().unwrap()[&mailbox_hash];
( (
f.permissions.clone(), f.permissions.clone(),
f.imap_path().to_string(), f.imap_path().to_string(),
@ -182,24 +182,24 @@ impl MailBackend for ImapType {
let tx = _tx; let tx = _tx;
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = connection.lock()?; let mut conn = connection.lock()?;
debug!("locked for get {}", folder_path); debug!("locked for get {}", mailbox_path);
/* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only /* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only
* returns READ-ONLY for both cases) */ * returns READ-ONLY for both cases) */
conn.send_command(format!("SELECT \"{}\"", folder_path).as_bytes())?; conn.send_command(format!("SELECT \"{}\"", mailbox_path).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
let examine_response = protocol_parser::select_response(&response)?; let examine_response = protocol_parser::select_response(&response)?;
*can_create_flags.lock().unwrap() = examine_response.can_create_flags; *can_create_flags.lock().unwrap() = examine_response.can_create_flags;
debug!( debug!(
"folder: {} examine_response: {:?}", "mailbox: {} examine_response: {:?}",
folder_path, examine_response mailbox_path, examine_response
); );
let mut exists: usize = examine_response.uidnext - 1; let mut exists: usize = examine_response.uidnext - 1;
{ {
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
let v = uidvalidities let v = uidvalidities
.entry(folder_hash) .entry(mailbox_hash)
.or_insert(examine_response.uidvalidity); .or_insert(examine_response.uidvalidity);
*v = examine_response.uidvalidity; *v = examine_response.uidvalidity;
@ -210,11 +210,11 @@ impl MailBackend for ImapType {
permissions.rename_messages = !examine_response.read_only; permissions.rename_messages = !examine_response.read_only;
permissions.delete_messages = !examine_response.read_only; permissions.delete_messages = !examine_response.read_only;
permissions.delete_messages = !examine_response.read_only; permissions.delete_messages = !examine_response.read_only;
let mut folder_exists = folder_exists.lock().unwrap(); let mut mailbox_exists = mailbox_exists.lock().unwrap();
*folder_exists = exists; *mailbox_exists = exists;
} }
/* reselecting the same mailbox with EXAMINE prevents expunging it */ /* reselecting the same mailbox with EXAMINE prevents expunging it */
conn.send_command(format!("EXAMINE \"{}\"", folder_path).as_bytes())?; conn.send_command(format!("EXAMINE \"{}\"", mailbox_path).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
let mut tag_lck = tag_index.write().unwrap(); let mut tag_lck = tag_index.write().unwrap();
@ -247,7 +247,7 @@ impl MailBackend for ImapType {
let mut env = envelope.unwrap(); let mut env = envelope.unwrap();
let mut h = DefaultHasher::new(); let mut h = DefaultHasher::new();
h.write_usize(uid); h.write_usize(uid);
h.write(folder_path.as_bytes()); h.write(mailbox_path.as_bytes());
env.set_hash(h.finish()); env.set_hash(h.finish());
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
if !flags.contains(Flag::SEEN) { if !flags.contains(Flag::SEEN) {
@ -266,7 +266,7 @@ impl MailBackend for ImapType {
.hash_index .hash_index
.lock() .lock()
.unwrap() .unwrap()
.insert(env.hash(), (uid, folder_hash)); .insert(env.hash(), (uid, mailbox_hash));
uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); uid_store.uid_index.lock().unwrap().insert(uid, env.hash());
envelopes.push(env); envelopes.push(env);
} }
@ -290,15 +290,15 @@ impl MailBackend for ImapType {
fn refresh( fn refresh(
&mut self, &mut self,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
sender: RefreshEventConsumer, sender: RefreshEventConsumer,
) -> Result<Async<()>> { ) -> Result<Async<()>> {
self.connection.lock().unwrap().connect()?; self.connection.lock().unwrap().connect()?;
let inbox = self let inbox = self
.folders .mailboxes
.read() .read()
.unwrap() .unwrap()
.get(&folder_hash) .get(&mailbox_hash)
.map(std::clone::Clone::clone) .map(std::clone::Clone::clone)
.unwrap(); .unwrap();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
@ -340,7 +340,7 @@ impl MailBackend for ImapType {
sender: RefreshEventConsumer, sender: RefreshEventConsumer,
work_context: WorkContext, work_context: WorkContext,
) -> Result<std::thread::ThreadId> { ) -> Result<std::thread::ThreadId> {
let folders = self.folders.clone(); let mailboxes = self.mailboxes.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
let conn = ImapConnection::new_connection(&self.server_conf, self.online.clone()); let conn = ImapConnection::new_connection(&self.server_conf, self.online.clone());
let main_conn = self.connection.clone(); let main_conn = self.connection.clone();
@ -365,7 +365,7 @@ impl MailBackend for ImapType {
is_online, is_online,
main_conn, main_conn,
uid_store, uid_store,
folders, mailboxes,
sender, sender,
work_context, work_context,
tag_index, tag_index,
@ -379,38 +379,41 @@ impl MailBackend for ImapType {
Ok(handle.thread().id()) Ok(handle.thread().id())
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
{ {
let folders = self.folders.read().unwrap(); let mailboxes = self.mailboxes.read().unwrap();
if !folders.is_empty() { if !mailboxes.is_empty() {
return Ok(folders return Ok(mailboxes
.iter() .iter()
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder)) .map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Mailbox))
.collect()); .collect());
} }
} }
let mut folders = self.folders.write()?; let mut mailboxes = self.mailboxes.write()?;
*folders = ImapType::imap_folders(&self.connection)?; *mailboxes = ImapType::imap_mailboxes(&self.connection)?;
folders.retain(|_, f| (self.is_subscribed)(f.path())); mailboxes.retain(|_, f| (self.is_subscribed)(f.path()));
let keys = folders.keys().cloned().collect::<FnvHashSet<FolderHash>>(); let keys = mailboxes
.keys()
.cloned()
.collect::<FnvHashSet<MailboxHash>>();
let mut uid_lock = self.uid_store.uidvalidity.lock().unwrap(); let mut uid_lock = self.uid_store.uidvalidity.lock().unwrap();
for f in folders.values_mut() { for f in mailboxes.values_mut() {
uid_lock.entry(f.hash()).or_default(); uid_lock.entry(f.hash()).or_default();
f.children.retain(|c| keys.contains(c)); f.children.retain(|c| keys.contains(c));
} }
drop(uid_lock); drop(uid_lock);
Ok(folders Ok(mailboxes
.iter() .iter()
.filter(|(_, f)| f.is_subscribed) .filter(|(_, f)| f.is_subscribed)
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder)) .map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Mailbox))
.collect()) .collect())
} }
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> { fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
let (uid, folder_hash) = self.uid_store.hash_index.lock().unwrap()[&hash]; let (uid, mailbox_hash) = self.uid_store.hash_index.lock().unwrap()[&hash];
Box::new(ImapOp::new( Box::new(ImapOp::new(
uid, uid,
self.folders.read().unwrap()[&folder_hash] self.mailboxes.read().unwrap()[&mailbox_hash]
.imap_path() .imap_path()
.to_string(), .to_string(),
self.connection.clone(), self.connection.clone(),
@ -419,28 +422,28 @@ impl MailBackend for ImapType {
)) ))
} }
fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> { fn save(&self, bytes: &[u8], mailbox: &str, flags: Option<Flag>) -> Result<()> {
let path = { let path = {
let folders = self.folders.read().unwrap(); let mailboxes = self.mailboxes.read().unwrap();
let f_result = folders let f_result = mailboxes
.values() .values()
.find(|v| v.path == folder || v.name == folder); .find(|v| v.path == mailbox || v.name == mailbox);
if f_result if f_result
.map(|f| !f.permissions.lock().unwrap().create_messages) .map(|f| !f.permissions.lock().unwrap().create_messages)
.unwrap_or(false) .unwrap_or(false)
{ {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"You are not allowed to create messages in folder {}", "You are not allowed to create messages in mailbox {}",
folder mailbox
))); )));
} }
f_result f_result
.map(|v| v.imap_path().to_string()) .map(|v| v.imap_path().to_string())
.ok_or(MeliError::new(format!( .ok_or(MeliError::new(format!(
"Folder with name {} not found.", "Mailbox with name {} not found.",
folder mailbox
)))? )))?
}; };
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
@ -478,10 +481,10 @@ impl MailBackend for ImapType {
} }
} }
fn create_folder( fn create_mailbox(
&mut self, &mut self,
mut path: String, mut path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> { ) -> Result<(MailboxHash, FnvHashMap<MailboxHash, Mailbox>)> {
/* Must transform path to something the IMAP server will accept /* Must transform path to something the IMAP server will accept
* *
* Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths * Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths
@ -496,21 +499,21 @@ impl MailBackend for ImapType {
* decision is unpleasant for you. * decision is unpleasant for you.
*/ */
let mut folders = self.folders.write().unwrap(); let mut mailboxes = self.mailboxes.write().unwrap();
for root_folder in folders.values().filter(|f| f.parent.is_none()) { for root_mailbox in mailboxes.values().filter(|f| f.parent.is_none()) {
if path.starts_with(&root_folder.name) { if path.starts_with(&root_mailbox.name) {
debug!("path starts with {:?}", &root_folder); debug!("path starts with {:?}", &root_mailbox);
path = path.replace( path = path.replace(
'/', '/',
(root_folder.separator as char).encode_utf8(&mut [0; 4]), (root_mailbox.separator as char).encode_utf8(&mut [0; 4]),
); );
break; break;
} }
} }
if folders.values().any(|f| f.path == path) { if mailboxes.values().any(|f| f.path == path) {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Folder named `{}` in account `{}` already exists.", "Mailbox named `{}` in account `{}` already exists.",
path, self.account_name, path, self.account_name,
))); )));
} }
@ -527,21 +530,24 @@ impl MailBackend for ImapType {
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
ret?; ret?;
let new_hash = get_path_hash!(path.as_str()); let new_hash = get_path_hash!(path.as_str());
folders.clear(); mailboxes.clear();
drop(folders); drop(mailboxes);
Ok((new_hash, self.folders().map_err(|err| MeliError::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err)))?)) Ok((new_hash, self.mailboxes().map_err(|err| MeliError::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err)))?))
} }
fn delete_folder(&mut self, folder_hash: FolderHash) -> Result<FnvHashMap<FolderHash, Folder>> { fn delete_mailbox(
let mut folders = self.folders.write().unwrap(); &mut self,
let permissions = folders[&folder_hash].permissions(); mailbox_hash: MailboxHash,
) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
let mut mailboxes = self.mailboxes.write().unwrap();
let permissions = mailboxes[&mailbox_hash].permissions();
if !permissions.delete_mailbox { if !permissions.delete_mailbox {
return Err(MeliError::new(format!("You do not have permission to delete `{}`. Set permissions for this mailbox are {}", folders[&folder_hash].name(), permissions))); return Err(MeliError::new(format!("You do not have permission to delete `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
} }
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
{ {
let mut conn_lck = self.connection.lock()?; let mut conn_lck = self.connection.lock()?;
if !folders[&folder_hash].no_select { if !mailboxes[&mailbox_hash].no_select {
/* make sure mailbox is not selected before it gets deleted, otherwise /* make sure mailbox is not selected before it gets deleted, otherwise
* connection gets dropped by server */ * connection gets dropped by server */
if conn_lck if conn_lck
@ -550,42 +556,46 @@ impl MailBackend for ImapType {
.any(|cap| cap.eq_ignore_ascii_case(b"UNSELECT")) .any(|cap| cap.eq_ignore_ascii_case(b"UNSELECT"))
{ {
conn_lck.send_command( conn_lck.send_command(
format!("UNSELECT \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("UNSELECT \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
} else { } else {
conn_lck.send_command( conn_lck.send_command(
format!("SELECT \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("SELECT \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
conn_lck.send_command( conn_lck.send_command(
format!("EXAMINE \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("EXAMINE \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
} }
} }
if folders[&folder_hash].is_subscribed() { if mailboxes[&mailbox_hash].is_subscribed() {
conn_lck.send_command( conn_lck.send_command(
format!("UNSUBSCRIBE \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("UNSUBSCRIBE \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
} }
conn_lck.send_command( conn_lck.send_command(
debug!(format!("DELETE \"{}\"", folders[&folder_hash].imap_path())).as_bytes(), debug!(format!(
"DELETE \"{}\"",
mailboxes[&mailbox_hash].imap_path()
))
.as_bytes(),
)?; )?;
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
} }
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
ret?; ret?;
folders.clear(); mailboxes.clear();
drop(folders); drop(mailboxes);
self.folders().map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err).into()) self.mailboxes().map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err).into())
} }
fn set_folder_subscription(&mut self, folder_hash: FolderHash, new_val: bool) -> Result<()> { fn set_mailbox_subscription(&mut self, mailbox_hash: MailboxHash, new_val: bool) -> Result<()> {
let mut folders = self.folders.write().unwrap(); let mut mailboxes = self.mailboxes.write().unwrap();
if folders[&folder_hash].is_subscribed() == new_val { if mailboxes[&mailbox_hash].is_subscribed() == new_val {
return Ok(()); return Ok(());
} }
@ -594,11 +604,11 @@ impl MailBackend for ImapType {
let mut conn_lck = self.connection.lock()?; let mut conn_lck = self.connection.lock()?;
if new_val { if new_val {
conn_lck.send_command( conn_lck.send_command(
format!("SUBSCRIBE \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("SUBSCRIBE \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
} else { } else {
conn_lck.send_command( conn_lck.send_command(
format!("UNSUBSCRIBE \"{}\"", folders[&folder_hash].imap_path()).as_bytes(), format!("UNSUBSCRIBE \"{}\"", mailboxes[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
} }
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
@ -606,24 +616,28 @@ impl MailBackend for ImapType {
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
if ret.is_ok() { if ret.is_ok() {
folders.entry(folder_hash).and_modify(|entry| { mailboxes.entry(mailbox_hash).and_modify(|entry| {
let _ = entry.set_is_subscribed(new_val); let _ = entry.set_is_subscribed(new_val);
}); });
} }
ret ret
} }
fn rename_folder(&mut self, folder_hash: FolderHash, mut new_path: String) -> Result<Folder> { fn rename_mailbox(
let mut folders = self.folders.write().unwrap(); &mut self,
let permissions = folders[&folder_hash].permissions(); mailbox_hash: MailboxHash,
mut new_path: String,
) -> Result<Mailbox> {
let mut mailboxes = self.mailboxes.write().unwrap();
let permissions = mailboxes[&mailbox_hash].permissions();
if !permissions.delete_mailbox { if !permissions.delete_mailbox {
return Err(MeliError::new(format!("You do not have permission to rename folder `{}` (rename is equivalent to delete + create). Set permissions for this mailbox are {}", folders[&folder_hash].name(), permissions))); return Err(MeliError::new(format!("You do not have permission to rename mailbox `{}` (rename is equivalent to delete + create). Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
} }
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
if folders[&folder_hash].separator != b'/' { if mailboxes[&mailbox_hash].separator != b'/' {
new_path = new_path.replace( new_path = new_path.replace(
'/', '/',
(folders[&folder_hash].separator as char).encode_utf8(&mut [0; 4]), (mailboxes[&mailbox_hash].separator as char).encode_utf8(&mut [0; 4]),
); );
} }
{ {
@ -631,7 +645,7 @@ impl MailBackend for ImapType {
conn_lck.send_command( conn_lck.send_command(
debug!(format!( debug!(format!(
"RENAME \"{}\" \"{}\"", "RENAME \"{}\" \"{}\"",
folders[&folder_hash].imap_path(), mailboxes[&mailbox_hash].imap_path(),
new_path new_path
)) ))
.as_bytes(), .as_bytes(),
@ -641,23 +655,23 @@ impl MailBackend for ImapType {
let new_hash = get_path_hash!(new_path.as_str()); let new_hash = get_path_hash!(new_path.as_str());
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
ret?; ret?;
folders.clear(); mailboxes.clear();
drop(folders); drop(mailboxes);
self.folders().map_err(|err| format!("Mailbox rename was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err))?; self.mailboxes().map_err(|err| format!("Mailbox rename was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err))?;
Ok(BackendFolder::clone( Ok(BackendMailbox::clone(
&self.folders.read().unwrap()[&new_hash], &self.mailboxes.read().unwrap()[&new_hash],
)) ))
} }
fn set_folder_permissions( fn set_mailbox_permissions(
&mut self, &mut self,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
_val: crate::backends::FolderPermissions, _val: crate::backends::MailboxPermissions,
) -> Result<()> { ) -> Result<()> {
let folders = self.folders.write().unwrap(); let mailboxes = self.mailboxes.write().unwrap();
let permissions = folders[&folder_hash].permissions(); let permissions = mailboxes[&mailbox_hash].permissions();
if !permissions.change_permissions { if !permissions.change_permissions {
return Err(MeliError::new(format!("You do not have permission to change permissions for folder `{}`. Set permissions for this mailbox are {}", folders[&folder_hash].name(), permissions))); return Err(MeliError::new(format!("You do not have permission to change permissions for mailbox `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions)));
} }
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
@ -698,7 +712,7 @@ impl ImapType {
can_create_flags: Arc::new(Mutex::new(false)), can_create_flags: Arc::new(Mutex::new(false)),
tag_index: Arc::new(RwLock::new(Default::default())), tag_index: Arc::new(RwLock::new(Default::default())),
folders: Arc::new(RwLock::new(Default::default())), mailboxes: Arc::new(RwLock::new(Default::default())),
connection: Arc::new(Mutex::new(connection)), connection: Arc::new(Mutex::new(connection)),
uid_store: Arc::new(UIDStore { uid_store: Arc::new(UIDStore {
uidvalidity: Default::default(), uidvalidity: Default::default(),
@ -742,10 +756,10 @@ impl ImapType {
} }
} }
pub fn imap_folders( pub fn imap_mailboxes(
connection: &Arc<Mutex<ImapConnection>>, connection: &Arc<Mutex<ImapConnection>>,
) -> Result<FnvHashMap<FolderHash, ImapFolder>> { ) -> Result<FnvHashMap<MailboxHash, ImapMailbox>> {
let mut folders: FnvHashMap<FolderHash, ImapFolder> = Default::default(); let mut mailboxes: FnvHashMap<MailboxHash, ImapMailbox> = Default::default();
let mut res = String::with_capacity(8 * 1024); let mut res = String::with_capacity(8 * 1024);
let mut conn = connection.lock().unwrap(); let mut conn = connection.lock().unwrap();
conn.send_command(b"LIST \"\" \"*\"")?; conn.send_command(b"LIST \"\" \"*\"")?;
@ -755,33 +769,33 @@ impl ImapType {
/* Remove "M__ OK .." line */ /* Remove "M__ OK .." line */
lines.next_back(); lines.next_back();
for l in lines.map(|l| l.trim()) { for l in lines.map(|l| l.trim()) {
if let Ok(mut folder) = if let Ok(mut mailbox) =
protocol_parser::list_folder_result(l.as_bytes()).to_full_result() protocol_parser::list_mailbox_result(l.as_bytes()).to_full_result()
{ {
if let Some(parent) = folder.parent { if let Some(parent) = mailbox.parent {
if folders.contains_key(&parent) { if mailboxes.contains_key(&parent) {
folders mailboxes
.entry(parent) .entry(parent)
.and_modify(|e| e.children.push(folder.hash)); .and_modify(|e| e.children.push(mailbox.hash));
} else { } else {
/* Insert dummy parent entry, populating only the children field. Later /* Insert dummy parent entry, populating only the children field. Later
* when we encounter the parent entry we will swap its children with * when we encounter the parent entry we will swap its children with
* dummy's */ * dummy's */
folders.insert( mailboxes.insert(
parent, parent,
ImapFolder { ImapMailbox {
children: vec![folder.hash], children: vec![mailbox.hash],
..ImapFolder::default() ..ImapMailbox::default()
}, },
); );
} }
} }
if folders.contains_key(&folder.hash) { if mailboxes.contains_key(&mailbox.hash) {
let entry = folders.entry(folder.hash).or_default(); let entry = mailboxes.entry(mailbox.hash).or_default();
std::mem::swap(&mut entry.children, &mut folder.children); std::mem::swap(&mut entry.children, &mut mailbox.children);
*entry = folder; *entry = mailbox;
} else { } else {
folders.insert(folder.hash, folder); mailboxes.insert(mailbox.hash, mailbox);
} }
} else { } else {
debug!("parse error for {:?}", l); debug!("parse error for {:?}", l);
@ -795,9 +809,9 @@ impl ImapType {
lines.next_back(); lines.next_back();
for l in lines.map(|l| l.trim()) { for l in lines.map(|l| l.trim()) {
if let Ok(subscription) = if let Ok(subscription) =
protocol_parser::list_folder_result(l.as_bytes()).to_full_result() protocol_parser::list_mailbox_result(l.as_bytes()).to_full_result()
{ {
if let Some(f) = folders.get_mut(&subscription.hash()) { if let Some(f) = mailboxes.get_mut(&subscription.hash()) {
if subscription.no_select { if subscription.no_select {
continue; continue;
} }
@ -807,7 +821,7 @@ impl ImapType {
debug!("parse error for {:?}", l); debug!("parse error for {:?}", l);
} }
} }
Ok(debug!(folders)) Ok(debug!(mailboxes))
} }
pub fn capabilities(&self) -> Vec<String> { pub fn capabilities(&self) -> Vec<String> {
@ -823,13 +837,13 @@ impl ImapType {
pub fn search( pub fn search(
&self, &self,
query: String, query: String,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
) -> Result<SmallVec<[EnvelopeHash; 512]>> { ) -> Result<SmallVec<[EnvelopeHash; 512]>> {
let folders_lck = self.folders.read()?; let mailboxes_lck = self.mailboxes.read()?;
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock()?; let mut conn = self.connection.lock()?;
conn.send_command( conn.send_command(
format!("EXAMINE \"{}\"", folders_lck[&folder_hash].imap_path()).as_bytes(), format!("EXAMINE \"{}\"", mailboxes_lck[&mailbox_hash].imap_path()).as_bytes(),
)?; )?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
conn.send_command(format!("UID SEARCH CHARSET UTF-8 {}", query).as_bytes())?; conn.send_command(format!("UID SEARCH CHARSET UTF-8 {}", query).as_bytes())?;

View File

@ -18,36 +18,38 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
use crate::backends::{BackendFolder, Folder, FolderHash, FolderPermissions, SpecialUsageMailbox}; use crate::backends::{
BackendMailbox, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox,
};
use crate::error::*; use crate::error::*;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct ImapFolder { pub struct ImapMailbox {
pub(super) hash: FolderHash, pub(super) hash: MailboxHash,
pub(super) imap_path: String, pub(super) imap_path: String,
pub(super) path: String, pub(super) path: String,
pub(super) name: String, pub(super) name: String,
pub(super) parent: Option<FolderHash>, pub(super) parent: Option<MailboxHash>,
pub(super) children: Vec<FolderHash>, pub(super) children: Vec<MailboxHash>,
pub separator: u8, pub separator: u8,
pub usage: Arc<RwLock<SpecialUsageMailbox>>, pub usage: Arc<RwLock<SpecialUsageMailbox>>,
pub no_select: bool, pub no_select: bool,
pub is_subscribed: bool, pub is_subscribed: bool,
pub permissions: Arc<Mutex<FolderPermissions>>, pub permissions: Arc<Mutex<MailboxPermissions>>,
pub exists: Arc<Mutex<usize>>, pub exists: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>, pub unseen: Arc<Mutex<usize>>,
} }
impl ImapFolder { impl ImapMailbox {
pub fn imap_path(&self) -> &str { pub fn imap_path(&self) -> &str {
&self.imap_path &self.imap_path
} }
} }
impl BackendFolder for ImapFolder { impl BackendMailbox for ImapMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
@ -63,11 +65,11 @@ impl BackendFolder for ImapFolder {
self.name = s.to_string(); self.name = s.to_string();
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.children &self.children
} }
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
Box::new(std::clone::Clone::clone(self)) Box::new(std::clone::Clone::clone(self))
} }
@ -75,11 +77,11 @@ impl BackendFolder for ImapFolder {
*self.usage.read().unwrap() *self.usage.read().unwrap()
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
self.parent self.parent
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
*self.permissions.lock().unwrap() *self.permissions.lock().unwrap()
} }
fn is_subscribed(&self) -> bool { fn is_subscribed(&self) -> bool {

View File

@ -34,7 +34,7 @@ pub struct ImapOp {
bytes: Option<String>, bytes: Option<String>,
headers: Option<String>, headers: Option<String>,
body: Option<String>, body: Option<String>,
folder_path: String, mailbox_path: String,
flags: Cell<Option<Flag>>, flags: Cell<Option<Flag>>,
connection: Arc<Mutex<ImapConnection>>, connection: Arc<Mutex<ImapConnection>>,
uid_store: Arc<UIDStore>, uid_store: Arc<UIDStore>,
@ -44,7 +44,7 @@ pub struct ImapOp {
impl ImapOp { impl ImapOp {
pub fn new( pub fn new(
uid: usize, uid: usize,
folder_path: String, mailbox_path: String,
connection: Arc<Mutex<ImapConnection>>, connection: Arc<Mutex<ImapConnection>>,
uid_store: Arc<UIDStore>, uid_store: Arc<UIDStore>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
@ -55,7 +55,7 @@ impl ImapOp {
bytes: None, bytes: None,
headers: None, headers: None,
body: None, body: None,
folder_path, mailbox_path,
flags: Cell::new(None), flags: Cell::new(None),
uid_store, uid_store,
tag_index, tag_index,
@ -78,7 +78,7 @@ impl BackendOp for ImapOp {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
{ {
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?; conn.send_command(format!("SELECT \"{}\"", &self.mailbox_path,).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
conn.send_command(format!("UID FETCH {} (FLAGS RFC822)", self.uid).as_bytes())?; conn.send_command(format!("UID FETCH {} (FLAGS RFC822)", self.uid).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
@ -116,7 +116,7 @@ impl BackendOp for ImapOp {
} else { } else {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("EXAMINE \"{}\"", &self.folder_path,).as_bytes()) conn.send_command(format!("EXAMINE \"{}\"", &self.mailbox_path,).as_bytes())
.unwrap(); .unwrap();
conn.read_response(&mut response).unwrap(); conn.read_response(&mut response).unwrap();
conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes()) conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes())
@ -154,7 +154,7 @@ impl BackendOp for ImapOp {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?; conn.send_command(format!("SELECT \"{}\"", &self.mailbox_path,).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
debug!(&response); debug!(&response);
conn.send_command( conn.send_command(
@ -190,7 +190,7 @@ impl BackendOp for ImapOp {
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> { fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?; conn.send_command(format!("SELECT \"{}\"", &self.mailbox_path,).as_bytes())?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
conn.send_command( conn.send_command(
format!( format!(

View File

@ -213,7 +213,7 @@ macro_rules! dbg_dmp (
* LIST (\HasChildren) "." INBOX * LIST (\HasChildren) "." INBOX
*/ */
named!( named!(
pub list_folder_result<ImapFolder>, pub list_mailbox_result<ImapMailbox>,
do_parse!( do_parse!(
ws!(alt_complete!(tag!("* LIST (") | tag!("* LSUB ("))) ws!(alt_complete!(tag!("* LIST (") | tag!("* LSUB (")))
>> properties: take_until!(&b")"[0..]) >> properties: take_until!(&b")"[0..])
@ -223,7 +223,7 @@ named!(
>> path: alt_complete!(delimited!(tag!("\""), is_not!("\""), tag!("\"")) | call!(rest)) >> path: alt_complete!(delimited!(tag!("\""), is_not!("\""), tag!("\"")) | call!(rest))
>> ({ >> ({
let separator: u8 = separator[0]; let separator: u8 = separator[0];
let mut f = ImapFolder::default(); let mut f = ImapMailbox::default();
f.no_select = false; f.no_select = false;
f.is_subscribed = false; f.is_subscribed = false;
for p in properties.split(|&b| b == b' ') { for p in properties.split(|&b| b == b' ') {

View File

@ -28,20 +28,20 @@ pub struct ImapWatchKit {
pub is_online: Arc<Mutex<(Instant, Result<()>)>>, pub is_online: Arc<Mutex<(Instant, Result<()>)>>,
pub main_conn: Arc<Mutex<ImapConnection>>, pub main_conn: Arc<Mutex<ImapConnection>>,
pub uid_store: Arc<UIDStore>, pub uid_store: Arc<UIDStore>,
pub folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>, pub mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, ImapMailbox>>>,
pub sender: RefreshEventConsumer, pub sender: RefreshEventConsumer,
pub work_context: WorkContext, pub work_context: WorkContext,
pub tag_index: Arc<RwLock<BTreeMap<u64, String>>>, pub tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
} }
macro_rules! exit_on_error { macro_rules! exit_on_error {
($sender:expr, $folder_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => { ($sender:expr, $mailbox_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => {
$(if let Err(e) = $result { $(if let Err(e) = $result {
debug!("failure: {}", e.to_string()); debug!("failure: {}", e.to_string());
$work_context.set_status.send(($thread_id, e.to_string())).unwrap(); $work_context.set_status.send(($thread_id, e.to_string())).unwrap();
$work_context.finished.send($thread_id).unwrap(); $work_context.finished.send($thread_id).unwrap();
$sender.send(RefreshEvent { $sender.send(RefreshEvent {
hash: $folder_hash, hash: $mailbox_hash,
kind: RefreshEventKind::Failure(e.clone()), kind: RefreshEventKind::Failure(e.clone()),
}); });
Err(e) Err(e)
@ -56,7 +56,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
mut conn, mut conn,
main_conn, main_conn,
uid_store, uid_store,
folders, mailboxes,
sender, sender,
work_context, work_context,
tag_index, tag_index,
@ -76,17 +76,17 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
.send((thread_id, "sleeping...".to_string())) .send((thread_id, "sleeping...".to_string()))
.unwrap(); .unwrap();
std::thread::sleep(std::time::Duration::from_millis(5 * 60 * 1000)); std::thread::sleep(std::time::Duration::from_millis(5 * 60 * 1000));
let folders = folders.read().unwrap(); let mailboxes = mailboxes.read().unwrap();
for folder in folders.values() { for mailbox in mailboxes.values() {
work_context work_context
.set_status .set_status
.send(( .send((
thread_id, thread_id,
format!("examining `{}` for updates...", folder.path()), format!("examining `{}` for updates...", mailbox.path()),
)) ))
.unwrap(); .unwrap();
examine_updates( examine_updates(
folder, mailbox,
&sender, &sender,
&mut conn, &mut conn,
&uid_store, &uid_store,
@ -109,7 +109,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
is_online, is_online,
main_conn, main_conn,
uid_store, uid_store,
folders, mailboxes,
sender, sender,
work_context, work_context,
tag_index, tag_index,
@ -122,16 +122,16 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
conn.connect()?; conn.connect()?;
let thread_id: std::thread::ThreadId = std::thread::current().id(); let thread_id: std::thread::ThreadId = std::thread::current().id();
let folder: ImapFolder = match folders let mailbox: ImapMailbox = match mailboxes
.read() .read()
.unwrap() .unwrap()
.values() .values()
.find(|f| f.parent.is_none() && (f.special_usage() == SpecialUsageMailbox::Inbox)) .find(|f| f.parent.is_none() && (f.special_usage() == SpecialUsageMailbox::Inbox))
.map(std::clone::Clone::clone) .map(std::clone::Clone::clone)
{ {
Some(folder) => folder, Some(mailbox) => mailbox,
None => { None => {
let err = MeliError::new("INBOX mailbox not found in local folder index. meli may have not parsed the IMAP folders correctly"); let err = MeliError::new("INBOX mailbox not found in local mailbox index. meli may have not parsed the IMAP mailboxes correctly");
debug!("failure: {}", err.to_string()); debug!("failure: {}", err.to_string());
work_context work_context
.set_status .set_status
@ -144,28 +144,28 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
return Err(err); return Err(err);
} }
}; };
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(format!("SELECT \"{}\"", folder.imap_path()).as_bytes()) conn.send_command(format!("SELECT \"{}\"", mailbox.imap_path()).as_bytes())
conn.read_response(&mut response) conn.read_response(&mut response)
); );
debug!("select response {}", &response); debug!("select response {}", &response);
{ {
let mut prev_exists = folder.exists.lock().unwrap(); let mut prev_exists = mailbox.exists.lock().unwrap();
*prev_exists = match protocol_parser::select_response(&response) { *prev_exists = match protocol_parser::select_response(&response) {
Ok(ok) => { Ok(ok) => {
{ {
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
if let Some(v) = uidvalidities.get_mut(&folder_hash) { if let Some(v) = uidvalidities.get_mut(&mailbox_hash) {
if *v != ok.uidvalidity { if *v != ok.uidvalidity {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
*prev_exists = 0; *prev_exists = 0;
@ -176,15 +176,15 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"Unknown mailbox: {} {}", "Unknown mailbox: {} {}",
folder.path(), mailbox.path(),
folder_hash mailbox_hash
))), ))),
}); });
} }
@ -200,7 +200,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(b"IDLE") conn.send_command(b"IDLE")
@ -214,14 +214,14 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
let mut watch = std::time::Instant::now(); let mut watch = std::time::Instant::now();
/* duration interval to send heartbeat */ /* duration interval to send heartbeat */
let _26_mins = std::time::Duration::from_secs(26 * 60); let _26_mins = std::time::Duration::from_secs(26 * 60);
/* duration interval to check other folders for changes */ /* duration interval to check other mailboxes for changes */
let _5_mins = std::time::Duration::from_secs(5 * 60); let _5_mins = std::time::Duration::from_secs(5 * 60);
while let Some(line) = iter.next() { while let Some(line) = iter.next() {
let now = std::time::Instant::now(); let now = std::time::Instant::now();
if now.duration_since(beat) >= _26_mins { if now.duration_since(beat) >= _26_mins {
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
iter.conn.set_nonblocking(true) iter.conn.set_nonblocking(true)
@ -237,21 +237,21 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
if now.duration_since(watch) >= _5_mins { if now.duration_since(watch) >= _5_mins {
/* Time to poll all inboxes */ /* Time to poll all inboxes */
let mut conn = main_conn.lock().unwrap(); let mut conn = main_conn.lock().unwrap();
for folder in folders.read().unwrap().values() { for mailbox in mailboxes.read().unwrap().values() {
work_context work_context
.set_status .set_status
.send(( .send((
thread_id, thread_id,
format!("examining `{}` for updates...", folder.path()), format!("examining `{}` for updates...", mailbox.path()),
)) ))
.unwrap(); .unwrap();
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
examine_updates( examine_updates(
folder, mailbox,
&sender, &sender,
&mut conn, &mut conn,
&uid_store, &uid_store,
@ -279,7 +279,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
/* UID SEARCH RECENT */ /* UID SEARCH RECENT */
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(b"EXAMINE INBOX") conn.send_command(b"EXAMINE INBOX")
@ -297,7 +297,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
Ok(v) => { Ok(v) => {
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command( conn.send_command(
@ -331,13 +331,13 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.hash_index .hash_index
.lock() .lock()
.unwrap() .unwrap()
.insert(env.hash(), (uid, folder_hash)); .insert(env.hash(), (uid, mailbox_hash));
uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); uid_store.uid_index.lock().unwrap().insert(uid, env.hash());
debug!( debug!(
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
env.subject(), env.subject(),
folder.path(), mailbox.path(),
); );
if let Some((_, keywords)) = flags { if let Some((_, keywords)) = flags {
let mut tag_lck = tag_index.write().unwrap(); let mut tag_lck = tag_index.write().unwrap();
@ -350,12 +350,12 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
} }
if !env.is_seen() { if !env.is_seen() {
*folder.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
*folder.exists.lock().unwrap() += 1; *mailbox.exists.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -390,7 +390,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
let mut conn = main_conn.lock().unwrap(); let mut conn = main_conn.lock().unwrap();
/* UID FETCH ALL UID, cross-ref, then FETCH difference headers /* UID FETCH ALL UID, cross-ref, then FETCH difference headers
* */ * */
let mut prev_exists = folder.exists.lock().unwrap(); let mut prev_exists = mailbox.exists.lock().unwrap();
debug!("exists {}", n); debug!("exists {}", n);
work_context work_context
.set_status .set_status
@ -400,14 +400,14 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
"got `{} EXISTS` notification (EXISTS was previously {} for {}", "got `{} EXISTS` notification (EXISTS was previously {} for {}",
n, n,
*prev_exists, *prev_exists,
folder.path() mailbox.path()
), ),
)) ))
.unwrap(); .unwrap();
if n > *prev_exists { if n > *prev_exists {
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(b"EXAMINE INBOX") conn.send_command(b"EXAMINE INBOX")
@ -450,7 +450,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.hash_index .hash_index
.lock() .lock()
.unwrap() .unwrap()
.insert(env.hash(), (uid, folder_hash)); .insert(env.hash(), (uid, mailbox_hash));
uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); uid_store.uid_index.lock().unwrap().insert(uid, env.hash());
if let Some((_, keywords)) = flags { if let Some((_, keywords)) = flags {
let mut tag_lck = tag_index.write().unwrap(); let mut tag_lck = tag_index.write().unwrap();
@ -466,13 +466,13 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
env.subject(), env.subject(),
folder.path(), mailbox.path(),
); );
if !env.is_seen() { if !env.is_seen() {
*folder.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -507,7 +507,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.unwrap(); .unwrap();
work_context.finished.send(thread_id).unwrap(); work_context.finished.send(thread_id).unwrap();
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"IDLE connection dropped: {}", "IDLE connection dropped: {}",
&err &err
@ -517,7 +517,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
pub fn examine_updates( pub fn examine_updates(
folder: &ImapFolder, mailbox: &ImapMailbox,
sender: &RefreshEventConsumer, sender: &RefreshEventConsumer,
conn: &mut ImapConnection, conn: &mut ImapConnection,
uid_store: &Arc<UIDStore>, uid_store: &Arc<UIDStore>,
@ -525,15 +525,15 @@ pub fn examine_updates(
tag_index: &Arc<RwLock<BTreeMap<u64, String>>>, tag_index: &Arc<RwLock<BTreeMap<u64, String>>>,
) -> Result<()> { ) -> Result<()> {
let thread_id: std::thread::ThreadId = std::thread::current().id(); let thread_id: std::thread::ThreadId = std::thread::current().id();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
debug!("examining folder {} {}", folder_hash, folder.path()); debug!("examining mailbox {} {}", mailbox_hash, mailbox.path());
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(format!("EXAMINE \"{}\"", folder.imap_path()).as_bytes()) conn.send_command(format!("EXAMINE \"{}\"", mailbox.imap_path()).as_bytes())
conn.read_response(&mut response) conn.read_response(&mut response)
); );
match protocol_parser::select_response(&response) { match protocol_parser::select_response(&response) {
@ -542,10 +542,10 @@ pub fn examine_updates(
{ {
let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();
if let Some(v) = uidvalidities.get_mut(&folder_hash) { if let Some(v) = uidvalidities.get_mut(&mailbox_hash) {
if *v != ok.uidvalidity { if *v != ok.uidvalidity {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
uid_store.uid_index.lock().unwrap().clear(); uid_store.uid_index.lock().unwrap().clear();
@ -555,27 +555,27 @@ pub fn examine_updates(
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"Unknown mailbox: {} {}", "Unknown mailbox: {} {}",
folder.path(), mailbox.path(),
folder_hash mailbox_hash
))), ))),
}); });
} }
} }
let mut prev_exists = folder.exists.lock().unwrap(); let mut prev_exists = mailbox.exists.lock().unwrap();
let n = ok.exists; let n = ok.exists;
if ok.recent > 0 { if ok.recent > 0 {
{ {
/* UID SEARCH RECENT */ /* UID SEARCH RECENT */
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command(b"UID SEARCH RECENT") conn.send_command(b"UID SEARCH RECENT")
@ -591,7 +591,7 @@ pub fn examine_updates(
Ok(v) => { Ok(v) => {
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command( conn.send_command(
@ -615,7 +615,7 @@ pub fn examine_updates(
.hash_index .hash_index
.lock() .lock()
.unwrap() .unwrap()
.insert(env.hash(), (uid, folder_hash)); .insert(env.hash(), (uid, mailbox_hash));
uid_store uid_store
.uid_index .uid_index
.lock() .lock()
@ -625,7 +625,7 @@ pub fn examine_updates(
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
env.subject(), env.subject(),
folder.path(), mailbox.path(),
); );
if let Some((_, keywords)) = flags { if let Some((_, keywords)) = flags {
let mut tag_lck = tag_index.write().unwrap(); let mut tag_lck = tag_index.write().unwrap();
@ -638,10 +638,10 @@ pub fn examine_updates(
} }
} }
if !env.is_seen() { if !env.is_seen() {
*folder.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -667,7 +667,7 @@ pub fn examine_updates(
debug!("exists {}", n); debug!("exists {}", n);
exit_on_error!( exit_on_error!(
sender, sender,
folder_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
conn.send_command( conn.send_command(
@ -693,7 +693,7 @@ pub fn examine_updates(
.hash_index .hash_index
.lock() .lock()
.unwrap() .unwrap()
.insert(env.hash(), (uid, folder_hash)); .insert(env.hash(), (uid, mailbox_hash));
uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); uid_store.uid_index.lock().unwrap().insert(uid, env.hash());
if let Some((_, keywords)) = flags { if let Some((_, keywords)) = flags {
let mut tag_lck = tag_index.write().unwrap(); let mut tag_lck = tag_index.write().unwrap();
@ -709,13 +709,13 @@ pub fn examine_updates(
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
env.subject(), env.subject(),
folder.path(), mailbox.path(),
); );
if !env.is_seen() { if !env.is_seen() {
*folder.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }

View File

@ -21,8 +21,8 @@
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp; use crate::backends::BackendOp;
use crate::backends::FolderHash; use crate::backends::MailboxHash;
use crate::backends::{BackendFolder, Folder, MailBackend, RefreshEventConsumer}; use crate::backends::{BackendMailbox, MailBackend, Mailbox, RefreshEventConsumer};
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::*; use crate::email::*;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
@ -71,8 +71,8 @@ use rfc8620::*;
pub mod objects; pub mod objects;
use objects::*; use objects::*;
pub mod folder; pub mod mailbox;
use folder::*; use mailbox::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EnvelopeCache { pub struct EnvelopeCache {
@ -189,7 +189,7 @@ pub struct JmapType {
connection: Arc<JmapConnection>, connection: Arc<JmapConnection>,
store: Arc<RwLock<Store>>, store: Arc<RwLock<Store>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
folders: Arc<RwLock<FnvHashMap<FolderHash, JmapFolder>>>, mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, JmapMailbox>>>,
} }
impl MailBackend for JmapType { impl MailBackend for JmapType {
@ -202,18 +202,18 @@ impl MailBackend for JmapType {
if Instant::now().duration_since(self.online.lock().unwrap().0) if Instant::now().duration_since(self.online.lock().unwrap().0)
>= std::time::Duration::new(2, 0) >= std::time::Duration::new(2, 0)
{ {
let _ = self.folders(); let _ = self.mailboxes();
} }
} }
} }
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let folders = self.folders.clone(); let mailboxes = self.mailboxes.clone();
let store = self.store.clone(); let store = self.store.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
let connection = self.connection.clone(); let connection = self.connection.clone();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let closure = move |_work_context| { let closure = move |_work_context| {
@ -221,7 +221,7 @@ impl MailBackend for JmapType {
&connection, &connection,
&store, &store,
&tag_index, &tag_index,
&folders.read().unwrap()[&folder_hash], &mailboxes.read().unwrap()[&mailbox_hash],
))) )))
.unwrap(); .unwrap();
tx.send(AsyncStatus::Finished).unwrap(); tx.send(AsyncStatus::Finished).unwrap();
@ -239,19 +239,19 @@ impl MailBackend for JmapType {
Err(MeliError::from("sadfsa")) Err(MeliError::from("sadfsa"))
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
if self.folders.read().unwrap().is_empty() { if self.mailboxes.read().unwrap().is_empty() {
let folders = std::dbg!(protocol::get_mailboxes(&self.connection))?; let mailboxes = std::dbg!(protocol::get_mailboxes(&self.connection))?;
*self.folders.write().unwrap() = folders; *self.mailboxes.write().unwrap() = mailboxes;
} }
Ok(self Ok(self
.folders .mailboxes
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.filter(|(_, f)| f.is_subscribed) .filter(|(_, f)| f.is_subscribed)
.map(|(&h, f)| (h, BackendFolder::clone(f) as Folder)) .map(|(&h, f)| (h, BackendMailbox::clone(f) as Mailbox))
.collect()) .collect())
} }
@ -263,7 +263,7 @@ impl MailBackend for JmapType {
)) ))
} }
fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> { fn save(&self, _bytes: &[u8], _mailbox: &str, _flags: Option<Flag>) -> Result<()> {
Ok(()) Ok(())
} }
@ -291,7 +291,7 @@ impl JmapType {
connection: Arc::new(JmapConnection::new(&server_conf, online.clone())?), connection: Arc::new(JmapConnection::new(&server_conf, online.clone())?),
store: Arc::new(RwLock::new(Store::default())), store: Arc::new(RwLock::new(Store::default())),
tag_index: Arc::new(RwLock::new(Default::default())), tag_index: Arc::new(RwLock::new(Default::default())),
folders: Arc::new(RwLock::new(FnvHashMap::default())), mailboxes: Arc::new(RwLock::new(FnvHashMap::default())),
account_name: s.name.clone(), account_name: s.name.clone(),
online, online,
is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)), is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)),

View File

@ -20,15 +20,15 @@
*/ */
use super::*; use super::*;
use crate::backends::{FolderPermissions, SpecialUsageMailbox}; use crate::backends::{MailboxPermissions, SpecialUsageMailbox};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct JmapFolder { pub struct JmapMailbox {
pub name: String, pub name: String,
pub path: String, pub path: String,
pub hash: FolderHash, pub hash: MailboxHash,
pub v: Vec<FolderHash>, pub v: Vec<MailboxHash>,
pub id: String, pub id: String,
pub is_subscribed: bool, pub is_subscribed: bool,
pub my_rights: JmapRights, pub my_rights: JmapRights,
@ -42,8 +42,8 @@ pub struct JmapFolder {
pub usage: Arc<RwLock<SpecialUsageMailbox>>, pub usage: Arc<RwLock<SpecialUsageMailbox>>,
} }
impl BackendFolder for JmapFolder { impl BackendMailbox for JmapMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
@ -57,20 +57,20 @@ impl BackendFolder for JmapFolder {
fn change_name(&mut self, _s: &str) {} fn change_name(&mut self, _s: &str) {}
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
Box::new(std::clone::Clone::clone(self)) Box::new(std::clone::Clone::clone(self))
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.v &self.v
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
None None
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
FolderPermissions::default() MailboxPermissions::default()
} }
fn special_usage(&self) -> SpecialUsageMailbox { fn special_usage(&self) -> SpecialUsageMailbox {
@ -83,7 +83,7 @@ impl BackendFolder for JmapFolder {
Some("sent") => SpecialUsageMailbox::Sent, Some("sent") => SpecialUsageMailbox::Sent,
Some(other) => { Some(other) => {
debug!( debug!(
"unknown JMAP mailbox role for folder {}: {}", "unknown JMAP mailbox role for mailbox {}: {}",
self.path(), self.path(),
other other
); );

View File

@ -394,7 +394,7 @@ pub struct EmailQueryResponse {
pub struct EmailQuery { pub struct EmailQuery {
#[serde(flatten)] #[serde(flatten)]
pub query_call: Query<EmailFilterCondition, EmailObject>, pub query_call: Query<EmailFilterCondition, EmailObject>,
//pub filter: EmailFilterCondition, /* "inMailboxes": [ folder.id ] },*/ //pub filter: EmailFilterCondition, /* "inMailboxes": [ mailbox.id ] },*/
pub collapse_threads: bool, pub collapse_threads: bool,
} }

View File

@ -19,7 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
use super::folder::JmapFolder; use super::mailbox::JmapMailbox;
use super::*; use super::*;
use serde::Serialize; use serde::Serialize;
use serde_json::{json, Value}; use serde_json::{json, Value};
@ -94,7 +94,7 @@ impl Request {
} }
} }
pub fn get_mailboxes(conn: &JmapConnection) -> Result<FnvHashMap<FolderHash, JmapFolder>> { pub fn get_mailboxes(conn: &JmapConnection) -> Result<FnvHashMap<MailboxHash, JmapMailbox>> {
let seq = get_request_no!(conn.request_no); let seq = get_request_no!(conn.request_no);
let res = conn let res = conn
.client .client
@ -141,7 +141,7 @@ pub fn get_mailboxes(conn: &JmapConnection) -> Result<FnvHashMap<FolderHash, Jma
let hash = crate::get_path_hash!(&name); let hash = crate::get_path_hash!(&name);
( (
hash, hash,
JmapFolder { JmapMailbox {
name: name.clone(), name: name.clone(),
hash, hash,
path: name, path: name,
@ -170,12 +170,12 @@ pub struct JsonResponse<'a> {
method_responses: Vec<MethodResponse<'a>>, method_responses: Vec<MethodResponse<'a>>,
} }
pub fn get_message_list(conn: &JmapConnection, folder: &JmapFolder) -> Result<Vec<String>> { pub fn get_message_list(conn: &JmapConnection, mailbox: &JmapMailbox) -> Result<Vec<String>> {
let email_call: EmailQuery = EmailQuery::new( let email_call: EmailQuery = EmailQuery::new(
Query::new() Query::new()
.account_id(conn.mail_account_id().to_string()) .account_id(conn.mail_account_id().to_string())
.filter(Some( .filter(Some(
EmailFilterCondition::new().in_mailbox(Some(folder.id.clone())), EmailFilterCondition::new().in_mailbox(Some(mailbox.id.clone())),
)) ))
.position(0), .position(0),
) )
@ -241,13 +241,13 @@ pub fn get(
conn: &JmapConnection, conn: &JmapConnection,
store: &Arc<RwLock<Store>>, store: &Arc<RwLock<Store>>,
tag_index: &Arc<RwLock<BTreeMap<u64, String>>>, tag_index: &Arc<RwLock<BTreeMap<u64, String>>>,
folder: &JmapFolder, mailbox: &JmapMailbox,
) -> Result<Vec<Envelope>> { ) -> Result<Vec<Envelope>> {
let email_query_call: EmailQuery = EmailQuery::new( let email_query_call: EmailQuery = EmailQuery::new(
Query::new() Query::new()
.account_id(conn.mail_account_id().to_string()) .account_id(conn.mail_account_id().to_string())
.filter(Some( .filter(Some(
EmailFilterCondition::new().in_mailbox(Some(folder.id.clone())), EmailFilterCondition::new().in_mailbox(Some(mailbox.id.clone())),
)) ))
.position(0), .position(0),
) )

View File

@ -39,7 +39,7 @@ use std::sync::{Arc, Mutex};
#[derive(Debug)] #[derive(Debug)]
pub struct MaildirOp { pub struct MaildirOp {
hash_index: HashIndexes, hash_index: HashIndexes,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
hash: EnvelopeHash, hash: EnvelopeHash,
slice: Option<Mmap>, slice: Option<Mmap>,
} }
@ -48,7 +48,7 @@ impl Clone for MaildirOp {
fn clone(&self) -> Self { fn clone(&self) -> Self {
MaildirOp { MaildirOp {
hash_index: self.hash_index.clone(), hash_index: self.hash_index.clone(),
folder_hash: self.folder_hash, mailbox_hash: self.mailbox_hash,
hash: self.hash, hash: self.hash,
slice: None, slice: None,
} }
@ -56,18 +56,18 @@ impl Clone for MaildirOp {
} }
impl MaildirOp { impl MaildirOp {
pub fn new(hash: EnvelopeHash, hash_index: HashIndexes, folder_hash: FolderHash) -> Self { pub fn new(hash: EnvelopeHash, hash_index: HashIndexes, mailbox_hash: MailboxHash) -> Self {
MaildirOp { MaildirOp {
hash_index, hash_index,
folder_hash, mailbox_hash,
hash, hash,
slice: None, slice: None,
} }
} }
fn path(&self) -> PathBuf { fn path(&self) -> PathBuf {
let map = self.hash_index.lock().unwrap(); let map = self.hash_index.lock().unwrap();
let map = &map[&self.folder_hash]; let map = &map[&self.mailbox_hash];
debug!("looking for {} in {} map", self.hash, self.folder_hash); debug!("looking for {} in {} map", self.hash, self.mailbox_hash);
if !map.contains_key(&self.hash) { if !map.contains_key(&self.hash) {
debug!("doesn't contain it though len = {}\n{:#?}", map.len(), map); debug!("doesn't contain it though len = {}\n{:#?}", map.len(), map);
for e in map.iter() { for e in map.iter() {
@ -155,7 +155,7 @@ impl<'a> BackendOp for MaildirOp {
let new_name: PathBuf = new_name.into(); let new_name: PathBuf = new_name.into();
let hash_index = self.hash_index.clone(); let hash_index = self.hash_index.clone();
let mut map = hash_index.lock().unwrap(); let mut map = hash_index.lock().unwrap();
let map = map.entry(self.folder_hash).or_default(); let map = map.entry(self.mailbox_hash).or_default();
map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone())); map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone()));
debug!("renaming {:?} to {:?}", path, new_name); debug!("renaming {:?} to {:?}", path, new_name);
@ -170,37 +170,37 @@ impl<'a> BackendOp for MaildirOp {
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct MaildirFolder { pub struct MaildirMailbox {
hash: FolderHash, hash: MailboxHash,
name: String, name: String,
fs_path: PathBuf, fs_path: PathBuf,
path: PathBuf, path: PathBuf,
parent: Option<FolderHash>, parent: Option<MailboxHash>,
children: Vec<FolderHash>, children: Vec<MailboxHash>,
pub usage: Arc<RwLock<SpecialUsageMailbox>>, pub usage: Arc<RwLock<SpecialUsageMailbox>>,
pub is_subscribed: bool, pub is_subscribed: bool,
permissions: FolderPermissions, permissions: MailboxPermissions,
pub total: Arc<Mutex<usize>>, pub total: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>, pub unseen: Arc<Mutex<usize>>,
} }
impl MaildirFolder { impl MaildirMailbox {
pub fn new( pub fn new(
path: String, path: String,
file_name: String, file_name: String,
parent: Option<FolderHash>, parent: Option<MailboxHash>,
children: Vec<FolderHash>, children: Vec<MailboxHash>,
settings: &AccountSettings, settings: &AccountSettings,
) -> Result<Self> { ) -> Result<Self> {
let pathbuf = PathBuf::from(&path); let pathbuf = PathBuf::from(&path);
let mut h = DefaultHasher::new(); let mut h = DefaultHasher::new();
pathbuf.hash(&mut h); pathbuf.hash(&mut h);
/* Check if folder path (Eg `INBOX/Lists/luddites`) is included in the subscribed /* Check if mailbox path (Eg `INBOX/Lists/luddites`) is included in the subscribed
* mailboxes in user configuration */ * mailboxes in user configuration */
let fname = pathbuf let fname = pathbuf
.strip_prefix( .strip_prefix(
PathBuf::from(&settings.root_folder) PathBuf::from(&settings.root_mailbox)
.expand() .expand()
.parent() .parent()
.unwrap_or_else(|| &Path::new("/")), .unwrap_or_else(|| &Path::new("/")),
@ -213,7 +213,7 @@ impl MaildirFolder {
true true
}; };
let ret = MaildirFolder { let ret = MaildirMailbox {
hash: h.finish(), hash: h.finish(),
name: file_name, name: file_name,
path: fname.unwrap().to_path_buf(), path: fname.unwrap().to_path_buf(),
@ -222,7 +222,7 @@ impl MaildirFolder {
children, children,
usage: Arc::new(RwLock::new(SpecialUsageMailbox::Normal)), usage: Arc::new(RwLock::new(SpecialUsageMailbox::Normal)),
is_subscribed: false, is_subscribed: false,
permissions: FolderPermissions { permissions: MailboxPermissions {
create_messages: !read_only, create_messages: !read_only,
remove_messages: !read_only, remove_messages: !read_only,
set_flags: !read_only, set_flags: !read_only,
@ -250,7 +250,7 @@ impl MaildirFolder {
p.push(d); p.push(d);
if !p.is_dir() { if !p.is_dir() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"{} is not a valid maildir folder", "{} is not a valid maildir mailbox",
path.display() path.display()
))); )));
} }
@ -260,8 +260,8 @@ impl MaildirFolder {
} }
} }
impl BackendFolder for MaildirFolder { impl BackendMailbox for MaildirMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
@ -277,11 +277,11 @@ impl BackendFolder for MaildirFolder {
self.name = s.to_string(); self.name = s.to_string();
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.children &self.children
} }
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
Box::new(std::clone::Clone::clone(self)) Box::new(std::clone::Clone::clone(self))
} }
@ -289,11 +289,11 @@ impl BackendFolder for MaildirFolder {
*self.usage.read().unwrap() *self.usage.read().unwrap()
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
self.parent self.parent
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
self.permissions self.permissions
} }
fn is_subscribed(&self) -> bool { fn is_subscribed(&self) -> bool {

View File

@ -20,10 +20,10 @@
*/ */
use super::{ use super::{
BackendFolder, BackendOp, Folder, FolderHash, MailBackend, RefreshEvent, RefreshEventConsumer, BackendMailbox, BackendOp, MailBackend, Mailbox, MailboxHash, RefreshEvent,
RefreshEventKind::*, RefreshEventConsumer, RefreshEventKind::*,
}; };
use super::{MaildirFolder, MaildirOp}; use super::{MaildirMailbox, MaildirOp};
use crate::async_workers::*; use crate::async_workers::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag}; use crate::email::{Envelope, EnvelopeHash, Flag};
@ -88,7 +88,7 @@ impl From<PathBuf> for MaildirPath {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct HashIndex { pub struct HashIndex {
index: FnvHashMap<EnvelopeHash, MaildirPath>, index: FnvHashMap<EnvelopeHash, MaildirPath>,
hash: FolderHash, hash: MailboxHash,
} }
impl Deref for HashIndex { impl Deref for HashIndex {
@ -104,14 +104,14 @@ impl DerefMut for HashIndex {
} }
} }
pub type HashIndexes = Arc<Mutex<FnvHashMap<FolderHash, HashIndex>>>; pub type HashIndexes = Arc<Mutex<FnvHashMap<MailboxHash, HashIndex>>>;
/// Maildir backend https://cr.yp.to/proto/maildir.html /// Maildir backend https://cr.yp.to/proto/maildir.html
#[derive(Debug)] #[derive(Debug)]
pub struct MaildirType { pub struct MaildirType {
name: String, name: String,
folders: FnvHashMap<FolderHash, MaildirFolder>, mailboxes: FnvHashMap<MailboxHash, MaildirMailbox>,
folder_index: Arc<Mutex<FnvHashMap<EnvelopeHash, FolderHash>>>, mailbox_index: Arc<Mutex<FnvHashMap<EnvelopeHash, MailboxHash>>>,
hash_indexes: HashIndexes, hash_indexes: HashIndexes,
path: PathBuf, path: PathBuf,
} }
@ -181,32 +181,32 @@ impl MailBackend for MaildirType {
Ok(()) Ok(())
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
Ok(self Ok(self
.folders .mailboxes
.iter() .iter()
.map(|(h, f)| (*h, BackendFolder::clone(f))) .map(|(h, f)| (*h, BackendMailbox::clone(f)))
.collect()) .collect())
} }
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
self.multicore(4, folder) self.multicore(4, mailbox)
} }
fn refresh( fn refresh(
&mut self, &mut self,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
sender: RefreshEventConsumer, sender: RefreshEventConsumer,
) -> Result<Async<()>> { ) -> Result<Async<()>> {
let w = AsyncBuilder::new(); let w = AsyncBuilder::new();
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
let handle = { let handle = {
let folder: &MaildirFolder = &self.folders[&folder_hash]; let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash];
let path: PathBuf = folder.fs_path().into(); let path: PathBuf = mailbox.fs_path().into();
let name = format!("refresh {:?}", folder.name()); let name = format!("refresh {:?}", mailbox.name());
let root_path = self.path.to_path_buf(); let root_path = self.path.to_path_buf();
let map = self.hash_indexes.clone(); let map = self.hash_indexes.clone();
let folder_index = self.folder_index.clone(); let mailbox_index = self.mailbox_index.clone();
Box::new(move |work_context: crate::async_workers::WorkContext| { Box::new(move |work_context: crate::async_workers::WorkContext| {
work_context work_context
@ -237,14 +237,14 @@ impl MailBackend for MaildirType {
} }
let mut current_hashes = { let mut current_hashes = {
let mut map = map.lock().unwrap(); let mut map = map.lock().unwrap();
let map = map.entry(folder_hash).or_default(); let map = map.entry(mailbox_hash).or_default();
map.keys().cloned().collect::<FnvHashSet<EnvelopeHash>>() map.keys().cloned().collect::<FnvHashSet<EnvelopeHash>>()
}; };
for file in files { for file in files {
let hash = get_file_hash(&file); let hash = get_file_hash(&file);
{ {
let mut map = map.lock().unwrap(); let mut map = map.lock().unwrap();
let map = map.entry(folder_hash).or_default(); let map = map.entry(mailbox_hash).or_default();
if map.contains_key(&hash) { if map.contains_key(&hash) {
map.remove(&hash); map.remove(&hash);
current_hashes.remove(&hash); current_hashes.remove(&hash);
@ -252,9 +252,9 @@ impl MailBackend for MaildirType {
} }
(*map).insert(hash, PathBuf::from(&file).into()); (*map).insert(hash, PathBuf::from(&file).into());
} }
let op = Box::new(MaildirOp::new(hash, map.clone(), folder_hash)); let op = Box::new(MaildirOp::new(hash, map.clone(), mailbox_hash));
if let Some(e) = Envelope::from_token(op, hash) { if let Some(e) = Envelope::from_token(op, hash) {
folder_index.lock().unwrap().insert(e.hash(), folder_hash); mailbox_index.lock().unwrap().insert(e.hash(), mailbox_hash);
let file_name = PathBuf::from(file) let file_name = PathBuf::from(file)
.strip_prefix(&root_path) .strip_prefix(&root_path)
.unwrap() .unwrap()
@ -277,7 +277,7 @@ impl MailBackend for MaildirType {
bincode::serialize_into(writer, &e).unwrap(); bincode::serialize_into(writer, &e).unwrap();
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(e)), kind: Create(Box::new(e)),
}); });
} else { } else {
@ -290,7 +290,7 @@ impl MailBackend for MaildirType {
} }
} }
for ev in current_hashes.into_iter().map(|h| RefreshEvent { for ev in current_hashes.into_iter().map(|h| RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Remove(h), kind: Remove(h),
}) { }) {
sender.send(ev); sender.send(ev);
@ -299,7 +299,7 @@ impl MailBackend for MaildirType {
}; };
if let Err(err) = thunk(&sender) { if let Err(err) = thunk(&sender) {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Failure(err), kind: Failure(err),
}); });
} }
@ -319,14 +319,14 @@ impl MailBackend for MaildirType {
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
debug!("watching {:?}", root_path); debug!("watching {:?}", root_path);
let hash_indexes = self.hash_indexes.clone(); let hash_indexes = self.hash_indexes.clone();
let folder_index = self.folder_index.clone(); let mailbox_index = self.mailbox_index.clone();
let folder_counts = self let mailbox_counts = self
.folders .mailboxes
.iter() .iter()
.map(|(&k, v)| (k, (v.unseen.clone(), v.total.clone()))) .map(|(&k, v)| (k, (v.unseen.clone(), v.total.clone())))
.collect::<FnvHashMap<FolderHash, (Arc<Mutex<usize>>, Arc<Mutex<usize>>)>>(); .collect::<FnvHashMap<MailboxHash, (Arc<Mutex<usize>>, Arc<Mutex<usize>>)>>();
let handle = thread::Builder::new() let handle = thread::Builder::new()
.name("folder watch".to_string()) .name("mailbox watch".to_string())
.spawn(move || { .spawn(move || {
// Move `watcher` in the closure's scope so that it doesn't get dropped. // Move `watcher` in the closure's scope so that it doesn't get dropped.
let _watcher = watcher; let _watcher = watcher;
@ -360,7 +360,7 @@ impl MailBackend for MaildirType {
} }
let folder_hash = get_path_hash!(pathbuf); let mailbox_hash = get_path_hash!(pathbuf);
let file_name = pathbuf let file_name = pathbuf
.as_path() .as_path()
.strip_prefix(&root_path) .strip_prefix(&root_path)
@ -368,12 +368,12 @@ impl MailBackend for MaildirType {
.to_path_buf(); .to_path_buf();
if let Some(env) = add_path_to_index( if let Some(env) = add_path_to_index(
&hash_indexes, &hash_indexes,
folder_hash, mailbox_hash,
pathbuf.as_path(), pathbuf.as_path(),
&cache_dir, &cache_dir,
file_name, file_name,
) { ) {
folder_index.lock().unwrap().insert(env.hash(),folder_hash); mailbox_index.lock().unwrap().insert(env.hash(),mailbox_hash);
debug!( debug!(
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
@ -381,11 +381,11 @@ impl MailBackend for MaildirType {
pathbuf.display() pathbuf.display()
); );
if !env.is_seen() { if !env.is_seen() {
*folder_counts[&folder_hash].0.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
} }
*folder_counts[&folder_hash].1.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -394,10 +394,10 @@ impl MailBackend for MaildirType {
DebouncedEvent::NoticeWrite(pathbuf) DebouncedEvent::NoticeWrite(pathbuf)
| DebouncedEvent::Write(pathbuf) => { | DebouncedEvent::Write(pathbuf) => {
debug!("DebouncedEvent::Write(path = {:?}", &pathbuf); debug!("DebouncedEvent::Write(path = {:?}", &pathbuf);
let folder_hash = get_path_hash!(pathbuf); let mailbox_hash = get_path_hash!(pathbuf);
let mut hash_indexes_lock = hash_indexes.lock().unwrap(); let mut hash_indexes_lock = hash_indexes.lock().unwrap();
let index_lock = let index_lock =
&mut hash_indexes_lock.entry(folder_hash).or_default(); &mut hash_indexes_lock.entry(mailbox_hash).or_default();
let file_name = pathbuf let file_name = pathbuf
.as_path() .as_path()
.strip_prefix(&root_path) .strip_prefix(&root_path)
@ -418,14 +418,14 @@ impl MailBackend for MaildirType {
* envelope. */ * envelope. */
if let Some(env) = add_path_to_index( if let Some(env) = add_path_to_index(
&hash_indexes, &hash_indexes,
folder_hash, mailbox_hash,
pathbuf.as_path(), pathbuf.as_path(),
&cache_dir, &cache_dir,
file_name, file_name,
) { ) {
folder_index.lock().unwrap().insert(env.hash(),folder_hash); mailbox_index.lock().unwrap().insert(env.hash(),mailbox_hash);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -438,7 +438,7 @@ impl MailBackend for MaildirType {
let op = Box::new(MaildirOp::new( let op = Box::new(MaildirOp::new(
new_hash, new_hash,
hash_indexes.clone(), hash_indexes.clone(),
folder_hash, mailbox_hash,
)); ));
if let Some(env) = Envelope::from_token(op, new_hash) { if let Some(env) = Envelope::from_token(op, new_hash) {
debug!("{}\t{:?}", new_hash, &pathbuf); debug!("{}\t{:?}", new_hash, &pathbuf);
@ -451,7 +451,7 @@ impl MailBackend for MaildirType {
/* Send Write notice */ /* Send Write notice */
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Update(old_hash, Box::new(env)), kind: Update(old_hash, Box::new(env)),
}); });
} }
@ -461,9 +461,9 @@ impl MailBackend for MaildirType {
DebouncedEvent::NoticeRemove(pathbuf) DebouncedEvent::NoticeRemove(pathbuf)
| DebouncedEvent::Remove(pathbuf) => { | DebouncedEvent::Remove(pathbuf) => {
debug!("DebouncedEvent::Remove(path = {:?}", pathbuf); debug!("DebouncedEvent::Remove(path = {:?}", pathbuf);
let folder_hash = get_path_hash!(pathbuf); let mailbox_hash = get_path_hash!(pathbuf);
let mut hash_indexes_lock = hash_indexes.lock().unwrap(); let mut hash_indexes_lock = hash_indexes.lock().unwrap();
let index_lock = hash_indexes_lock.entry(folder_hash).or_default(); let index_lock = hash_indexes_lock.entry(mailbox_hash).or_default();
let hash: EnvelopeHash = if let Some((k, _)) = let hash: EnvelopeHash = if let Some((k, _)) =
index_lock.iter().find(|(_, v)| *v.buf == pathbuf) index_lock.iter().find(|(_, v)| *v.buf == pathbuf)
{ {
@ -493,9 +493,9 @@ impl MailBackend for MaildirType {
}); });
//FIXME: check if envelope was unseen to update unseen count //FIXME: check if envelope was unseen to update unseen count
*folder_counts[&folder_hash].1.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Remove(hash), kind: Remove(hash),
}); });
} }
@ -505,12 +505,12 @@ impl MailBackend for MaildirType {
"DebouncedEvent::Rename(src = {:?}, dest = {:?})", "DebouncedEvent::Rename(src = {:?}, dest = {:?})",
src, dest src, dest
); );
let folder_hash = get_path_hash!(src); let mailbox_hash = get_path_hash!(src);
let old_hash: EnvelopeHash = get_file_hash(src.as_path()); let old_hash: EnvelopeHash = get_file_hash(src.as_path());
let new_hash: EnvelopeHash = get_file_hash(dest.as_path()); let new_hash: EnvelopeHash = get_file_hash(dest.as_path());
let mut hash_indexes_lock = hash_indexes.lock().unwrap(); let mut hash_indexes_lock = hash_indexes.lock().unwrap();
let index_lock = hash_indexes_lock.entry(folder_hash).or_default(); let index_lock = hash_indexes_lock.entry(mailbox_hash).or_default();
if index_lock.contains_key(&old_hash) if index_lock.contains_key(&old_hash)
&& !index_lock[&old_hash].removed && !index_lock[&old_hash].removed
@ -524,7 +524,7 @@ impl MailBackend for MaildirType {
hash: get_path_hash!(dest), hash: get_path_hash!(dest),
kind: Rename(old_hash, new_hash), kind: Rename(old_hash, new_hash),
}); });
folder_index.lock().unwrap().insert(new_hash,get_path_hash!(dest) ); mailbox_index.lock().unwrap().insert(new_hash,get_path_hash!(dest) );
index_lock.insert(new_hash, dest.into()); index_lock.insert(new_hash, dest.into());
continue; continue;
} else if !index_lock.contains_key(&new_hash) } else if !index_lock.contains_key(&new_hash)
@ -556,12 +556,12 @@ impl MailBackend for MaildirType {
drop(hash_indexes_lock); drop(hash_indexes_lock);
if let Some(env) = add_path_to_index( if let Some(env) = add_path_to_index(
&hash_indexes, &hash_indexes,
folder_hash, mailbox_hash,
dest.as_path(), dest.as_path(),
&cache_dir, &cache_dir,
file_name, file_name,
) { ) {
folder_index.lock().unwrap().insert(env.hash(),folder_hash); mailbox_index.lock().unwrap().insert(env.hash(), mailbox_hash);
debug!( debug!(
"Create event {} {} {}", "Create event {} {} {}",
env.hash(), env.hash(),
@ -569,11 +569,11 @@ impl MailBackend for MaildirType {
dest.display() dest.display()
); );
if !env.is_seen() { if !env.is_seen() {
*folder_counts[&folder_hash].0.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
} }
*folder_counts[&folder_hash].1.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
continue; continue;
@ -595,10 +595,10 @@ impl MailBackend for MaildirType {
}); });
*/ */
} }
/* Trigger rescan of folder */ /* Trigger rescan of mailbox */
DebouncedEvent::Rescan => { DebouncedEvent::Rescan => {
/* Actually should rescan all folders */ /* Actually should rescan all mailboxes */
unreachable!("Unimplemented: rescan of all folders in MaildirType") unreachable!("Unimplemented: rescan of all mailboxes in MaildirType")
} }
_ => {} _ => {}
}, },
@ -613,20 +613,20 @@ impl MailBackend for MaildirType {
Box::new(MaildirOp::new( Box::new(MaildirOp::new(
hash, hash,
self.hash_indexes.clone(), self.hash_indexes.clone(),
self.folder_index.lock().unwrap()[&hash], self.mailbox_index.lock().unwrap()[&hash],
)) ))
} }
fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> { fn save(&self, bytes: &[u8], mailbox: &str, flags: Option<Flag>) -> Result<()> {
for f in self.folders.values() { for f in self.mailboxes.values() {
if f.name == folder || f.path.to_str().unwrap() == folder { if f.name == mailbox || f.path.to_str().unwrap() == mailbox {
return MaildirType::save_to_folder(f.fs_path.clone(), bytes, flags); return MaildirType::save_to_mailbox(f.fs_path.clone(), bytes, flags);
} }
} }
Err(MeliError::new(format!( Err(MeliError::new(format!(
"'{}' is not a valid folder.", "'{}' is not a valid mailbox.",
folder mailbox
))) )))
} }
@ -634,35 +634,35 @@ impl MailBackend for MaildirType {
self self
} }
fn create_folder( fn create_mailbox(
&mut self, &mut self,
new_path: String, new_path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> { ) -> Result<(MailboxHash, FnvHashMap<MailboxHash, Mailbox>)> {
let mut path = self.path.clone(); let mut path = self.path.clone();
path.push(&new_path); path.push(&new_path);
if !path.starts_with(&self.path) { if !path.starts_with(&self.path) {
return Err(MeliError::new(format!("Path given (`{}`) is absolute. Please provide a path relative to the account's root folder.", &new_path))); return Err(MeliError::new(format!("Path given (`{}`) is absolute. Please provide a path relative to the account's root mailbox.", &new_path)));
} }
std::fs::create_dir(&path)?; std::fs::create_dir(&path)?;
/* create_dir does not create intermediate directories (like `mkdir -p`), so the parent must be a valid /* create_dir does not create intermediate directories (like `mkdir -p`), so the parent must be a valid
* folder at this point. */ * mailbox at this point. */
let parent = path.parent().and_then(|p| { let parent = path.parent().and_then(|p| {
self.folders self.mailboxes
.iter() .iter()
.find(|(_, f)| f.fs_path == p) .find(|(_, f)| f.fs_path == p)
.map(|item| *item.0) .map(|item| *item.0)
}); });
let folder_hash = get_path_hash!(&path); let mailbox_hash = get_path_hash!(&path);
if let Some(parent) = parent { if let Some(parent) = parent {
self.folders self.mailboxes
.entry(parent) .entry(parent)
.and_modify(|entry| entry.children.push(folder_hash)); .and_modify(|entry| entry.children.push(mailbox_hash));
} }
let new_folder = MaildirFolder { let new_mailbox = MaildirMailbox {
hash: folder_hash, hash: mailbox_hash,
path: PathBuf::from(&new_path), path: PathBuf::from(&new_path),
name: new_path, name: new_path,
fs_path: path, fs_path: path,
@ -675,29 +675,29 @@ impl MailBackend for MaildirType {
total: Default::default(), total: Default::default(),
}; };
self.folders.insert(folder_hash, new_folder); self.mailboxes.insert(mailbox_hash, new_mailbox);
Ok((folder_hash, self.folders()?)) Ok((mailbox_hash, self.mailboxes()?))
} }
fn delete_folder( fn delete_mailbox(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
) -> Result<FnvHashMap<FolderHash, Folder>> { ) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_folder_subscription(&mut self, _folder_hash: FolderHash, _val: bool) -> Result<()> { fn set_mailbox_subscription(&mut self, _mailbox_hash: MailboxHash, _val: bool) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn rename_folder(&mut self, _folder_hash: FolderHash, _new_path: String) -> Result<Folder> { fn rename_mailbox(&mut self, _mailbox_hash: MailboxHash, _new_path: String) -> Result<Mailbox> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn set_folder_permissions( fn set_mailbox_permissions(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
_val: crate::backends::FolderPermissions, _val: crate::backends::MailboxPermissions,
) -> Result<()> { ) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
@ -708,12 +708,12 @@ impl MaildirType {
settings: &AccountSettings, settings: &AccountSettings,
is_subscribed: Box<dyn Fn(&str) -> bool>, is_subscribed: Box<dyn Fn(&str) -> bool>,
) -> Result<Box<dyn MailBackend>> { ) -> Result<Box<dyn MailBackend>> {
let mut folders: FnvHashMap<FolderHash, MaildirFolder> = Default::default(); let mut mailboxes: FnvHashMap<MailboxHash, MaildirMailbox> = Default::default();
fn recurse_folders<P: AsRef<Path>>( fn recurse_mailboxes<P: AsRef<Path>>(
folders: &mut FnvHashMap<FolderHash, MaildirFolder>, mailboxes: &mut FnvHashMap<MailboxHash, MaildirMailbox>,
settings: &AccountSettings, settings: &AccountSettings,
p: P, p: P,
) -> Result<Vec<FolderHash>> { ) -> Result<Vec<MailboxHash>> {
if !p.as_ref().exists() || !p.as_ref().is_dir() { if !p.as_ref().exists() || !p.as_ref().is_dir() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Configuration error: Path \"{}\" {}", "Configuration error: Path \"{}\" {}",
@ -734,20 +734,20 @@ impl MaildirType {
continue 'entries; continue 'entries;
} }
if path.is_dir() { if path.is_dir() {
if let Ok(mut f) = MaildirFolder::new( if let Ok(mut f) = MaildirMailbox::new(
path.to_str().unwrap().to_string(), path.to_str().unwrap().to_string(),
path.file_name().unwrap().to_str().unwrap().to_string(), path.file_name().unwrap().to_str().unwrap().to_string(),
None, None,
Vec::new(), Vec::new(),
&settings, &settings,
) { ) {
f.children = recurse_folders(folders, settings, &path)?; f.children = recurse_mailboxes(mailboxes, settings, &path)?;
f.children f.children
.iter() .iter()
.map(|c| folders.get_mut(c).map(|f| f.parent = Some(f.hash))) .map(|c| mailboxes.get_mut(c).map(|f| f.parent = Some(f.hash)))
.count(); .count();
children.push(f.hash); children.push(f.hash);
folders.insert(f.hash, f); mailboxes.insert(f.hash, f);
} }
} }
} }
@ -755,55 +755,55 @@ impl MaildirType {
} }
Ok(children) Ok(children)
}; };
let root_path = PathBuf::from(settings.root_folder()).expand(); let root_path = PathBuf::from(settings.root_mailbox()).expand();
if !root_path.exists() { if !root_path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Configuration error ({}): root_path `{}` is not a valid directory.", "Configuration error ({}): root_path `{}` is not a valid directory.",
settings.name(), settings.name(),
settings.root_folder.as_str() settings.root_mailbox.as_str()
))); )));
} else if !root_path.is_dir() { } else if !root_path.is_dir() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Configuration error ({}): root_path `{}` is not a directory.", "Configuration error ({}): root_path `{}` is not a directory.",
settings.name(), settings.name(),
settings.root_folder.as_str() settings.root_mailbox.as_str()
))); )));
} }
if let Ok(f) = MaildirFolder::new( if let Ok(f) = MaildirMailbox::new(
root_path.to_str().unwrap().to_string(), root_path.to_str().unwrap().to_string(),
root_path.file_name().unwrap().to_str().unwrap().to_string(), root_path.file_name().unwrap().to_str().unwrap().to_string(),
None, None,
Vec::with_capacity(0), Vec::with_capacity(0),
settings, settings,
) { ) {
folders.insert(f.hash, f); mailboxes.insert(f.hash, f);
} }
if folders.is_empty() { if mailboxes.is_empty() {
let children = recurse_folders(&mut folders, settings, &root_path)?; let children = recurse_mailboxes(&mut mailboxes, settings, &root_path)?;
children children
.iter() .iter()
.map(|c| folders.get_mut(c).map(|f| f.parent = None)) .map(|c| mailboxes.get_mut(c).map(|f| f.parent = None))
.count(); .count();
} else { } else {
let root_hash = *folders.keys().nth(0).unwrap(); let root_hash = *mailboxes.keys().nth(0).unwrap();
let children = recurse_folders(&mut folders, settings, &root_path)?; let children = recurse_mailboxes(&mut mailboxes, settings, &root_path)?;
children children
.iter() .iter()
.map(|c| folders.get_mut(c).map(|f| f.parent = Some(root_hash))) .map(|c| mailboxes.get_mut(c).map(|f| f.parent = Some(root_hash)))
.count(); .count();
folders.get_mut(&root_hash).map(|f| f.children = children); mailboxes.get_mut(&root_hash).map(|f| f.children = children);
} }
for f in folders.values_mut() { for f in mailboxes.values_mut() {
if is_subscribed(f.path()) { if is_subscribed(f.path()) {
f.is_subscribed = true; f.is_subscribed = true;
} }
} }
let mut hash_indexes = let mut hash_indexes =
FnvHashMap::with_capacity_and_hasher(folders.len(), Default::default()); FnvHashMap::with_capacity_and_hasher(mailboxes.len(), Default::default());
for &fh in folders.keys() { for &fh in mailboxes.keys() {
hash_indexes.insert( hash_indexes.insert(
fh, fh,
HashIndex { HashIndex {
@ -814,37 +814,37 @@ impl MaildirType {
} }
Ok(Box::new(MaildirType { Ok(Box::new(MaildirType {
name: settings.name().to_string(), name: settings.name().to_string(),
folders, mailboxes,
hash_indexes: Arc::new(Mutex::new(hash_indexes)), hash_indexes: Arc::new(Mutex::new(hash_indexes)),
folder_index: Default::default(), mailbox_index: Default::default(),
path: root_path, path: root_path,
})) }))
} }
fn owned_folder_idx(&self, folder: &Folder) -> FolderHash { fn owned_mailbox_idx(&self, mailbox: &Mailbox) -> MailboxHash {
*self *self
.folders .mailboxes
.iter() .iter()
.find(|(_, f)| f.hash() == folder.hash()) .find(|(_, f)| f.hash() == mailbox.hash())
.unwrap() .unwrap()
.0 .0
} }
pub fn multicore(&mut self, cores: usize, folder: &Folder) -> Async<Result<Vec<Envelope>>> { pub fn multicore(&mut self, cores: usize, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let folder: &MaildirFolder = &self.folders[&self.owned_folder_idx(folder)]; let mailbox: &MaildirMailbox = &self.mailboxes[&self.owned_mailbox_idx(mailbox)];
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let unseen = folder.unseen.clone(); let unseen = mailbox.unseen.clone();
let total = folder.total.clone(); let total = mailbox.total.clone();
let tx_final = w.tx(); let tx_final = w.tx();
let mut path: PathBuf = folder.fs_path().into(); let mut path: PathBuf = mailbox.fs_path().into();
let name = format!("parsing {:?}", folder.name()); let name = format!("parsing {:?}", mailbox.name());
let root_path = self.path.to_path_buf(); let root_path = self.path.to_path_buf();
let map = self.hash_indexes.clone(); let map = self.hash_indexes.clone();
let folder_index = self.folder_index.clone(); let mailbox_index = self.mailbox_index.clone();
let closure = move |work_context: crate::async_workers::WorkContext| { let closure = move |work_context: crate::async_workers::WorkContext| {
work_context work_context
@ -886,7 +886,7 @@ impl MaildirType {
let cache_dir = cache_dir.clone(); let cache_dir = cache_dir.clone();
let tx = tx.clone(); let tx = tx.clone();
let map = map.clone(); let map = map.clone();
let folder_index = folder_index.clone(); let mailbox_index = mailbox_index.clone();
let root_path = root_path.clone(); let root_path = root_path.clone();
let s = scope.builder().name(name.clone()).spawn(move |_| { let s = scope.builder().name(name.clone()).spawn(move |_| {
let len = chunk.len(); let len = chunk.len();
@ -896,7 +896,7 @@ impl MaildirType {
for c in chunk.chunks(size) { for c in chunk.chunks(size) {
//thread::yield_now(); //thread::yield_now();
let map = map.clone(); let map = map.clone();
let folder_index = folder_index.clone(); let mailbox_index = mailbox_index.clone();
let len = c.len(); let len = c.len();
for file in c { for file in c {
/* Check if we have a cache file with this email's /* Check if we have a cache file with this email's
@ -916,13 +916,13 @@ impl MaildirType {
bincode::deserialize_from(reader); bincode::deserialize_from(reader);
if let Ok(env) = result { if let Ok(env) = result {
let mut map = map.lock().unwrap(); let mut map = map.lock().unwrap();
let map = map.entry(folder_hash).or_default(); let map = map.entry(mailbox_hash).or_default();
let hash = env.hash(); let hash = env.hash();
map.insert(hash, file.clone().into()); map.insert(hash, file.clone().into());
folder_index mailbox_index
.lock() .lock()
.unwrap() .unwrap()
.insert(hash, folder_hash); .insert(hash, mailbox_hash);
if !env.is_seen() { if !env.is_seen() {
*unseen.lock().unwrap() += 1; *unseen.lock().unwrap() += 1;
} }
@ -934,19 +934,19 @@ impl MaildirType {
let hash = get_file_hash(file); let hash = get_file_hash(file);
{ {
let mut map = map.lock().unwrap(); let mut map = map.lock().unwrap();
let map = map.entry(folder_hash).or_default(); let map = map.entry(mailbox_hash).or_default();
(*map).insert(hash, PathBuf::from(file).into()); (*map).insert(hash, PathBuf::from(file).into());
} }
let op = Box::new(MaildirOp::new( let op = Box::new(MaildirOp::new(
hash, hash,
map.clone(), map.clone(),
folder_hash, mailbox_hash,
)); ));
if let Some(e) = Envelope::from_token(op, hash) { if let Some(e) = Envelope::from_token(op, hash) {
folder_index mailbox_index
.lock() .lock()
.unwrap() .unwrap()
.insert(e.hash(), folder_hash); .insert(e.hash(), mailbox_hash);
if let Ok(cached) = if let Ok(cached) =
cache_dir.place_cache_file(file_name) cache_dir.place_cache_file(file_name)
{ {
@ -1011,7 +1011,7 @@ impl MaildirType {
w.build(handle) w.build(handle)
} }
pub fn save_to_folder(mut path: PathBuf, bytes: &[u8], flags: Option<Flag>) -> Result<()> { pub fn save_to_mailbox(mut path: PathBuf, bytes: &[u8], flags: Option<Flag>) -> Result<()> {
path.push("cur"); path.push("cur");
{ {
let mut rand_buf = [0u8; 16]; let mut rand_buf = [0u8; 16];
@ -1071,18 +1071,18 @@ impl MaildirType {
} }
pub fn validate_config(s: &AccountSettings) -> Result<()> { pub fn validate_config(s: &AccountSettings) -> Result<()> {
let root_path = PathBuf::from(s.root_folder()).expand(); let root_path = PathBuf::from(s.root_mailbox()).expand();
if !root_path.exists() { if !root_path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Configuration error ({}): root_path `{}` is not a valid directory.", "Configuration error ({}): root_path `{}` is not a valid directory.",
s.name(), s.name(),
s.root_folder.as_str() s.root_mailbox.as_str()
))); )));
} else if !root_path.is_dir() { } else if !root_path.is_dir() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Configuration error ({}): root_path `{}` is not a directory.", "Configuration error ({}): root_path `{}` is not a directory.",
s.name(), s.name(),
s.root_folder.as_str() s.root_mailbox.as_str()
))); )));
} }
@ -1092,7 +1092,7 @@ impl MaildirType {
fn add_path_to_index( fn add_path_to_index(
hash_index: &HashIndexes, hash_index: &HashIndexes,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
path: &Path, path: &Path,
cache_dir: &xdg::BaseDirectories, cache_dir: &xdg::BaseDirectories,
file_name: PathBuf, file_name: PathBuf,
@ -1102,16 +1102,16 @@ fn add_path_to_index(
let hash = get_file_hash(path); let hash = get_file_hash(path);
{ {
let mut map = hash_index.lock().unwrap(); let mut map = hash_index.lock().unwrap();
let map = map.entry(folder_hash).or_default(); let map = map.entry(mailbox_hash).or_default();
map.insert(hash, path.to_path_buf().into()); map.insert(hash, path.to_path_buf().into());
debug!( debug!(
"inserted {} in {} map, len={}", "inserted {} in {} map, len={}",
hash, hash,
folder_hash, mailbox_hash,
map.len() map.len()
); );
} }
let op = Box::new(MaildirOp::new(hash, hash_index.clone(), folder_hash)); let op = Box::new(MaildirOp::new(hash, hash_index.clone(), mailbox_hash));
if let Some(e) = Envelope::from_token(op, hash) { if let Some(e) = Envelope::from_token(op, hash) {
debug!("add_path_to_index gen {}\t{}", hash, file_name.display()); debug!("add_path_to_index gen {}\t{}", hash, file_name.display());
if let Ok(cached) = cache_dir.place_cache_file(file_name) { if let Ok(cached) = cache_dir.place_cache_file(file_name) {

View File

@ -25,9 +25,9 @@
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp; use crate::backends::BackendOp;
use crate::backends::FolderHash; use crate::backends::MailboxHash;
use crate::backends::{ use crate::backends::{
BackendFolder, Folder, FolderPermissions, MailBackend, RefreshEvent, RefreshEventConsumer, BackendMailbox, MailBackend, Mailbox, MailboxPermissions, RefreshEvent, RefreshEventConsumer,
RefreshEventKind, SpecialUsageMailbox, RefreshEventKind, SpecialUsageMailbox,
}; };
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
@ -74,22 +74,22 @@ fn get_rw_lock_blocking(f: &File) {
} }
#[derive(Debug)] #[derive(Debug)]
struct MboxFolder { struct MboxMailbox {
hash: FolderHash, hash: MailboxHash,
name: String, name: String,
path: PathBuf, path: PathBuf,
content: Vec<u8>, content: Vec<u8>,
children: Vec<FolderHash>, children: Vec<MailboxHash>,
parent: Option<FolderHash>, parent: Option<MailboxHash>,
usage: Arc<RwLock<SpecialUsageMailbox>>, usage: Arc<RwLock<SpecialUsageMailbox>>,
is_subscribed: bool, is_subscribed: bool,
permissions: FolderPermissions, permissions: MailboxPermissions,
pub total: Arc<Mutex<usize>>, pub total: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>, pub unseen: Arc<Mutex<usize>>,
} }
impl BackendFolder for MboxFolder { impl BackendMailbox for MboxMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
@ -106,8 +106,8 @@ impl BackendFolder for MboxFolder {
self.name = s.to_string(); self.name = s.to_string();
} }
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
Box::new(MboxFolder { Box::new(MboxMailbox {
hash: self.hash, hash: self.hash,
name: self.name.clone(), name: self.name.clone(),
path: self.path.clone(), path: self.path.clone(),
@ -122,11 +122,11 @@ impl BackendFolder for MboxFolder {
}) })
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.children &self.children
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
self.parent self.parent
} }
@ -134,7 +134,7 @@ impl BackendFolder for MboxFolder {
*self.usage.read().unwrap() *self.usage.read().unwrap()
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
self.permissions self.permissions
} }
fn is_subscribed(&self) -> bool { fn is_subscribed(&self) -> bool {
@ -388,28 +388,28 @@ pub fn mbox_parse(
pub struct MboxType { pub struct MboxType {
path: PathBuf, path: PathBuf,
index: Arc<Mutex<FnvHashMap<EnvelopeHash, (Offset, Length)>>>, index: Arc<Mutex<FnvHashMap<EnvelopeHash, (Offset, Length)>>>,
folders: Arc<Mutex<FnvHashMap<FolderHash, MboxFolder>>>, mailboxes: Arc<Mutex<FnvHashMap<MailboxHash, MboxMailbox>>>,
} }
impl MailBackend for MboxType { impl MailBackend for MboxType {
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let index = self.index.clone(); let index = self.index.clone();
let folder_path = folder.path().to_string(); let mailbox_path = mailbox.path().to_string();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let folders = self.folders.clone(); let mailboxes = self.mailboxes.clone();
let closure = move |_work_context| { let closure = move |_work_context| {
let tx = tx.clone(); let tx = tx.clone();
let index = index.clone(); let index = index.clone();
let file = match std::fs::OpenOptions::new() let file = match std::fs::OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.open(&folder_path) .open(&mailbox_path)
{ {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
@ -431,9 +431,9 @@ impl MailBackend for MboxType {
.to_full_result() .to_full_result()
.map_err(|e| MeliError::from(e)); .map_err(|e| MeliError::from(e));
{ {
let mut folder_lock = folders.lock().unwrap(); let mut mailbox_lock = mailboxes.lock().unwrap();
folder_lock mailbox_lock
.entry(folder_hash) .entry(mailbox_hash)
.and_modify(|f| f.content = contents); .and_modify(|f| f.content = contents);
} }
@ -454,7 +454,7 @@ impl MailBackend for MboxType {
let mut watcher = watcher(tx, std::time::Duration::from_secs(10)) let mut watcher = watcher(tx, std::time::Duration::from_secs(10))
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
.map_err(MeliError::new)?; .map_err(MeliError::new)?;
for f in self.folders.lock().unwrap().values() { for f in self.mailboxes.lock().unwrap().values() {
watcher watcher
.watch(&f.path, RecursiveMode::Recursive) .watch(&f.path, RecursiveMode::Recursive)
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
@ -462,7 +462,7 @@ impl MailBackend for MboxType {
debug!("watching {:?}", f.path.as_path()); debug!("watching {:?}", f.path.as_path());
} }
let index = self.index.clone(); let index = self.index.clone();
let folders = self.folders.clone(); let mailboxes = self.mailboxes.clone();
let handle = std::thread::Builder::new() let handle = std::thread::Builder::new()
.name(format!( .name(format!(
"watching {}", "watching {}",
@ -473,7 +473,7 @@ impl MailBackend for MboxType {
let _watcher = watcher; let _watcher = watcher;
let _work_context = work_context; let _work_context = work_context;
let index = index; let index = index;
let folders = folders; let mailboxes = mailboxes;
loop { loop {
match rx.recv() { match rx.recv() {
/* /*
@ -490,7 +490,7 @@ impl MailBackend for MboxType {
/* Update */ /* Update */
DebouncedEvent::NoticeWrite(pathbuf) DebouncedEvent::NoticeWrite(pathbuf)
| DebouncedEvent::Write(pathbuf) => { | DebouncedEvent::Write(pathbuf) => {
let folder_hash = get_path_hash!(&pathbuf); let mailbox_hash = get_path_hash!(&pathbuf);
let file = match std::fs::OpenOptions::new() let file = match std::fs::OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
@ -502,7 +502,7 @@ impl MailBackend for MboxType {
} }
}; };
get_rw_lock_blocking(&file); get_rw_lock_blocking(&file);
let mut folder_lock = folders.lock().unwrap(); let mut mailbox_lock = mailboxes.lock().unwrap();
let mut buf_reader = BufReader::new(file); let mut buf_reader = BufReader::new(file);
let mut contents = Vec::new(); let mut contents = Vec::new();
if let Err(e) = buf_reader.read_to_end(&mut contents) { if let Err(e) = buf_reader.read_to_end(&mut contents) {
@ -510,46 +510,46 @@ impl MailBackend for MboxType {
continue; continue;
}; };
if contents if contents
.starts_with(folder_lock[&folder_hash].content.as_slice()) .starts_with(mailbox_lock[&mailbox_hash].content.as_slice())
{ {
if let Ok(envelopes) = mbox_parse( if let Ok(envelopes) = mbox_parse(
index.clone(), index.clone(),
&contents[folder_lock[&folder_hash].content.len()..], &contents[mailbox_lock[&mailbox_hash].content.len()..],
folder_lock[&folder_hash].content.len(), mailbox_lock[&mailbox_hash].content.len(),
) )
.to_full_result() .to_full_result()
{ {
for env in envelopes { for env in envelopes {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Create(Box::new(env)), kind: RefreshEventKind::Create(Box::new(env)),
}); });
} }
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
} }
folder_lock mailbox_lock
.entry(folder_hash) .entry(mailbox_hash)
.and_modify(|f| f.content = contents); .and_modify(|f| f.content = contents);
} }
/* Remove */ /* Remove */
DebouncedEvent::NoticeRemove(pathbuf) DebouncedEvent::NoticeRemove(pathbuf)
| DebouncedEvent::Remove(pathbuf) => { | DebouncedEvent::Remove(pathbuf) => {
if folders if mailboxes
.lock() .lock()
.unwrap() .unwrap()
.values() .values()
.any(|f| &f.path == &pathbuf) .any(|f| &f.path == &pathbuf)
{ {
let folder_hash = get_path_hash!(&pathbuf); let mailbox_hash = get_path_hash!(&pathbuf);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"mbox folder {} was removed.", "mbox mailbox {} was removed.",
pathbuf.display() pathbuf.display()
))), ))),
}); });
@ -557,12 +557,12 @@ impl MailBackend for MboxType {
} }
} }
DebouncedEvent::Rename(src, dest) => { DebouncedEvent::Rename(src, dest) => {
if folders.lock().unwrap().values().any(|f| &f.path == &src) { if mailboxes.lock().unwrap().values().any(|f| &f.path == &src) {
let folder_hash = get_path_hash!(&src); let mailbox_hash = get_path_hash!(&src);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: folder_hash, hash: mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"mbox folder {} was renamed to {}.", "mbox mailbox {} was renamed to {}.",
src.display(), src.display(),
dest.display() dest.display()
))), ))),
@ -570,9 +570,9 @@ impl MailBackend for MboxType {
return; return;
} }
} }
/* Trigger rescan of folders */ /* Trigger rescan of mailboxes */
DebouncedEvent::Rescan => { DebouncedEvent::Rescan => {
for h in folders.lock().unwrap().keys() { for h in mailboxes.lock().unwrap().keys() {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: *h, hash: *h,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
@ -588,13 +588,13 @@ impl MailBackend for MboxType {
})?; })?;
Ok(handle.thread().id()) Ok(handle.thread().id())
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
Ok(self Ok(self
.folders .mailboxes
.lock() .lock()
.unwrap() .unwrap()
.iter() .iter()
.map(|(h, f)| (*h, f.clone() as Folder)) .map(|(h, f)| (*h, f.clone() as Mailbox))
.collect()) .collect())
} }
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> { fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
@ -605,7 +605,7 @@ impl MailBackend for MboxType {
Box::new(MboxOp::new(hash, self.path.as_path(), offset, length)) Box::new(MboxOp::new(hash, self.path.as_path(), offset, length))
} }
fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> { fn save(&self, _bytes: &[u8], _mailbox: &str, _flags: Option<Flag>) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
@ -619,11 +619,11 @@ impl MboxType {
s: &AccountSettings, s: &AccountSettings,
_is_subscribed: Box<dyn Fn(&str) -> bool>, _is_subscribed: Box<dyn Fn(&str) -> bool>,
) -> Result<Box<dyn MailBackend>> { ) -> Result<Box<dyn MailBackend>> {
let path = Path::new(s.root_folder.as_str()).expand(); let path = Path::new(s.root_mailbox.as_str()).expand();
if !path.exists() { if !path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"\"root_folder\" {} for account {} is not a valid path.", "\"root_mailbox\" {} for account {} is not a valid path.",
s.root_folder.as_str(), s.root_mailbox.as_str(),
s.name() s.name()
))); )));
} }
@ -644,9 +644,9 @@ impl MboxType {
true true
}; };
ret.folders.lock().unwrap().insert( ret.mailboxes.lock().unwrap().insert(
hash, hash,
MboxFolder { MboxMailbox {
hash, hash,
path: ret.path.clone(), path: ret.path.clone(),
name, name,
@ -655,7 +655,7 @@ impl MboxType {
parent: None, parent: None,
usage: Arc::new(RwLock::new(SpecialUsageMailbox::Normal)), usage: Arc::new(RwLock::new(SpecialUsageMailbox::Normal)),
is_subscribed: true, is_subscribed: true,
permissions: FolderPermissions { permissions: MailboxPermissions {
create_messages: !read_only, create_messages: !read_only,
remove_messages: !read_only, remove_messages: !read_only,
set_flags: !read_only, set_flags: !read_only,
@ -671,8 +671,8 @@ impl MboxType {
); );
/* /*
/* Look for other mailboxes */ /* Look for other mailboxes */
let parent_folder = Path::new(path).parent().unwrap(); let parent_mailbox = Path::new(path).parent().unwrap();
let read_dir = std::fs::read_dir(parent_folder); let read_dir = std::fs::read_dir(parent_mailbox);
if read_dir.is_ok() { if read_dir.is_ok() {
for f in read_dir.unwrap() { for f in read_dir.unwrap() {
if f.is_err() { if f.is_err() {
@ -685,9 +685,9 @@ impl MboxType {
.map(|f| f.to_string_lossy().into()) .map(|f| f.to_string_lossy().into())
.unwrap_or(String::new()); .unwrap_or(String::new());
let hash = get_path_hash!(f); let hash = get_path_hash!(f);
ret.folders.lock().unwrap().insert( ret.mailboxes.lock().unwrap().insert(
hash, hash,
MboxFolder { MboxMailbox {
hash, hash,
path: f, path: f,
name, name,
@ -704,11 +704,11 @@ impl MboxType {
} }
pub fn validate_config(s: &AccountSettings) -> Result<()> { pub fn validate_config(s: &AccountSettings) -> Result<()> {
let path = Path::new(s.root_folder.as_str()).expand(); let path = Path::new(s.root_mailbox.as_str()).expand();
if !path.exists() { if !path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"\"root_folder\" {} for account {} is not a valid path.", "\"root_mailbox\" {} for account {} is not a valid path.",
s.root_folder.as_str(), s.root_mailbox.as_str(),
s.name() s.name()
))); )));
} }

View File

@ -20,9 +20,9 @@
*/ */
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::FolderHash; use crate::backends::MailboxHash;
use crate::backends::{ use crate::backends::{
BackendFolder, BackendOp, Folder, FolderPermissions, MailBackend, RefreshEventConsumer, BackendMailbox, BackendOp, MailBackend, Mailbox, MailboxPermissions, RefreshEventConsumer,
SpecialUsageMailbox, SpecialUsageMailbox,
}; };
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
@ -54,7 +54,7 @@ unsafe impl Sync for DbWrapper {}
#[derive(Debug)] #[derive(Debug)]
pub struct NotmuchDb { pub struct NotmuchDb {
database: DbWrapper, database: DbWrapper,
folders: Arc<RwLock<FnvHashMap<FolderHash, NotmuchFolder>>>, mailboxes: Arc<RwLock<FnvHashMap<MailboxHash, NotmuchMailbox>>>,
index: Arc<RwLock<FnvHashMap<EnvelopeHash, &'static CStr>>>, index: Arc<RwLock<FnvHashMap<EnvelopeHash, &'static CStr>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
path: PathBuf, path: PathBuf,
@ -66,7 +66,7 @@ unsafe impl Sync for NotmuchDb {}
impl Drop for NotmuchDb { impl Drop for NotmuchDb {
fn drop(&mut self) { fn drop(&mut self) {
for f in self.folders.write().unwrap().values_mut() { for f in self.mailboxes.write().unwrap().values_mut() {
if let Some(query) = f.query.take() { if let Some(query) = f.query.take() {
unsafe { unsafe {
notmuch_query_destroy(query); notmuch_query_destroy(query);
@ -82,10 +82,10 @@ impl Drop for NotmuchDb {
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct NotmuchFolder { struct NotmuchMailbox {
hash: FolderHash, hash: MailboxHash,
children: Vec<FolderHash>, children: Vec<MailboxHash>,
parent: Option<FolderHash>, parent: Option<MailboxHash>,
name: String, name: String,
path: String, path: String,
query_str: String, query_str: String,
@ -97,8 +97,8 @@ struct NotmuchFolder {
unseen: Arc<Mutex<usize>>, unseen: Arc<Mutex<usize>>,
} }
impl BackendFolder for NotmuchFolder { impl BackendMailbox for NotmuchMailbox {
fn hash(&self) -> FolderHash { fn hash(&self) -> MailboxHash {
self.hash self.hash
} }
@ -112,15 +112,15 @@ impl BackendFolder for NotmuchFolder {
fn change_name(&mut self, _s: &str) {} fn change_name(&mut self, _s: &str) {}
fn clone(&self) -> Folder { fn clone(&self) -> Mailbox {
Box::new(std::clone::Clone::clone(self)) Box::new(std::clone::Clone::clone(self))
} }
fn children(&self) -> &[FolderHash] { fn children(&self) -> &[MailboxHash] {
&self.children &self.children
} }
fn parent(&self) -> Option<FolderHash> { fn parent(&self) -> Option<MailboxHash> {
self.parent self.parent
} }
@ -128,8 +128,8 @@ impl BackendFolder for NotmuchFolder {
*self.usage.read().unwrap() *self.usage.read().unwrap()
} }
fn permissions(&self) -> FolderPermissions { fn permissions(&self) -> MailboxPermissions {
FolderPermissions::default() MailboxPermissions::default()
} }
fn is_subscribed(&self) -> bool { fn is_subscribed(&self) -> bool {
@ -150,8 +150,8 @@ impl BackendFolder for NotmuchFolder {
} }
} }
unsafe impl Send for NotmuchFolder {} unsafe impl Send for NotmuchMailbox {}
unsafe impl Sync for NotmuchFolder {} unsafe impl Sync for NotmuchMailbox {}
impl NotmuchDb { impl NotmuchDb {
pub fn new( pub fn new(
@ -159,11 +159,11 @@ impl NotmuchDb {
_is_subscribed: Box<dyn Fn(&str) -> bool>, _is_subscribed: Box<dyn Fn(&str) -> bool>,
) -> Result<Box<dyn MailBackend>> { ) -> Result<Box<dyn MailBackend>> {
let mut database: *mut notmuch_database_t = std::ptr::null_mut(); let mut database: *mut notmuch_database_t = std::ptr::null_mut();
let path = Path::new(s.root_folder.as_str()).expand().to_path_buf(); let path = Path::new(s.root_mailbox.as_str()).expand().to_path_buf();
if !path.exists() { if !path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"\"root_folder\" {} for account {} is not a valid path.", "\"root_mailbox\" {} for account {} is not a valid path.",
s.root_folder.as_str(), s.root_mailbox.as_str(),
s.name() s.name()
))); )));
} }
@ -180,22 +180,22 @@ impl NotmuchDb {
if status != 0 { if status != 0 {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Could not open notmuch database at path {}. notmuch_database_open returned {}.", "Could not open notmuch database at path {}. notmuch_database_open returned {}.",
s.root_folder.as_str(), s.root_mailbox.as_str(),
status status
))); )));
} }
assert!(!database.is_null()); assert!(!database.is_null());
let mut folders = FnvHashMap::default(); let mut mailboxes = FnvHashMap::default();
for (k, f) in s.folders.iter() { for (k, f) in s.mailboxes.iter() {
if let Some(query_str) = f.extra.get("query") { if let Some(query_str) = f.extra.get("query") {
let hash = { let hash = {
let mut h = DefaultHasher::new(); let mut h = DefaultHasher::new();
k.hash(&mut h); k.hash(&mut h);
h.finish() h.finish()
}; };
folders.insert( mailboxes.insert(
hash, hash,
NotmuchFolder { NotmuchMailbox {
hash, hash,
name: k.to_string(), name: k.to_string(),
path: k.to_string(), path: k.to_string(),
@ -211,7 +211,7 @@ impl NotmuchDb {
); );
} else { } else {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"notmuch folder configuration entry \"{}\" should have a \"query\" value set.", "notmuch mailbox configuration entry \"{}\" should have a \"query\" value set.",
k k
))); )));
} }
@ -225,24 +225,24 @@ impl NotmuchDb {
index: Arc::new(RwLock::new(Default::default())), index: Arc::new(RwLock::new(Default::default())),
tag_index: Arc::new(RwLock::new(Default::default())), tag_index: Arc::new(RwLock::new(Default::default())),
folders: Arc::new(RwLock::new(folders)), mailboxes: Arc::new(RwLock::new(mailboxes)),
save_messages_to: None, save_messages_to: None,
})) }))
} }
pub fn validate_config(s: &AccountSettings) -> Result<()> { pub fn validate_config(s: &AccountSettings) -> Result<()> {
let path = Path::new(s.root_folder.as_str()).expand().to_path_buf(); let path = Path::new(s.root_mailbox.as_str()).expand().to_path_buf();
if !path.exists() { if !path.exists() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"\"root_folder\" {} for account {} is not a valid path.", "\"root_mailbox\" {} for account {} is not a valid path.",
s.root_folder.as_str(), s.root_mailbox.as_str(),
s.name() s.name()
))); )));
} }
for (k, f) in s.folders.iter() { for (k, f) in s.mailboxes.iter() {
if f.extra.get("query").is_none() { if f.extra.get("query").is_none() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"notmuch folder configuration entry \"{}\" should have a \"query\" value set.", "notmuch mailbox configuration entry \"{}\" should have a \"query\" value set.",
k k
))); )));
} }
@ -288,21 +288,21 @@ impl MailBackend for NotmuchDb {
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let database = self.database.clone(); let database = self.database.clone();
let index = self.index.clone(); let index = self.index.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.tag_index.clone();
let folders = self.folders.clone(); let mailboxes = self.mailboxes.clone();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
let closure = move |_work_context| { let closure = move |_work_context| {
let mut ret: Vec<Envelope> = Vec::new(); let mut ret: Vec<Envelope> = Vec::new();
let database_lck = database.inner.read().unwrap(); let database_lck = database.inner.read().unwrap();
let mut folders_lck = folders.write().unwrap(); let mut mailboxes_lck = mailboxes.write().unwrap();
let folder = folders_lck.get_mut(&folder_hash).unwrap(); let mailbox = mailboxes_lck.get_mut(&mailbox_hash).unwrap();
let query_str = std::ffi::CString::new(folder.query_str.as_str()).unwrap(); let query_str = std::ffi::CString::new(mailbox.query_str.as_str()).unwrap();
let query: *mut notmuch_query_t = let query: *mut notmuch_query_t =
unsafe { notmuch_query_create(*database_lck, query_str.as_ptr()) }; unsafe { notmuch_query_create(*database_lck, query_str.as_ptr()) };
if query.is_null() { if query.is_null() {
@ -319,7 +319,7 @@ impl MailBackend for NotmuchDb {
if status != 0 { if status != 0 {
tx.send(AsyncStatus::Payload(Err(MeliError::new(format!( tx.send(AsyncStatus::Payload(Err(MeliError::new(format!(
"Search for {} returned {}", "Search for {} returned {}",
folder.query_str.as_str(), mailbox.query_str.as_str(),
status, status,
))))) )))))
.unwrap(); .unwrap();
@ -383,7 +383,7 @@ impl MailBackend for NotmuchDb {
index.write().unwrap().remove(&env_hash); index.write().unwrap().remove(&env_hash);
} }
} }
folder.query = Some(query); mailbox.query = Some(query);
tx.send(AsyncStatus::Payload(Ok(ret))).unwrap(); tx.send(AsyncStatus::Payload(Ok(ret))).unwrap();
tx.send(AsyncStatus::Finished).unwrap(); tx.send(AsyncStatus::Finished).unwrap();
}; };
@ -405,13 +405,13 @@ impl MailBackend for NotmuchDb {
.spawn(move || {})?; .spawn(move || {})?;
Ok(handle.thread().id()) Ok(handle.thread().id())
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
Ok(self Ok(self
.folders .mailboxes
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.map(|(k, f)| (*k, BackendFolder::clone(f))) .map(|(k, f)| (*k, BackendMailbox::clone(f)))
.collect()) .collect())
} }
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> { fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
@ -424,7 +424,7 @@ impl MailBackend for NotmuchDb {
}) })
} }
fn save(&self, bytes: &[u8], _folder: &str, flags: Option<Flag>) -> Result<()> { fn save(&self, bytes: &[u8], _mailbox: &str, flags: Option<Flag>) -> Result<()> {
let mut path = self let mut path = self
.save_messages_to .save_messages_to
.as_ref() .as_ref()
@ -435,7 +435,7 @@ impl MailBackend for NotmuchDb {
path.push(d); path.push(d);
if !path.is_dir() { if !path.is_dir() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"{} is not a valid maildir folder", "{} is not a valid maildir mailbox",
path.display() path.display()
))); )));
} }
@ -443,7 +443,7 @@ impl MailBackend for NotmuchDb {
} }
path.push("cur"); path.push("cur");
} }
crate::backends::MaildirType::save_to_folder(path, bytes, flags) crate::backends::MaildirType::save_to_mailbox(path, bytes, flags)
} }
fn as_any(&self) -> &dyn::std::any::Any { fn as_any(&self) -> &dyn::std::any::Any {

View File

@ -20,7 +20,7 @@
*/ */
use super::*; use super::*;
use crate::backends::FolderHash; use crate::backends::MailboxHash;
use core::ops::{Index, IndexMut}; use core::ops::{Index, IndexMut};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -67,9 +67,9 @@ pub struct Collection {
message_ids: FnvHashMap<Vec<u8>, EnvelopeHash>, message_ids: FnvHashMap<Vec<u8>, EnvelopeHash>,
date_index: BTreeMap<UnixTimestamp, EnvelopeHash>, date_index: BTreeMap<UnixTimestamp, EnvelopeHash>,
subject_index: Option<BTreeMap<String, EnvelopeHash>>, subject_index: Option<BTreeMap<String, EnvelopeHash>>,
pub threads: FnvHashMap<FolderHash, Threads>, pub threads: FnvHashMap<MailboxHash, Threads>,
sent_folder: Option<FolderHash>, sent_mailbox: Option<MailboxHash>,
pub mailboxes: FnvHashMap<FolderHash, FnvHashSet<EnvelopeHash>>, pub mailboxes: FnvHashMap<MailboxHash, FnvHashSet<EnvelopeHash>>,
} }
impl Drop for Collection { impl Drop for Collection {
@ -112,7 +112,7 @@ impl Collection {
subject_index, subject_index,
threads, threads,
mailboxes, mailboxes,
sent_folder: None, sent_mailbox: None,
} }
} }
@ -124,18 +124,18 @@ impl Collection {
self.envelopes.read().unwrap().is_empty() self.envelopes.read().unwrap().is_empty()
} }
pub fn remove(&mut self, envelope_hash: EnvelopeHash, folder_hash: FolderHash) { pub fn remove(&mut self, envelope_hash: EnvelopeHash, mailbox_hash: MailboxHash) {
debug!("DEBUG: Removing {}", envelope_hash); debug!("DEBUG: Removing {}", envelope_hash);
self.envelopes.write().unwrap().remove(&envelope_hash); self.envelopes.write().unwrap().remove(&envelope_hash);
self.mailboxes.entry(folder_hash).and_modify(|m| { self.mailboxes.entry(mailbox_hash).and_modify(|m| {
m.remove(&envelope_hash); m.remove(&envelope_hash);
}); });
self.threads self.threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.remove(envelope_hash); .remove(envelope_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in self.threads.iter_mut() {
if *h == folder_hash { if *h == mailbox_hash {
continue; continue;
} }
t.remove(envelope_hash); t.remove(envelope_hash);
@ -146,13 +146,13 @@ impl Collection {
&mut self, &mut self,
old_hash: EnvelopeHash, old_hash: EnvelopeHash,
new_hash: EnvelopeHash, new_hash: EnvelopeHash,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
) { ) {
if !self.envelopes.write().unwrap().contains_key(&old_hash) { if !self.envelopes.write().unwrap().contains_key(&old_hash) {
return; return;
} }
let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
self.mailboxes.entry(folder_hash).and_modify(|m| { self.mailboxes.entry(mailbox_hash).and_modify(|m| {
m.remove(&old_hash); m.remove(&old_hash);
m.insert(new_hash); m.insert(new_hash);
}); });
@ -163,7 +163,7 @@ impl Collection {
{ {
if self if self
.threads .threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.update_envelope(&self.envelopes, old_hash, new_hash) .update_envelope(&self.envelopes, old_hash, new_hash)
.is_ok() .is_ok()
@ -173,11 +173,11 @@ impl Collection {
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
self.threads self.threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, new_hash); .insert(&mut self.envelopes, new_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in self.threads.iter_mut() {
if *h == folder_hash { if *h == mailbox_hash {
continue; continue;
} }
t.update_envelope(&self.envelopes, old_hash, new_hash) t.update_envelope(&self.envelopes, old_hash, new_hash)
@ -187,14 +187,14 @@ 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 /// Returns a list of already existing mailboxs whose threads were updated
pub fn merge( pub fn merge(
&mut self, &mut self,
mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>, mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
sent_folder: Option<FolderHash>, sent_mailbox: Option<MailboxHash>,
) -> Option<SmallVec<[FolderHash; 8]>> { ) -> Option<SmallVec<[MailboxHash; 8]>> {
self.sent_folder = sent_folder; self.sent_mailbox = sent_mailbox;
for (h, e) in new_envelopes.iter() { for (h, e) in new_envelopes.iter() {
self.message_ids.insert(e.message_id().raw().to_vec(), *h); self.message_ids.insert(e.message_id().raw().to_vec(), *h);
} }
@ -203,21 +203,21 @@ impl Collection {
ref mut threads, ref mut threads,
ref mut envelopes, ref mut envelopes,
ref mut mailboxes, ref mut mailboxes,
ref sent_folder, ref sent_mailbox,
.. ..
} = self; } = self;
if !threads.contains_key(&folder_hash) { if !threads.contains_key(&mailbox_hash) {
threads.insert(folder_hash, Threads::new(new_envelopes.len())); threads.insert(mailbox_hash, Threads::new(new_envelopes.len()));
mailboxes.insert(folder_hash, new_envelopes.keys().cloned().collect()); mailboxes.insert(mailbox_hash, new_envelopes.keys().cloned().collect());
for (h, e) in new_envelopes { for (h, e) in new_envelopes {
envelopes.write().unwrap().insert(h, e); envelopes.write().unwrap().insert(h, e);
} }
} else { } else {
mailboxes.entry(folder_hash).and_modify(|m| { mailboxes.entry(mailbox_hash).and_modify(|m| {
m.extend(new_envelopes.keys().cloned()); m.extend(new_envelopes.keys().cloned());
}); });
threads.entry(folder_hash).and_modify(|t| { threads.entry(mailbox_hash).and_modify(|t| {
let mut ordered_hash_set = let mut ordered_hash_set =
new_envelopes.keys().cloned().collect::<Vec<EnvelopeHash>>(); new_envelopes.keys().cloned().collect::<Vec<EnvelopeHash>>();
ordered_hash_set.sort_by(|a, b| { ordered_hash_set.sort_by(|a, b| {
@ -237,14 +237,14 @@ impl Collection {
} }
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
let keys = threads.keys().cloned().collect::<Vec<FolderHash>>(); let keys = threads.keys().cloned().collect::<Vec<MailboxHash>>();
for t_fh in keys { for t_fh in keys {
if t_fh == folder_hash { if t_fh == mailbox_hash {
continue; continue;
} }
if sent_folder.map(|f| f == folder_hash).unwrap_or(false) { if sent_mailbox.map(|f| f == mailbox_hash).unwrap_or(false) {
let envelopes_lck = envelopes.read().unwrap(); let envelopes_lck = envelopes.read().unwrap();
let mut ordered_hash_set = threads[&folder_hash] let mut ordered_hash_set = threads[&mailbox_hash]
.hash_set .hash_set
.iter() .iter()
.cloned() .cloned()
@ -265,7 +265,7 @@ impl Collection {
} }
continue; continue;
} }
if sent_folder.map(|f| f == t_fh).unwrap_or(false) { if sent_mailbox.map(|f| f == t_fh).unwrap_or(false) {
let envelopes_lck = envelopes.read().unwrap(); let envelopes_lck = envelopes.read().unwrap();
let mut ordered_hash_set = threads[&t_fh] let mut ordered_hash_set = threads[&t_fh]
.hash_set .hash_set
@ -282,12 +282,12 @@ impl Collection {
let mut updated = false; let mut updated = false;
for h in ordered_hash_set { for h in ordered_hash_set {
updated |= threads updated |= threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert_reply(envelopes, h); .insert_reply(envelopes, h);
} }
if updated { if updated {
ret.push(folder_hash); ret.push(mailbox_hash);
} }
} }
} }
@ -302,19 +302,23 @@ impl Collection {
&mut self, &mut self,
old_hash: EnvelopeHash, old_hash: EnvelopeHash,
mut envelope: Envelope, mut envelope: Envelope,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
) { ) {
let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
envelope.set_thread(old_env.thread()); envelope.set_thread(old_env.thread());
let new_hash = envelope.hash(); let new_hash = envelope.hash();
self.mailboxes.entry(folder_hash).and_modify(|m| { self.mailboxes.entry(mailbox_hash).and_modify(|m| {
m.remove(&old_hash); m.remove(&old_hash);
m.insert(new_hash); m.insert(new_hash);
}); });
self.message_ids self.message_ids
.insert(envelope.message_id().raw().to_vec(), new_hash); .insert(envelope.message_id().raw().to_vec(), new_hash);
self.envelopes.write().unwrap().insert(new_hash, envelope); self.envelopes.write().unwrap().insert(new_hash, envelope);
if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) { if self
.sent_mailbox
.map(|f| f == mailbox_hash)
.unwrap_or(false)
{
for (_, t) in self.threads.iter_mut() { for (_, t) in self.threads.iter_mut() {
t.update_envelope(&self.envelopes, old_hash, new_hash) t.update_envelope(&self.envelopes, old_hash, new_hash)
.unwrap_or(()); .unwrap_or(());
@ -323,7 +327,7 @@ impl Collection {
{ {
if self if self
.threads .threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.update_envelope(&self.envelopes, old_hash, new_hash) .update_envelope(&self.envelopes, old_hash, new_hash)
.is_ok() .is_ok()
@ -333,11 +337,11 @@ impl Collection {
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
self.threads self.threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, new_hash); .insert(&mut self.envelopes, new_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in self.threads.iter_mut() {
if *h == folder_hash { if *h == mailbox_hash {
continue; continue;
} }
t.update_envelope(&self.envelopes, old_hash, new_hash) t.update_envelope(&self.envelopes, old_hash, new_hash)
@ -346,19 +350,23 @@ impl Collection {
} }
} }
pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) { pub fn insert(&mut self, envelope: Envelope, mailbox_hash: MailboxHash) {
let hash = envelope.hash(); let hash = envelope.hash();
self.mailboxes.entry(folder_hash).and_modify(|m| { self.mailboxes.entry(mailbox_hash).and_modify(|m| {
m.insert(hash); m.insert(hash);
}); });
self.message_ids self.message_ids
.insert(envelope.message_id().raw().to_vec(), hash); .insert(envelope.message_id().raw().to_vec(), hash);
self.envelopes.write().unwrap().insert(hash, envelope); self.envelopes.write().unwrap().insert(hash, envelope);
self.threads self.threads
.entry(folder_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, hash); .insert(&mut self.envelopes, hash);
if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) { if self
.sent_mailbox
.map(|f| f == mailbox_hash)
.unwrap_or(false)
{
self.insert_reply(hash); self.insert_reply(hash);
} }
} }
@ -385,15 +393,15 @@ impl Collection {
} }
} }
impl Index<&FolderHash> for Collection { impl Index<&MailboxHash> for Collection {
type Output = FnvHashSet<EnvelopeHash>; type Output = FnvHashSet<EnvelopeHash>;
fn index(&self, index: &FolderHash) -> &FnvHashSet<EnvelopeHash> { fn index(&self, index: &MailboxHash) -> &FnvHashSet<EnvelopeHash> {
&self.mailboxes[index] &self.mailboxes[index]
} }
} }
impl IndexMut<&FolderHash> for Collection { impl IndexMut<&MailboxHash> for Collection {
fn index_mut(&mut self, index: &FolderHash) -> &mut FnvHashSet<EnvelopeHash> { fn index_mut(&mut self, index: &MailboxHash) -> &mut FnvHashSet<EnvelopeHash> {
self.mailboxes.get_mut(index).unwrap() self.mailboxes.get_mut(index).unwrap()
} }
} }

View File

@ -25,14 +25,14 @@ use std::collections::HashMap;
#[derive(Debug, Serialize, Default, Clone)] #[derive(Debug, Serialize, Default, Clone)]
pub struct AccountSettings { pub struct AccountSettings {
pub name: String, pub name: String,
pub root_folder: String, pub root_mailbox: String,
pub format: String, pub format: String,
pub identity: String, pub identity: String,
pub read_only: bool, pub read_only: bool,
pub display_name: Option<String>, pub display_name: Option<String>,
pub subscribed_folders: Vec<String>, pub subscribed_mailboxes: Vec<String>,
#[serde(default)] #[serde(default)]
pub folders: HashMap<String, FolderConf>, pub mailboxes: HashMap<String, MailboxConf>,
#[serde(default)] #[serde(default)]
pub manual_refresh: bool, pub manual_refresh: bool,
#[serde(flatten)] #[serde(flatten)]
@ -49,8 +49,8 @@ impl AccountSettings {
pub fn set_name(&mut self, s: String) { pub fn set_name(&mut self, s: String) {
self.name = s; self.name = s;
} }
pub fn root_folder(&self) -> &str { pub fn root_mailbox(&self) -> &str {
&self.root_folder &self.root_mailbox
} }
pub fn identity(&self) -> &str { pub fn identity(&self) -> &str {
&self.identity &self.identity
@ -62,8 +62,8 @@ impl AccountSettings {
self.display_name.as_ref() self.display_name.as_ref()
} }
pub fn subscribed_folders(&self) -> &Vec<String> { pub fn subscribed_mailboxes(&self) -> &Vec<String> {
&self.subscribed_folders &self.subscribed_mailboxes
} }
#[cfg(feature = "vcard")] #[cfg(feature = "vcard")]
@ -74,7 +74,7 @@ impl AccountSettings {
#[serde(default)] #[serde(default)]
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FolderConf { pub struct MailboxConf {
pub alias: Option<String>, pub alias: Option<String>,
#[serde(default = "true_val")] #[serde(default = "true_val")]
pub autoload: bool, pub autoload: bool,
@ -88,9 +88,9 @@ pub struct FolderConf {
pub extra: HashMap<String, String>, pub extra: HashMap<String, String>,
} }
impl Default for FolderConf { impl Default for MailboxConf {
fn default() -> Self { fn default() -> Self {
FolderConf { MailboxConf {
alias: None, alias: None,
autoload: true, autoload: true,
subscribe: ToggleFlag::Unset, subscribe: ToggleFlag::Unset,
@ -101,7 +101,7 @@ impl Default for FolderConf {
} }
} }
impl FolderConf { impl MailboxConf {
pub fn alias(&self) -> Option<&str> { pub fn alias(&self) -> Option<&str> {
self.alias.as_ref().map(String::as_str) self.alias.as_ref().map(String::as_str)
} }

View File

@ -650,7 +650,7 @@ impl Threads {
&mut self, &mut self,
envelopes: &mut Envelopes, envelopes: &mut Envelopes,
env_hash: EnvelopeHash, env_hash: EnvelopeHash,
other_folder: bool, other_mailbox: bool,
) -> bool { ) -> bool {
let envelopes_lck = envelopes.read().unwrap(); let envelopes_lck = envelopes.read().unwrap();
let reply_to_id: Option<ThreadNodeHash> = envelopes_lck[&env_hash] let reply_to_id: Option<ThreadNodeHash> = envelopes_lck[&env_hash]
@ -664,7 +664,7 @@ impl Threads {
return false; return false;
} }
if other_folder if other_mailbox
&& reply_to_id.is_none() && reply_to_id.is_none()
&& !self.message_ids.contains_key(message_id) && !self.message_ids.contains_key(message_id)
&& !envelopes_lck[&env_hash] && !envelopes_lck[&env_hash]

View File

@ -9,29 +9,29 @@
# #
# Setting up a Maildir account # Setting up a Maildir account
#[accounts.account-name] #[accounts.account-name]
#root_folder = "/path/to/root/folder" #root_mailbox = "/path/to/root/mailbox"
#format = "Maildir" #format = "Maildir"
#index_style = "Conversations" # or [plain, threaded, compact] #index_style = "Conversations" # or [plain, threaded, compact]
#identity="email@address.tld" #identity="email@address.tld"
#display_name = "Name" #display_name = "Name"
#subscribed_folders = ["INBOX", "INBOX/Sent", "INBOX/Drafts", "INBOX/Junk"] #subscribed_mailboxes = ["INBOX", "INBOX/Sent", "INBOX/Drafts", "INBOX/Junk"]
# Set folder-specific settings # Set mailbox-specific settings
# [accounts.account-name.folders] # [accounts.account-name.mailboxes]
# "INBOX" = { rename="Inbox" } # "INBOX" = { rename="Inbox" }
# "drafts" = { rename="Drafts" } # "drafts" = { rename="Drafts" }
# "foobar-devel" = { ignore = true } # don't show notifications for this folder # "foobar-devel" = { ignore = true } # don't show notifications for this mailbox
# Setting up an mbox account # Setting up an mbox account
#[accounts.mbox] #[accounts.mbox]
#root_folder = "/var/mail/username" #root_mailbox = "/var/mail/username"
#format = "mbox" #format = "mbox"
#index_style = "Compact" #index_style = "Compact"
#identity="username@hostname.local" #identity="username@hostname.local"
# #
# Setting up an IMAP account # Setting up an IMAP account
#[accounts."imap"] #[accounts."imap"]
#root_folder = "INBOX" #root_mailbox = "INBOX"
#format = "imap" #format = "imap"
#server_hostname="mail.server.tld" #server_hostname="mail.server.tld"
#server_password="pha2hiLohs2eeeish2phaii1We3ood4chakaiv0hien2ahie3m" #server_password="pha2hiLohs2eeeish2phaii1We3ood4chakaiv0hien2ahie3m"
@ -42,20 +42,20 @@
#index_style = "Conversations" #index_style = "Conversations"
#identity = "username@server.tld" #identity = "username@server.tld"
#display_name = "Name Name" #display_name = "Name Name"
## match every folder: ## match every mailbox:
#subscribed_folders = ["*" ] #subscribed_mailboxes = ["*" ]
## match specific folders: ## match specific mailboxes:
#subscribed_folders = ["INBOX", "INBOX/Sent", "INBOX/Drafts", "INBOX/Junk"] #subscribed_mailboxes = ["INBOX", "INBOX/Sent", "INBOX/Drafts", "INBOX/Junk"]
# Setting up an account for an already existing notmuch database # Setting up an account for an already existing notmuch database
#[accounts.notmuch] #[accounts.notmuch]
#root_folder = "/path/to/folder" # where .notmuch/ directory is located #root_mailbox = "/path/to/folder" # where .notmuch/ directory is located
#format = "notmuch" #format = "notmuch"
#index_style = "conversations" #index_style = "conversations"
#identity="username@server.tld" #identity="username@server.tld"
#display_name = "Name Name" #display_name = "Name Name"
# # notmuch folders are virtual, they are defined by their alias and the notmuch query that corresponds to their content. # # notmuch mailboxes are virtual, they are defined by their alias and the notmuch query that corresponds to their content.
# [accounts.notmuch.folders] # [accounts.notmuch.mailboxes]
# "INBOX" = { query="tag:inbox", subscribe = true } # "INBOX" = { query="tag:inbox", subscribe = true }
# "Drafts" = { query="tag:draft", subscribe = true } # "Drafts" = { query="tag:draft", subscribe = true }
# "Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true } # "Sent" = { query="from:username@server.tld from:username2@server.tld", subscribe = true }
@ -88,8 +88,8 @@
#[shortcuts.listing] #[shortcuts.listing]
#prev_page = "PageUp" #prev_page = "PageUp"
#next_page = "PageDown" #next_page = "PageDown"
#prev_folder = 'K' #prev_mailbox = 'K'
#next_folder = 'J' #next_mailbox = 'J'
#prev_account = 'l' #prev_account = 'l'
#next_account = 'h' #next_account = 'h'
#new_mail = 'm' #new_mail = 'm'

View File

@ -24,7 +24,7 @@
use melib::parsec::*; use melib::parsec::*;
use melib::UnixTimestamp; use melib::UnixTimestamp;
use melib::{ use melib::{
backends::{FolderHash, MailBackend}, backends::{MailBackend, MailboxHash},
email::EnvelopeHash, email::EnvelopeHash,
thread::{SortField, SortOrder}, thread::{SortField, SortOrder},
Result, Result,
@ -429,7 +429,7 @@ pub fn query_to_imap(q: &Query) -> String {
pub fn imap_search( pub fn imap_search(
term: &str, term: &str,
(_sort_field, _sort_order): (SortField, SortOrder), (_sort_field, _sort_order): (SortField, SortOrder),
folder_hash: FolderHash, mailbox_hash: MailboxHash,
backend: &Arc<RwLock<Box<dyn MailBackend>>>, backend: &Arc<RwLock<Box<dyn MailBackend>>>,
) -> Result<smallvec::SmallVec<[EnvelopeHash; 512]>> { ) -> Result<smallvec::SmallVec<[EnvelopeHash; 512]>> {
let query = query().parse(term)?.1; let query = query().parse(term)?.1;
@ -437,7 +437,7 @@ pub fn imap_search(
let b = (*backend_lck).as_any(); let b = (*backend_lck).as_any();
if let Some(imap_backend) = b.downcast_ref::<melib::backends::ImapType>() { if let Some(imap_backend) = b.downcast_ref::<melib::backends::ImapType>() {
imap_backend.search(query_to_imap(&query), folder_hash) imap_backend.search(query_to_imap(&query), mailbox_hash)
} else { } else {
panic!("Could not downcast ImapType backend. BUG"); panic!("Could not downcast ImapType backend. BUG");
} }

View File

@ -22,8 +22,8 @@
/*! Entities that handle Mail specific functions. /*! Entities that handle Mail specific functions.
*/ */
use super::*; use super::*;
use melib::backends::Folder; use melib::backends::Mailbox;
use melib::backends::FolderHash; use melib::backends::MailboxHash;
use melib::thread::ThreadNodeHash; use melib::thread::ThreadNodeHash;
pub mod listing; pub mod listing;

View File

@ -63,7 +63,7 @@ impl std::ops::DerefMut for EmbedStatus {
#[derive(Debug)] #[derive(Debug)]
pub struct Composer { pub struct Composer {
reply_context: Option<(FolderHash, EnvelopeHash)>, reply_context: Option<(MailboxHash, EnvelopeHash)>,
account_cursor: usize, account_cursor: usize,
cursor: Cursor, cursor: Cursor,
@ -164,7 +164,7 @@ impl Composer {
} }
pub fn with_context( pub fn with_context(
coordinates: (usize, FolderHash), coordinates: (usize, MailboxHash),
msg: EnvelopeHash, msg: EnvelopeHash,
context: &Context, context: &Context,
) -> Self { ) -> Self {
@ -1092,7 +1092,7 @@ pub fn send_draft(
context: &mut Context, context: &mut Context,
account_cursor: usize, account_cursor: usize,
mut draft: Draft, mut draft: Draft,
folder_type: SpecialUsageMailbox, mailbox_type: SpecialUsageMailbox,
flags: Flag, flags: Flag,
) -> bool { ) -> bool {
use std::io::Write; use std::io::Write;
@ -1229,7 +1229,7 @@ pub fn send_draft(
save_draft( save_draft(
bytes.as_bytes(), bytes.as_bytes(),
context, context,
folder_type, mailbox_type,
flags, flags,
account_cursor, account_cursor,
); );
@ -1239,12 +1239,12 @@ pub fn send_draft(
pub fn save_draft( pub fn save_draft(
bytes: &[u8], bytes: &[u8],
context: &mut Context, context: &mut Context,
folder_type: SpecialUsageMailbox, mailbox_type: SpecialUsageMailbox,
flags: Flag, flags: Flag,
account_cursor: usize, account_cursor: usize,
) { ) {
if let Err(MeliError { summary, details }) = if let Err(MeliError { summary, details }) =
context.accounts[account_cursor].save_special(bytes, folder_type, flags) context.accounts[account_cursor].save_special(bytes, mailbox_type, flags)
{ {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
summary.map(|s| s.into()), summary.map(|s| s.into()),

View File

@ -125,7 +125,7 @@ struct AccountMenuEntry {
name: String, name: String,
// Index in the config account vector. // Index in the config account vector.
index: usize, index: usize,
entries: SmallVec<[(usize, FolderHash); 16]>, entries: SmallVec<[(usize, MailboxHash); 16]>,
} }
pub trait MailListingTrait: ListingTrait { pub trait MailListingTrait: ListingTrait {
@ -137,10 +137,10 @@ pub trait MailListingTrait: ListingTrait {
) { ) {
let account = &mut context.accounts[self.coordinates().0]; let account = &mut context.accounts[self.coordinates().0];
let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new(); let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new();
let folder_hash = self.coordinates().1; let mailbox_hash = self.coordinates().1;
for (_, h) in account.collection.threads[&folder_hash].thread_group_iter(thread_hash) { for (_, h) in account.collection.threads[&mailbox_hash].thread_group_iter(thread_hash) {
envs_to_set.push( envs_to_set.push(
account.collection.threads[&folder_hash].thread_nodes()[&h] account.collection.threads[&mailbox_hash].thread_nodes()[&h]
.message() .message()
.unwrap(), .unwrap(),
); );
@ -210,8 +210,8 @@ pub trait MailListingTrait: ListingTrait {
} }
pub trait ListingTrait: Component { pub trait ListingTrait: Component {
fn coordinates(&self) -> (usize, FolderHash); fn coordinates(&self) -> (usize, MailboxHash);
fn set_coordinates(&mut self, _: (usize, FolderHash)); fn set_coordinates(&mut self, _: (usize, MailboxHash));
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context); fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context);
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);
fn filter(&mut self, _filter_term: &str, _context: &Context) {} fn filter(&mut self, _filter_term: &str, _context: &Context) {}
@ -446,11 +446,11 @@ impl Component for Listing {
self.change_account(context); self.change_account(context);
} else { } else {
self.accounts[*account_index].entries = context.accounts[*account_index] self.accounts[*account_index].entries = context.accounts[*account_index]
.list_folders() .list_mailboxes()
.into_iter() .into_iter()
.filter(|folder_node| { .filter(|mailbox_node| {
context.accounts[*account_index][&folder_node.hash] context.accounts[*account_index][&mailbox_node.hash]
.ref_folder .ref_mailbox
.is_subscribed() .is_subscribed()
}) })
.map(|f| (f.depth, f.hash)) .map(|f| (f.depth, f.hash))
@ -459,14 +459,14 @@ impl Component for Listing {
} }
return true; return true;
} }
UIEvent::MailboxDelete((account_index, _folder_hash)) UIEvent::MailboxDelete((account_index, _mailbox_hash))
| UIEvent::MailboxCreate((account_index, _folder_hash)) => { | UIEvent::MailboxCreate((account_index, _mailbox_hash)) => {
self.accounts[*account_index].entries = context.accounts[*account_index] self.accounts[*account_index].entries = context.accounts[*account_index]
.list_folders() .list_mailboxes()
.into_iter() .into_iter()
.filter(|folder_node| { .filter(|mailbox_node| {
context.accounts[*account_index][&folder_node.hash] context.accounts[*account_index][&mailbox_node.hash]
.ref_folder .ref_mailbox
.is_subscribed() .is_subscribed()
}) })
.map(|f| (f.depth, f.hash)) .map(|f| (f.depth, f.hash))
@ -495,8 +495,8 @@ impl Component for Listing {
let shortcuts = self.get_shortcuts(context); let shortcuts = self.get_shortcuts(context);
match *event { match *event {
UIEvent::Input(ref k) UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_folder"]) if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"])
|| shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_folder"]) => || shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) =>
{ {
let amount = if self.cmd_buf.is_empty() { let amount = if self.cmd_buf.is_empty() {
1 1
@ -514,28 +514,28 @@ impl Component for Listing {
return true; return true;
}; };
match k { match k {
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_folder"]) => { k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"]) => {
if let Some((_, folder_hash)) = self.accounts[self.cursor_pos.0] if let Some((_, mailbox_hash)) = self.accounts[self.cursor_pos.0]
.entries .entries
.get(self.cursor_pos.1 + amount) .get(self.cursor_pos.1 + amount)
{ {
self.cursor_pos.1 += amount; self.cursor_pos.1 += amount;
self.component self.component
.set_coordinates((self.cursor_pos.0, *folder_hash)); .set_coordinates((self.cursor_pos.0, *mailbox_hash));
self.set_dirty(true); self.set_dirty(true);
} else { } else {
return true; return true;
} }
} }
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_folder"]) => { k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) => {
if self.cursor_pos.1 >= amount { if self.cursor_pos.1 >= amount {
if let Some((_, folder_hash)) = self.accounts[self.cursor_pos.0] if let Some((_, mailbox_hash)) = self.accounts[self.cursor_pos.0]
.entries .entries
.get(self.cursor_pos.1 - amount) .get(self.cursor_pos.1 - amount)
{ {
self.cursor_pos.1 -= amount; self.cursor_pos.1 -= amount;
self.component self.component
.set_coordinates((self.cursor_pos.0, *folder_hash)); .set_coordinates((self.cursor_pos.0, *mailbox_hash));
self.set_dirty(true); self.set_dirty(true);
} else { } else {
return true; return true;
@ -546,16 +546,16 @@ impl Component for Listing {
} }
_ => {} _ => {}
} }
if let Some((_, folder_hash)) = self.accounts[self.cursor_pos.0] if let Some((_, mailbox_hash)) = self.accounts[self.cursor_pos.0]
.entries .entries
.get(self.cursor_pos.1) .get(self.cursor_pos.1)
{ {
/* Account might have no folders yet if it's offline */ /* Account might have no mailboxes yet if it's offline */
/* Check if per-folder configuration overrides general configuration */ /* Check if per-mailbox configuration overrides general configuration */
if let Some(index_style) = context if let Some(index_style) = context
.accounts .accounts
.get(self.cursor_pos.0) .get(self.cursor_pos.0)
.and_then(|account| account[folder_hash].conf.conf_override.index_style) .and_then(|account| account[mailbox_hash].conf.conf_override.index_style)
{ {
self.component.set_style(index_style); self.component.set_style(index_style);
} else if let Some(index_style) = context } else if let Some(index_style) = context
@ -642,12 +642,12 @@ impl Component for Listing {
return true; return true;
} }
Action::ViewMailbox(idx) => { Action::ViewMailbox(idx) => {
if let Some((_, folder_hash)) = if let Some((_, mailbox_hash)) =
self.accounts[self.cursor_pos.0].entries.get(*idx) self.accounts[self.cursor_pos.0].entries.get(*idx)
{ {
self.cursor_pos.1 = *idx; self.cursor_pos.1 = *idx;
self.component self.component
.set_coordinates((self.cursor_pos.0, *folder_hash)); .set_coordinates((self.cursor_pos.0, *mailbox_hash));
self.set_dirty(true); self.set_dirty(true);
} else { } else {
return true; return true;
@ -791,8 +791,8 @@ impl Component for Listing {
if shortcut!(key == shortcuts[Listing::DESCRIPTION]["refresh"]) => if shortcut!(key == shortcuts[Listing::DESCRIPTION]["refresh"]) =>
{ {
let account = &mut context.accounts[self.cursor_pos.0]; let account = &mut context.accounts[self.cursor_pos.0];
if let Some(&folder_hash) = account.folders_order.get(self.cursor_pos.1) { if let Some(&mailbox_hash) = account.mailboxes_order.get(self.cursor_pos.1) {
if let Err(err) = account.refresh(folder_hash) { if let Err(err) = account.refresh(mailbox_hash) {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not refresh.".to_string()), Some("Could not refresh.".to_string()),
err.to_string(), err.to_string(),
@ -862,36 +862,36 @@ impl Component for Listing {
} }
fn get_status(&self, context: &Context) -> String { fn get_status(&self, context: &Context) -> String {
let folder_hash = if let Some((_, folder_hash)) = self.accounts[self.cursor_pos.0] let mailbox_hash = if let Some((_, mailbox_hash)) = self.accounts[self.cursor_pos.0]
.entries .entries
.get(self.cursor_pos.1) .get(self.cursor_pos.1)
{ {
*folder_hash *mailbox_hash
} else { } else {
return String::new(); return String::new();
}; };
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
use crate::conf::accounts::MailboxStatus; use crate::conf::accounts::MailboxStatus;
match account[&folder_hash].status { match account[&mailbox_hash].status {
MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!( MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!(
"Mailbox: {}, Messages: {}, New: {}", "Mailbox: {}, Messages: {}, New: {}",
account[&folder_hash].ref_folder.name(), account[&mailbox_hash].ref_mailbox.name(),
account.collection[&folder_hash].len(), account.collection[&mailbox_hash].len(),
account[&folder_hash] account[&mailbox_hash]
.ref_folder .ref_mailbox
.count() .count()
.ok() .ok()
.map(|(v, _)| v) .map(|(v, _)| v)
.unwrap_or(0), .unwrap_or(0),
), ),
MailboxStatus::Failed(_) | MailboxStatus::None => account[&folder_hash].status(), MailboxStatus::Failed(_) | MailboxStatus::None => account[&mailbox_hash].status(),
} }
} }
} }
impl From<(IndexStyle, (usize, FolderHash))> for ListingComponent { impl From<(IndexStyle, (usize, MailboxHash))> for ListingComponent {
fn from((index_style, coordinates): (IndexStyle, (usize, FolderHash))) -> Self { fn from((index_style, coordinates): (IndexStyle, (usize, MailboxHash))) -> Self {
match index_style { match index_style {
IndexStyle::Plain => Plain(PlainListing::new(coordinates)), IndexStyle::Plain => Plain(PlainListing::new(coordinates)),
IndexStyle::Threaded => Threaded(ThreadListing::new(coordinates)), IndexStyle::Threaded => Threaded(ThreadListing::new(coordinates)),
@ -909,10 +909,10 @@ impl Listing {
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, a)| { .map(|(i, a)| {
let entries: SmallVec<[(usize, FolderHash); 16]> = a let entries: SmallVec<[(usize, MailboxHash); 16]> = a
.list_folders() .list_mailboxes()
.into_iter() .into_iter()
.filter(|folder_node| a[&folder_node.hash].ref_folder.is_subscribed()) .filter(|mailbox_node| a[&mailbox_node.hash].ref_mailbox.is_subscribed())
.map(|f| (f.depth, f.hash)) .map(|f| (f.depth, f.hash))
.collect::<_>(); .collect::<_>();
@ -981,10 +981,10 @@ impl Listing {
debug!("BUG: invalid area in print_account"); debug!("BUG: invalid area in print_account");
} }
// Each entry and its index in the account // Each entry and its index in the account
let folders: FnvHashMap<FolderHash, Folder> = context.accounts[a.index] let mailboxes: FnvHashMap<MailboxHash, Mailbox> = context.accounts[a.index]
.folder_entries .mailbox_entries
.iter() .iter()
.map(|(&hash, entry)| (hash, entry.ref_folder.clone())) .map(|(&hash, entry)| (hash, entry.ref_mailbox.clone()))
.collect(); .collect();
let upper_left = upper_left!(area); let upper_left = upper_left!(area);
@ -992,21 +992,21 @@ impl Listing {
let must_highlight_account: bool = self.cursor_pos.0 == a.index; let must_highlight_account: bool = self.cursor_pos.0 == a.index;
let mut lines: Vec<(usize, usize, FolderHash, Option<usize>)> = Vec::new(); let mut lines: Vec<(usize, usize, MailboxHash, Option<usize>)> = Vec::new();
for (i, &(depth, folder_hash)) in a.entries.iter().enumerate() { for (i, &(depth, mailbox_hash)) in a.entries.iter().enumerate() {
if folders[&folder_hash].is_subscribed() { if mailboxes[&mailbox_hash].is_subscribed() {
match context.accounts[a.index].status(folder_hash) { match context.accounts[a.index].status(mailbox_hash) {
Ok(_) => { Ok(_) => {
lines.push(( lines.push((
depth, depth,
i, i,
folder_hash, mailbox_hash,
folders[&folder_hash].count().ok().map(|(v, _)| v), mailboxes[&mailbox_hash].count().ok().map(|(v, _)| v),
)); ));
} }
Err(_) => { Err(_) => {
lines.push((depth, i, folder_hash, None)); lines.push((depth, i, mailbox_hash, None));
} }
} }
} }
@ -1075,8 +1075,8 @@ impl Listing {
) )
}; };
let (depth, inc, folder_idx, count) = lines[idx]; let (depth, inc, mailbox_idx, count) = lines[idx];
/* Calculate how many columns the folder index tags should occupy with right alignment, /* Calculate how many columns the mailbox index tags should occupy with right alignment,
* eg. * eg.
* 1 * 1
* 2 * 2
@ -1084,7 +1084,7 @@ impl Listing {
* 9 * 9
* 10 * 10
*/ */
let total_folder_no_digits = { let total_mailbox_no_digits = {
let mut len = lines_len; let mut len = lines_len;
let mut ctr = 1; let mut ctr = 1;
while len > 9 { while len > 9 {
@ -1094,7 +1094,7 @@ impl Listing {
ctr ctr
}; };
let (x, _) = write_string_to_grid( let (x, _) = write_string_to_grid(
&format!("{:>width$}", inc, width = total_folder_no_digits), &format!("{:>width$}", inc, width = total_mailbox_no_digits),
grid, grid,
index_att.fg, index_att.fg,
index_att.bg, index_att.bg,
@ -1112,7 +1112,7 @@ impl Listing {
None, None,
); );
let (x, _) = write_string_to_grid( let (x, _) = write_string_to_grid(
folders[&folder_idx].name(), mailboxes[&mailbox_idx].name(),
grid, grid,
att.fg, att.fg,
att.bg, att.bg,
@ -1145,7 +1145,7 @@ impl Listing {
}, },
( (
( (
/* Hide part of folder name if need be to fit the message count */ /* Hide part of mailbox name if need be to fit the message count */
std::cmp::min(x, get_x(bottom_right).saturating_sub(count_string.len())), std::cmp::min(x, get_x(bottom_right).saturating_sub(count_string.len())),
y, y,
), ),
@ -1167,27 +1167,27 @@ impl Listing {
fn change_account(&mut self, context: &mut Context) { fn change_account(&mut self, context: &mut Context) {
self.accounts[self.cursor_pos.0].entries = context.accounts[self.cursor_pos.0] self.accounts[self.cursor_pos.0].entries = context.accounts[self.cursor_pos.0]
.list_folders() .list_mailboxes()
.into_iter() .into_iter()
.filter(|folder_node| { .filter(|mailbox_node| {
context.accounts[self.cursor_pos.0][&folder_node.hash] context.accounts[self.cursor_pos.0][&mailbox_node.hash]
.ref_folder .ref_mailbox
.is_subscribed() .is_subscribed()
}) })
.map(|f| (f.depth, f.hash)) .map(|f| (f.depth, f.hash))
.collect::<_>(); .collect::<_>();
/* Account might have no folders yet if it's offline */ /* Account might have no mailboxes yet if it's offline */
if let Some((_, folder_hash)) = self.accounts[self.cursor_pos.0] if let Some((_, mailbox_hash)) = self.accounts[self.cursor_pos.0]
.entries .entries
.get(self.cursor_pos.1) .get(self.cursor_pos.1)
{ {
self.component self.component
.set_coordinates((self.cursor_pos.0, *folder_hash)); .set_coordinates((self.cursor_pos.0, *mailbox_hash));
/* Check if per-folder configuration overrides general configuration */ /* Check if per-mailbox configuration overrides general configuration */
if let Some(index_style) = context if let Some(index_style) = context
.accounts .accounts
.get(self.cursor_pos.0) .get(self.cursor_pos.0)
.and_then(|account| account[folder_hash].conf.conf_override.index_style) .and_then(|account| account[mailbox_hash].conf.conf_override.index_style)
{ {
self.component.set_style(index_style); self.component.set_style(index_style);
} else if let Some(index_style) = context } else if let Some(index_style) = context

View File

@ -48,9 +48,9 @@ macro_rules! address_list {
/// `ThreadView`. /// `ThreadView`.
#[derive(Debug)] #[derive(Debug)]
pub struct CompactListing { pub struct CompactListing {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, FolderHash, usize), cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, FolderHash, usize), new_cursor_pos: (usize, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -100,7 +100,7 @@ impl MailListingTrait for CompactListing {
SmallVec::from_iter(iter.into_iter()) SmallVec::from_iter(iter.into_iter())
} }
/// Fill the `self.data_columns` `CellBuffers` with the contents of the account folder the user has /// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has
/// chosen. /// chosen.
fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { fn refresh_mailbox(&mut self, context: &mut Context, force: bool) {
self.dirty = true; self.dirty = true;
@ -184,11 +184,11 @@ impl MailListingTrait for CompactListing {
} }
impl ListingTrait for CompactListing { impl ListingTrait for CompactListing {
fn coordinates(&self) -> (usize, FolderHash) { fn coordinates(&self) -> (usize, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1) (self.new_cursor_pos.0, self.new_cursor_pos.1)
} }
fn set_coordinates(&mut self, coordinates: (usize, FolderHash)) { fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false; self.unfocused = false;
self.view = ThreadView::default(); self.view = ThreadView::default();
@ -618,7 +618,7 @@ impl fmt::Display for CompactListing {
impl CompactListing { impl CompactListing {
const DESCRIPTION: &'static str = "compact listing"; const DESCRIPTION: &'static str = "compact listing";
pub fn new(coordinates: (usize, FolderHash)) -> Self { pub fn new(coordinates: (usize, MailboxHash)) -> Self {
CompactListing { CompactListing {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),
@ -650,14 +650,14 @@ impl CompactListing {
hash: ThreadHash, hash: ThreadHash,
) -> EntryStrings { ) -> EntryStrings {
let thread = threads.thread_ref(hash); let thread = threads.thread_ref(hash);
let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mailbox = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf;
let mut tags = String::new(); let mut tags = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new(); let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if folder if mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()
@ -669,7 +669,7 @@ impl CompactListing {
tags.push(' '); tags.push(' ');
tags.push_str(tags_lck.get(t).as_ref().unwrap()); tags.push_str(tags_lck.get(t).as_ref().unwrap());
tags.push(' '); tags.push(' ');
if let Some(&c) = folder if let Some(&c) = mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()

View File

@ -27,9 +27,9 @@ use std::iter::FromIterator;
/// `ThreadView`. /// `ThreadView`.
#[derive(Debug)] #[derive(Debug)]
pub struct ConversationsListing { pub struct ConversationsListing {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, FolderHash, usize), cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, FolderHash, usize), new_cursor_pos: (usize, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -79,11 +79,11 @@ impl MailListingTrait for ConversationsListing {
SmallVec::from_iter(iter.into_iter()) SmallVec::from_iter(iter.into_iter())
} }
/// Fill the `self.data_columns` `CellBuffers` with the contents of the account folder the user has /// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has
/// chosen. /// chosen.
fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { fn refresh_mailbox(&mut self, context: &mut Context, force: bool) {
self.dirty = true; self.dirty = true;
let old_folder_hash = self.cursor_pos.1; let old_mailbox_hash = self.cursor_pos.1;
let old_cursor_pos = self.cursor_pos; let old_cursor_pos = self.cursor_pos;
if !(self.cursor_pos.0 == self.new_cursor_pos.0 if !(self.cursor_pos.0 == self.new_cursor_pos.0
&& self.cursor_pos.1 == self.new_cursor_pos.1) && self.cursor_pos.1 == self.new_cursor_pos.1)
@ -159,7 +159,8 @@ impl MailListingTrait for ConversationsListing {
Box::new(roots.into_iter()) as Box<dyn Iterator<Item = ThreadHash>>, Box::new(roots.into_iter()) as Box<dyn Iterator<Item = ThreadHash>>,
); );
if !force && old_cursor_pos == self.new_cursor_pos && old_folder_hash == self.cursor_pos.1 { if !force && old_cursor_pos == self.new_cursor_pos && old_mailbox_hash == self.cursor_pos.1
{
self.view.update(context); self.view.update(context);
} else if self.unfocused { } else if self.unfocused {
let thread_group = self.get_thread_under_cursor(self.cursor_pos.2); let thread_group = self.get_thread_under_cursor(self.cursor_pos.2);
@ -170,11 +171,11 @@ impl MailListingTrait for ConversationsListing {
} }
impl ListingTrait for ConversationsListing { impl ListingTrait for ConversationsListing {
fn coordinates(&self) -> (usize, FolderHash) { fn coordinates(&self) -> (usize, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1) (self.new_cursor_pos.0, self.new_cursor_pos.1)
} }
fn set_coordinates(&mut self, coordinates: (usize, FolderHash)) { fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false; self.unfocused = false;
@ -559,7 +560,7 @@ impl fmt::Display for ConversationsListing {
impl ConversationsListing { impl ConversationsListing {
const DESCRIPTION: &'static str = "compact listing"; const DESCRIPTION: &'static str = "compact listing";
pub fn new(coordinates: (usize, FolderHash)) -> Self { pub fn new(coordinates: (usize, MailboxHash)) -> Self {
ConversationsListing { ConversationsListing {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),
@ -592,14 +593,14 @@ impl ConversationsListing {
hash: ThreadHash, hash: ThreadHash,
) -> EntryStrings { ) -> EntryStrings {
let thread = threads.thread_ref(hash); let thread = threads.thread_ref(hash);
let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mailbox = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf;
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::new(); let mut colors = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if folder if mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()
@ -611,7 +612,7 @@ impl ConversationsListing {
tags.push(' '); tags.push(' ');
tags.push_str(tags_lck.get(t).as_ref().unwrap()); tags.push_str(tags_lck.get(t).as_ref().unwrap());
tags.push(' '); tags.push(' ');
if let Some(&c) = folder if let Some(&c) = mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()

View File

@ -24,7 +24,7 @@ use crate::components::utilities::PageMovement;
#[derive(Debug)] #[derive(Debug)]
pub struct OfflineListing { pub struct OfflineListing {
cursor_pos: (usize, FolderHash), cursor_pos: (usize, MailboxHash),
_row_updates: SmallVec<[ThreadHash; 8]>, _row_updates: SmallVec<[ThreadHash; 8]>,
id: ComponentId, id: ComponentId,
@ -44,11 +44,11 @@ impl MailListingTrait for OfflineListing {
} }
impl ListingTrait for OfflineListing { impl ListingTrait for OfflineListing {
fn coordinates(&self) -> (usize, FolderHash) { fn coordinates(&self) -> (usize, MailboxHash) {
self.cursor_pos self.cursor_pos
} }
fn set_coordinates(&mut self, coordinates: (usize, FolderHash)) { fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
self.cursor_pos = coordinates; self.cursor_pos = coordinates;
} }
@ -75,7 +75,7 @@ impl fmt::Display for OfflineListing {
} }
impl OfflineListing { impl OfflineListing {
pub fn new(cursor_pos: (usize, FolderHash)) -> Self { pub fn new(cursor_pos: (usize, MailboxHash)) -> Self {
OfflineListing { OfflineListing {
cursor_pos, cursor_pos,
_row_updates: SmallVec::new(), _row_updates: SmallVec::new(),

View File

@ -47,9 +47,9 @@ macro_rules! address_list {
/// `MailView`. /// `MailView`.
#[derive(Debug)] #[derive(Debug)]
pub struct PlainListing { pub struct PlainListing {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, FolderHash, usize), cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, FolderHash, usize), new_cursor_pos: (usize, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -101,7 +101,7 @@ impl MailListingTrait for PlainListing {
*/ */
} }
/// Fill the `self.data_columns` `CellBuffers` with the contents of the account folder the user has /// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has
/// chosen. /// chosen.
fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { fn refresh_mailbox(&mut self, context: &mut Context, force: bool) {
self.dirty = true; self.dirty = true;
@ -188,11 +188,11 @@ impl MailListingTrait for PlainListing {
} }
impl ListingTrait for PlainListing { impl ListingTrait for PlainListing {
fn coordinates(&self) -> (usize, FolderHash) { fn coordinates(&self) -> (usize, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1) (self.new_cursor_pos.0, self.new_cursor_pos.1)
} }
fn set_coordinates(&mut self, coordinates: (usize, FolderHash)) { fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false; self.unfocused = false;
self.view = MailView::default(); self.view = MailView::default();
@ -584,7 +584,7 @@ impl fmt::Display for PlainListing {
impl PlainListing { impl PlainListing {
const DESCRIPTION: &'static str = "plain listing"; const DESCRIPTION: &'static str = "plain listing";
pub fn new(coordinates: (usize, FolderHash)) -> Self { pub fn new(coordinates: (usize, MailboxHash)) -> Self {
PlainListing { PlainListing {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),
@ -613,14 +613,14 @@ impl PlainListing {
} }
} }
fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings { fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings {
let folder = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf; let mailbox = &context.accounts[self.cursor_pos.0][&self.cursor_pos.1].conf;
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::new(); let mut colors = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap(); let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if folder if mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()
@ -632,7 +632,7 @@ impl PlainListing {
tags.push(' '); tags.push(' ');
tags.push_str(tags_lck.get(t).as_ref().unwrap()); tags.push_str(tags_lck.get(t).as_ref().unwrap());
tags.push(' '); tags.push(' ');
if let Some(&c) = folder if let Some(&c) = mailbox
.conf_override .conf_override
.tags .tags
.as_ref() .as_ref()

View File

@ -28,9 +28,9 @@ const MAX_COLS: usize = 500;
/// `MailView`. /// `MailView`.
#[derive(Debug)] #[derive(Debug)]
pub struct ThreadListing { pub struct ThreadListing {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, FolderHash, usize), cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, FolderHash, usize), new_cursor_pos: (usize, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -59,7 +59,7 @@ impl MailListingTrait for ThreadListing {
SmallVec::new() SmallVec::new()
} }
/// Fill the `self.content` `CellBuffer` with the contents of the account folder the user has /// Fill the `self.content` `CellBuffer` with the contents of the account mailbox the user has
/// chosen. /// chosen.
fn refresh_mailbox(&mut self, context: &mut Context, _force: bool) { fn refresh_mailbox(&mut self, context: &mut Context, _force: bool) {
self.dirty = true; self.dirty = true;
@ -127,7 +127,7 @@ impl MailListingTrait for ThreadListing {
ret ret
}; };
if threads.len() == 0 { if threads.len() == 0 {
let message = format!("Folder `{}` is empty.", account[&self.cursor_pos.1].name()); let message = format!("Mailbox `{}` is empty.", account[&self.cursor_pos.1].name());
self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context); self.content = CellBuffer::new_with_context(message.len(), 1, default_cell, context);
write_string_to_grid( write_string_to_grid(
&message, &message,
@ -226,10 +226,10 @@ impl MailListingTrait for ThreadListing {
} }
impl ListingTrait for ThreadListing { impl ListingTrait for ThreadListing {
fn coordinates(&self) -> (usize, FolderHash) { fn coordinates(&self) -> (usize, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1) (self.new_cursor_pos.0, self.new_cursor_pos.1)
} }
fn set_coordinates(&mut self, coordinates: (usize, FolderHash)) { fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false; self.unfocused = false;
self.view = None; self.view = None;
@ -396,7 +396,7 @@ impl fmt::Display for ThreadListing {
} }
impl ThreadListing { impl ThreadListing {
pub fn new(coordinates: (usize, FolderHash)) -> Self { pub fn new(coordinates: (usize, MailboxHash)) -> Self {
ThreadListing { ThreadListing {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),

View File

@ -308,9 +308,9 @@ impl StatusPanel {
} }
} }
let count = a let count = a
.folder_entries .mailbox_entries
.values() .values()
.map(|entry| &entry.ref_folder) .map(|entry| &entry.ref_mailbox)
.fold((0, 0), |acc, f| { .fold((0, 0), |acc, f| {
let count = f.count().unwrap_or((0, 0)); let count = f.count().unwrap_or((0, 0));
(acc.0 + count.0, acc.1 + count.1) (acc.0 + count.0, acc.1 + count.1)
@ -361,9 +361,9 @@ impl StatusPanel {
None, None,
); );
for (i, f) in a for (i, f) in a
.folder_entries .mailbox_entries
.values() .values()
.map(|entry| &entry.ref_folder) .map(|entry| &entry.ref_mailbox)
.filter(|f| f.special_usage() != SpecialUsageMailbox::Normal) .filter(|f| f.special_usage() != SpecialUsageMailbox::Normal)
.enumerate() .enumerate()
{ {
@ -479,9 +479,9 @@ impl Component for AccountStatus {
None, None,
); );
for f in a for f in a
.folder_entries .mailbox_entries
.values() .values()
.map(|entry| &entry.ref_folder) .map(|entry| &entry.ref_mailbox)
.filter(|f| f.special_usage() != SpecialUsageMailbox::Normal) .filter(|f| f.special_usage() != SpecialUsageMailbox::Normal)
{ {
line += 1; line += 1;
@ -497,7 +497,7 @@ impl Component for AccountStatus {
} }
line += 2; line += 2;
write_string_to_grid( write_string_to_grid(
"Subscribed folders:", "Subscribed mailboxes:",
&mut self.content, &mut self.content,
self.theme_default.fg, self.theme_default.fg,
self.theme_default.bg, self.theme_default.bg,
@ -506,8 +506,8 @@ impl Component for AccountStatus {
None, None,
); );
line += 2; line += 2;
for folder_node in a.list_folders() { for mailbox_node in a.list_mailboxes() {
let f: &Folder = &a[&folder_node.hash].ref_folder; let f: &Mailbox = &a[&mailbox_node.hash].ref_mailbox;
if f.is_subscribed() { if f.is_subscribed() {
write_string_to_grid( write_string_to_grid(
f.path(), f.path(),

View File

@ -86,7 +86,7 @@ impl ViewMode {
/// menus /// menus
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MailView { pub struct MailView {
coordinates: (usize, FolderHash, EnvelopeHash), coordinates: (usize, MailboxHash, EnvelopeHash),
pager: Pager, pager: Pager,
subview: Option<Box<dyn Component>>, subview: Option<Box<dyn Component>>,
dirty: bool, dirty: bool,
@ -124,7 +124,7 @@ impl fmt::Display for MailView {
impl MailView { impl MailView {
const DESCRIPTION: &'static str = "view mail"; const DESCRIPTION: &'static str = "view mail";
pub fn new( pub fn new(
coordinates: (usize, FolderHash, EnvelopeHash), coordinates: (usize, MailboxHash, EnvelopeHash),
pager: Option<Pager>, pager: Option<Pager>,
subview: Option<Box<dyn Component>>, subview: Option<Box<dyn Component>>,
context: &Context, context: &Context,
@ -342,7 +342,7 @@ impl MailView {
} }
} }
pub fn update(&mut self, new_coordinates: (usize, FolderHash, EnvelopeHash)) { pub fn update(&mut self, new_coordinates: (usize, MailboxHash, EnvelopeHash)) {
self.coordinates = new_coordinates; self.coordinates = new_coordinates;
self.mode = ViewMode::Normal; self.mode = ViewMode::Normal;
self.initialised = false; self.initialised = false;

View File

@ -51,7 +51,7 @@ pub struct ThreadView {
expanded_pos: usize, expanded_pos: usize,
new_expanded_pos: usize, new_expanded_pos: usize,
reversed: bool, reversed: bool,
coordinates: (usize, FolderHash, usize), coordinates: (usize, MailboxHash, usize),
thread_group: ThreadHash, thread_group: ThreadHash,
mailview: MailView, mailview: MailView,
show_mailview: bool, show_mailview: bool,
@ -69,13 +69,13 @@ pub struct ThreadView {
impl ThreadView { impl ThreadView {
const DESCRIPTION: &'static str = "thread view"; const DESCRIPTION: &'static str = "thread view";
/* /*
* coordinates: (account index, folder_hash, root set thread_node index) * coordinates: (account index, mailbox_hash, root set thread_node index)
* expanded_hash: optional position of expanded entry when we render the threadview. Default * expanded_hash: optional position of expanded entry when we render the threadview. Default
* expanded message is the last one. * expanded message is the last one.
* context: current context * context: current context
*/ */
pub fn new( pub fn new(
coordinates: (usize, FolderHash, usize), coordinates: (usize, MailboxHash, usize),
thread_group: ThreadHash, thread_group: ThreadHash,
expanded_hash: Option<ThreadNodeHash>, expanded_hash: Option<ThreadNodeHash>,
context: &Context, context: &Context,

View File

@ -51,7 +51,7 @@ use self::notifications::NotificationsSettings;
use self::terminal::TerminalSettings; use self::terminal::TerminalSettings;
use crate::pager::PagerSettings; use crate::pager::PagerSettings;
use crate::plugins::Plugin; use crate::plugins::Plugin;
use melib::conf::{AccountSettings, FolderConf, ToggleFlag}; use melib::conf::{AccountSettings, MailboxConf, ToggleFlag};
use melib::error::*; use melib::error::*;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
@ -85,27 +85,27 @@ pub struct MailUIConf {
#[serde(default)] #[serde(default)]
#[derive(Debug, Default, Clone, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct FileFolderConf { pub struct FileMailboxConf {
#[serde(flatten)] #[serde(flatten)]
pub conf_override: MailUIConf, pub conf_override: MailUIConf,
#[serde(flatten)] #[serde(flatten)]
pub folder_conf: FolderConf, pub mailbox_conf: MailboxConf,
} }
impl FileFolderConf { impl FileMailboxConf {
pub fn conf_override(&self) -> &MailUIConf { pub fn conf_override(&self) -> &MailUIConf {
&self.conf_override &self.conf_override
} }
pub fn folder_conf(&self) -> &FolderConf { pub fn mailbox_conf(&self) -> &MailboxConf {
&self.folder_conf &self.mailbox_conf
} }
} }
use crate::conf::deserializers::extra_settings; use crate::conf::deserializers::extra_settings;
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct FileAccount { pub struct FileAccount {
root_folder: String, root_mailbox: String,
format: String, format: String,
identity: String, identity: String,
#[serde(default = "none")] #[serde(default = "none")]
@ -115,9 +115,9 @@ pub struct FileAccount {
#[serde(default = "false_val")] #[serde(default = "false_val")]
read_only: bool, read_only: bool,
#[serde(default)] #[serde(default)]
subscribed_folders: Vec<String>, subscribed_mailboxes: Vec<String>,
#[serde(default)] #[serde(default)]
folders: HashMap<String, FileFolderConf>, mailboxes: HashMap<String, FileMailboxConf>,
#[serde(default)] #[serde(default)]
cache_type: CacheType, cache_type: CacheType,
#[serde(default)] #[serde(default)]
@ -132,44 +132,44 @@ pub struct FileAccount {
impl From<FileAccount> for AccountConf { impl From<FileAccount> for AccountConf {
fn from(x: FileAccount) -> Self { fn from(x: FileAccount) -> Self {
let format = x.format.to_lowercase(); let format = x.format.to_lowercase();
let root_folder = x.root_folder.clone(); let root_mailbox = x.root_mailbox.clone();
let identity = x.identity.clone(); let identity = x.identity.clone();
let display_name = x.display_name.clone(); let display_name = x.display_name.clone();
let folders = x let mailboxes = x
.folders .mailboxes
.iter() .iter()
.map(|(k, v)| (k.clone(), v.folder_conf.clone())) .map(|(k, v)| (k.clone(), v.mailbox_conf.clone()))
.collect(); .collect();
let acc = AccountSettings { let acc = AccountSettings {
name: String::new(), name: String::new(),
root_folder, root_mailbox,
format, format,
identity, identity,
read_only: x.read_only, read_only: x.read_only,
display_name, display_name,
subscribed_folders: x.subscribed_folders.clone(), subscribed_mailboxes: x.subscribed_mailboxes.clone(),
folders, mailboxes,
manual_refresh: x.manual_refresh, manual_refresh: x.manual_refresh,
extra: x.extra.clone(), extra: x.extra.clone(),
}; };
let folder_confs = x.folders.clone(); let mailbox_confs = x.mailboxes.clone();
AccountConf { AccountConf {
account: acc, account: acc,
conf: x, conf: x,
folder_confs, mailbox_confs,
} }
} }
} }
impl FileAccount { impl FileAccount {
pub fn folders(&self) -> &HashMap<String, FileFolderConf> { pub fn mailboxes(&self) -> &HashMap<String, FileMailboxConf> {
&self.folders &self.mailboxes
} }
pub fn folder(&self) -> &str { pub fn mailbox(&self) -> &str {
&self.root_folder &self.root_mailbox
} }
pub fn index_style(&self) -> IndexStyle { pub fn index_style(&self) -> IndexStyle {
@ -207,7 +207,7 @@ pub struct FileSettings {
pub struct AccountConf { pub struct AccountConf {
pub(crate) account: AccountSettings, pub(crate) account: AccountSettings,
pub(crate) conf: FileAccount, pub(crate) conf: FileAccount,
pub(crate) folder_confs: HashMap<String, FileFolderConf>, pub(crate) mailbox_confs: HashMap<String, FileMailboxConf>,
} }
impl AccountConf { impl AccountConf {
@ -342,13 +342,13 @@ impl FileSettings {
s.terminal.themes.validate()?; s.terminal.themes.validate()?;
for (name, acc) in &s.accounts { for (name, acc) in &s.accounts {
let FileAccount { let FileAccount {
root_folder, root_mailbox,
format, format,
identity, identity,
read_only, read_only,
display_name, display_name,
subscribed_folders, subscribed_mailboxes,
folders, mailboxes,
extra, extra,
manual_refresh, manual_refresh,
refresh_command: _, refresh_command: _,
@ -359,16 +359,16 @@ impl FileSettings {
let lowercase_format = format.to_lowercase(); let lowercase_format = format.to_lowercase();
let s = AccountSettings { let s = AccountSettings {
name: name.to_string(), name: name.to_string(),
root_folder, root_mailbox,
format: format.clone(), format: format.clone(),
identity, identity,
read_only, read_only,
display_name, display_name,
subscribed_folders, subscribed_mailboxes,
manual_refresh, manual_refresh,
folders: folders mailboxes: mailboxes
.into_iter() .into_iter()
.map(|(k, v)| (k, v.folder_conf)) .map(|(k, v)| (k, v.mailbox_conf))
.collect(), .collect(),
extra, extra,
}; };
@ -714,8 +714,8 @@ mod pp {
let mut ret = pp_helper(&p_buf, 0)?; let mut ret = pp_helper(&p_buf, 0)?;
drop(p_buf); drop(p_buf);
if let Ok(xdg_dirs) = xdg::BaseDirectories::with_prefix("meli") { if let Ok(xdg_dirs) = xdg::BaseDirectories::with_prefix("meli") {
for theme_folder in xdg_dirs.find_config_files("themes") { for theme_mailbox in xdg_dirs.find_config_files("themes") {
let read_dir = std::fs::read_dir(theme_folder)?; let read_dir = std::fs::read_dir(theme_mailbox)?;
for theme in read_dir { for theme in read_dir {
ret.extend(pp_helper(&theme?.path(), 0)?.chars()); ret.extend(pp_helper(&theme?.path(), 0)?.chars());
} }

View File

@ -23,11 +23,11 @@
* Account management from user configuration. * Account management from user configuration.
*/ */
use super::{AccountConf, FileFolderConf}; use super::{AccountConf, FileMailboxConf};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::{ use melib::backends::{
BackendOp, Backends, Folder, FolderHash, MailBackend, NotifyFn, ReadOnlyOp, RefreshEvent, BackendOp, Backends, MailBackend, Mailbox, MailboxHash, NotifyFn, ReadOnlyOp, RefreshEvent,
RefreshEventConsumer, RefreshEventKind, SpecialUsageMailbox, RefreshEventConsumer, RefreshEventKind, SpecialUsageMailbox,
}; };
use melib::email::*; use melib::email::*;
@ -84,15 +84,15 @@ impl MailboxStatus {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct FolderEntry { pub struct MailboxEntry {
pub status: MailboxStatus, pub status: MailboxStatus,
pub name: String, pub name: String,
pub ref_folder: Folder, pub ref_mailbox: Mailbox,
pub conf: FileFolderConf, pub conf: FileMailboxConf,
pub worker: Worker, pub worker: Worker,
} }
impl FolderEntry { impl MailboxEntry {
pub fn status(&self) -> String { pub fn status(&self) -> String {
match self.status { match self.status {
MailboxStatus::Available => self.name().to_string(), MailboxStatus::Available => self.name().to_string(),
@ -114,10 +114,10 @@ pub struct Account {
pub index: usize, pub index: usize,
name: String, name: String,
pub is_online: bool, pub is_online: bool,
pub(crate) folder_entries: FnvHashMap<FolderHash, FolderEntry>, pub(crate) mailbox_entries: FnvHashMap<MailboxHash, MailboxEntry>,
pub(crate) folders_order: Vec<FolderHash>, pub(crate) mailboxes_order: Vec<MailboxHash>,
tree: Vec<FolderNode>, tree: Vec<MailboxNode>,
sent_folder: Option<FolderHash>, sent_mailbox: Option<MailboxHash>,
pub(crate) collection: Collection, pub(crate) collection: Collection,
pub(crate) address_book: AddressBook, pub(crate) address_book: AddressBook,
pub(crate) work_context: WorkContext, pub(crate) work_context: WorkContext,
@ -126,7 +126,7 @@ pub struct Account {
pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>, pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>,
sender: Sender<ThreadEvent>, sender: Sender<ThreadEvent>,
event_queue: VecDeque<(FolderHash, RefreshEvent)>, event_queue: VecDeque<(MailboxHash, RefreshEvent)>,
notify_fn: Arc<NotifyFn>, notify_fn: Arc<NotifyFn>,
} }
@ -177,10 +177,10 @@ impl Drop for Account {
} }
#[derive(Serialize, Debug, Clone, Default)] #[derive(Serialize, Debug, Clone, Default)]
pub struct FolderNode { pub struct MailboxNode {
pub hash: FolderHash, pub hash: MailboxHash,
pub depth: usize, pub depth: usize,
pub children: Vec<FolderNode>, pub children: Vec<MailboxNode>,
} }
impl Account { impl Account {
@ -197,11 +197,11 @@ impl Account {
let backend = map.get(settings.account().format())( let backend = map.get(settings.account().format())(
settings.account(), settings.account(),
Box::new(move |path: &str| { Box::new(move |path: &str| {
s.account.subscribed_folders.is_empty() s.account.subscribed_mailboxes.is_empty()
|| (s.folder_confs.contains_key(path) || (s.mailbox_confs.contains_key(path)
&& s.folder_confs[path].folder_conf().subscribe.is_true()) && s.mailbox_confs[path].mailbox_conf().subscribe.is_true())
|| s.account || s.account
.subscribed_folders .subscribed_mailboxes
.iter() .iter()
.any(|m| path.matches_glob(m)) .any(|m| path.matches_glob(m))
}), }),
@ -233,11 +233,11 @@ impl Account {
index, index,
name, name,
is_online: false, is_online: false,
folder_entries: Default::default(), mailbox_entries: Default::default(),
folders_order: Default::default(), mailboxes_order: Default::default(),
tree: Default::default(), tree: Default::default(),
address_book, address_book,
sent_folder: Default::default(), sent_mailbox: Default::default(),
collection: Default::default(), collection: Default::default(),
work_context, work_context,
runtime_settings: settings.clone(), runtime_settings: settings.clone(),
@ -251,22 +251,22 @@ impl Account {
} }
fn init(&mut self) { fn init(&mut self) {
let mut ref_folders: FnvHashMap<FolderHash, Folder> = let mut ref_mailboxes: FnvHashMap<MailboxHash, Mailbox> =
match self.backend.read().unwrap().folders() { match self.backend.read().unwrap().mailboxes() {
Ok(f) => f, Ok(f) => f,
Err(err) => { Err(err) => {
debug!(&err); debug!(&err);
return; return;
} }
}; };
let mut folder_entries: FnvHashMap<FolderHash, FolderEntry> = let mut mailbox_entries: FnvHashMap<MailboxHash, MailboxEntry> =
FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default()); FnvHashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
let mut folders_order: Vec<FolderHash> = Vec::with_capacity(ref_folders.len()); let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len());
let mut sent_folder = None; let mut sent_mailbox = None;
for f in ref_folders.values_mut() { for f in ref_mailboxes.values_mut() {
if let Some(conf) = self.settings.folder_confs.get_mut(f.path()) { if let Some(conf) = self.settings.mailbox_confs.get_mut(f.path()) {
conf.folder_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal { conf.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
Some(f.special_usage()) Some(f.special_usage())
} else { } else {
let tmp = SpecialUsageMailbox::detect_usage(f.name()); let tmp = SpecialUsageMailbox::detect_usage(f.name());
@ -275,21 +275,21 @@ impl Account {
} }
tmp tmp
}; };
match conf.folder_conf.usage { match conf.mailbox_conf.usage {
Some(SpecialUsageMailbox::Sent) => { Some(SpecialUsageMailbox::Sent) => {
sent_folder = Some(f.hash()); sent_mailbox = Some(f.hash());
} }
None => { None => {
if f.special_usage() == SpecialUsageMailbox::Sent { if f.special_usage() == SpecialUsageMailbox::Sent {
sent_folder = Some(f.hash()); sent_mailbox = Some(f.hash());
} }
} }
_ => {} _ => {}
} }
folder_entries.insert( mailbox_entries.insert(
f.hash(), f.hash(),
FolderEntry { MailboxEntry {
ref_folder: f.clone(), ref_mailbox: f.clone(),
name: f.path().to_string(), name: f.path().to_string(),
status: MailboxStatus::None, status: MailboxStatus::None,
conf: conf.clone(), conf: conf.clone(),
@ -297,8 +297,8 @@ impl Account {
}, },
); );
} else { } else {
let mut new = FileFolderConf::default(); let mut new = FileMailboxConf::default();
new.folder_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal { new.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
Some(f.special_usage()) Some(f.special_usage())
} else { } else {
let tmp = SpecialUsageMailbox::detect_usage(f.name()); let tmp = SpecialUsageMailbox::detect_usage(f.name());
@ -307,14 +307,14 @@ impl Account {
} }
tmp tmp
}; };
if new.folder_conf.usage == Some(SpecialUsageMailbox::Sent) { if new.mailbox_conf.usage == Some(SpecialUsageMailbox::Sent) {
sent_folder = Some(f.hash()); sent_mailbox = Some(f.hash());
} }
folder_entries.insert( mailbox_entries.insert(
f.hash(), f.hash(),
FolderEntry { MailboxEntry {
ref_folder: f.clone(), ref_mailbox: f.clone(),
name: f.path().to_string(), name: f.path().to_string(),
status: MailboxStatus::None, status: MailboxStatus::None,
conf: new, conf: new,
@ -324,14 +324,14 @@ impl Account {
} }
} }
let mut tree: Vec<FolderNode> = Vec::new(); let mut tree: Vec<MailboxNode> = Vec::new();
let mut collection: Collection = Collection::new(Default::default()); let mut collection: Collection = Collection::new(Default::default());
for (h, f) in ref_folders.iter() { for (h, f) in ref_mailboxes.iter() {
if !f.is_subscribed() { if !f.is_subscribed() {
/* Skip unsubscribed folder */ /* Skip unsubscribed mailbox */
continue; continue;
} }
folder_entries.entry(*h).and_modify(|entry| { mailbox_entries.entry(*h).and_modify(|entry| {
entry.status = MailboxStatus::Parsing(0, 0); entry.status = MailboxStatus::Parsing(0, 0);
entry.worker = Account::new_worker( entry.worker = Account::new_worker(
f.clone(), f.clone(),
@ -344,32 +344,32 @@ impl Account {
collection.threads.insert(*h, Threads::default()); collection.threads.insert(*h, Threads::default());
} }
build_folders_order(&mut tree, &folder_entries, &mut folders_order); build_mailboxes_order(&mut tree, &mailbox_entries, &mut mailboxes_order);
self.folders_order = folders_order; self.mailboxes_order = mailboxes_order;
self.folder_entries = folder_entries; self.mailbox_entries = mailbox_entries;
self.tree = tree; self.tree = tree;
self.sent_folder = sent_folder; self.sent_mailbox = sent_mailbox;
self.collection = collection; self.collection = collection;
} }
fn new_worker( fn new_worker(
folder: Folder, mailbox: Mailbox,
backend: &Arc<RwLock<Box<dyn MailBackend>>>, backend: &Arc<RwLock<Box<dyn MailBackend>>>,
work_context: &WorkContext, work_context: &WorkContext,
notify_fn: Arc<NotifyFn>, notify_fn: Arc<NotifyFn>,
) -> Worker { ) -> Worker {
let mut mailbox_handle = backend.write().unwrap().get(&folder); let mut mailbox_handle = backend.write().unwrap().get(&mailbox);
let mut builder = AsyncBuilder::new(); let mut builder = AsyncBuilder::new();
let our_tx = builder.tx(); let our_tx = builder.tx();
let folder_hash = folder.hash(); let mailbox_hash = mailbox.hash();
let priority = match folder.special_usage() { let priority = match mailbox.special_usage() {
SpecialUsageMailbox::Inbox => 0, SpecialUsageMailbox::Inbox => 0,
SpecialUsageMailbox::Sent => 1, SpecialUsageMailbox::Sent => 1,
SpecialUsageMailbox::Drafts | SpecialUsageMailbox::Trash => 2, SpecialUsageMailbox::Drafts | SpecialUsageMailbox::Trash => 2,
_ => { _ => {
3 * folder 3 * mailbox
.path() .path()
.split(if folder.path().contains('/') { .split(if mailbox.path().contains('/') {
'/' '/'
} else { } else {
'.' '.'
@ -385,7 +385,7 @@ impl Account {
*/ */
builder.set_priority(priority).set_is_static(true); builder.set_priority(priority).set_is_static(true);
let mut w = builder.build(Box::new(move |work_context| { let mut w = builder.build(Box::new(move |work_context| {
let name = format!("Parsing {}", folder.path()); let name = format!("Parsing {}", mailbox.path());
let work = mailbox_handle.work().unwrap(); let work = mailbox_handle.work().unwrap();
work_context.new_work.send(work).unwrap(); work_context.new_work.send(work).unwrap();
let thread_id = std::thread::current().id(); let thread_id = std::thread::current().id();
@ -399,12 +399,12 @@ impl Account {
match debug!(mailbox_handle.poll_block()) { match debug!(mailbox_handle.poll_block()) {
Ok(s @ AsyncStatus::Payload(_)) => { Ok(s @ AsyncStatus::Payload(_)) => {
our_tx.send(s).unwrap(); our_tx.send(s).unwrap();
debug!("notifying for {}", folder_hash); debug!("notifying for {}", mailbox_hash);
notify_fn.notify(folder_hash); notify_fn.notify(mailbox_hash);
} }
Ok(s @ AsyncStatus::Finished) => { Ok(s @ AsyncStatus::Finished) => {
our_tx.send(s).unwrap(); our_tx.send(s).unwrap();
notify_fn.notify(folder_hash); notify_fn.notify(mailbox_hash);
debug!("exiting"); debug!("exiting");
work_context.finished.send(thread_id).unwrap(); work_context.finished.send(thread_id).unwrap();
return; return;
@ -424,15 +424,15 @@ impl Account {
} }
Some(w) Some(w)
} }
pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> { pub fn reload(&mut self, event: RefreshEvent, mailbox_hash: MailboxHash) -> Option<UIEvent> {
if !self.folder_entries[&folder_hash].status.is_available() { if !self.mailbox_entries[&mailbox_hash].status.is_available() {
self.event_queue.push_back((folder_hash, event)); self.event_queue.push_back((mailbox_hash, event));
return None; return None;
} }
let kind = event.kind(); let kind = event.kind();
{ {
//let mailbox: &mut Mailbox = self.folders[idx].as_mut().unwrap().as_mut().unwrap(); //let mailbox: &mut Mailbox = self.mailboxes[idx].as_mut().unwrap().as_mut().unwrap();
match kind { match kind {
RefreshEventKind::Update(old_hash, envelope) => { RefreshEventKind::Update(old_hash, envelope) => {
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
@ -450,12 +450,12 @@ impl Account {
); );
} }
} }
self.collection.update(old_hash, *envelope, folder_hash); self.collection.update(old_hash, *envelope, mailbox_hash);
return Some(EnvelopeUpdate(old_hash)); return Some(EnvelopeUpdate(old_hash));
} }
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);
self.collection.rename(old_hash, new_hash, folder_hash); self.collection.rename(old_hash, new_hash, mailbox_hash);
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
{ {
let envelopes = self.collection.envelopes.read(); let envelopes = self.collection.envelopes.read();
@ -478,7 +478,7 @@ impl Account {
RefreshEventKind::Create(envelope) => { RefreshEventKind::Create(envelope) => {
let env_hash = envelope.hash(); let env_hash = envelope.hash();
if self.collection.contains_key(&env_hash) if self.collection.contains_key(&env_hash)
&& self.collection[&folder_hash].contains(&env_hash) && self.collection[&mailbox_hash].contains(&env_hash)
{ {
return None; return None;
} }
@ -505,38 +505,30 @@ impl Account {
); );
} }
} }
self.collection.insert(*envelope, folder_hash); self.collection.insert(*envelope, mailbox_hash);
if self
.sent_folder
.as_ref()
.map(|h| *h == folder_hash)
.unwrap_or(false)
{
self.collection.insert_reply(env_hash);
}
if self.folder_entries[&folder_hash] if self.mailbox_entries[&mailbox_hash]
.conf .conf
.folder_conf .mailbox_conf
.ignore .ignore
.is_true() .is_true()
{ {
return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
} }
let thread = { let thread = {
let thread_hash = self.collection.get_env(env_hash).thread(); let thread_hash = self.collection.get_env(env_hash).thread();
self.collection.threads[&folder_hash] self.collection.threads[&mailbox_hash]
.find_group(self.collection.threads[&folder_hash][&thread_hash].group) .find_group(self.collection.threads[&mailbox_hash][&thread_hash].group)
}; };
if self.collection.threads[&folder_hash] if self.collection.threads[&mailbox_hash]
.thread_ref(thread) .thread_ref(thread)
.snoozed() .snoozed()
{ {
return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
} }
if is_seen || is_draft { if is_seen || is_draft {
return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash)));
} }
return Some(Notification( return Some(Notification(
@ -545,7 +537,7 @@ impl Account {
"{}\n{} {}", "{}\n{} {}",
subject, subject,
self.name, self.name,
self.folder_entries[&folder_hash].name() self.mailbox_entries[&mailbox_hash].name()
), ),
Some(crate::types::NotificationType::NewMail), Some(crate::types::NotificationType::NewMail),
)); ));
@ -567,19 +559,21 @@ impl Account {
); );
} }
} }
self.collection.remove(envelope_hash, folder_hash); self.collection.remove(envelope_hash, mailbox_hash);
return Some(EnvelopeRemove(envelope_hash)); return Some(EnvelopeRemove(envelope_hash));
} }
RefreshEventKind::Rescan => { RefreshEventKind::Rescan => {
let handle = Account::new_worker( let handle = Account::new_worker(
self.folder_entries[&folder_hash].ref_folder.clone(), self.mailbox_entries[&mailbox_hash].ref_mailbox.clone(),
&mut self.backend, &mut self.backend,
&self.work_context, &self.work_context,
self.notify_fn.clone(), self.notify_fn.clone(),
); );
self.folder_entries.entry(folder_hash).and_modify(|entry| { self.mailbox_entries
entry.worker = handle; .entry(mailbox_hash)
}); .and_modify(|entry| {
entry.worker = handle;
});
} }
RefreshEventKind::Failure(e) => { RefreshEventKind::Failure(e) => {
debug!("RefreshEvent Failure: {}", e.to_string()); debug!("RefreshEvent Failure: {}", e.to_string());
@ -599,7 +593,7 @@ impl Account {
} }
None None
} }
pub fn refresh(&mut self, folder_hash: FolderHash) -> Result<()> { pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> {
if let Some(ref refresh_command) = self.settings.conf().refresh_command { if let Some(ref refresh_command) = self.settings.conf().refresh_command {
let parts = crate::split_command!(refresh_command); let parts = crate::split_command!(refresh_command);
let (cmd, args) = (parts[0], &parts[1..]); let (cmd, args) = (parts[0], &parts[1..]);
@ -616,7 +610,7 @@ impl Account {
let r = RefreshEventConsumer::new(Box::new(move |r| { let r = RefreshEventConsumer::new(Box::new(move |r| {
sender_.send(ThreadEvent::from(r)).unwrap(); sender_.send(ThreadEvent::from(r)).unwrap();
})); }));
let mut h = self.backend.write().unwrap().refresh(folder_hash, r)?; let mut h = self.backend.write().unwrap().refresh(mailbox_hash, r)?;
self.work_context.new_work.send(h.work().unwrap()).unwrap(); self.work_context.new_work.send(h.work().unwrap()).unwrap();
Ok(()) Ok(())
} }
@ -661,9 +655,9 @@ impl Account {
self.tree.is_empty() self.tree.is_empty()
} }
pub fn list_folders(&self) -> Vec<FolderNode> { pub fn list_mailboxes(&self) -> Vec<MailboxNode> {
let mut ret = Vec::with_capacity(self.folder_entries.len()); let mut ret = Vec::with_capacity(self.mailbox_entries.len());
fn rec(node: &FolderNode, ret: &mut Vec<FolderNode>) { fn rec(node: &MailboxNode, ret: &mut Vec<MailboxNode>) {
ret.push(node.clone()); ret.push(node.clone());
for c in node.children.iter() { for c in node.children.iter() {
rec(c, ret); rec(c, ret);
@ -675,20 +669,22 @@ impl Account {
ret ret
} }
pub fn folders_order(&self) -> &Vec<FolderHash> { pub fn mailboxes_order(&self) -> &Vec<MailboxHash> {
&self.folders_order &self.mailboxes_order
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
fn load_mailbox(&mut self, folder_hash: FolderHash, payload: Result<Vec<Envelope>>) { fn load_mailbox(&mut self, mailbox_hash: MailboxHash, payload: Result<Vec<Envelope>>) {
if payload.is_err() { if payload.is_err() {
self.folder_entries.entry(folder_hash).and_modify(|entry| { self.mailbox_entries
entry.status = MailboxStatus::Failed(payload.unwrap_err()); .entry(mailbox_hash)
}); .and_modify(|entry| {
entry.status = MailboxStatus::Failed(payload.unwrap_err());
});
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(folder_hash))) .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(mailbox_hash)))
.unwrap(); .unwrap();
return; return;
} }
@ -697,37 +693,37 @@ impl Account {
.into_iter() .into_iter()
.map(|e| (e.hash(), e)) .map(|e| (e.hash(), e))
.collect::<FnvHashMap<EnvelopeHash, Envelope>>(); .collect::<FnvHashMap<EnvelopeHash, Envelope>>();
if let Some(updated_folders) = if let Some(updated_mailboxes) =
self.collection self.collection
.merge(envelopes, folder_hash, self.sent_folder) .merge(envelopes, mailbox_hash, self.sent_mailbox)
{ {
for f in updated_folders { for f in updated_mailboxes {
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f))) .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f)))
.unwrap(); .unwrap();
} }
} }
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(folder_hash))) .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(mailbox_hash)))
.unwrap(); .unwrap();
} }
pub fn status(&mut self, folder_hash: FolderHash) -> result::Result<(), usize> { pub fn status(&mut self, mailbox_hash: MailboxHash) -> result::Result<(), usize> {
if folder_hash == 0 { if mailbox_hash == 0 {
return Err(0); return Err(0);
} }
loop { loop {
match self match self
.folder_entries .mailbox_entries
.get_mut(&folder_hash) .get_mut(&mailbox_hash)
.unwrap() .unwrap()
.worker .worker
.as_mut() .as_mut()
{ {
None => { None => {
return if self.folder_entries[&folder_hash].status.is_available() return if self.mailbox_entries[&mailbox_hash].status.is_available()
|| (self.folder_entries[&folder_hash].status.is_parsing() || (self.mailbox_entries[&mailbox_hash].status.is_parsing()
&& self.collection.mailboxes.contains_key(&folder_hash)) && self.collection.mailboxes.contains_key(&mailbox_hash))
{ {
Ok(()) Ok(())
} else { } else {
@ -739,31 +735,33 @@ impl Account {
break; break;
} }
Ok(AsyncStatus::Payload(envs)) => { Ok(AsyncStatus::Payload(envs)) => {
debug!("got payload in status for {}", folder_hash); debug!("got payload in status for {}", mailbox_hash);
self.load_mailbox(folder_hash, envs); self.load_mailbox(mailbox_hash, envs);
} }
Ok(AsyncStatus::Finished) => { Ok(AsyncStatus::Finished) => {
debug!("got finished in status for {}", folder_hash); debug!("got finished in status for {}", mailbox_hash);
self.folder_entries.entry(folder_hash).and_modify(|entry| { self.mailbox_entries
entry.status = MailboxStatus::Available; .entry(mailbox_hash)
entry.worker = None; .and_modify(|entry| {
}); entry.status = MailboxStatus::Available;
entry.worker = None;
});
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
self.index, self.index,
folder_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
} }
Ok(AsyncStatus::ProgressReport(n)) => { Ok(AsyncStatus::ProgressReport(n)) => {
self.folder_entries.entry(folder_hash).and_modify(|entry| { self.mailbox_entries
match entry.status { .entry(mailbox_hash)
.and_modify(|entry| match entry.status {
MailboxStatus::Parsing(ref mut d, _) => { MailboxStatus::Parsing(ref mut d, _) => {
*d += n; *d += n;
} }
_ => {} _ => {}
} });
});
//return Err(n); //return Err(n);
} }
_ => { _ => {
@ -772,9 +770,9 @@ impl Account {
}, },
}; };
} }
if self.folder_entries[&folder_hash].status.is_available() if self.mailbox_entries[&mailbox_hash].status.is_available()
|| (self.folder_entries[&folder_hash].status.is_parsing() || (self.mailbox_entries[&mailbox_hash].status.is_parsing()
&& self.collection.mailboxes.contains_key(&folder_hash)) && self.collection.mailboxes.contains_key(&mailbox_hash))
{ {
Ok(()) Ok(())
} else { } else {
@ -785,23 +783,27 @@ impl Account {
pub fn save_special( pub fn save_special(
&self, &self,
bytes: &[u8], bytes: &[u8],
folder_type: SpecialUsageMailbox, mailbox_type: SpecialUsageMailbox,
flags: Flag, flags: Flag,
) -> Result<()> { ) -> Result<()> {
let mut failure = true; let mut failure = true;
for folder in &[ for mailbox in &[
self.special_use_folder(folder_type), self.special_use_mailbox(mailbox_type),
self.special_use_folder(SpecialUsageMailbox::Inbox), self.special_use_mailbox(SpecialUsageMailbox::Inbox),
self.special_use_folder(SpecialUsageMailbox::Normal), self.special_use_mailbox(SpecialUsageMailbox::Normal),
] { ] {
if folder.is_none() { if mailbox.is_none() {
continue; continue;
} }
let folder = folder.unwrap(); let mailbox = mailbox.unwrap();
if let Err(e) = self.save(bytes, folder, Some(flags)) { if let Err(e) = self.save(bytes, mailbox, Some(flags)) {
debug!("{:?} could not save msg", e); debug!("{:?} could not save msg", e);
melib::log( melib::log(
format!("Could not save in '{}' folder: {}.", folder, e.to_string()), format!(
"Could not save in '{}' mailbox: {}.",
mailbox,
e.to_string()
),
melib::ERROR, melib::ERROR,
); );
} else { } else {
@ -824,19 +826,19 @@ impl Account {
"Message was stored in {} so that you can restore it manually.", "Message was stored in {} so that you can restore it manually.",
file.path.display() file.path.display()
)) ))
.set_summary("Could not save in any folder")); .set_summary("Could not save in any mailbox"));
} }
Ok(()) Ok(())
} }
pub fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> { pub fn save(&self, bytes: &[u8], mailbox: &str, flags: Option<Flag>) -> Result<()> {
if self.settings.account.read_only() { if self.settings.account.read_only() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Account {} is read-only.", "Account {} is read-only.",
self.name.as_str() self.name.as_str()
))); )));
} }
self.backend.write().unwrap().save(bytes, folder, flags) self.backend.write().unwrap().save(bytes, mailbox, flags)
} }
pub fn contains_key(&self, h: EnvelopeHash) -> bool { pub fn contains_key(&self, h: EnvelopeHash) -> bool {
@ -851,127 +853,132 @@ impl Account {
} }
} }
pub fn thread(&self, h: ThreadNodeHash, f: FolderHash) -> &ThreadNode { pub fn thread(&self, h: ThreadNodeHash, f: MailboxHash) -> &ThreadNode {
&self.collection.threads[&f].thread_nodes()[&h] &self.collection.threads[&f].thread_nodes()[&h]
} }
pub fn folder_operation( pub fn mailbox_operation(
&mut self, &mut self,
op: crate::execute::actions::FolderOperation, op: crate::execute::actions::MailboxOperation,
) -> Result<String> { ) -> Result<String> {
use crate::execute::actions::FolderOperation; use crate::execute::actions::MailboxOperation;
if self.settings.account.read_only() { if self.settings.account.read_only() {
return Err(MeliError::new("Account is read-only.")); return Err(MeliError::new("Account is read-only."));
} }
match op { match op {
FolderOperation::Create(path) => { MailboxOperation::Create(path) => {
let (folder_hash, mut folders) = self let (mailbox_hash, mut mailboxes) = self
.backend .backend
.write() .write()
.unwrap() .unwrap()
.create_folder(path.to_string())?; .create_mailbox(path.to_string())?;
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxCreate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxCreate((
self.index, self.index,
folder_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
let mut new = FileFolderConf::default(); let mut new = FileMailboxConf::default();
new.folder_conf.subscribe = super::ToggleFlag::InternalVal(true); new.mailbox_conf.subscribe = super::ToggleFlag::InternalVal(true);
new.folder_conf.usage = new.mailbox_conf.usage = if mailboxes[&mailbox_hash].special_usage()
if folders[&folder_hash].special_usage() != SpecialUsageMailbox::Normal { != SpecialUsageMailbox::Normal
Some(folders[&folder_hash].special_usage()) {
} else { Some(mailboxes[&mailbox_hash].special_usage())
let tmp = SpecialUsageMailbox::detect_usage(folders[&folder_hash].name()); } else {
if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None { let tmp = SpecialUsageMailbox::detect_usage(mailboxes[&mailbox_hash].name());
folders.entry(folder_hash).and_modify(|entry| { if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
let _ = entry.set_special_usage(tmp.unwrap()); mailboxes.entry(mailbox_hash).and_modify(|entry| {
}); let _ = entry.set_special_usage(tmp.unwrap());
} });
tmp }
}; tmp
/* if new folder has parent, we need to update its children field */ };
if let Some(parent_hash) = folders[&folder_hash].parent() { /* if new mailbox has parent, we need to update its children field */
self.folder_entries.entry(parent_hash).and_modify(|parent| { if let Some(parent_hash) = mailboxes[&mailbox_hash].parent() {
parent.ref_folder = folders.remove(&parent_hash).unwrap(); self.mailbox_entries
}); .entry(parent_hash)
.and_modify(|parent| {
parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap();
});
} }
self.folder_entries.insert( self.mailbox_entries.insert(
folder_hash, mailbox_hash,
FolderEntry { MailboxEntry {
name: folders[&folder_hash].path().to_string(), name: mailboxes[&mailbox_hash].path().to_string(),
status: MailboxStatus::Parsing(0, 0), status: MailboxStatus::Parsing(0, 0),
conf: new, conf: new,
worker: Account::new_worker( worker: Account::new_worker(
folders[&folder_hash].clone(), mailboxes[&mailbox_hash].clone(),
&mut self.backend, &mut self.backend,
&self.work_context, &self.work_context,
self.notify_fn.clone(), self.notify_fn.clone(),
), ),
ref_folder: folders.remove(&folder_hash).unwrap(), ref_mailbox: mailboxes.remove(&mailbox_hash).unwrap(),
}, },
); );
self.collection self.collection
.threads .threads
.insert(folder_hash, Threads::default()); .insert(mailbox_hash, Threads::default());
self.collection self.collection
.mailboxes .mailboxes
.insert(folder_hash, Default::default()); .insert(mailbox_hash, Default::default());
build_folders_order( build_mailboxes_order(
&mut self.tree, &mut self.tree,
&self.folder_entries, &self.mailbox_entries,
&mut self.folders_order, &mut self.mailboxes_order,
); );
Ok(format!("`{}` successfully created.", &path)) Ok(format!("`{}` successfully created.", &path))
} }
FolderOperation::Delete(path) => { MailboxOperation::Delete(path) => {
if self.folder_entries.len() == 1 { if self.mailbox_entries.len() == 1 {
return Err(MeliError::new("Cannot delete only mailbox.")); return Err(MeliError::new("Cannot delete only mailbox."));
} }
let folder_hash = if let Some((folder_hash, _)) = self let mailbox_hash = if let Some((mailbox_hash, _)) = self
.folder_entries .mailbox_entries
.iter() .iter()
.find(|(_, f)| f.ref_folder.path() == path) .find(|(_, f)| f.ref_mailbox.path() == path)
{ {
*folder_hash *mailbox_hash
} else { } else {
return Err(MeliError::new("Mailbox with that path not found.")); return Err(MeliError::new("Mailbox with that path not found."));
}; };
let mut folders = self.backend.write().unwrap().delete_folder(folder_hash)?; let mut mailboxes = self.backend.write().unwrap().delete_mailbox(mailbox_hash)?;
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete((
self.index, self.index,
folder_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
if let Some(pos) = self.folders_order.iter().position(|&h| h == folder_hash) { if let Some(pos) = self.mailboxes_order.iter().position(|&h| h == mailbox_hash) {
self.folders_order.remove(pos); self.mailboxes_order.remove(pos);
} }
if let Some(pos) = self.tree.iter().position(|n| n.hash == folder_hash) { if let Some(pos) = self.tree.iter().position(|n| n.hash == mailbox_hash) {
self.tree.remove(pos); self.tree.remove(pos);
} }
if self.sent_folder == Some(folder_hash) { if self.sent_mailbox == Some(mailbox_hash) {
self.sent_folder = None; self.sent_mailbox = None;
} }
self.collection.threads.remove(&folder_hash); self.collection.threads.remove(&mailbox_hash);
/* if deleted folder had parent, we need to update its children field */ /* if deleted mailbox had parent, we need to update its children field */
if let Some(parent_hash) = self if let Some(parent_hash) = self
.folder_entries .mailbox_entries
.remove(&folder_hash) .remove(&mailbox_hash)
.unwrap() .unwrap()
.ref_folder .ref_mailbox
.parent() .parent()
{ {
self.folder_entries.entry(parent_hash).and_modify(|parent| { self.mailbox_entries
parent.ref_folder = folders.remove(&parent_hash).unwrap(); .entry(parent_hash)
}); .and_modify(|parent| {
parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap();
});
} }
self.collection.mailboxes.remove(&folder_hash); self.collection.mailboxes.remove(&mailbox_hash);
build_folders_order( build_mailboxes_order(
&mut self.tree, &mut self.tree,
&self.folder_entries, &self.mailbox_entries,
&mut self.folders_order, &mut self.mailboxes_order,
); );
// FIXME Kill worker as well // FIXME Kill worker as well
@ -979,18 +986,18 @@ impl Account {
Ok(format!("'`{}` has been deleted.", &path)) Ok(format!("'`{}` has been deleted.", &path))
} }
FolderOperation::Subscribe(_) => Err(MeliError::new("Not implemented.")), MailboxOperation::Subscribe(_) => Err(MeliError::new("Not implemented.")),
FolderOperation::Unsubscribe(_) => Err(MeliError::new("Not implemented.")), MailboxOperation::Unsubscribe(_) => Err(MeliError::new("Not implemented.")),
FolderOperation::Rename(_, _) => Err(MeliError::new("Not implemented.")), MailboxOperation::Rename(_, _) => Err(MeliError::new("Not implemented.")),
FolderOperation::SetPermissions(_) => Err(MeliError::new("Not implemented.")), MailboxOperation::SetPermissions(_) => Err(MeliError::new("Not implemented.")),
} }
} }
pub fn special_use_folder(&self, special_use: SpecialUsageMailbox) -> Option<&str> { pub fn special_use_mailbox(&self, special_use: SpecialUsageMailbox) -> Option<&str> {
let ret = self let ret = self
.folder_entries .mailbox_entries
.iter() .iter()
.find(|(_, f)| f.conf.folder_conf().usage == Some(special_use)); .find(|(_, f)| f.conf.mailbox_conf().usage == Some(special_use));
if let Some(ret) = ret.as_ref() { if let Some(ret) = ret.as_ref() {
Some(ret.1.name()) Some(ret.1.name())
} else { } else {
@ -1017,10 +1024,10 @@ impl Account {
&self, &self,
search_term: &str, search_term: &str,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
folder_hash: FolderHash, mailbox_hash: MailboxHash,
) -> Result<SmallVec<[EnvelopeHash; 512]>> { ) -> Result<SmallVec<[EnvelopeHash; 512]>> {
if self.settings.account().format() == "imap" { if self.settings.account().format() == "imap" {
return crate::cache::imap_search(search_term, sort, folder_hash, &self.backend); return crate::cache::imap_search(search_term, sort, mailbox_hash, &self.backend);
} }
#[cfg(feature = "notmuch")] #[cfg(feature = "notmuch")]
@ -1049,7 +1056,7 @@ impl Account {
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
let envelopes = self.collection.envelopes.read().unwrap(); let envelopes = self.collection.envelopes.read().unwrap();
for &env_hash in &self.collection[&folder_hash].iter() { for &env_hash in &self.collection[&mailbox_hash].iter() {
let envelope = &envelopes[&env_hash]; let envelope = &envelopes[&env_hash];
if envelope.subject().contains(&search_term) { if envelope.subject().contains(&search_term) {
ret.push(env_hash); ret.push(env_hash);
@ -1072,97 +1079,97 @@ impl Account {
} }
} }
impl Index<&FolderHash> for Account { impl Index<&MailboxHash> for Account {
type Output = FolderEntry; type Output = MailboxEntry;
fn index(&self, index: &FolderHash) -> &FolderEntry { fn index(&self, index: &MailboxHash) -> &MailboxEntry {
&self.folder_entries[index] &self.mailbox_entries[index]
} }
} }
impl IndexMut<&FolderHash> for Account { impl IndexMut<&MailboxHash> for Account {
fn index_mut(&mut self, index: &FolderHash) -> &mut FolderEntry { fn index_mut(&mut self, index: &MailboxHash) -> &mut MailboxEntry {
self.folder_entries.get_mut(index).unwrap() self.mailbox_entries.get_mut(index).unwrap()
} }
} }
fn build_folders_order( fn build_mailboxes_order(
tree: &mut Vec<FolderNode>, tree: &mut Vec<MailboxNode>,
folder_entries: &FnvHashMap<FolderHash, FolderEntry>, mailbox_entries: &FnvHashMap<MailboxHash, MailboxEntry>,
folders_order: &mut Vec<FolderHash>, mailboxes_order: &mut Vec<MailboxHash>,
) { ) {
tree.clear(); tree.clear();
folders_order.clear(); mailboxes_order.clear();
for (h, f) in folder_entries.iter() { for (h, f) in mailbox_entries.iter() {
if f.ref_folder.parent().is_none() { if f.ref_mailbox.parent().is_none() {
fn rec( fn rec(
h: FolderHash, h: MailboxHash,
folder_entries: &FnvHashMap<FolderHash, FolderEntry>, mailbox_entries: &FnvHashMap<MailboxHash, MailboxEntry>,
depth: usize, depth: usize,
) -> FolderNode { ) -> MailboxNode {
let mut node = FolderNode { let mut node = MailboxNode {
hash: h, hash: h,
children: Vec::new(), children: Vec::new(),
depth, depth,
}; };
for &c in folder_entries[&h].ref_folder.children() { for &c in mailbox_entries[&h].ref_mailbox.children() {
if folder_entries.contains_key(&c) { if mailbox_entries.contains_key(&c) {
node.children.push(rec(c, folder_entries, depth + 1)); node.children.push(rec(c, mailbox_entries, depth + 1));
} }
} }
node node
}; };
tree.push(rec(*h, &folder_entries, 0)); tree.push(rec(*h, &mailbox_entries, 0));
} }
} }
tree.sort_unstable_by(|a, b| { tree.sort_unstable_by(|a, b| {
if folder_entries[&b.hash] if mailbox_entries[&b.hash]
.ref_folder .ref_mailbox
.path() .path()
.eq_ignore_ascii_case("INBOX") .eq_ignore_ascii_case("INBOX")
{ {
std::cmp::Ordering::Greater std::cmp::Ordering::Greater
} else if folder_entries[&a.hash] } else if mailbox_entries[&a.hash]
.ref_folder .ref_mailbox
.path() .path()
.eq_ignore_ascii_case("INBOX") .eq_ignore_ascii_case("INBOX")
{ {
std::cmp::Ordering::Less std::cmp::Ordering::Less
} else { } else {
folder_entries[&a.hash] mailbox_entries[&a.hash]
.ref_folder .ref_mailbox
.path() .path()
.cmp(&folder_entries[&b.hash].ref_folder.path()) .cmp(&mailbox_entries[&b.hash].ref_mailbox.path())
} }
}); });
let mut stack: SmallVec<[Option<&FolderNode>; 16]> = SmallVec::new(); let mut stack: SmallVec<[Option<&MailboxNode>; 16]> = SmallVec::new();
for n in tree.iter_mut() { for n in tree.iter_mut() {
folders_order.push(n.hash); mailboxes_order.push(n.hash);
n.children.sort_unstable_by(|a, b| { n.children.sort_unstable_by(|a, b| {
if folder_entries[&b.hash] if mailbox_entries[&b.hash]
.ref_folder .ref_mailbox
.path() .path()
.eq_ignore_ascii_case("INBOX") .eq_ignore_ascii_case("INBOX")
{ {
std::cmp::Ordering::Greater std::cmp::Ordering::Greater
} else if folder_entries[&a.hash] } else if mailbox_entries[&a.hash]
.ref_folder .ref_mailbox
.path() .path()
.eq_ignore_ascii_case("INBOX") .eq_ignore_ascii_case("INBOX")
{ {
std::cmp::Ordering::Less std::cmp::Ordering::Less
} else { } else {
folder_entries[&a.hash] mailbox_entries[&a.hash]
.ref_folder .ref_mailbox
.path() .path()
.cmp(&folder_entries[&b.hash].ref_folder.path()) .cmp(&mailbox_entries[&b.hash].ref_mailbox.path())
} }
}); });
stack.extend(n.children.iter().rev().map(Some)); stack.extend(n.children.iter().rev().map(Some));
while let Some(Some(next)) = stack.pop() { while let Some(Some(next)) = stack.pop() {
folders_order.push(next.hash); mailboxes_order.push(next.hash);
stack.extend(next.children.iter().rev().map(Some)); stack.extend(next.children.iter().rev().map(Some));
} }
} }

View File

@ -109,13 +109,13 @@ shortcut_key_values! { "listing",
scroll_down |> "Scroll down list." |> Key::Down, scroll_down |> "Scroll down list." |> Key::Down,
new_mail |> "Start new mail draft in new tab." |> Key::Char('m'), new_mail |> "Start new mail draft in new tab." |> Key::Char('m'),
next_account |> "Go to next account." |> Key::Char('h'), next_account |> "Go to next account." |> Key::Char('h'),
next_folder |> "Go to next folder." |> Key::Char('J'), next_mailbox |> "Go to next mailbox." |> Key::Char('J'),
next_page |> "Go to next page." |> Key::PageDown, next_page |> "Go to next page." |> Key::PageDown,
prev_account |> "Go to previous account." |> Key::Char('l'), prev_account |> "Go to previous account." |> Key::Char('l'),
prev_folder |> "Go to previous folder." |> Key::Char('K'), prev_mailbox |> "Go to previous mailbox." |> Key::Char('K'),
prev_page |> "Go to previous page." |> Key::PageUp, prev_page |> "Go to previous page." |> Key::PageUp,
search |> "Search within list of e-mails." |> Key::Char('/'), search |> "Search within list of e-mails." |> Key::Char('/'),
refresh |> "Manually request a folder refresh." |> Key::F(5), refresh |> "Manually request a mailbox refresh." |> Key::F(5),
set_seen |> "Set thread as seen." |> Key::Char('n'), set_seen |> "Set thread as seen." |> Key::Char('n'),
toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`') toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`')
} }

View File

@ -25,7 +25,7 @@ pub use melib::thread::{SortField, SortOrder};
use nom::{digit, not_line_ending, IResult}; use nom::{digit, not_line_ending, IResult};
use std; use std;
pub mod actions; pub mod actions;
use actions::FolderOperation; use actions::MailboxOperation;
pub mod history; pub mod history;
pub use crate::actions::AccountAction::{self, *}; pub use crate::actions::AccountAction::{self, *};
pub use crate::actions::Action::{self, *}; pub use crate::actions::Action::{self, *};
@ -247,74 +247,74 @@ define_commands!([
); );
) )
}, },
{ tags: ["create-folder "], { tags: ["create-mailbox "],
desc: "create-folder ACCOUNT FOLDER_PATH", desc: "create-mailbox ACCOUNT MAILBOX_PATH",
parser:( parser:(
named!( create_folder<Action>, named!( create_mailbox<Action>,
do_parse!( do_parse!(
ws!(tag!("create-folder")) ws!(tag!("create-mailbox"))
>> account: quoted_argument >> account: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> path: quoted_argument >> path: quoted_argument
>> (Folder(account.to_string(), FolderOperation::Create(path.to_string()))) >> (Mailbox(account.to_string(), MailboxOperation::Create(path.to_string())))
) )
); );
) )
}, },
{ tags: ["subscribe-folder "], { tags: ["subscribe-mailbox "],
desc: "subscribe-folder ACCOUNT FOLDER_PATH", desc: "subscribe-mailbox ACCOUNT MAILBOX_PATH",
parser:( parser:(
named!( sub_folder<Action>, named!( sub_mailbox<Action>,
do_parse!( do_parse!(
ws!(tag!("subscribe-folder")) ws!(tag!("subscribe-mailbox"))
>> account: quoted_argument >> account: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> path: quoted_argument >> path: quoted_argument
>> (Folder(account.to_string(), FolderOperation::Subscribe(path.to_string()))) >> (Mailbox(account.to_string(), MailboxOperation::Subscribe(path.to_string())))
) )
); );
) )
}, },
{ tags: ["unsubscribe-folder "], { tags: ["unsubscribe-mailbox "],
desc: "unsubscribe-folder ACCOUNT FOLDER_PATH", desc: "unsubscribe-mailbox ACCOUNT MAILBOX_PATH",
parser:( parser:(
named!( unsub_folder<Action>, named!( unsub_mailbox<Action>,
do_parse!( do_parse!(
ws!(tag!("unsubscribe-folder")) ws!(tag!("unsubscribe-mailbox"))
>> account: quoted_argument >> account: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> path: quoted_argument >> path: quoted_argument
>> (Folder(account.to_string(), FolderOperation::Unsubscribe(path.to_string()))) >> (Mailbox(account.to_string(), MailboxOperation::Unsubscribe(path.to_string())))
) )
); );
) )
}, },
{ tags: ["rename-folder "], { tags: ["rename-mailbox "],
desc: "rename-folder ACCOUNT FOLDER_PATH_SRC FOLDER_PATH_DEST", desc: "rename-mailbox ACCOUNT MAILBOX_PATH_SRC MAILBOX_PATH_DEST",
parser:( parser:(
named!( rename_folder<Action>, named!( rename_mailbox<Action>,
do_parse!( do_parse!(
ws!(tag!("rename-folder")) ws!(tag!("rename-mailbox"))
>> account: quoted_argument >> account: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> src: quoted_argument >> src: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> dest: quoted_argument >> dest: quoted_argument
>> (Folder(account.to_string(), FolderOperation::Rename(src.to_string(), dest.to_string()))) >> (Mailbox(account.to_string(), MailboxOperation::Rename(src.to_string(), dest.to_string())))
) )
); );
) )
}, },
{ tags: ["delete-folder "], { tags: ["delete-mailbox "],
desc: "delete-folder ACCOUNT FOLDER_PATH", desc: "delete-mailbox ACCOUNT MAILBOX_PATH",
parser:( parser:(
named!( delete_folder<Action>, named!( delete_mailbox<Action>,
do_parse!( do_parse!(
ws!(tag!("delete-folder")) ws!(tag!("delete-mailbox"))
>> account: quoted_argument >> account: quoted_argument
>> is_a!(" ") >> is_a!(" ")
>> path: quoted_argument >> path: quoted_argument
>> (Folder(account.to_string(), FolderOperation::Delete(path.to_string()))) >> (Mailbox(account.to_string(), MailboxOperation::Delete(path.to_string())))
) )
); );
) )
@ -437,5 +437,5 @@ named!(account_action<Action>, alt_complete!(reindex));
named!(view<Action>, alt_complete!(pipe | save_attachment)); named!(view<Action>, alt_complete!(pipe | save_attachment));
named!(pub parse_command<Action>, named!(pub parse_command<Action>,
alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | view | compose_action | create_folder | sub_folder | unsub_folder | delete_folder | rename_folder | account_action ) alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | view | compose_action | create_mailbox | sub_mailbox | unsub_mailbox | delete_mailbox | rename_mailbox | account_action )
); );

View File

@ -24,7 +24,7 @@
*/ */
use crate::components::Component; use crate::components::Component;
use melib::backends::FolderHash; use melib::backends::MailboxHash;
pub use melib::thread::{SortField, SortOrder}; pub use melib::thread::{SortField, SortOrder};
use melib::{Draft, EnvelopeHash}; use melib::{Draft, EnvelopeHash};
@ -55,7 +55,7 @@ pub enum ListingAction {
pub enum TabAction { pub enum TabAction {
New(Option<Box<dyn Component>>), New(Option<Box<dyn Component>>),
NewDraft(usize, Option<Draft>), NewDraft(usize, Option<Draft>),
Reply((usize, FolderHash), EnvelopeHash), // thread coordinates (account, mailbox) and envelope Reply((usize, MailboxHash), EnvelopeHash), // thread coordinates (account, mailbox) and envelope
Close, Close,
Edit(usize, EnvelopeHash), // account_position, envelope hash Edit(usize, EnvelopeHash), // account_position, envelope hash
Kill(Uuid), Kill(Uuid),
@ -87,14 +87,14 @@ pub enum AccountAction {
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FolderOperation { pub enum MailboxOperation {
Create(NewFolderPath), Create(NewMailboxPath),
Delete(FolderPath), Delete(MailboxPath),
Subscribe(FolderPath), Subscribe(MailboxPath),
Unsubscribe(FolderPath), Unsubscribe(MailboxPath),
Rename(FolderPath, NewFolderPath), Rename(MailboxPath, NewMailboxPath),
// Placeholder // Placeholder
SetPermissions(FolderPath), SetPermissions(MailboxPath),
} }
#[derive(Debug)] #[derive(Debug)]
@ -110,7 +110,7 @@ pub enum Action {
SetEnv(String, String), SetEnv(String, String),
PrintEnv(String), PrintEnv(String),
Compose(ComposeAction), Compose(ComposeAction),
Folder(AccountName, FolderOperation), Mailbox(AccountName, MailboxOperation),
AccountAction(AccountName, AccountAction), AccountAction(AccountName, AccountAction),
} }
@ -128,12 +128,12 @@ impl Action {
Action::SetEnv(_, _) => false, Action::SetEnv(_, _) => false,
Action::PrintEnv(_) => false, Action::PrintEnv(_) => false,
Action::Compose(_) => false, Action::Compose(_) => false,
Action::Folder(_, _) => true, Action::Mailbox(_, _) => true,
Action::AccountAction(_, _) => false, Action::AccountAction(_, _) => false,
} }
} }
} }
type AccountName = String; type AccountName = String;
type FolderPath = String; type MailboxPath = String;
type NewFolderPath = String; type NewMailboxPath = String;

View File

@ -22,8 +22,8 @@
use super::*; use super::*;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::FolderHash; use melib::backends::MailboxHash;
use melib::backends::{Backend, BackendOp, Backends, Folder, MailBackend, RefreshEventConsumer}; use melib::backends::{Backend, BackendOp, Backends, MailBackend, Mailbox, RefreshEventConsumer};
use melib::conf::AccountSettings; use melib::conf::AccountSettings;
use melib::email::{Envelope, EnvelopeHash, Flag}; use melib::email::{Envelope, EnvelopeHash, Flag};
use melib::error::{MeliError, Result}; use melib::error::{MeliError, Result};
@ -86,9 +86,9 @@ impl MailBackend for PluginBackend {
fn connect(&mut self) {} fn connect(&mut self) {}
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> { fn get(&mut self, mailbox: &Mailbox) -> Async<Result<Vec<Envelope>>> {
let mut w = AsyncBuilder::new(); let mut w = AsyncBuilder::new();
let _folder_hash = folder.hash(); let _mailbox_hash = mailbox.hash();
let channel = self.channel.clone(); let channel = self.channel.clone();
let handle = { let handle = {
let tx = w.tx(); let tx = w.tx();
@ -180,7 +180,7 @@ impl MailBackend for PluginBackend {
fn refresh( fn refresh(
&mut self, &mut self,
_folder_hash: FolderHash, _mailbox_hash: MailboxHash,
_sender: RefreshEventConsumer, _sender: RefreshEventConsumer,
) -> Result<Async<()>> { ) -> Result<Async<()>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
@ -193,9 +193,9 @@ impl MailBackend for PluginBackend {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> { fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {
let mut ret: FnvHashMap<FolderHash, Folder> = Default::default(); let mut ret: FnvHashMap<MailboxHash, Mailbox> = Default::default();
ret.insert(0, Folder::default()); ret.insert(0, Mailbox::default());
Ok(ret) Ok(ret)
} }
@ -208,13 +208,13 @@ impl MailBackend for PluginBackend {
}) })
} }
fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> { fn save(&self, _bytes: &[u8], _mailbox: &str, _flags: Option<Flag>) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn create_folder( fn create_mailbox(
&mut self, &mut self,
_name: String, _name: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> { ) -> Result<(MailboxHash, FnvHashMap<MailboxHash, Mailbox>)> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {

View File

@ -30,7 +30,7 @@ Input is received in the main loop from threads which listen on the stdin for us
use super::*; use super::*;
use crate::plugins::PluginManager; use crate::plugins::PluginManager;
use melib::backends::{FolderHash, NotifyFn}; use melib::backends::{MailboxHash, NotifyFn};
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use fnv::FnvHashMap; use fnv::FnvHashMap;
@ -85,7 +85,7 @@ impl InputHandler {
/// A context container for loaded settings, accounts, UI changes, etc. /// A context container for loaded settings, accounts, UI changes, etc.
pub struct Context { pub struct Context {
pub accounts: Vec<Account>, pub accounts: Vec<Account>,
pub mailbox_hashes: FnvHashMap<FolderHash, usize>, pub mailbox_hashes: FnvHashMap<MailboxHash, usize>,
pub settings: Settings, pub settings: Settings,
pub runtime_settings: Settings, pub runtime_settings: Settings,
@ -126,12 +126,12 @@ impl Context {
pub fn account_status( pub fn account_status(
&mut self, &mut self,
idx_a: usize, idx_a: usize,
folder_hash: FolderHash, mailbox_hash: MailboxHash,
) -> result::Result<(), usize> { ) -> result::Result<(), usize> {
match self.accounts[idx_a].status(folder_hash) { match self.accounts[idx_a].status(mailbox_hash) {
Ok(()) => { Ok(()) => {
self.replies self.replies
.push_back(UIEvent::MailboxUpdate((idx_a, folder_hash))); .push_back(UIEvent::MailboxUpdate((idx_a, mailbox_hash)));
Ok(()) Ok(())
} }
Err(n) => Err(n), Err(n) => Err(n),
@ -149,13 +149,13 @@ impl Context {
let ret = accounts[account_pos].is_online(); let ret = accounts[account_pos].is_online();
if ret.is_ok() { if ret.is_ok() {
if !was_online { if !was_online {
for folder_node in accounts[account_pos].list_folders() { for mailbox_node in accounts[account_pos].list_mailboxes() {
debug!( debug!(
"hash & folder: {:?} {}", "hash & mailbox: {:?} {}",
folder_node.hash, mailbox_node.hash,
accounts[account_pos][&folder_node.hash].name() accounts[account_pos][&mailbox_node.hash].name()
); );
mailbox_hashes.insert(folder_node.hash, account_pos); mailbox_hashes.insert(mailbox_node.hash, account_pos);
} }
/* Account::watch() needs /* Account::watch() needs
* - work_controller to pass `work_context` to the watcher threads and then add them * - work_controller to pass `work_context` to the watcher threads and then add them
@ -267,7 +267,7 @@ impl State {
&backends, &backends,
work_controller.get_context(), work_controller.get_context(),
sender.clone(), sender.clone(),
NotifyFn::new(Box::new(move |f: FolderHash| { NotifyFn::new(Box::new(move |f: MailboxHash| {
sender sender
.send(ThreadEvent::UIEvent(UIEvent::WorkerProgress(f))) .send(ThreadEvent::UIEvent(UIEvent::WorkerProgress(f)))
.unwrap(); .unwrap();
@ -347,7 +347,7 @@ impl State {
for i in 0..s.context.accounts.len() { for i in 0..s.context.accounts.len() {
if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() { if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() {
return Err(MeliError::new(format!( return Err(MeliError::new(format!(
"Account {} has no folders configured.", "Account {} has no mailboxes configured.",
s.context.accounts[i].name() s.context.accounts[i].name()
))); )));
} }
@ -357,7 +357,7 @@ impl State {
} }
/* /*
* When we receive a folder hash from a watcher thread, * When we receive a mailbox hash from a watcher thread,
* we match the hash to the index of the mailbox, request a reload * we match the hash to the index of the mailbox, request a reload
* and startup a thread to remind us to poll it every now and then till it's finished. * and startup a thread to remind us to poll it every now and then till it's finished.
*/ */
@ -796,14 +796,14 @@ impl State {
env::var(key.as_str()).unwrap_or_else(|e| e.to_string()), env::var(key.as_str()).unwrap_or_else(|e| e.to_string()),
))); )));
} }
Folder(account_name, op) => { Mailbox(account_name, op) => {
if let Some(account) = self if let Some(account) = self
.context .context
.accounts .accounts
.iter_mut() .iter_mut()
.find(|a| a.name() == account_name) .find(|a| a.name() == account_name)
{ {
match account.folder_operation(op) { match account.mailbox_operation(op) {
Err(err) => { Err(err) => {
self.context.replies.push_back(UIEvent::StatusEvent( self.context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()), StatusEvent::DisplayMessage(err.to_string()),
@ -911,9 +911,9 @@ impl State {
self.child = Some(child); self.child = Some(child);
return; return;
} }
UIEvent::WorkerProgress(folder_hash) => { UIEvent::WorkerProgress(mailbox_hash) => {
if let Some(&account_idx) = self.context.mailbox_hashes.get(&folder_hash) { if let Some(&account_idx) = self.context.mailbox_hashes.get(&mailbox_hash) {
let _ = self.context.accounts[account_idx].status(folder_hash); let _ = self.context.accounts[account_idx].status(mailbox_hash);
} }
return; return;
} }

View File

@ -38,7 +38,7 @@ pub use self::helpers::*;
use super::execute::Action; use super::execute::Action;
use super::terminal::*; use super::terminal::*;
use melib::backends::FolderHash; use melib::backends::MailboxHash;
use melib::{EnvelopeHash, RefreshEvent}; use melib::{EnvelopeHash, RefreshEvent};
use nix::unistd::Pid; use nix::unistd::Pid;
use std; use std;
@ -63,7 +63,7 @@ pub enum ThreadEvent {
Input(Key), Input(Key),
/// User input and input as raw bytes. /// User input and input as raw bytes.
InputRaw((Key, Vec<u8>)), InputRaw((Key, Vec<u8>)),
/// A watched folder has been refreshed. /// A watched Mailbox has been refreshed.
RefreshMailbox(Box<RefreshEvent>), RefreshMailbox(Box<RefreshEvent>),
UIEvent(UIEvent), UIEvent(UIEvent),
/// A thread has updated some of its information /// A thread has updated some of its information
@ -110,13 +110,13 @@ pub enum UIEvent {
Notification(Option<String>, String, Option<NotificationType>), Notification(Option<String>, String, Option<NotificationType>),
Action(Action), Action(Action),
StatusEvent(StatusEvent), StatusEvent(StatusEvent),
MailboxUpdate((usize, FolderHash)), // (account_idx, mailbox_idx) MailboxUpdate((usize, MailboxHash)), // (account_idx, mailbox_idx)
MailboxDelete((usize, FolderHash)), MailboxDelete((usize, MailboxHash)),
MailboxCreate((usize, FolderHash)), MailboxCreate((usize, MailboxHash)),
AccountStatusChange(usize), AccountStatusChange(usize),
ComponentKill(Uuid), ComponentKill(Uuid),
WorkerProgress(FolderHash), WorkerProgress(MailboxHash),
StartupCheck(FolderHash), StartupCheck(MailboxHash),
RefreshEvent(Box<RefreshEvent>), RefreshEvent(Box<RefreshEvent>),
EnvelopeUpdate(EnvelopeHash), EnvelopeUpdate(EnvelopeHash),
EnvelopeRename(EnvelopeHash, EnvelopeHash), // old_hash, new_hash EnvelopeRename(EnvelopeHash, EnvelopeHash), // old_hash, new_hash