melib/notmuch: add support for virtual mailbox hierarchy
Add optional "parent" property to notmuch mailbox configuration. Closes #167 https://git.meli.delivery/meli/meli/issues/167sieve
parent
4f45b10974
commit
7606317f24
|
@ -187,21 +187,38 @@ Its format is described below in
|
|||
notmuch is supported by loading the dynamic library libnotmuch.
|
||||
If its location is missing from your library paths, you must add it yourself.
|
||||
Alternatively, you can specify its path by using a setting.
|
||||
.Bl -tag -width 36n
|
||||
.It Ic root_mailbox
|
||||
points to the directory which contains the
|
||||
.Pa .notmuch/
|
||||
subdirectory.
|
||||
.Pp
|
||||
notmuch mailboxes are virtual, since they are defined by user-given notmuch queries.
|
||||
You must explicitly state the mailboxes you want in the
|
||||
.Ic mailboxes
|
||||
field and set the
|
||||
.Ar query
|
||||
property to each of them.
|
||||
To create a tree hierarchy with virtual mailboxes, define the
|
||||
.Ar parent
|
||||
property to a mailbox as the name of the parent mailbox you have used in your configuration.
|
||||
.Pp
|
||||
Account properties:
|
||||
.Bl -tag -width 36n
|
||||
.It Ic root_mailbox
|
||||
points to the directory which contains the
|
||||
.Pa .notmuch/
|
||||
subdirectory.
|
||||
.It Ic library_file_path Ar Path
|
||||
Use an arbitrary location of libnotmuch by specifying its full filesystem path.
|
||||
.Pq Em optional
|
||||
.El
|
||||
Mailbox properties:
|
||||
.Bl -tag -width 36n
|
||||
.It Ic query Ar String
|
||||
The notmuch query that defines what content this virtual mailbox has.
|
||||
Refer to
|
||||
.Xr notmuch-search-terms 7
|
||||
for notmuch's search syntax.
|
||||
.It Ic parent Ar String
|
||||
If you wish to build a mailbox hierarchy, define the name of a parent mailbox you have used in your configuration.
|
||||
.Pq Em optional
|
||||
.El
|
||||
Example:
|
||||
.Bd -literal
|
||||
[accounts.notmuch]
|
||||
|
@ -212,6 +229,8 @@ format = "notmuch"
|
|||
"INBOX" = { query="tag:inbox", subscribe = true }
|
||||
"Drafts" = { query="tag:draft", subscribe = true }
|
||||
"Sent" = { query="from:username@example.com from:username2@example.com", subscribe = true }
|
||||
"Archives" = { query="tag:archived", subscribe = true }
|
||||
"Archives/2019" = { query="tag:archived date:01-2019..12-2019", parent="Archives", subscribe = true }
|
||||
.Ed
|
||||
.Ss IMAP only
|
||||
IMAP specific options are:
|
||||
|
|
|
@ -356,10 +356,14 @@ impl NotmuchDb {
|
|||
}
|
||||
path.pop();
|
||||
|
||||
let mut mailboxes = HashMap::default();
|
||||
let mut mailboxes = HashMap::with_capacity(s.mailboxes.len());
|
||||
let mut parents: Vec<(MailboxHash, &str)> = Vec::with_capacity(s.mailboxes.len());
|
||||
for (k, f) in s.mailboxes.iter() {
|
||||
if let Some(query_str) = f.extra.get("query") {
|
||||
let hash = MailboxHash::from_bytes(k.as_bytes());
|
||||
if let Some(parent) = f.extra.get("parent") {
|
||||
parents.push((hash, parent));
|
||||
}
|
||||
mailboxes.insert(
|
||||
hash,
|
||||
NotmuchMailbox {
|
||||
|
@ -383,6 +387,27 @@ impl NotmuchDb {
|
|||
.set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
}
|
||||
for (hash, parent) in parents {
|
||||
if let Some(&parent_hash) = mailboxes
|
||||
.iter()
|
||||
.find(|(_, v)| v.name == parent)
|
||||
.map(|(k, _)| k)
|
||||
{
|
||||
mailboxes
|
||||
.entry(parent_hash)
|
||||
.or_default()
|
||||
.children
|
||||
.push(hash);
|
||||
mailboxes.entry(hash).or_default().parent = Some(parent_hash);
|
||||
} else {
|
||||
return Err(Error::new(format!(
|
||||
"Mailbox configuration for `{}` defines its parent mailbox as `{}` but no mailbox exists with this exact name.",
|
||||
mailboxes[&hash].name(),
|
||||
parent
|
||||
))
|
||||
.set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
let account_hash = AccountHash::from_bytes(s.name().as_bytes());
|
||||
Ok(Box::new(NotmuchDb {
|
||||
|
@ -439,6 +464,7 @@ impl NotmuchDb {
|
|||
)).set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
}
|
||||
let mut parents: Vec<(String, String)> = Vec::with_capacity(s.mailboxes.len());
|
||||
for (k, f) in s.mailboxes.iter_mut() {
|
||||
if f.extra.remove("query").is_none() {
|
||||
return Err(Error::new(format!(
|
||||
|
@ -448,6 +474,34 @@ impl NotmuchDb {
|
|||
))
|
||||
.set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
if let Some(parent) = f.extra.remove("parent") {
|
||||
parents.push((k.clone(), parent));
|
||||
}
|
||||
}
|
||||
let mut path = Vec::with_capacity(8);
|
||||
for (mbox, parent) in parents.iter() {
|
||||
if !s.mailboxes.contains_key(parent) {
|
||||
return Err(Error::new(format!(
|
||||
"Mailbox configuration for `{}` defines its parent mailbox as `{}` but no mailbox exists with this exact name.",
|
||||
mbox,
|
||||
parent
|
||||
))
|
||||
.set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
path.clear();
|
||||
path.push(mbox.as_str());
|
||||
let mut iter = parent.as_str();
|
||||
while let Some((k, v)) = parents.iter().find(|(k, _v)| k == iter) {
|
||||
if k == mbox {
|
||||
return Err(Error::new(format!(
|
||||
"Found cycle in mailbox hierarchy: {}",
|
||||
path.join("->")
|
||||
))
|
||||
.set_kind(ErrorKind::Configuration));
|
||||
}
|
||||
path.push(k.as_str());
|
||||
iter = v.as_str();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue