Subject: notmuch: Add "maildir:" search option

The current "folder:" search terms are near useless when you have
recursive folders, introduce a boolean "maildir:" search term to
exactly match the maildir folder.

Given a Maildir++ layout like:

        ~/Maildir/
        ~/Maildir/cur
        ~/Maildir/new
        ~/Maildir/tmp
        ~/Maildir/.Sent
        ~/Maildir/.Sent/cur
        ~/Maildir/.Sent/new
        ~/Maildir/.Sent/tmp
        ~/Maildir/.INBOX.LKML
        ~/Maildir/.INBOX.LKML/cur
        ~/Maildir/.INBOX.LKML/new
        ~/Maildir/.INBOX.LKML/tmp
        ~/Maildir/.INBOX.LKML.netdev
        ~/Maildir/.INBOX.LKML.netdev/cur
        ~/Maildir/.INBOX.LKML.netdev/new
        ~/Maildir/.INBOX.LKML.netdev/tmp
        ~/Maildir/.INBOX.LKML.arch
        ~/Maildir/.INBOX.LKML.arch/cur
        ~/Maildir/.INBOX.LKML.arch/new
        ~/Maildir/.INBOX.LKML.arch/tmp

This patch generates the following search index:

        $ delve -a Maildir/.notmuch/xapian/ | ~/s XMAILDIR
        XMAILDIR:INBOX
        XMAILDIR:INBOX/LKML
        XMAILDIR:INBOX/LKML/arch
        XMAILDIR:INBOX/LKML/netdev
        XMAILDIR:Sent

Which allows one (me!!1) to pose queries like:

        maildir:INBOX and not tag:list

to more easily find offlist mail (from people like my family who don't
actually send their stuff over LKML :-).

Signed-off-by: Peter Zijlstra <peterz at infradead.org>
---

XXX: now I need to go figure out how to do searches like:

  subject:PATCH/0

which would mandate that PATCH is the first word occurring in the
subject. I think the position index holds enough information but I
need to look into that and obviously the query parser needs work for
this.


 lib/database.cc |  7 ++++---
 lib/message.cc  | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index a021bf17253c..53aeaa68954d 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -208,15 +208,16 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
     { "thread",                        "G" },
     { "tag",                   "K" },
     { "is",                    "K" },
-    { "id",                    "Q" }
+    { "id",                    "Q" },
+    { "maildir",               "XMAILDIR:" },
 };

 static prefix_t PROBABILISTIC_PREFIX[]= {
     { "from",                  "XFROM" },
     { "to",                    "XTO" },
     { "attachment",            "XATTACHMENT" },
-    { "subject",               "XSUBJECT"},
-    { "folder",                        "XFOLDER"}
+    { "subject",               "XSUBJECT" },
+    { "folder",                        "XFOLDER" },
 };

 const char *
diff --git a/lib/message.cc b/lib/message.cc
index 1b4637950f8e..45a727a6208f 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -22,6 +22,7 @@
 #include "database-private.h"

 #include <stdint.h>
+#include <string.h>

 #include <gmime/gmime.h>

@@ -485,6 +486,8 @@ _notmuch_message_add_filename (notmuch_message_t *message,
     notmuch_status_t status;
     void *local = talloc_new (message);
     char *direntry;
+    char *maildir;
+    int i;

     if (filename == NULL)
        INTERNAL_ERROR ("Message filename cannot be NULL.");
@@ -507,6 +510,43 @@ _notmuch_message_add_filename (notmuch_message_t *message,
     /* New terms allow user to search with folder: specification. */
     _notmuch_message_gen_terms (message, "folder", directory);

+    /* Convert the directory into a maildir path */
+    maildir = talloc_strdup(local, directory);
+
+    /* Strip the maildir "cur", "new" directory entries. */
+    i = strlen(maildir);
+    if (strncmp(maildir + i - 3, "cur", 3) == 0 ||
+       strncmp(maildir + i - 3, "new", 3) == 0) {
+           maildir[i - 3] = '\0';
+           i -= 3;
+    }
+
+    /* Strip trailing '/' */
+    while (maildir[i-1] == '/') {
+           maildir[i-1] = '\0';
+           i--;
+    }
+
+    /* Strip leading '/' */
+    while (maildir[0] == '/')
+           maildir++;
+
+    /* Strip leading '.' */
+    while (maildir[0] == '.')
+           maildir++;
+
+    /* Replace all remaining '.' with '/' */
+    for (i = 0; maildir[i]; i++) {
+           if (maildir[i] == '.')
+                   maildir[i] = '/';
+    }
+
+    /* If there's no string left, we're the "INBOX" */
+    if (maildir[0] == '\0')
+           maildir = talloc_strdup(local, "INBOX");
+
+    _notmuch_message_add_term (message, "maildir", maildir);
+
     talloc_free (local);

     return NOTMUCH_STATUS_SUCCESS;

Reply via email to