conf: add * glob expansion to subscribed_folders field
You can now do: subscribed_folders = [ "*", ]jmap
parent
b327bee3e4
commit
12e4258ae4
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue