summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2022-12-04 16:07:32 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2022-12-09 12:35:10 +0200
commit7606317f24d076bdc7db873c2b15811728ed946a (patch)
tree982085d14b22b4de94c646b508f25a0a82a5792d
parent4f45b109745ebc29febc452b9bcb0cd88f131ffc (diff)
downloadmeli-7606317f24d076bdc7db873c2b15811728ed946a.zip
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/167
-rw-r--r--docs/meli.conf.529
-rw-r--r--melib/src/backends/notmuch.rs56
2 files changed, 79 insertions, 6 deletions
diff --git a/docs/meli.conf.5 b/docs/meli.conf.5
index 52bba8d3..40d67192 100644
--- a/docs/meli.conf.5
+++ b/docs/meli.conf.5
@@ -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:
diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs
index e33c8756..c8d69c71 100644
--- a/melib/src/backends/notmuch.rs
+++ b/melib/src/backends/notmuch.rs
@@ -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(())
}