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

2009-12-06 Thread Michiel Buddingh'

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

On Fri, 27 Nov 2009, Carl Worth  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) {
+

[notmuch] notmuch_threads_back and notmuch_messages_back

2009-12-06 Thread Ruben Pollan
On 19:57, Fri 27 Nov 09, Carl Worth wrote:
> (I'd like a verb that pairs better
> with "advance" than the non-verb "back"---any suggestions)?

What about regress?
I'm not a native English speaker, so maybe someone can suggest something better.

> So those won't need any new code. The one case that will need new code
> is that for notmuch_message_get_replies and
> notmuch_message_get_toplevel_messages the messages iterator is currently
> built on a singly-linked list. Making it doubly linked would obviously
> not be hard though.

I'm trying to convert it to a doubly linked list, but I'm not sure if I
understand well how they work.

I don't see how _notmuch_message_list_append works. It says "node can of course
point to an arbitrarily long list of nodes", but the code is:

void
_notmuch_message_list_append (notmuch_message_list_t *list,
  notmuch_message_node_t *node)
{   
*(list->tail) = node;
list->tail = >next;
}

Should not be something like:

void
_notmuch_message_list_append (notmuch_message_list_t *list,
  notmuch_message_node_t *node)
{   
notmuch_message_node_t *next_node;

*(list->tail) = node;
for (next_node = node->next; next_node->next != NULL;
 next_node = next_node->next);
list->tail = _node->next;
}

Do I miss something? Or the function is just designed to work on a single node
not a list of them?


-- 
Rub?n Poll?n  | jabber:meskio at jabber.org
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 No vamos a reivindicar nada,
no vamos a pedir nada.
Tomaremos, okuparemos.
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20091206/acc97ac4/attachment.pgp>


[notmuch] [PATCH] notmuch-restore.c: only update tags for messages that differ from dump file.

2009-12-06 Thread da...@tethera.net
From: David Bremner 

The main feature of this patch is that it compares the list of current
tags on a message with those read by restore. Only if the two lists
differ is the tag list in the message replaced.  In my experiments this leads to
a large performance improvement.

Since I had to rewrite the parsing of tags from the dump file anyway
to keep a list of tags (in case they should be written to the
database), I decided to make it a bit more robust. It sorts the
incoming tags (it is critical for the comparison of the two tag lists
that they are both sorted), and allows arbitrary whitespace (as
determined by "isspace") between tags.

The patch allocates a temporary array to keep track of the current
list of tags using calloc and grows it as neccesary using realloc.
---
 notmuch-restore.c |   73 
 1 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/notmuch-restore.c b/notmuch-restore.c
index 1b9598d..31e29f6 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -18,8 +18,17 @@
  * Author: Carl Worth 
  */

+#include 
+#include 
+#include 
 #include "notmuch-client.h"

+#define DEFAULT_TAG_ARRAY_SIZE 2
+/* for qsort */
+static int scmp( const void *sp1, const void *sp2 )
+{
+return( strcmp(*(const char **)sp1, *(const char **)sp2) );
+}
 int
 notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
 {
@@ -31,6 +40,9 @@ notmuch_restore_command (unused (void *ctx), int argc, char 
*argv[])
 ssize_t line_len;
 regex_t regex;
 int rerr;
+char **tag_array=NULL;
+int tag_array_size=DEFAULT_TAG_ARRAY_SIZE;
+

 config = notmuch_config_open (ctx, NULL, NULL);
 if (config == NULL)
@@ -61,11 +73,18 @@ notmuch_restore_command (unused (void *ctx), int argc, char 
*argv[])
  "^([^ ]+) \\(([^)]*)\\)$",
  REG_EXTENDED);

+/* Make an array of pointers to point to individual tokens */
+tag_array=calloc(tag_array_size,sizeof(char*));
+
 while ((line_len = getline (, _size, input)) != -1) {
regmatch_t match[3];
-   char *message_id, *tags, *tag, *next;
+   char *message_id, *tags,  *next;
notmuch_message_t *message;
notmuch_status_t status;
+   int tag_count;
+
+   notmuch_tags_t *tag_list;
+   int i;

chomp_newline (line);

@@ -89,26 +108,53 @@ notmuch_restore_command (unused (void *ctx), int argc, 
char *argv[])
goto NEXT_LINE;
}

-   notmuch_message_freeze (message);
+   next=tags;
+   tag_count=0;
+   while(*next){
+ while(*next && isspace(*next))
+   next++;
+ if (*next) {
+   while (tag_count>= tag_array_size){
+ tag_array_size*=2;
+ tag_array=realloc(tag_array,tag_array_size*sizeof(char *));
+   }
+   tag_array[tag_count]=next;
+   tag_count++;
+ }
+ while (*next && !isspace(*next))
+   next++;
+ if (*next){
+   *next='\0';
+   next++;
+ }
+   }
+
+   qsort(tag_array,tag_count,sizeof(char*),scmp);
+   
+   tag_list = notmuch_message_get_tags (message);
+   i=0;
+   while (notmuch_tags_has_more (tag_list) && i