conf: add * glob expansion to subscribed_folders field

You can now do:
 subscribed_folders = [ "*", ]
jmap
Manos Pitsidianakis 2019-11-23 17:56:38 +02:00
parent b327bee3e4
commit 12e4258ae4
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 102 additions and 49 deletions

View File

@ -151,6 +151,10 @@ impl From<FileAccount> for AccountConf {
let mut folder_confs = x.folders.clone(); let mut folder_confs = x.folders.clone();
for s in &x.subscribed_folders { for s in &x.subscribed_folders {
if !folder_confs.contains_key(s) { if !folder_confs.contains_key(s) {
use text_processing::GlobMatch;
if s.is_glob() {
continue;
}
folder_confs.insert( folder_confs.insert(
s.to_string(), s.to_string(),
FileFolderConf { FileFolderConf {
@ -173,24 +177,7 @@ impl From<FileAccount> for AccountConf {
.split(if s.contains('/') { '/' } else { '.' }) .split(if s.contains('/') { '/' } else { '.' })
.last() .last()
.unwrap_or(""); .unwrap_or("");
folder_confs.get_mut(s).unwrap().folder_conf.usage = folder_confs.get_mut(s).unwrap().folder_conf.usage = usage(name);
if name.eq_ignore_ascii_case("inbox") {
Some(SpecialUseMailbox::Inbox)
} else if name.eq_ignore_ascii_case("archive") {
Some(SpecialUseMailbox::Archive)
} else if name.eq_ignore_ascii_case("drafts") {
Some(SpecialUseMailbox::Drafts)
} else if name.eq_ignore_ascii_case("junk") {
Some(SpecialUseMailbox::Junk)
} else if name.eq_ignore_ascii_case("spam") {
Some(SpecialUseMailbox::Junk)
} else if name.eq_ignore_ascii_case("sent") {
Some(SpecialUseMailbox::Sent)
} else if name.eq_ignore_ascii_case("trash") {
Some(SpecialUseMailbox::Trash)
} else {
Some(SpecialUseMailbox::Normal)
};
} }
if folder_confs[s].folder_conf().ignore.is_unset() { if folder_confs[s].folder_conf().ignore.is_unset() {
@ -552,3 +539,23 @@ impl Serialize for CacheType {
} }
} }
} }
pub fn usage(name: &str) -> Option<SpecialUseMailbox> {
if name.eq_ignore_ascii_case("inbox") {
Some(SpecialUseMailbox::Inbox)
} else if name.eq_ignore_ascii_case("archive") {
Some(SpecialUseMailbox::Archive)
} else if name.eq_ignore_ascii_case("drafts") {
Some(SpecialUseMailbox::Drafts)
} else if name.eq_ignore_ascii_case("junk") {
Some(SpecialUseMailbox::Junk)
} else if name.eq_ignore_ascii_case("spam") {
Some(SpecialUseMailbox::Junk)
} else if name.eq_ignore_ascii_case("sent") {
Some(SpecialUseMailbox::Sent)
} else if name.eq_ignore_ascii_case("trash") {
Some(SpecialUseMailbox::Trash)
} else {
Some(SpecialUseMailbox::Normal)
}
}

View File

@ -35,6 +35,7 @@ use melib::mailbox::*;
use melib::thread::{SortField, SortOrder, ThreadHash, ThreadNode, Threads}; use melib::thread::{SortField, SortOrder, ThreadHash, ThreadNode, Threads};
use melib::AddressBook; use melib::AddressBook;
use melib::StackVec; use melib::StackVec;
use text_processing::GlobMatch;
use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification}; use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
use crate::{workers::WorkController, StatusEvent, ThreadEvent}; use crate::{workers::WorkController, StatusEvent, ThreadEvent};
@ -239,8 +240,12 @@ 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.folder_confs.contains_key(path) (s.folder_confs.contains_key(path)
&& s.folder_confs[path].folder_conf().subscribe.is_true() && s.folder_confs[path].folder_conf().subscribe.is_true())
|| s.account
.subscribed_folders
.iter()
.any(|m| path.matches_glob(m))
}), }),
)?; )?;
let notify_fn = Arc::new(notify_fn); let notify_fn = Arc::new(notify_fn);
@ -299,24 +304,37 @@ impl Account {
let mut folder_confs = FnvHashMap::default(); let mut folder_confs = FnvHashMap::default();
let mut sent_folder = None; let mut sent_folder = None;
for f in ref_folders.values_mut() { for f in ref_folders.values() {
if !self.settings.folder_confs.contains_key(f.path()) if !((self.settings.folder_confs.contains_key(f.path())
|| self.settings.folder_confs[f.path()] && self.settings.folder_confs[f.path()]
.folder_conf() .folder_conf()
.subscribe .subscribe
.is_false() .is_true())
|| self
.settings
.account
.subscribed_folders
.iter()
.any(|m| f.path().matches_glob(m)))
{ {
/* Skip unsubscribed folder */ /* Skip unsubscribed folder */
continue; continue;
} }
match self.settings.folder_confs[f.path()].folder_conf().usage { if self.settings.folder_confs.contains_key(f.path()) {
Some(SpecialUseMailbox::Sent) => { match self.settings.folder_confs[f.path()].folder_conf().usage {
sent_folder = Some(f.hash()); Some(SpecialUseMailbox::Sent) => {
sent_folder = Some(f.hash());
}
_ => {}
} }
_ => {} folder_confs.insert(f.hash(), self.settings.folder_confs[f.path()].clone());
} else {
let mut new = FileFolderConf::default();
new.folder_conf.subscribe = super::ToggleFlag::InternalVal(true);
new.folder_conf.usage = super::usage(f.name());
folder_confs.insert(f.hash(), new);
} }
folder_confs.insert(f.hash(), self.settings.folder_confs[f.path()].clone());
folder_names.insert(f.hash(), f.path().to_string()); folder_names.insert(f.hash(), f.path().to_string());
} }
@ -324,12 +342,7 @@ impl Account {
let mut tree: Vec<FolderNode> = Vec::new(); let mut tree: Vec<FolderNode> = 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_folders.iter() {
if !self.settings.folder_confs.contains_key(f.path()) if !folder_confs.contains_key(&h) {
|| self.settings.folder_confs[f.path()]
.folder_conf()
.subscribe
.is_false()
{
/* Skip unsubscribed folder */ /* Skip unsubscribed folder */
continue; continue;
} }
@ -362,7 +375,7 @@ impl Account {
workers.insert( workers.insert(
*h, *h,
Account::new_worker( Account::new_worker(
&self.settings, &folder_confs,
f.clone(), f.clone(),
&mut self.backend, &mut self.backend,
&self.work_context, &self.work_context,
@ -372,12 +385,32 @@ impl Account {
collection.threads.insert(*h, Threads::default()); collection.threads.insert(*h, Threads::default());
} }
tree.sort_unstable_by_key(|f| ref_folders[&f.hash].path()); tree.sort_unstable_by(|a, b| {
if ref_folders[&b.hash].path().eq_ignore_ascii_case("INBOX") {
std::cmp::Ordering::Greater
} else if ref_folders[&a.hash].path().eq_ignore_ascii_case("INBOX") {
std::cmp::Ordering::Less
} else {
ref_folders[&a.hash]
.path()
.cmp(&ref_folders[&b.hash].path())
}
});
let mut stack: StackVec<Option<&FolderNode>> = StackVec::new(); let mut stack: StackVec<Option<&FolderNode>> = StackVec::new();
for n in tree.iter_mut() { for n in tree.iter_mut() {
folders_order.push(n.hash); folders_order.push(n.hash);
n.kids.sort_unstable_by_key(|f| ref_folders[&f.hash].path()); n.kids.sort_unstable_by(|a, b| {
if ref_folders[&b.hash].path().eq_ignore_ascii_case("INBOX") {
std::cmp::Ordering::Greater
} else if ref_folders[&a.hash].path().eq_ignore_ascii_case("INBOX") {
std::cmp::Ordering::Less
} else {
ref_folders[&a.hash]
.path()
.cmp(&ref_folders[&b.hash].path())
}
});
stack.extend(n.kids.iter().rev().map(Some)); stack.extend(n.kids.iter().rev().map(Some));
while let Some(Some(next)) = stack.pop() { while let Some(Some(next)) = stack.pop() {
folders_order.push(next.hash); folders_order.push(next.hash);
@ -396,7 +429,7 @@ impl Account {
} }
fn new_worker( fn new_worker(
settings: &AccountConf, folder_confs: &FnvHashMap<FolderHash, FileFolderConf>,
folder: Folder, folder: Folder,
backend: &Arc<RwLock<Box<dyn MailBackend>>>, backend: &Arc<RwLock<Box<dyn MailBackend>>>,
work_context: &WorkContext, work_context: &WorkContext,
@ -406,7 +439,7 @@ impl Account {
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 folder_hash = folder.hash();
let priority = match settings.folder_confs[folder.path()].folder_conf().usage { let priority = match folder_confs[&folder.hash()].folder_conf().usage {
Some(SpecialUseMailbox::Inbox) => 0, Some(SpecialUseMailbox::Inbox) => 0,
Some(SpecialUseMailbox::Sent) => 1, Some(SpecialUseMailbox::Sent) => 1,
Some(SpecialUseMailbox::Drafts) | Some(SpecialUseMailbox::Trash) => 2, Some(SpecialUseMailbox::Drafts) | Some(SpecialUseMailbox::Trash) => 2,
@ -576,7 +609,7 @@ impl Account {
let ref_folders: FnvHashMap<FolderHash, Folder> = let ref_folders: FnvHashMap<FolderHash, Folder> =
self.backend.read().unwrap().folders().unwrap(); self.backend.read().unwrap().folders().unwrap();
let folder_conf = &self.settings.folder_confs[&self.folder_names[&folder_hash]]; let folder_conf = &self.folder_confs[&folder_hash];
if folder_conf.folder_conf().ignore.is_true() { if folder_conf.folder_conf().ignore.is_true() {
return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); return Some(UIEvent::MailboxUpdate((self.index, folder_hash)));
} }
@ -628,7 +661,7 @@ impl Account {
let ref_folders: FnvHashMap<FolderHash, Folder> = let ref_folders: FnvHashMap<FolderHash, Folder> =
self.backend.read().unwrap().folders().unwrap(); self.backend.read().unwrap().folders().unwrap();
let handle = Account::new_worker( let handle = Account::new_worker(
&self.settings, &self.folder_confs,
ref_folders[&folder_hash].clone(), ref_folders[&folder_hash].clone(),
&mut self.backend, &mut self.backend,
&self.work_context, &self.work_context,
@ -694,15 +727,15 @@ impl Account {
self.folders.is_empty() self.folders.is_empty()
} }
pub fn list_folders(&self) -> Vec<Folder> { pub fn list_folders(&self) -> Vec<Folder> {
let folder_confs = self.settings.conf().folders();
let mut folders = if let Ok(folders) = self.backend.read().unwrap().folders() { let mut folders = if let Ok(folders) = self.backend.read().unwrap().folders() {
folders folders
} else { } else {
return Vec::new(); return Vec::new();
}; };
let folder_confs = &self.folder_confs;
//debug!("folder renames: {:?}", folder_renames); //debug!("folder renames: {:?}", folder_renames);
for f in folders.values_mut() { for f in folders.values_mut() {
if let Some(r) = folder_confs.get(f.path()) { if let Some(r) = folder_confs.get(&f.hash()) {
if let Some(rename) = r.folder_conf().rename() { if let Some(rename) = r.folder_conf().rename() {
f.change_name(rename); f.change_name(rename);
} }
@ -725,8 +758,19 @@ impl Account {
let mut folders: Vec<Folder> = folders let mut folders: Vec<Folder> = folders
.drain() .drain()
.map(|(_, f)| f) .map(|(_, f)| f)
.filter(|f| self.folders.contains_key(&f.hash())) .filter(|f| {
self.folders.contains_key(&f.hash())
|| self
.settings
.account
.subscribed_folders
.iter()
.any(|m| f.path().matches_glob(m))
})
.collect(); .collect();
if order.is_empty() {
return Vec::new();
}
folders.sort_unstable_by(|a, b| order[&a.hash()].partial_cmp(&order[&b.hash()]).unwrap()); folders.sort_unstable_by(|a, b| order[&a.hash()].partial_cmp(&order[&b.hash()]).unwrap());
folders folders
} }
@ -860,12 +904,11 @@ impl Account {
pub fn sent_folder(&self) -> &str { pub fn sent_folder(&self) -> &str {
let sent_folder = self let sent_folder = self
.settings
.folder_confs .folder_confs
.iter() .iter()
.find(|(_, f)| f.folder_conf().usage == Some(SpecialUseMailbox::Sent)); .find(|(_, f)| f.folder_conf().usage == Some(SpecialUseMailbox::Sent));
if let Some(sent_folder) = sent_folder.as_ref() { if let Some(sent_folder) = sent_folder.as_ref() {
sent_folder.0 &self.folder_names[&sent_folder.0]
} else { } else {
"" ""
} }
@ -873,11 +916,14 @@ impl Account {
pub fn special_use_folder(&self, special_use: SpecialUseMailbox) -> Option<&str> { pub fn special_use_folder(&self, special_use: SpecialUseMailbox) -> Option<&str> {
let ret = self let ret = self
.settings
.folder_confs .folder_confs
.iter() .iter()
.find(|(_, f)| f.folder_conf().usage == Some(special_use)); .find(|(_, f)| f.folder_conf().usage == Some(special_use));
ret.as_ref().map(|r| r.0.as_str()) if let Some(ret) = ret.as_ref() {
Some(&self.folder_names[&ret.0])
} else {
None
}
} }
/* Call only in Context::is_online, since only Context can launch the watcher threads if an /* Call only in Context::is_online, since only Context can launch the watcher threads if an