[notmuch] [PATCH] notmuch: Add Maildir directory name as tag name for messages

Michiel Buddingh' michiel at michielbuddingh.net
Sun Dec 6 11:55:22 PST 2009


First of all, apologies for taking so long to get back to this.

On Fri, 27 Nov 2009, Carl Worth <cworth at cworth.org> wrote:
> The auto-detection is just three additional stats (at most) for each
> directory, right? That seems cheap enough to me.

If that's cheap enough, then I won't disagree with auto-detection.  
Jan Janak's patch seems to take most of the disk access cost out of it,
in any case.

> That seems orthogonal to me. Would the dovecot index files be easy to
> skip with a pattern-based blacklist?

Yes, and that's a much more elegant solution.

> > I'll be happy to implement them, although I'd like for others to
> > chime in on the configure-as-Maildir vs. autodetect-Maildir issue.
> > And thanks for your patience in working through my patch.

I didn't mean to call a vote--rather to solicit the opinions of others
with possibly even more exotic mail storage configurations.

A new patch is attached.  Apologies for the rather verbose Maildir
handling logic, but I couldn't find a way to minimize the calls to
is_maildir that was both neat and readable.

-- 
Michiel

---
 notmuch-client.h |    1 +
 notmuch-new.c    |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 50a30fe..7bc84a1 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -77,6 +77,7 @@ typedef struct {
     int saw_read_only_directory;
     int output_is_a_tty;
     int verbose;
+    int tag_maildir;
 
     int total_files;
     int processed_files;
diff --git a/notmuch-new.c b/notmuch-new.c
index 9d20616..8742ab4 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -109,6 +109,60 @@ is_maildir (struct dirent **entries, int count)
     return 0;
 }
 
+/* Tag new mail according to its Maildir attribute flags.
+ *
+ * Test if the mail file's filename contains any of the
+ * standard Maildir attributes, and translate these to
+ * the corresponding standard notmuch tags.
+ *
+ * If the message is not marked as 'seen', or if no
+ * flags are present, tag as 'inbox, unread'.
+ */
+static void
+derive_tags_from_maildir_flags (notmuch_message_t *message,
+				const char * path)
+{
+    int seen = FALSE;
+    int end_of_flags = FALSE;
+    size_t l = strlen(path);
+
+    /* Non-experimental message flags start with this */
+    char * i = strstr(path, ":2,");
+    i = (i) ? i : strstr(path, "!2,"); /* This format is used on VFAT */
+    if (i != NULL) {
+	i += 3;
+	for (; i < (path + l) && !end_of_flags; i++) {
+	    switch (*i) {
+	    case 'F' :
+		notmuch_message_add_tag (message, "flagged");
+		break;
+	    case 'R': /* replied */
+		notmuch_message_add_tag (message, "answered");
+		break;
+	    case 'D':
+		notmuch_message_add_tag (message, "draft");
+		break;
+	    case 'S': /* seen */
+		seen = TRUE;
+		break;
+	    case 'T': /* trashed */
+		notmuch_message_add_tag (message, "deleted");
+		break;
+	    case 'P': /* passed */
+		notmuch_message_add_tag (message, "forwarded");
+		break;
+	    default:
+		end_of_flags = TRUE;
+		break;
+	    }
+	}
+    }
+
+    if (i == NULL || !seen) {
+	tag_inbox_and_unread (message);
+    }
+}
+
 /* Examine 'path' recursively as follows:
  *
  *   o Ask the filesystem for the mtime of 'path' (path_mtime)
@@ -142,6 +196,7 @@ add_files_recursive (notmuch_database_t *notmuch,
     notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
     notmuch_message_t *message = NULL;
     struct dirent **namelist = NULL;
+    int maildir_detected = -1; /* -1 = unset */
     int num_entries;
 
     /* If we're told to, we bail out on encountering a read-only
@@ -189,13 +244,37 @@ add_files_recursive (notmuch_database_t *notmuch,
 	if (strcmp (entry->d_name, ".") == 0 ||
 	    strcmp (entry->d_name, "..") == 0 ||
 	    (entry->d_type == DT_DIR &&
-	     (strcmp (entry->d_name, "tmp") == 0) &&
-	     is_maildir (namelist, num_entries)) ||
-	    strcmp (entry->d_name, ".notmuch") ==0)
+	     strcmp (entry->d_name, ".notmuch") == 0))
 	{
 	    continue;
 	}
 
+
+	/* If this directory is a Maildir folder, we need to
+	 * ignore any subdirectories marked tmp/, and scan for
+	 * Maildir attributes on messages contained in the sub-
+	 * directories 'new' and 'cur'. */
+	if (maildir_detected != 0 &&
+	    entry->d_type == DT_DIR &&
+	    ((strcmp (entry->d_name, "tmp") == 0) ||
+	     (strcmp (entry->d_name, "new") == 0) ||
+	     (strcmp (entry->d_name, "cur") == 0))) {
+
+	    /* is_maildir scans the entire directory.  No need to
+	       do this more than once, if at all */
+	    if (maildir_detected == -1) {
+		maildir_detected = is_maildir (namelist, num_entries);
+	    }
+
+	    if (maildir_detected == 1) {
+		if (strcmp (entry->d_name, "tmp") == 0) {
+		    continue;
+		} else {
+		    state->tag_maildir = TRUE;
+		}
+	    }
+	}
+
 	next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
 
 	if (stat (next, st)) {
@@ -240,7 +319,12 @@ add_files_recursive (notmuch_database_t *notmuch,
 		    /* success */
 		    case NOTMUCH_STATUS_SUCCESS:
 			state->added_messages++;
-			tag_inbox_and_unread (message);
+			if (state->tag_maildir) {
+			    derive_tags_from_maildir_flags (message,
+							    entry->d_name);
+			} else {
+			    tag_inbox_and_unread (message);
+			}
 			break;
 		    /* Non-fatal issues (go on to next file) */
 		    case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
@@ -282,6 +366,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 	    status = add_files_recursive (notmuch, next, st, state);
 	    if (status && ret == NOTMUCH_STATUS_SUCCESS)
 		ret = status;
+	    state->tag_maildir = FALSE;
 	}
 
 	talloc_free (next);
-- 
1.6.5.4


More information about the notmuch mailing list