[notmuch] [PATCH] Older versions of install do not support -C.

2009-11-17 Thread Jan Janak
Do not use -C cmdline option of install, older versions, commonly found in
distributions like Debian, do not seem to support it. Running make install
on such systems (tested on Debian Lenny) fails.

Signed-off-by: Jan Janak 
---
 Makefile.local |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index f824bed..f51f1d1 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -27,11 +27,11 @@ install: all notmuch.1.gz
for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 \
$(DESTDIR)/etc/bash_completion.d/ ; \
do \
-   install -C -d $$d ; \
+   install -d $$d ; \
done ;
-   install -C notmuch $(DESTDIR)$(prefix)/bin/
-   install -C -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
-   install -C notmuch-completion.bash \
+   install notmuch $(DESTDIR)$(prefix)/bin/
+   install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
+   install notmuch-completion.bash \
$(DESTDIR)/etc/bash_completion.d/notmuch

 SRCS  := $(SRCS) $(notmuch_client_srcs)
-- 
1.6.3.3



[notmuch] What a great idea!

2009-11-17 Thread Jan Janak
Hello,

First of all, notmuch is a wonderful idea, both the cmdline tool and
the emacs interface! Thanks a lot for writing it, I was really excited
when I read the announcement today.

Have you considered sending an announcement to the org-mode mailing list?
http://org-mode.org

Various ways of searching/referencing emails from emacs were discussed
there several times and none of them were as elegant as notmuch (not
even close). Maybe notmuch would attract some of the developers
there..

   -- Jan


[notmuch] What a great idea!

2009-11-17 Thread Jan Janak
On Tue, Nov 17, 2009 at 11:35 PM, Jan Janak  wrote:
> Hello,
>
> First of all, notmuch is a wonderful idea, both the cmdline tool and
> the emacs interface! Thanks a lot for writing it, I was really excited
> when I read the announcement today.
>
> Have you considered sending an announcement to the org-mode mailing list?
> http://org-mode.org

Sorry, wrong URL, the correct one is: http://orgmode.org

> Various ways of searching/referencing emails from emacs were discussed
> there several times and none of them were as elegant as notmuch (not
> even close). Maybe notmuch would attract some of the developers
> there..

  -- Jan


[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags

2009-11-18 Thread Jan Janak
This patch makes it possible to convert subdirectory names inside the
spool directory into message tags. Messages stored in subdirectory
"foo" will be marked with tag "foo". Message duplicates found in several
subdirectories will be given one tag per subdirectory.

This feature can be used to synchronize notmuch's tags with with gmail
tags, for example. Gmail IMAP servers convert tags to IMAP
subdirectories and those subdirectories can be converted back to tags
in notmuch.

The patch modifies notmuch_database_add_message function to return a
pointer to the message even if a message duplicate was found in the
database. This is needed if we want to add a tag for each subdirectory
in which a message duplicate was found.

In addition to that, it makes the pointer to notmuch_config_t global
(previously it was a local variable in notmuch_new_command). The
configuration data structure is used by the function which converts
subdirectory names to tags.

Finally, there is a new function called subdir_to_tag. The function
extracts the name of the subdirectory inside the spool from the full
path of the message (also removing Maildir's cur,dir,and tmp
subdirectories) and adds it as a new tag to the message.

Signed-off-by: Jan Janak 
---
 lib/database.cc |3 +-
 notmuch-new.c   |   74 +-
 2 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 3c8d626..f7799d2 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -949,7 +949,8 @@ notmuch_database_add_message (notmuch_database_t *notmuch,

   DONE:
 if (message) {
-   if (ret == NOTMUCH_STATUS_SUCCESS && message_ret)
+   if ((ret == NOTMUCH_STATUS_SUCCESS ||
+ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) && 
message_ret)
*message_ret = message;
else
notmuch_message_destroy (message);
diff --git a/notmuch-new.c b/notmuch-new.c
index 83a05ba..d94ce16 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -19,6 +19,9 @@
  */

 #include "notmuch-client.h"
+#include 
+
+static notmuch_config_t *config = 0;

 static volatile sig_atomic_t do_add_files_print_progress = 0;

@@ -45,6 +48,69 @@ tag_inbox_and_unread (notmuch_message_t *message)
 notmuch_message_add_tag (message, "unread");
 }

+/*
+ * Extracts the sub-directory from the filename and adds it as a new tag to
+ * the message. The filename must begin with the database directory configured
+ * in the configuration file. This prefix is then removed. If the remaining
+ * sub-directory ends with one of the Maildir special directories (/tmp, /new,
+ * /cur) then they are removed as well. If there is anything left then the
+ * function adds it as a new tag to the message.
+ *
+ * The function does nothing if it cannot extract a sub-directory from
+ * filename.
+ */
+static void
+subdir_to_tag (char* filename, notmuch_message_t *message)
+{
+   const char* db_path;
+   char *msg_dir, *tmp;
+   int db_path_len, msg_dir_len;
+
+   if (config == NULL) return;
+db_path = notmuch_config_get_database_path (config);
+   if (db_path == NULL) return;
+   db_path_len = strlen(db_path);
+
+   /* Make a copy of the string as dirname may need to modify it. */
+   tmp = talloc_strdup(message, filename);
+   msg_dir = dirname(tmp);
+   msg_dir_len = strlen(msg_dir);
+
+   /* If msg_dir starts with db_path, remove it, including the / which 
delimits
+* it from the rest of the directory name. */
+   if (db_path_len < msg_dir_len &&
+   !strncmp(db_path, msg_dir, db_path_len)) {
+   msg_dir += db_path_len + 1;
+   msg_dir_len -= db_path_len + 1;
+   } else {
+   /* If we get here, either the message filename is not inside the
+* database directory configured in the configuration file, or 
it is a
+* file in the root directory of the database. Either way we 
just skip
+* it because we do not know how to convert it to a meaningful
+* subdirectory string that we could add as tag. */
+   goto out;
+   }
+
+   /* Special conditioning for Maildirs. If the remainder of the directory
+* name ends with /new, /cur, or /tmp then remove it. */
+   if ((msg_dir_len >= 4) &&
+   (!strncmp(msg_dir + msg_dir_len - 4, "/new", 4) ||
+!strncmp(msg_dir + msg_dir_len - 4, "/cur", 4) ||
+!strncmp(msg_dir + msg_dir_len - 4, "/tmp", 4))) {
+   msg_dir[msg_dir_len - 4] = '\0';
+   }
+
+   /* If, after all the modifications, we still have a subdirectory, add it
+* as tag. */
+   if (strlen(msg_dir)) {
+   notmuch_message_add_tag (message, msg_dir);
+   }

[notmuch] Why is no. of files from count_files reset to 0?

2009-11-18 Thread Jan Janak
Hello,

The function count_file returns the total number of files to be
processed, the result is then stored in add_files_state.total_files.
But that variable is reset back to 0 in notmuch_new_command.

When I comment out the following line (before add_files is called):

add_files_state.total_files = 0;

The progress indicator shows the total number of files to be
processed, as well as the time remaining. This is, IMHO, much better,
especially if you process a large collection of emails.

Is there any reason for having the variable reset to 0 before calling
add_files? Thanks!

   -- Jan


[notmuch] [PATCH] Makefile: Make object targets depend on Makefiles

2009-11-19 Thread Jan Janak
All objects need to be recompiled when any of the Makefiles changes, so
we make them all depend on all the Makefiles.

Signed-off-by: Jan Janak 
---
 Makefile |   11 +++
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 96aaa73..2787aff 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,9 @@ CFLAGS=-O2
 extra_cflags = `pkg-config --cflags glib-2.0 gmime-2.4 talloc`
 extra_cxxflags = `xapian-config --cxxflags`

+all_deps = Makefile Makefile.local Makefile.config \
+  lib/Makefile lib/Makefile.local
+
 # Now smash together user's values with our extra values
 override CFLAGS += $(WARN_FLAGS) $(extra_cflags)
 override CXXFLAGS += $(WARN_FLAGS) $(extra_cflags) $(extra_cxxflags)
@@ -21,19 +24,19 @@ include lib/Makefile.local
 # And get user settings from the output of configure
 include Makefile.config

-%.o: %.cc
+%.o: %.cc $(all_deps)
$(CXX) -c $(CFLAGS) $(CXXFLAGS) $< -o $@

-%.o: %.c
+%.o: %.c $(all_deps)
$(CC) -c $(CFLAGS) $< -o $@

-.deps/%.d: %.c
+.deps/%.d: %.c $(all_deps)
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@.; \
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@. > $@; \
rm -f $@.

-.deps/%.d: %.cc
+.deps/%.d: %.cc $(all_deps)
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
$(CXX) -M $(CPPFLAGS) $(CXXFLAGS) $< > $@.; \
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@. > $@; \
-- 
1.6.3.3



[notmuch] [PATCH 1/2] notmuch: Support for notmuch_database_get_tags

2009-11-19 Thread Jan Janak
This patch adds a new function called notmuch_database_get_tags which
can be used to obtain a list of all tags defined in the database (that
is, the list all tags from all messages). The function produces an
alphabetically sorted list.

To add support for the new function, we rip the guts off of
notmuch_message_get_tags and put them in a new generic function
called _notmuch_convert_tags. The generic function takes a TermIterator
as argument and produces a notmuch_tags_t list of tags.

Function notmuch_message_get_tags is then reimplemented to call the
generic function with message->doc.termlist_begin() as argument.

Similarly, we implement notmuch_message_database_tags, the function
calls the generic function with db->xapian_db->allterms_begin() as
argument.

Finally, notmuch_database_get_tags is exported through lib/notmuch.h

Signed-off-by: Jan Janak 
---
 lib/database.cc |   48 
 lib/message.cc  |   38 ++
 lib/notmuch.h   |4 
 3 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 4998fc9..b1c15c3 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -983,3 +983,51 @@ notmuch_database_add_message (notmuch_database_t *notmuch,

 return ret;
 }
+
+notmuch_tags_t *
+_notmuch_convert_tags (void* ctx, Xapian::TermIterator i);
+
+/* Converts tags from the format used in Xapian to a list in
+   notmuch_tags_t. */
+notmuch_tags_t *
+_notmuch_convert_tags (void* ctx, Xapian::TermIterator i)
+{
+const char *prefix = _find_prefix ("tag");
+notmuch_tags_t *tags;
+std::string tag;
+
+/* Currently this iteration is written with the assumption that
+ * "tag" has a single-character prefix. */
+assert (strlen (prefix) == 1);
+
+tags = _notmuch_tags_create (ctx);
+if (unlikely (tags == NULL))
+   return NULL;
+
+i.skip_to (prefix);
+
+while (1) {
+   tag = *i;
+
+   if (tag.empty () || tag[0] != *prefix)
+   break;
+
+   _notmuch_tags_add_tag (tags, tag.c_str () + 1);
+
+   i++;
+}
+
+_notmuch_tags_prepare_iterator (tags);
+
+return tags;
+}
+
+/*
+ * Returns a list of all tags defined in a notmuch database. The resulting
+ * list is sorted alphabetically.
+ */
+notmuch_tags_t *
+notmuch_database_get_tags (notmuch_database_t *db)
+{
+   return _notmuch_convert_tags(db, db->xapian_db->allterms_begin());
+}
diff --git a/lib/message.cc b/lib/message.cc
index 9488fb6..af23bb2 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -41,6 +41,9 @@ struct _notmuch_message {
 Xapian::Document doc;
 };

+extern notmuch_tags_t *
+_notmuch_convert_tags (void* ctx, Xapian::TermIterator i);
+
 /* "128 bits of thread-id ought to be enough for anybody" */
 #define NOTMUCH_THREAD_ID_BITS  128
 #define NOTMUCH_THREAD_ID_DIGITS (NOTMUCH_THREAD_ID_BITS / 4)
@@ -445,43 +448,14 @@ notmuch_message_get_date (notmuch_message_t *message)
 return Xapian::sortable_unserialise (value);
 }

+
 notmuch_tags_t *
 notmuch_message_get_tags (notmuch_message_t *message)
 {
-const char *prefix = _find_prefix ("tag");
-Xapian::TermIterator i, end;
-notmuch_tags_t *tags;
-std::string tag;
-
-/* Currently this iteration is written with the assumption that
- * "tag" has a single-character prefix. */
-assert (strlen (prefix) == 1);
-
-tags = _notmuch_tags_create (message);
-if (unlikely (tags == NULL))
-   return NULL;
-
-i = message->doc.termlist_begin ();
-end = message->doc.termlist_end ();
-
-i.skip_to (prefix);
-
-while (1) {
-   tag = *i;
-
-   if (tag.empty () || tag[0] != *prefix)
-   break;
-
-   _notmuch_tags_add_tag (tags, tag.c_str () + 1);
-
-   i++;
-}
-
-_notmuch_tags_prepare_iterator (tags);
-
-return tags;
+   return _notmuch_convert_tags(message, message->doc.termlist_begin());
 }

+
 void
 _notmuch_message_set_date (notmuch_message_t *message,
   const char *date)
diff --git a/lib/notmuch.h b/lib/notmuch.h
index cc713a3..1edcfd6 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -271,6 +271,10 @@ notmuch_message_t *
 notmuch_database_find_message (notmuch_database_t *database,
   const char *message_id);

+notmuch_tags_t *
+notmuch_database_get_tags (notmuch_database_t *database);
+
+
 /* Create a new query for 'database'.
  *
  * Here, 'database' should be an open database, (see
-- 
1.6.3.3



[notmuch] [PATCH 2/2] notmuch list: A new command to produce various lists.

2009-11-19 Thread Jan Janak
Here we create a new notmuch command called list. The purpose of the
command is to produce various lists from the notmuch database.

At the moment we support only one command, notmuch list tags. This
command creates a list of all tags found in the database.

Signed-off-by: Jan Janak 
---
 Makefile.local   |1 +
 notmuch-client.h |3 ++
 notmuch-list.c   |   98 ++
 notmuch.c|   10 +
 4 files changed, 112 insertions(+), 0 deletions(-)
 create mode 100644 notmuch-list.c

diff --git a/Makefile.local b/Makefile.local
index 27e42ba..fb6d5c3 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -12,6 +12,7 @@ notmuch_client_srcs = \
notmuch-show.c  \
notmuch-tag.c   \
notmuch-time.c  \
+notmuch-list.c  \
gmime-filter-reply.c\
query-string.c  \
show-message.c
diff --git a/notmuch-client.h b/notmuch-client.h
index b65aa77..ae876b5 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -114,6 +114,9 @@ notmuch_show_command (void *ctx, int argc, char *argv[]);
 int
 notmuch_tag_command (void *ctx, int argc, char *argv[]);

+int
+notmuch_list_command (void *ctx, int argc, char *argv[]);
+
 const char *
 notmuch_time_relative_date (const void *ctx, time_t then);

diff --git a/notmuch-list.c b/notmuch-list.c
new file mode 100644
index 000..fe71108
--- /dev/null
+++ b/notmuch-list.c
@@ -0,0 +1,98 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright ?? 2009 Carl Worth
+ * Copyright ?? 2009 Jan Janak
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Authors: Carl Worth 
+ *  Jan Janak 
+ */
+
+#include "notmuch-client.h"
+
+enum list_cmd {
+   LIST_TAGS
+};
+
+
+static int
+list_all_tags(notmuch_database_t* db)
+{
+   notmuch_tags_t* tags;
+   const char* t;
+
+   if ((tags = notmuch_database_get_tags(db)) == NULL) {
+   fprintf(stderr, "Error while obtaining tags from the 
database.\n");
+   return 1;
+   }
+
+   while((t = notmuch_tags_get(tags))) {
+   printf("%s\n", t);
+   notmuch_tags_advance(tags);
+   }
+
+   notmuch_tags_destroy(tags);
+   return 0;
+}
+
+int
+notmuch_list_command (void *ctx, int argc, char *argv[])
+{
+notmuch_config_t *config;
+notmuch_database_t *db;
+   enum list_cmd cmd;
+
+   config = NULL;
+   db = NULL;
+
+   if (argc < 1) {
+   fprintf(stderr, "Error: notmuch list requires at least one 
parameter.\n");
+   fprintf(stderr, "(See notmuch help list)\n");
+   goto error;
+   }
+
+   if (!strcmp(argv[0], "tags")) {
+   cmd = LIST_TAGS;
+   } else {
+   fprintf(stderr, "Sub-command '%s' not supported.\n", argv[0]);
+   goto error;
+   }
+
+if ((config = notmuch_config_open (ctx, NULL, NULL)) == NULL) {
+   goto error;
+   }
+
+db = notmuch_database_open (notmuch_config_get_database_path (config));
+if (db == NULL) {
+   goto error;
+   }
+
+   switch(cmd) {
+   case LIST_TAGS:
+   if (list_all_tags(db) != 0) goto error;
+   break;
+
+   default:
+   fprintf(stderr, "Unsupported command: bug in 
notmuch_list_command.\n");
+   goto error;
+   }
+
+notmuch_database_close (db);
+return 0;
+
+error:
+   if (db) notmuch_database_close(db);
+   return 1;
+}
diff --git a/notmuch.c b/notmuch.c
index 5cc8e4c..1baa22d 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -230,6 +230,16 @@ command_t commands[] = {
   "\t\tSo if you've previously been using sup for mail, then the\n"
   "\t\t\"notmuch restore\" command provides you a way to import\n"
   "\t\tall of your tags (or labels as sup calls them)." },
+   { "list", notmuch_list_command,
+ "",
+ "\t\tShow additional information about the database.",
+ "\t\tThe following sub-commands are supported:"
+ "\n\n"
+ "\t\ttags\n"
+ "\n"
+ "\t\t\tGenerate a 

[notmuch] [PATCH 2/2] notmuch list: A new command to produce various lists.

2009-11-19 Thread Jan Janak
Carl and others,

I implemented a new notmuch command that can be used to list all tags
present in the database:

  $ notmuch list tags

If you run this, you'll get an alphabetically sorted list of all
tags--one tag per line.

The main reason why I implemented this is because I am also working on
adding the tag completion feature to the Emacs mode. This is very
useful if you have a large collection of tags--it can save you some
typing and, perhaps more importantly, it minimizes the risk of having
typos in tag names. I'll send a patch for that later too.

Let me know what do you think.

  -- Jan

On Thu, Nov 19, 2009 at 12:34 PM, Jan Janak  wrote:
> Here we create a new notmuch command called list. The purpose of the
> command is to produce various lists from the notmuch database.
>
> At the moment we support only one command, notmuch list tags. This
> command creates a list of all tags found in the database.
>
> Signed-off-by: Jan Janak 
> ---
> ?Makefile.local ? | ? ?1 +
> ?notmuch-client.h | ? ?3 ++
> ?notmuch-list.c ? | ? 98 
> ++
> ?notmuch.c ? ? ? ?| ? 10 +
> ?4 files changed, 112 insertions(+), 0 deletions(-)
> ?create mode 100644 notmuch-list.c
>
> diff --git a/Makefile.local b/Makefile.local
> index 27e42ba..fb6d5c3 100644
> --- a/Makefile.local
> +++ b/Makefile.local
> @@ -12,6 +12,7 @@ notmuch_client_srcs = ? ? ? ? \
> ? ? ? ?notmuch-show.c ? ? ? ? ?\
> ? ? ? ?notmuch-tag.c ? ? ? ? ? \
> ? ? ? ?notmuch-time.c ? ? ? ? ?\
> + ? ?notmuch-list.c ? ? ?\
> ? ? ? ?gmime-filter-reply.c ? ?\
> ? ? ? ?query-string.c ? ? ? ? ?\
> ? ? ? ?show-message.c
> diff --git a/notmuch-client.h b/notmuch-client.h
> index b65aa77..ae876b5 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -114,6 +114,9 @@ notmuch_show_command (void *ctx, int argc, char *argv[]);
> ?int
> ?notmuch_tag_command (void *ctx, int argc, char *argv[]);
>
> +int
> +notmuch_list_command (void *ctx, int argc, char *argv[]);
> +
> ?const char *
> ?notmuch_time_relative_date (const void *ctx, time_t then);
>
> diff --git a/notmuch-list.c b/notmuch-list.c
> new file mode 100644
> index 000..fe71108
> --- /dev/null
> +++ b/notmuch-list.c
> @@ -0,0 +1,98 @@
> +/* notmuch - Not much of an email program, (just index and search)
> + *
> + * Copyright ? 2009 Carl Worth
> + * Copyright ? 2009 Jan Janak
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. ?If not, see http://www.gnu.org/licenses/ .
> + *
> + * Authors: Carl Worth 
> + * ? ? ? ? ?Jan Janak 
> + */
> +
> +#include "notmuch-client.h"
> +
> +enum list_cmd {
> + ? ? ? LIST_TAGS
> +};
> +
> +
> +static int
> +list_all_tags(notmuch_database_t* db)
> +{
> + ? ? ? notmuch_tags_t* tags;
> + ? ? ? const char* t;
> +
> + ? ? ? if ((tags = notmuch_database_get_tags(db)) == NULL) {
> + ? ? ? ? ? ? ? fprintf(stderr, "Error while obtaining tags from the 
> database.\n");
> + ? ? ? ? ? ? ? return 1;
> + ? ? ? }
> +
> + ? ? ? while((t = notmuch_tags_get(tags))) {
> + ? ? ? ? ? ? ? printf("%s\n", t);
> + ? ? ? ? ? ? ? notmuch_tags_advance(tags);
> + ? ? ? }
> +
> + ? ? ? notmuch_tags_destroy(tags);
> + ? ? ? return 0;
> +}
> +
> +int
> +notmuch_list_command (void *ctx, int argc, char *argv[])
> +{
> + ? ?notmuch_config_t *config;
> + ? ?notmuch_database_t *db;
> + ? ? ? enum list_cmd cmd;
> +
> + ? ? ? config = NULL;
> + ? ? ? db = NULL;
> +
> + ? ? ? if (argc < 1) {
> + ? ? ? ? ? ? ? fprintf(stderr, "Error: notmuch list requires at least one 
> parameter.\n");
> + ? ? ? ? ? ? ? fprintf(stderr, "(See notmuch help list)\n");
> + ? ? ? ? ? ? ? goto error;
> + ? ? ? }
> +
> + ? ? ? if (!strcmp(argv[0], "tags")) {
> + ? ? ? ? ? ? ? cmd = LIST_TAGS;
> + ? ? ? } else {
> + ? ? ? ? ? ? ? fprintf(stderr, "Sub-command '%s' not supported.\n", argv[0]);
> + ? ? ? ? ? ? ? goto error;
> + ? ? ? }
> +
> + ? ?if ((config = notmuch_config_open (ctx, NULL, NULL)) == NULL) {
> + ? ? 

[notmuch] [PATCH] notmuch.el: Completion for tag names.

2009-11-19 Thread Jan Janak
Add support for completion of tag names. Several commands ask the user
for a tag name. With this feature the user can just press tab and emacs
automatically retrieves the list of all existing tags from notmuch
database with 'notmuch list tags' and presents a completion buffer to
the user.

Signed-off-by: Jan Janak 
---
 notmuch.el |   22 +-
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 706e9f3..587e093 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -165,7 +165,8 @@ Unlike builtin `next-line' this version accepts no 
arguments."

 (defun notmuch-show-add-tag (&rest toadd)
   "Add a tag to the current message."
-  (interactive "sTag to add: ")
+  (interactive
+   (list (notmuch-tag-with-completion "Tag to add: ")))
   (apply 'notmuch-call-notmuch-process
 (append (cons "tag"
   (mapcar (lambda (s) (concat "+" s)) toadd))
@@ -174,7 +175,8 @@ Unlike builtin `next-line' this version accepts no 
arguments."

 (defun notmuch-show-remove-tag (&rest toremove)
   "Remove a tag from the current message."
-  (interactive "sTag to remove: ")
+  (interactive
+   (list (notmuch-tag-with-completion "Tag to remove: ")))
   (let ((tags (notmuch-show-get-tags)))
 (if (intersection tags toremove :test 'string=)
(progn
@@ -873,13 +875,22 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
   (let ((end (- (point) 1)))
(split-string (buffer-substring beg end))

+(defun notmuch-tag-with-completion (prompt)
+  (let ((tag-list
+(with-output-to-string
+  (with-current-buffer standard-output
+(call-process "notmuch" nil t nil "list" "tags")
+(completing-read prompt (split-string tag-list "\n+" t) nil nil nil)))
+
 (defun notmuch-search-add-tag (tag)
-  (interactive "sTag to add: ")
+  (interactive
+   (list (notmuch-tag-with-completion "Tag to add: ")))
   (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete-dups (sort (cons tag 
(notmuch-search-get-tags)) 'string<

 (defun notmuch-search-remove-tag (tag)
-  (interactive "sTag to remove: ")
+  (interactive
+   (list (notmuch-tag-with-completion "Tag to remove: ")))
   (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags

@@ -964,7 +975,8 @@ current search results AND the additional query string 
provided."

 Runs a new search matching only messages that match both the
 current search results AND that are tagged with the given tag."
-  (interactive "sFilter by tag: ")
+  (interactive
+   (list (notmuch-tag-with-completion "Filter by tag: ")))
   (notmuch-search (concat notmuch-search-query-string " and tag:" tag) 
notmuch-search-oldest-first))

 (defun notmuch ()
-- 
1.6.3.3



[notmuch] [PATCH 2/2] notmuch list: A new command to produce various lists.

2009-11-19 Thread Jan Janak
On Thu, Nov 19, 2009 at 3:41 PM, Carl Worth  wrote:
> On Thu, 19 Nov 2009 12:52:49 +0100, Jan Janak  wrote:
>> I implemented a new notmuch command that can be used to list all tags
>> present in the database:
>
> Ah, very very interesting! I'd been planning on doing something like
> this soon. And I was just thinking of "notmuch tags" as the command
> line. What other ideas do you have in mind for "notmuch list" ?

Yes, I considered "notmuch tags" too, but then I realized that we
already have "notmuch tag" and I was worried that having both tag and
tags as commands could be confusing.

I was also thinking that "notmuch list" could be extended to list
other terms than just tags, but I currently have no use-case for that.

In any case, this is just an initial proposal, I can change it to use
some other command name if you prefer that.

> One way we could possibly do "notmuch tags" is to have it accept search
> terms and then return the list of all tags from the matched messages.
> Then of course we'd need a syntax for a search term to match all
> messages, (which we want in any case).

That sounds like a good idea. If the user does not provide any search
terms then we could return all tags from the database like we do now.
If there is a search term then we could iterate through all the
messages that match it, collect their tags, sort them and present to
the user.

>> The main reason why I implemented this is because I am also working on
>> adding the tag completion feature to the Emacs mode. This is very
>> useful if you have a large collection of tags--it can save you some
>> typing and, perhaps more importantly, it minimizes the risk of having
>> typos in tag names. I'll send a patch for that later too.
>
> That will be a very nice feature to have, yes.
>
> The other reason I've wanted this is have something like a "folder view"
> that would show a list of tags and a number of messages with each tag,
> (or a number of messages with that tag and the inbox tag).

Yeah, I would want that too :-). I've already looked into this and it
seems like it should be easy to implement. At least it seems to be
easy to get the numbers from Xapian. So we would just need to come up
with a format for the list of tags with message counts, read it into
emacs and present in a buffer.

  -- Jan


[notmuch] Segfault searching for tags

2009-11-20 Thread Jan Janak
On Fri, Nov 20, 2009 at 2:10 PM, Jeffrey Ollie  wrote:
> On Fri, Nov 20, 2009 at 5:32 AM, Carl Worth  wrote:
>> On Thu, 19 Nov 2009 16:45:43 +0100, Adrian Perez de Castro > igalia.com> wrote:
>>> The thing is that in notmuch_message_get_in_reply_to(), line 288, a NULL
>>> instance of Xapian::TermIterator is dereferenced. In my particular case,
>>> the culpript is a cache file of Claws-Mail, as seen in the following GDB
>>> session:
>>
>> Not quite NULL, (nor is it quite dereferencing---this is nasty C++
>> overloading), but yeah, the idea is the same. We need to protect all of
>> our "calls" to this overloaded operator to not call it when the iterator
>> is equal to the value returned by termlist_end ().
>>
>> On Thu, 19 Nov 2009 20:23:15 -0600, Jeffrey Ollie  wrote:
>>> I straced some of the crashes, and the last file that was read before
>>> the crash was a malformed message. ?I've attached one of the messages.
>>
>> Thanks for the file. I never like to push code that I haven't tested, so
>> this was very helpful.
>>
>> Below is the patch that I just pushed which seems to do the trick.
>
> Ah, excellent! ?This does indeed seem to prevent the crash. ?Now I
> just need to figure out how to get all my mail out of GMail.

I did exactly that with offlineimap. It crashes from time to time, but
then you can just restart it and continue.

A few days ago I sent a patch which converts mail subdirectories to
tags and because Gmail IMAP server converts labels to subdirectories,
you can use that to convert gmail's labels to notmuch tags
automatically.

   -- Jan


[notmuch] Recommended Coding Style?

2009-11-20 Thread Jan Janak
Hi Guys,

Is there any recommended coding style for the C/C++ code in notmuch?

  -- Jan


[notmuch] Asynchronous tagging

2009-11-21 Thread Jan Janak
On Sat, Nov 21, 2009 at 9:01 PM, Carl Worth  wrote:
>> 3. I had initially put 'notmuch new' in a cron job (instead of
>> offlineimap postsync hook) and new/search would sometimes complain about
>> missing files in the maildir. ?The first time this happened, it did not
>> correct itself and I ended up reimporting the database (I had moved some
>> things around so I could have been at fault). ?Since then I have seen
>> these errors on a couple occasions, but they always go away upon
>> rerunning 'notmuch new'. ?My guess is that it has to do with offlineimap
>> changing flags so I moved 'notmuch new' to the postsync hook and have
>> not seen the errors since. ?If it is important that notmuch never runs
>> concurrently with an offlineimap sync, it should eventually go in the
>> docs.
>
> Thanks for the pointer.
>
> Does offlineimap use tmp while it's delivering message and then move
> things to new? If so, then maybe all we need to do to fix notmuch to not
> look into tmp directories?

Yes, it does. I think all delivery agents work this way, IIRC the
reason why messages are first written in tmp and then moved to new is
to make sure that clients do not see partially written messages.
Maildir has been designed to be lock-less so this is needed.

I get errors about missing files too. There are several reasons why
that can happen:

 1) A message is moved from one folder to another in other mail
clients that work with
the Maildir spool.

 2) A client changes the flags on a message, for example, when you
read a message or
mark it as deleted. Maildir stores flags in filenames.

 3) Message flags are updated on the IMAP server (for example when you
mark a message
as read in gmail). Offlineimap keeps message flags synchronized.
If you mark a
local message as read then the change is propagated to the IMAP
server and vice
versa.

 -- Jan


[notmuch] [PATCH 2/2] notmuch list: A new command to produce various lists.

2009-11-21 Thread Jan Janak
On Thu, Nov 19, 2009 at 3:41 PM, Carl Worth  wrote:
> On Thu, 19 Nov 2009 12:52:49 +0100, Jan Janak  wrote:
>> I implemented a new notmuch command that can be used to list all tags
>> present in the database:
>
> Ah, very very interesting! I'd been planning on doing something like
> this soon. And I was just thinking of "notmuch tags" as the command
> line. What other ideas do you have in mind for "notmuch list" ?
>
> One way we could possibly do "notmuch tags" is to have it accept search
> terms and then return the list of all tags from the matched messages.
> Then of course we'd need a syntax for a search term to match all
> messages, (which we want in any case).
>
>> The main reason why I implemented this is because I am also working on
>> adding the tag completion feature to the Emacs mode. This is very
>> useful if you have a large collection of tags--it can save you some
>> typing and, perhaps more importantly, it minimizes the risk of having
>> typos in tag names. I'll send a patch for that later too.
>
> That will be a very nice feature to have, yes.
>
> The other reason I've wanted this is have something like a "folder view"
> that would show a list of tags and a number of messages with each tag,
> (or a number of messages with that tag and the inbox tag).
>
> I know that Keith said he'd prefer to use a view like that as his
> primary way of reading mail.
>
> Actual review of the patch later.

Carl and others,

My patch no longer works and I have been thinking about updating it to
current HEAD. But before I do that, I wanted to check with you to see
if you would prefer to use a different name for the command, here are
some options:

  1) notmuch tags
  2) notmuch list tags
  3) notmuch list-tag

Any opinions?

I also plan to add support for search-terms later so that we can
produce tag lists for a set of messages, as you mentioned in one of
your previous emails.

A quick description for those who joined later: This command produces
a list of all tags defined in the database. The emacs interface uses
it to implement tag name completion.

  -- Jan


[notmuch] Asynchronous tagging

2009-11-21 Thread Jan Janak
On Sat, Nov 21, 2009 at 10:04 PM, Jed Brown  wrote:
>> ?3) Message flags are updated on the IMAP server (for example when you
>> mark a message as read in gmail). Offlineimap keeps message flags
>> synchronized. ?If you mark a local message as read then the change is
>> propagated to the IMAP server and vice versa.
>
> Do you know if Offlineimap (or some similar tool) can be told not to
> bother keeping flags synchronized?

Try using the cmdline option -q, from offlineimap's help:

-q  Run  only quick synchronizations.   Ignore any flag updates on IMAP servers.

This kinda works, but even with this option I am still seeing missing
files if I work with my inbox in gmail. AFAIK there is currently no
easy way to prevent that.

  -- Jan


[notmuch] RFC: Multiple filenames for email messages

2009-11-21 Thread Jan Janak
The comment of _notmuch_message_set_filename says:

   XXX: We should still figure out if we think it's important to store
   multiple filenames for email messages with identical message IDs.

I have lots of such messages in my email collection, both in my local
copy of my Gmail account and also in the local copy of my company's
IMAP account.

My dream mail indexing tool should be able to apply tags automatically
based on, among other things, the name of the directory the message is
stored in. If there are multiple copies of the same message scattered
across multiple directories, I would like to apply more tags.

I assume that most tags will be applied (either manually or
automatically) after 'notmuch-new', I currently do some of it with a
simple shell script. The script does not apply tags based on directory
names yet, but it would make notmuch really flexible if we could do
that *and* if we could get access to all filenames of a particular
message.

I'd like to propose that we store all filenames for email messages in
the database, not just one per message. I'd be happy to work on it and
submit a patch if others think that this would be good to have.

  -- Jan


[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags

2009-11-22 Thread Jan Janak
On Sat, Nov 21, 2009 at 7:44 PM, Carl Worth  wrote:
> On Wed, 18 Nov 2009 05:57:03 +0100, Jan Janak  wrote:
>> This patch makes it possible to convert subdirectory names inside the
>> spool directory into message tags. Messages stored in subdirectory
>> "foo" will be marked with tag "foo". Message duplicates found in several
>> subdirectories will be given one tag per subdirectory.
>
> Hi Jan,
>
> I just pushed out a patch from Aneesh for similar functionality, but
> with a simpler implementation.
>
> One thing that patch loses is the addition of multiple tags when a
> message appears in multiple directories. Would you like to code up that
> feature on top of the current code?

Looking at the commit log history, I noticed that you reverted the
commit, so I guess this question is no more relevant.

By the way, although I provided a similar patch some time ago, I agree
that it is better not to have this hard-wired in 'notmuch-new'. It
helped me with the initial import, but since then I have been trying
to get it working with a script run after 'notmuch-new'.

   -- Jan


[notmuch] [PATCH] notmuch-new: Eliminate gcc warning caused by ino_cmp.

2009-11-22 Thread Jan Janak
The function passed to scandir in the fourth argument takes two
const void* arguments. To eliminate the gcc warning about incompatible
types, we change ino_cmp to match this and then re-type the parameters
in the body of ino_cmp.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 0dd2784..6db3d0f 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -75,9 +75,10 @@ add_files_print_progress (add_files_state_t *state)
 fflush (stdout);
 }

-static int ino_cmp(const struct dirent **a, const struct dirent **b)
+static int ino_cmp(const void *a, const void *b)
 {
-return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
+return ((*(const struct dirent**)a)->d_ino <
+   (*(const struct dirent**)b)->d_ino) ? -1 : 1;
 }

 /* Examine 'path' recursively as follows:
-- 
1.6.3.3



[notmuch] [PATCH] makefile: Tell echo to interpret escape sequences.

2009-11-22 Thread Jan Janak
The initial message that informs the user about the possibility to use
make V=1 contains a \n at the end, but echo wouldn't interpret that
properly without the -e command line option.
---
 Makefile |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Makefile b/Makefile
index ae8bff1..3553ff4 100644
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ include Makefile.config
 # user how to enable verbose compiles.
 ifeq ($(V),)
 quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
-quiet = @echo $(quiet_DOC)$(eval quiet_DOC:=)"  $1 $@"; $($1)
+quiet = @echo -e $(quiet_DOC)$(eval quiet_DOC:=)"  $1  $@"; $($1)
 endif
 # The user has explicitly enabled quiet compilation.
 ifeq ($(V),0)
-- 
1.6.3.3



[notmuch] [PATCH] makefile: Declare clean target as phony.

2009-11-22 Thread Jan Janak
This ensures that make clean always proceeds, even if the user
accidentally creates a file named 'clean'. Also, it ignores errors in
rm and other commands.

Signed-off-by: Jan Janak 
---
 Makefile |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index 3553ff4..2d19a6e 100644
--- a/Makefile
+++ b/Makefile
@@ -75,5 +75,6 @@ DEPS := $(SRCS:%.c=.deps/%.d)
 DEPS := $(DEPS:%.cc=.deps/%.d)
 -include $(DEPS)

+.PHONY : clean
 clean:
rm -f $(CLEAN); rm -rf .deps
-- 
1.6.3.3



[notmuch] [PATCH 3/3] notmuch.el: Select tag names with completion.

2009-11-23 Thread Jan Janak
Several commands ask the user for a tag name. With this feature the
user can just press tab and Emacs automatically retrieves the list of
all existing tags from notmuch database with 'notmuch search-tags' and
presents a completion buffer to the user.

This feature is very useful for users who have a large number of tags
because it saves typing and minimizes the risk of typos.

Signed-off-by: Jan Janak 
---
 notmuch.el |   22 +-
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 5927737..b6be395 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -139,6 +139,13 @@ within the current window."
   (or (memq prop buffer-invisibility-spec)
  (assq prop buffer-invisibility-spec)

+(defun notmuch-select-tag-with-completion (prompt)
+  (let ((tag-list
+(with-output-to-string
+  (with-current-buffer standard-output
+(call-process notmuch-command nil t nil "search-tags")
+(completing-read prompt (split-string tag-list "\n+" t) nil nil nil)))
+
 (defun notmuch-show-next-line ()
   "Like builtin `next-line' but ensuring we end on a visible character.

@@ -202,7 +209,8 @@ Unlike builtin `next-line' this version accepts no 
arguments."

 (defun notmuch-show-add-tag (&rest toadd)
   "Add a tag to the current message."
-  (interactive "sTag to add: ")
+  (interactive
+   (list (notmuch-select-tag-with-completion "Tag to add: ")))
   (apply 'notmuch-call-notmuch-process
 (append (cons "tag"
   (mapcar (lambda (s) (concat "+" s)) toadd))
@@ -211,7 +219,8 @@ Unlike builtin `next-line' this version accepts no 
arguments."

 (defun notmuch-show-remove-tag (&rest toremove)
   "Remove a tag from the current message."
-  (interactive "sTag to remove: ")
+  (interactive
+   (list (notmuch-select-tag-with-completion "Tag to remove: ")))
   (let ((tags (notmuch-show-get-tags)))
 (if (intersection tags toremove :test 'string=)
(progn
@@ -970,12 +979,14 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
(split-string (buffer-substring beg end))

 (defun notmuch-search-add-tag (tag)
-  (interactive "sTag to add: ")
+  (interactive
+   (list (notmuch-select-tag-with-completion "Tag to add: ")))
   (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete-dups (sort (cons tag 
(notmuch-search-get-tags)) 'string<

 (defun notmuch-search-remove-tag (tag)
-  (interactive "sTag to remove: ")
+  (interactive
+   (list (notmuch-select-tag-with-completion "Tag to remove: ")))
   (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags

@@ -1061,7 +1072,8 @@ current search results AND the additional query string 
provided."

 Runs a new search matching only messages that match both the
 current search results AND that are tagged with the given tag."
-  (interactive "sFilter by tag: ")
+  (interactive
+   (list (notmuch-select-tag-with-completion "Filter by tag: ")))
   (notmuch-search (concat notmuch-search-query-string " and tag:" tag) 
notmuch-search-oldest-first))

 (defun notmuch ()
-- 
1.6.3.3



[notmuch] [PATCH 2/3] notmuch: New command 'search-tags'.

2009-11-23 Thread Jan Janak
This is a new notmuch command that can be used to search for all tags
found in the database. The resulting list is alphabetically sorted.

The primary use-case for this new command is to provide the tag
completion feature in Emacs (and other interfaces).

Signed-off-by: Jan Janak 
---
 Makefile.local|1 +
 notmuch-client.h  |3 ++
 notmuch-search-tags.c |   71 +
 notmuch.c |6 
 4 files changed, 81 insertions(+), 0 deletions(-)
 create mode 100644 notmuch-search-tags.c

diff --git a/Makefile.local b/Makefile.local
index 2828659..d8f7906 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -12,6 +12,7 @@ notmuch_client_srcs = \
notmuch-reply.c \
notmuch-restore.c   \
notmuch-search.c\
+   notmuch-search-tags.c   \
notmuch-setup.c \
notmuch-show.c  \
notmuch-tag.c   \
diff --git a/notmuch-client.h b/notmuch-client.h
index ea77686..c6142b5 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -114,6 +114,9 @@ notmuch_show_command (void *ctx, int argc, char *argv[]);
 int
 notmuch_tag_command (void *ctx, int argc, char *argv[]);

+int
+notmuch_search_tags_command (void *ctx, int argc, char *argv[]);
+
 const char *
 notmuch_time_relative_date (const void *ctx, time_t then);

diff --git a/notmuch-search-tags.c b/notmuch-search-tags.c
new file mode 100644
index 000..1201165
--- /dev/null
+++ b/notmuch-search-tags.c
@@ -0,0 +1,71 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright ?? 2009 Carl Worth
+ * Copyright ?? 2009 Jan Janak
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Jan Janak 
+ */
+
+#include "notmuch-client.h"
+
+static int
+list_all_tags (notmuch_database_t* db)
+{
+notmuch_tags_t* tags;
+const char* t;
+
+if ((tags = notmuch_database_get_all_tags (db)) == NULL) {
+   fprintf (stderr, "Error while obtaining tags from the database.\n");
+   return 1;
+}
+
+while((t = notmuch_tags_get (tags))) {
+   printf ("%s\n", t);
+   notmuch_tags_advance (tags);
+}
+
+notmuch_tags_destroy (tags);
+return 0;
+}
+
+int
+notmuch_search_tags_command (void *ctx, int argc, char *argv[])
+{
+notmuch_config_t *config;
+notmuch_database_t *db;
+
+config = NULL;
+db = NULL;
+
+if ((config = notmuch_config_open (ctx, NULL, NULL)) == NULL) {
+   goto error;
+}
+
+db = notmuch_database_open (notmuch_config_get_database_path (config),
+   NOTMUCH_DATABASE_MODE_READ_ONLY);
+if (db == NULL) {
+   goto error;
+}
+
+if (list_all_tags (db) != 0) goto error;
+
+notmuch_database_close (db);
+return 0;
+
+error:
+if (db) notmuch_database_close (db);
+return 1;
+}
diff --git a/notmuch.c b/notmuch.c
index 5cc8e4c..b1d7cf9 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -230,6 +230,12 @@ command_t commands[] = {
   "\t\tSo if you've previously been using sup for mail, then the\n"
   "\t\t\"notmuch restore\" command provides you a way to import\n"
   "\t\tall of your tags (or labels as sup calls them)." },
+{ "search-tags", notmuch_search_tags_command,
+  NULL,
+  "List all tags found in the database.",
+  "\t\tThis command returns an alphabetically sorted list of all tags\n"
+  "\t\tthat are present in the database. In other words, the resulting\n"
+  "\t\tlist is a collection of all tags from all messages." },
 { "help", notmuch_help_command,
   "[]",
   "\t\tThis message, or more detailed help for the named command.",
-- 
1.6.3.3



[notmuch] [PATCH 1/3] notmuch: New function to retrieve all tags from the database.

2009-11-23 Thread Jan Janak
This patch adds a new function called notmuch_database_get_all_tags
which can be used to obtain a list of all tags from the database
(in other words, the list contains all tags from all messages). The
function produces an alphabetically sorted list.

To add support for the new function, we rip the guts off of
notmuch_message_get_tags and put them in a new generic function
called _notmuch_convert_tags. The generic function takes a
Xapian::TermIterator as argument and uses the iterator to find tags.
This makes the function usable with different Xapian objects.

Function notmuch_message_get_tags is then reimplemented to call the
generic function with message->doc.termlist_begin() as argument.

Similarly, we implement notmuch_message_database_get_all_tags, the
function calls the generic function with db->xapian_db->allterms_begin()
as argument.

Finally, notmuch_database_get_all_tags is exported through
lib/notmuch.h

Signed-off-by: Jan Janak 
---
 lib/database-private.h |   13 +
 lib/database.cc|   43 +++
 lib/message.cc |   34 +++---
 lib/notmuch.h  |   10 ++
 4 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/lib/database-private.h b/lib/database-private.h
index 5f178f3..37f9bf8 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -34,4 +34,17 @@ struct _notmuch_database {
 Xapian::TermGenerator *term_gen;
 };

+/* Convert tags from Xapian internal format to notmuch format.
+ *
+ * The function gets a TermIterator as argument and uses that iterator to find
+ * all tag terms in the object. The tags are then converted to a
+ * notmuch_tags_t list and returned. The function needs to allocate memory for
+ * the resulting list and it uses the argument ctx as talloc context.
+ *
+ * The function returns NULL on failure.
+ */
+notmuch_tags_t *
+_notmuch_convert_tags (void *ctx, Xapian::TermIterator &i,
+  Xapian::TermIterator &end);
+
 #endif
diff --git a/lib/database.cc b/lib/database.cc
index 2c90019..5d2add7 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1026,3 +1026,46 @@ notmuch_database_add_message (notmuch_database_t 
*notmuch,

 return ret;
 }
+
+notmuch_tags_t *
+_notmuch_convert_tags (void *ctx, Xapian::TermIterator &i,
+  Xapian::TermIterator &end)
+{
+const char *prefix = _find_prefix ("tag");
+notmuch_tags_t *tags;
+std::string tag;
+
+/* Currently this iteration is written with the assumption that
+ * "tag" has a single-character prefix. */
+assert (strlen (prefix) == 1);
+
+tags = _notmuch_tags_create (ctx);
+if (unlikely (tags == NULL))
+   return NULL;
+
+i.skip_to (prefix);
+
+while (i != end) {
+   tag = *i;
+
+   if (tag.empty () || tag[0] != *prefix)
+   break;
+
+   _notmuch_tags_add_tag (tags, tag.c_str () + 1);
+
+   i++;
+}
+
+_notmuch_tags_prepare_iterator (tags);
+
+return tags;
+}
+
+notmuch_tags_t *
+notmuch_database_get_all_tags (notmuch_database_t *db)
+{
+Xapian::TermIterator i, end;
+i = db->xapian_db->allterms_begin();
+end = db->xapian_db->allterms_end();
+return _notmuch_convert_tags(db, i, end);
+}
diff --git a/lib/message.cc b/lib/message.cc
index 017c47b..d27ea92 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -459,38 +459,10 @@ notmuch_message_get_date (notmuch_message_t *message)
 notmuch_tags_t *
 notmuch_message_get_tags (notmuch_message_t *message)
 {
-const char *prefix = _find_prefix ("tag");
 Xapian::TermIterator i, end;
-notmuch_tags_t *tags;
-std::string tag;
-
-/* Currently this iteration is written with the assumption that
- * "tag" has a single-character prefix. */
-assert (strlen (prefix) == 1);
-
-tags = _notmuch_tags_create (message);
-if (unlikely (tags == NULL))
-   return NULL;
-
-i = message->doc.termlist_begin ();
-end = message->doc.termlist_end ();
-
-i.skip_to (prefix);
-
-while (i != end) {
-   tag = *i;
-
-   if (tag.empty () || tag[0] != *prefix)
-   break;
-
-   _notmuch_tags_add_tag (tags, tag.c_str () + 1);
-
-   i++;
-}
-
-_notmuch_tags_prepare_iterator (tags);
-
-return tags;
+i = message->doc.termlist_begin();
+end = message->doc.termlist_end();
+return _notmuch_convert_tags(message, i, end);
 }

 void
diff --git a/lib/notmuch.h b/lib/notmuch.h
index a61cd02..e2f1398 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -280,6 +280,16 @@ notmuch_message_t *
 notmuch_database_find_message (notmuch_database_t *database,
   const char *message_id);

+/* Return a list of all tags found in the database.
+ *
+ * This function creates a list of all tags found in the database. The
+ * resulting list contains all tags from all messages

[notmuch] search-tags and tag completion in notmuch.el

2009-11-23 Thread Jan Janak
Hello,

The three patches I sent to the list a couple of minutes ago is another
revision of the patches that I had sent earlier. The first two patches
implement support for 'notmuch search-tags'. The last patch adds support
for tag completion to notmuch.el using the new command.

Right now 'notmuch search-tags' can only list all tags from the
database, it does not support search-terms yet (i.e. it cannot list tags
for a restricted set of messages or threads), but I am working on that
feature and I'm gonna send another patch implementing that soon. I think
sending more smaller incremental patches makes it easier to review them
(and for me personally it is easier to keep them up-to-date on top of
moving Carl's git repository).

I considered implementing 'notmuch search --output=tags' (as we
discussed in another email), but it turned out that:

  * Having 'notmuch search-tags' would be consistent with Carl's
'notmuch search-messages'.

  * 'notmuch search' supports other command line options (--first,
--max-threads, --sort) and these would only work when the user uses
the command to search for messages. They would probably be useless
if we use the command to search for tags and messages (well, at
least some of them). Which means we would have to let the user know
in the documentation, or disable some of them based on the value of
the --output command line parameter, etc etc...

  * 'notmuch search-tags' is easier on fingers than 
'notmuch search --output=tags' :-).

In any case, we should probably keep it consistent with other commands
and because Carl submitted 'notmuch search-messages", I did the same for
tags.

I'd personally prefer to use different commands for different kinds of
output rather than overloading 'notmuch search' with more command line
options, but it's just a personal preference. I can change the patch
again if we decide that we're going to overload 'notmuch search' rather
than add more commands.

Comments, ideas, and suggestions are welcome!

  -- Jan


[notmuch] [PATCH] notmuch-new: Eliminate gcc warning caused by ino_cmp.

2009-11-23 Thread Jan Janak
On Mon, Nov 23, 2009 at 3:38 AM, Carl Worth  wrote:
> On Sun, 22 Nov 2009 13:32:36 +0100, Jan Janak  wrote:
>> The function passed to scandir in the fourth argument takes two
>> const void* arguments. To eliminate the gcc warning about incompatible
>> types, we change ino_cmp to match this and then re-type the parameters
>> in the body of ino_cmp.
>
> Actually, on my system at least, (Linux with glibc 2.10.1), our current
> function matches the prototype. So applying your patch actually
> *introduces* a warning where there was no warning before.
>
> What a nuisance...
>
> Any ideas for a good fix, anyone?

OK, I have an older version of glibc. If the original code works with
glibc 2.10 then just ignore the patch. I think testing for a
particular version of glibc is not worth the effort (it's just a
warning anyway).

  -- Jan


[notmuch] [PATCH] makefile: Tell echo to interpret escape sequences.

2009-11-23 Thread Jan Janak
On Mon, Nov 23, 2009 at 3:41 AM, Carl Worth  wrote:
> On Sun, 22 Nov 2009 13:44:37 +0100, Jan Janak  wrote:
>> The initial message that informs the user about the possibility to use
>> make V=1 contains a \n at the end, but echo wouldn't interpret that
>> properly without the -e command line option.
>
> Patch doesn't work for me.
>
> Before patch:
>
> ? ? ? ?0:~/src/notmuch:(master)$ make
> ? ? ? ?Use "make V=1" to see the verbose compile lines.
> ? ? ? ? ?CC ? ?notmuch-new.o
> ? ? ? ? ?CXX ? notmuch
>
> After patch:
>
> ? ? ? ?0:~/src/notmuch:(master)$ make
> ? ? ? ?-e Use "make V=1" to see the verbose compile lines.
> ? ? ? ? ?CC ? ?debugger.o
> ? ? ? ?-e ? CC gmime-filter-reply.o
> ? ? ? ?-e ? CC notmuch.o
>
> It's a shame that simple things like "echo" aren't easy to use portably.
> (And yes, I know that autoconf has a bunch of tests for echo, such as
> how to get the behavior of "echo -n", etc.)

It seems your echo interprets escape sequences by default. When I run
make, the first line of output looks like this:

Use "make V=1" to see the verbose compile lines.\n  CC  debugger.o
  CCgmime-filter-reply.o
  CCnotmuch.o

This is on Debian Lenny. Anyway, this one is not important either.

  -- Jan


[notmuch] [PATCH 3/3] change config file location to be ~/.notmuch/config

2009-11-24 Thread Jan Janak
On Mon, Nov 23, 2009 at 5:55 AM, Carl Worth  wrote:
> On Sun, 22 Nov 2009 18:14:20 -0500, Jameson Graef Rollins  finestructure.net> wrote:
>> I think Carl said he wanted to keep the ability to specify exactly
>> where the database is stored, so if we could move away from something
>> that makes any implicit assumptions about relative paths between the
>> database and the maildir, then all should be ok.
>
> Well, I chose the relative-path assumptions intentionally. The idea is
> that if I move my mail from ~/Mail to ~/mail then the .notmuch directory
> moves with it and everything continues to work just fine.

Yeah, having relative paths in the database is a really good thing,
IMHO. I was pleasantly surprised that notmuch continued working after
I moved my mail from one directory to another :-).

  -- Jan


[notmuch] notmuch 'index' mode.

2009-11-24 Thread Jan Janak
On Tue, Nov 24, 2009 at 4:16 AM, Carl Worth  wrote:
> And notice, I don't think we'll need to do the "virtual tag" thing of
> associating a tag name with a search and doing the work of making
> notmuch maintain the consistency of that tag and search string. It will
> be much more clean (and shouldn't be any less fast) to just do the
> searches for the original search terms, (rather than searching for tag
> terms that were previously applied by searching for the search terms).
>
> Then tags become something that are just for manual manipulation. What
> do you think?

I like this. I think this is much cleaner than the "virtual tag" approach.

  -- Jan


[notmuch] notmuch 'index' mode.

2009-11-24 Thread Jan Janak
On 24-11 08:38, Keith Packard wrote:
> On Tue, 24 Nov 2009 13:14:07 +0100, Jan Janak  wrote:
> 
> > I like this. I think this is much cleaner than the "virtual tag"
> > approach.
> 
> A disadvantage I see is that you would not see this 'virtual tags' in
> the list of tags on each message. 

Maybe I don't understand how virtual tags are really supposed to work. I
thought that the term "virtual tags" is just another name for "named" search
terms and it is named "virtual tags" because they can actually be attached to
messages stored in the database. And if I remember it correctly, Carl said
somewhere that virtual tags will be added/removed automatically to messages if
the corresponding search term gets changed.

If my understanding is correct, then we won't be able to show virtual tags
along with "normal" tags anyway. We would probably need a separate list just
for virtual tags. One of the reasons is that you can add and remove normal
tags to messages manually, but you cannot easily do the same with virtual
tags.

If you remove a virtual tag from a message and then update the search term
bound to that virtual tag, as soon as you change the search term, the virtual
tag might be added to the message again if the new search expression still
matches the message.

Unlike real tags, the user won't be able to add and remove virtual tags to
messages arbitrarily without the risk that notmuch changes the selection
behind his back on the next update of the configuration file (assuming that
the search expression is stored in the configuration file).

We would probably need to make sure that the user knows which tags are virtual
and which are real and that means notmuch would have to present them
differently, possibly in a separate list.

Thinking more about this, we could probably make it possible to add and remove
virtual tags to messages manually by storing the information about what the
user did with the virtual tag along with the message (i.e. this virtual tag is
pinned to the message so don't remove it when the search term is changed).

Maybe I just don't understand how virtual tags are really supposed to work,
but it seems to me as a can of worms just waiting to be opened :-).

  -- Jan


[notmuch] [PATCH 1/4] notmuch-new: Remove tag_add_inbox_unread in favor of a generic solution.

2009-11-24 Thread Jan Janak
Instead of adding 'inbox' and 'unread' tags directly in the code of
'notmuch-new', we can specify a list of tags to be added to newly
created messages with a configuration file option or a command line
option. That's more flexible, it allows the user to select which tags
should be added.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |8 
 1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index e32b92a..9970407 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -41,13 +41,6 @@ handle_sigint (unused (int sig))
 }

 static void
-tag_inbox_and_unread (notmuch_message_t *message)
-{
-notmuch_message_add_tag (message, "inbox");
-notmuch_message_add_tag (message, "unread");
-}
-
-static void
 add_files_print_progress (add_files_state_t *state)
 {
 struct timeval tv_now;
@@ -198,7 +191,6 @@ add_files_recursive (notmuch_database_t *notmuch,
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
-   tag_inbox_and_unread (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-- 
1.6.3.3



[notmuch] [PATCH 2/4] notmuch: Config option to specify tags to be applied by 'notmuch new'.

2009-11-24 Thread Jan Janak
Add support for section [new] in the configuration file. This section
is supposed to contain options for 'notmuch new'. Currently there is
only one option called tags.

The tags option can be used to configure a set of tags to be applied
by 'notmuch new'. Individual tags are separated by semicolon.

'notmuch new' is modified not to apply 'inbox' and 'unread' by default,
but instead it obtains the set of tags to be applied from the new
configuration file option.

Signed-off-by: Jan Janak 
---
 notmuch-client.h |3 +++
 notmuch-config.c |   44 
 notmuch-new.c|   19 ++-
 3 files changed, 65 insertions(+), 1 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index c04eaeb..0fb9c19 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -184,6 +184,9 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 const char *other_email[],
 size_t length);

+char **
+notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length);
+
 notmuch_bool_t
 debugger_is_active (void);

diff --git a/notmuch-config.c b/notmuch-config.c
index fc65d6b..7f62a80 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -22,6 +22,7 @@

 #include 
 #include 
+#include 

 static const char toplevel_config_comment[] =
 " .notmuch-config - Configuration file for the notmuch mail system\n"
@@ -62,6 +63,9 @@ struct _notmuch_config {
 char *user_primary_email;
 char **user_other_email;
 size_t user_other_email_length;
+
+char **new_tags;
+size_t new_tags_length;
 };

 static int
@@ -199,6 +203,8 @@ notmuch_config_open (void *ctx,
 config->user_primary_email = NULL;
 config->user_other_email = NULL;
 config->user_other_email_length = 0;
+config->new_tags = NULL;
+config->new_tags_length = 0;

 if (! g_key_file_load_from_file (config->key_file,
 config->filename,
@@ -450,3 +456,41 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 talloc_free (config->user_other_email);
 config->user_other_email = NULL;
 }
+
+char **
+notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
+{
+char **tags;
+size_t len;
+unsigned int i;
+char *start, *end;
+
+if (config->new_tags == NULL) {
+   config->new_tags_length = 0;
+   tags = g_key_file_get_string_list (config->key_file, "new", "tags",
+  &len, NULL);
+
+   if (tags) {
+   config->new_tags = talloc_size (config, sizeof(char*) *
+   (len + 1));
+   for (i = 0; i < len; i++) {
+   /* Remove leading and trailing white space around the tag and
+* filter out empty tags. */
+   start = tags[i];
+   end = start + strlen (start) - 1;
+   while (isspace (*start)) start++;
+   while (end > start && isspace (*end)) end--;
+   if (end >= start) {
+   config->new_tags[config->new_tags_length++] =
+   talloc_strndup (config->new_tags, start,
+   end - start + 1);
+   }
+   }
+   config->new_tags[config->new_tags_length] = NULL;
+   g_strfreev (tags);
+   }
+}
+
+*length = config->new_tags_length;
+return config->new_tags;
+}
diff --git a/notmuch-new.c b/notmuch-new.c
index 9970407..10745e8 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -24,6 +24,8 @@

 static volatile sig_atomic_t do_add_files_print_progress = 0;

+static notmuch_config_t *config = NULL;
+
 static void
 handle_sigalrm (unused (int signal))
 {
@@ -68,6 +70,21 @@ add_files_print_progress (add_files_state_t *state)
 fflush (stdout);
 }

+static void
+apply_tags (notmuch_message_t *message)
+{
+char** tags;
+unsigned int count, i;
+
+if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
+   return;
+
+for (i = 0; i < count; i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+}
+}
+
 static int ino_cmp(const struct dirent **a, const struct dirent **b)
 {
 return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
@@ -191,6 +208,7 @@ add_files_recursive (notmuch_database_t *notmuch,
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
+   apply_tags (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
@@ -388,7 +406,6 @@ count_files (const char *path, int *count)
 int
 not

[notmuch] [PATCH 4/4] notmuch-new: New cmdline option --tag=.

2009-11-24 Thread Jan Janak
The list of tags to be applied by 'notmuch new' can be configured in
the configuration file. This command line option can be used to
override the list of tags from the coonfiguration file on the command
line. You may repeat the option several times if you want to apply
more than one tag:

  notmuch new --tag=apple --tag=orange

This is useful, for example, if you have an archive of messages you
would like to add to the database with a special tag so that they can
be easily identified later. To do that, you could simply copy the files
from the archive to the database directory and then index them all with:

  notmuch new --tag=prehistory

Tags to be applied every time 'notmuch new' is run can be specified in
the configuration file. One-time tags for individual runs can be
specified on the command line with this new option.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   40 ++--
 notmuch.c |8 +++-
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 10745e8..94036da 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -26,6 +26,9 @@ static volatile sig_atomic_t do_add_files_print_progress = 0;

 static notmuch_config_t *config = NULL;

+static char **cmdline_tags = NULL;
+static unsigned int cmdline_tags_count = 0;
+
 static void
 handle_sigalrm (unused (int signal))
 {
@@ -76,12 +79,19 @@ apply_tags (notmuch_message_t *message)
 char** tags;
 unsigned int count, i;

-if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
-   return;
+if (cmdline_tags_count) {
+   for (i = 0; i < cmdline_tags_count; i++) {
+   if (cmdline_tags[i])
+   notmuch_message_add_tag (message, cmdline_tags[i]);
+   }
+} else {
+   if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
+   return;

-for (i = 0; i < count; i++) {
-   if (tags[i])
-   notmuch_message_add_tag (message, tags[i]);
+   for (i = 0; i < count; i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+   }
 }
 }

@@ -413,7 +423,8 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 int ret = 0;
 struct stat st;
 const char *db_path;
-char *dot_notmuch_path;
+char *dot_notmuch_path, *opt;
+char **tmp;
 struct sigaction action;
 int i;

@@ -423,6 +434,23 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 for (i = 0; i < argc && argv[i][0] == '-'; i++) {
if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {
add_files_state.verbose = 1;
+   } else if (STRNCMP_LITERAL (argv[i], "--tag=") == 0) {
+   opt = argv[i] + sizeof ("--tag=") - 1;
+   /* FIXME: We should check for leading and trailing white-space in
+* option value here and remove it.
+*/
+   if (*opt == '\0') {
+   fprintf (stderr, "Option value missing: %s\n", argv[i]);
+   return 1;
+   }
+   tmp = talloc_realloc (ctx, cmdline_tags, char*,
+ cmdline_tags_count + 1);
+   if (tmp == NULL) {
+   fprintf (stderr, "Notmuch ran out of memory.\n");
+   return 1;
+   }
+   tmp[cmdline_tags_count++] = opt;
+   cmdline_tags = tmp;
} else {
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
return 1;
diff --git a/notmuch.c b/notmuch.c
index b84e284..fb0c2a7 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -123,7 +123,7 @@ command_t commands[] = {
   "\t\tInvoking notmuch with no command argument will run setup if\n"
   "\t\tthe setup command has not previously been completed." },
 { "new", notmuch_new_command,
-  "[--verbose]",
+  "[--verbose] [--tag=]",
   "\t\tFind and import new messages to the notmuch database.",
   "\t\tScans all sub-directories of the mail directory, performing\n"
   "\t\tfull-text indexing on new messages that are found. Each new\n"
@@ -145,6 +145,12 @@ command_t commands[] = {
   "\t\t\tVerbose operation. Shows paths of message files as\n"
   "\t\t\tthey are being indexed.\n"
   "\n"
+  "\t\t--tag=\n"
+  "\n"
+  "\t\t\tAdd the tag  to all messages newly added to the\n"
+  "\t\t\tdatabase. You may repeat this option several times if\n"
+  "\t\t\tyou want to add more tags.\n"
+  "\n"
   "\t\tNote: \"notmuch new\" runs (other than the first run) will\n"
   "\t\tskip any read-only directories, so you can use that to mark\n"
   "\t\tdirectories that will not receive any new mail (and make\n"
-- 
1.6.3.3



[notmuch] [PATCH 0/4] Make tags applied by 'notmuch new' configurable.

2009-11-24 Thread Jan Janak
I would like to propose that we make the list of tags applied by 'notmuch new'
configurable. Right now notmuch applies two tags to all new messages added to
the database, 'inbox' and 'unread'. The two tags are added by the C code in
notmuch-new.c and they cannot be changed without editing the source file and
recompiling notmuch.

The four patches that follow this email allow for configuring the tags to be
added by 'notmuch new' either in the configuration file or on the command
line.

This change was motivated by my desire to remove both tags from newly added
messages. My rules for adding these two tags are more complex and I do it in
a script run after 'notmuch new'. Instead of 'inbox' and 'unread', I configure
'notmuch new' to add a new tag called 'new' (and only that one). This tag
marks newly added messages that haven't been properly tagged yet by my 
auto-tagging scripts. The last script I run after 'notmuch new' removes that
tag. My auto-tagging scripts process only messages with the tag 'new'.

On a side note; It may seem logical to add/omit the tag 'unread' directly in 
'notmuch new' based on the Maildir flags extracted from the filename of the
message. I suggest that we don't do that in 'notmuch new'. A better way would
be writing a small script or command that can be run *after* 'notmuch new'.
We could then distribute it with notmuch (maybe with other small tagging
scripts for common situations). 

I think Maildir flags should be processed after 'notmuch new' is because if
there are multiple copies of a message with different flags, we may need to
see all flags from all filenames to set corresponding tags properly and we may
also need to take the directory part into consideration (i.e. the new mail is
in 'new', not 'cur').

The list of tags to be applied by notmuch can be configured in the
configuration file. There is a new section [new] which contains configuration
options for 'notmuch new'. There is only one option called 'tags'. The option
contains a semicolon separated list of tags:

  [new]
  tags=inbox;unread  # Emulate the original behavior

One of the patches updates 'notmuch setup' to create the section and add
the tags option with tags 'inbox' and 'unread', but only if a new
configuration file is being created. If the configuration file already exists
then it just copies the contents from the old configuration file to the new
one.

We do not ask the user for the list of tags in the interactive part, that would
have been too much. Users can edit the configuration file manually if they want
to change the list of tags. If they create a new configuration file then they
probably want to accept the default anyway.

There is one catch for users who already have a configuration file and start
using the patches. They will need to add the new section and the tags option
manually if they want to preserve current behavior of applying 'inbox' and
'unread' automatically by 'notmuch new'.

The last patch in the set adds a new command line option to 'notmuch new'.
The name of the option is --tag and it can be used to override any tags
configured in the configuration file. For example:

  notmuch new --tag=outbox --tag=read

adds the tags 'outbox' and 'read' and ignores any tags from the configuration
file.

Comments and opinions are welcome!

   -- Jan


[notmuch] [PATCH 3/4] notmuch-setup: Copy/create the new section with tags for 'notmuch-new'.

2009-11-24 Thread Jan Janak
If the user runs 'notmuch setup' and there is no configuration file yet
then we also add the new section [new] to the configuration file and
set the tags option as:

  tags=inbox;unread

This will be picked up by 'notmuch new' and all new mail added to the
database will be tagged with the two tags as before.

If the user already has a configuration file and runs 'notmuch setup'
then we just copy whatever tags we find in the old configuration file
to the new one. If there are no tags in the old configuration file then
we assume that the user configured notmuch that way and the new config
file would also have no tags in the section [new].

We never ask the user interactively for the list of tags to be used by
'notmuch new', it is assumed that beginners would want to stick to the
defaults and advanced users can edit the configuration manually.

Signed-off-by: Jan Janak 
---
 notmuch-client.h |4 
 notmuch-config.c |   40 
 notmuch-setup.c  |   14 ++
 3 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 0fb9c19..bb7d3d4 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -187,6 +187,10 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 char **
 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length);

+void
+notmuch_config_set_new_tags (notmuch_config_t *config, const char *tags[],
+size_t length);
+
 notmuch_bool_t
 debugger_is_active (void);

diff --git a/notmuch-config.c b/notmuch-config.c
index 7f62a80..e884621 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -54,6 +54,16 @@ static const char user_config_comment[] =
 " recipient list of replies, and will set the From address based on the\n"
 " address to which the original email was addressed.\n";

+static const char new_config_comment[] =
+" Configuration section for 'notmuch new'\n"
+"\n"
+" The only supported value at the moment is 'tags. This option contains 
a\n"
+" list of tags (separated by ';') that should be  automatically applied 
to\n"
+" newly added messages.\n"
+"\n"
+" Note that 'notmuch new' also has a command line option which can be 
used\n"
+" to add additional tags to the ones configured here.\n";
+
 struct _notmuch_config {
 char *filename;
 GKeyFile *key_file;
@@ -174,6 +184,7 @@ notmuch_config_open (void *ctx,
 GError *error = NULL;
 int is_new = 0;
 char *notmuch_config_env = NULL;
+const char* def_new_tags[2] = {"inbox", "unread"};

 if (is_new_ret)
*is_new_ret = 0;
@@ -270,6 +281,20 @@ notmuch_config_open (void *ctx,
}
 }

+/* If we have no configuration file then we configure "inbox" and "unread"
+ * tags by default for 'notmuch new'. This ensures that the Emacs mode
+ * would still work as expected.
+ *
+ * We do not ask the user for tags to be used by 'notmuch new'. That's too
+ * much detail for beginners and others can edit the configuration file by
+ * hand.
+ */
+if (is_new) {
+   notmuch_config_set_new_tags (config, def_new_tags,
+sizeof(def_new_tags) /
+sizeof(const char*));
+}
+
 /* When we create a new configuration file here, we  add some
  * comments to help the user understand what can be done. */
 if (is_new) {
@@ -279,6 +304,8 @@ notmuch_config_open (void *ctx,
database_config_comment, NULL);
g_key_file_set_comment (config->key_file, "user", NULL,
user_config_comment, NULL);
+   g_key_file_set_comment (config->key_file, "new", NULL,
+   new_config_comment, NULL);
 }

 if (is_new_ret)
@@ -494,3 +521,16 @@ notmuch_config_get_new_tags (notmuch_config_t *config, 
size_t *length)
 *length = config->new_tags_length;
 return config->new_tags;
 }
+
+void
+notmuch_config_set_new_tags (notmuch_config_t *config,
+const char *tags[],
+size_t length)
+{
+g_key_file_set_string_list (config->key_file,
+   "new", "tags",
+   tags, length);
+
+talloc_free (config->new_tags);
+config->user_other_email = NULL;
+}
diff --git a/notmuch-setup.c b/notmuch-setup.c
index d06fbf8..c1406db 100644
--- a/notmuch-setup.c
+++ b/notmuch-setup.c
@@ -96,6 +96,8 @@ notmuch_setup_command (unused (void *ctx),
 notmuch_config_t *config;
 char **old_other_emails;
 size_t old_other_emails_len;
+char **new_tags;
+

[notmuch] [PATCH 2/2] search-tags: Add support for search-terms.

2009-11-25 Thread Jan Janak
This patch adds support for search-terms to 'notmuch search-tags'. If
no search-term is provided then the command returns a list of all tags
from the database.

If the user provides one or more search-terms as arguments then the
command collects tags from matching messages only.

This could be used by functions in the Emacs mode to further limit the
list of tags offered for completion. For example, functions that remove
tags from message(s) could offer only tags present in the message(s).

Signed-off-by: Jan Janak 
---
 notmuch-search-tags.c |   55 
 notmuch.c |   13 +++
 2 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/notmuch-search-tags.c b/notmuch-search-tags.c
index 1201165..7a1305e 100644
--- a/notmuch-search-tags.c
+++ b/notmuch-search-tags.c
@@ -21,34 +21,31 @@

 #include "notmuch-client.h"

-static int
-list_all_tags (notmuch_database_t* db)
+static void
+print_tags (notmuch_tags_t *tags)
 {
-notmuch_tags_t* tags;
-const char* t;
+const char *t;

-if ((tags = notmuch_database_get_all_tags (db)) == NULL) {
-   fprintf (stderr, "Error while obtaining tags from the database.\n");
-   return 1;
-}
-
-while((t = notmuch_tags_get (tags))) {
+while ((t = notmuch_tags_get (tags))) {
printf ("%s\n", t);
notmuch_tags_advance (tags);
 }
-
-notmuch_tags_destroy (tags);
-return 0;
 }

 int
 notmuch_search_tags_command (void *ctx, int argc, char *argv[])
 {
+notmuch_messages_t *msgs;
+notmuch_tags_t *tags;
 notmuch_config_t *config;
 notmuch_database_t *db;
+notmuch_query_t *query;
+char *query_str;

+tags = NULL;
 config = NULL;
 db = NULL;
+query = NULL;

 if ((config = notmuch_config_open (ctx, NULL, NULL)) == NULL) {
goto error;
@@ -60,12 +57,42 @@ notmuch_search_tags_command (void *ctx, int argc, char 
*argv[])
goto error;
 }

-if (list_all_tags (db) != 0) goto error;
+if (argc > 0) {
+   if ((query_str = query_string_from_args (ctx, argc, argv)) == NULL) {
+   fprintf (stderr, "Out of memory.\n");
+   goto error;
+   }
+
+   if (*query_str == '\0') {
+   fprintf (stderr, "Error: Invalid search string.\n");
+   goto error;
+   }
+
+   if ((query = notmuch_query_create (db, query_str)) == NULL) {
+   fprintf (stderr, "Out of memory\n");
+   goto error;
+   }
+
+
+   msgs = notmuch_query_search_messages (query);
+   if ((tags = notmuch_messages_collect_tags (msgs)) == NULL) goto error;
+} else {
+   if ((tags = notmuch_database_get_all_tags (db)) == NULL) {
+   fprintf (stderr, "Error while getting tags from the database.\n");
+   goto error;
+   }
+}
+
+print_tags (tags);

+notmuch_tags_destroy (tags);
+if (query) notmuch_query_destroy (query);
 notmuch_database_close (db);
 return 0;

 error:
+if (tags) notmuch_tags_destroy (tags);
+if (query) notmuch_query_destroy (query);
 if (db) notmuch_database_close (db);
 return 1;
 }
diff --git a/notmuch.c b/notmuch.c
index c57bb5c..5b0284c 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -255,11 +255,14 @@ command_t commands[] = {
   "\t\t\"notmuch restore\" command provides you a way to import\n"
   "\t\tall of your tags (or labels as sup calls them)." },
 { "search-tags", notmuch_search_tags_command,
-  NULL,
-  "List all tags found in the database.",
-  "\t\tThis command returns an alphabetically sorted list of all tags\n"
-  "\t\tthat are present in the database. In other words, the resulting\n"
-  "\t\tlist is a collection of all tags from all messages." },
+  "[ [...] ]",
+  "\t\tList all tags found in the database or matching messages.",
+  "\t\tRun this command without any search-term(s) to obtain a list\n"
+  "\t\tof all tags found in the database. If you provide one or more\n"
+  "\t\tsearch-terms as argument(s) then the resulting list will\n"
+  "\t\tcontain tags only from messages that match the search-term(s).\n"
+  "\n"
+  "\t\tIn both cases the list will be alphabetically sorted." },
 { "help", notmuch_help_command,
   "[]",
   "\t\tThis message, or more detailed help for the named command.",
-- 
1.6.3.3



[notmuch] [PATCH 1/2] lib: New function to collect tags from a list of messages.

2009-11-25 Thread Jan Janak
This patch adds a new function that can be used to collect a list of
unique tags from a list of messages. 'notmuch search-tags' uses the
function to get a list of tags from messages matching a search-term,
but it has the potential to be used elsewhere so we put it in the lib.

Signed-off-by: Jan Janak 
---
 lib/messages.c |   40 
 lib/notmuch.h  |   15 +++
 2 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/lib/messages.c b/lib/messages.c
index 54c0ab0..aa92535 100644
--- a/lib/messages.c
+++ b/lib/messages.c
@@ -20,6 +20,8 @@

 #include "notmuch-private.h"

+#include 
+
 /* Create a new notmuch_message_list_t object, with 'ctx' as its
  * talloc owner.
  *
@@ -140,3 +142,41 @@ notmuch_messages_destroy (notmuch_messages_t *messages)
 {
 talloc_free (messages);
 }
+
+
+notmuch_tags_t *
+notmuch_messages_collect_tags (notmuch_messages_t *messages)
+{
+notmuch_tags_t *tags, *msg_tags;
+notmuch_message_t *msg;
+GHashTable *htable;
+GList *keys, *l;
+const char *tag;
+
+tags = _notmuch_tags_create (messages);
+if (tags == NULL) return NULL;
+
+htable = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL);
+
+while ((msg = notmuch_messages_get (messages))) {
+   msg_tags = notmuch_message_get_tags (msg);
+   while ((tag = notmuch_tags_get (msg_tags))) {
+   g_hash_table_insert (htable, xstrdup (tag), NULL);
+   notmuch_tags_advance (msg_tags);
+   }
+   notmuch_tags_destroy (msg_tags);
+   notmuch_message_destroy (msg);
+   notmuch_messages_advance (messages);
+}
+
+keys = g_hash_table_get_keys (htable);
+for (l = keys; l; l = l->next) {
+   _notmuch_tags_add_tag (tags, (char *)l->data);
+}
+
+g_list_free (keys);
+g_hash_table_destroy (htable);
+
+_notmuch_tags_prepare_iterator (tags);
+return tags;
+}
diff --git a/lib/notmuch.h b/lib/notmuch.h
index c05e802..9fa2770 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -635,6 +635,21 @@ notmuch_messages_advance (notmuch_messages_t *messages);
 void
 notmuch_messages_destroy (notmuch_messages_t *messages);

+/* Return a list of tags from all messages.
+ *
+ * The resulting list is guaranteed not to contain duplicated tags.
+ *
+ * WARNING: You can no longer iterate over messages after calling this
+ * function, because the iterator will point at the end of the list.
+ * We do not have a function to reset the iterator yet and the only
+ * way how you can iterate over the list again is to recreate the
+ * message list.
+ *
+ * The function returns NULL on error.
+ */
+notmuch_tags_t *
+notmuch_messages_collect_tags (notmuch_messages_t *messages);
+
 /* Get the message ID of 'message'.
  *
  * The returned string belongs to 'message' and as such, should not be
-- 
1.6.3.3



[notmuch] [PATCH] notmuch.el: When removing tags, offer only those a msg/thread has set.

2009-11-25 Thread Jan Janak
When removing a tag from a message or thread, build a completion buffer
which contains only tags that the message or thread has really set.

Signed-off-by: Jan Janak 
---
 notmuch.el |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index a9f534b..9594f63 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -137,11 +137,11 @@ within the current window."
   (or (memq prop buffer-invisibility-spec)
  (assq prop buffer-invisibility-spec)

-(defun notmuch-select-tag-with-completion (prompt)
+(defun notmuch-select-tag-with-completion (prompt &rest search-terms)
   (let ((tag-list
 (with-output-to-string
   (with-current-buffer standard-output
-(call-process notmuch-command nil t nil "search-tags")
+(apply 'call-process notmuch-command nil t nil "search-tags" 
search-terms)
 (completing-read prompt (split-string tag-list "\n+" t) nil nil nil)))

 (defun notmuch-show-next-line ()
@@ -218,7 +218,7 @@ Unlike builtin `next-line' this version accepts no 
arguments."
 (defun notmuch-show-remove-tag (&rest toremove)
   "Remove a tag from the current message."
   (interactive
-   (list (notmuch-select-tag-with-completion "Tag to remove: ")))
+   (list (notmuch-select-tag-with-completion "Tag to remove: " 
(notmuch-show-get-message-id
   (let ((tags (notmuch-show-get-tags)))
 (if (intersection tags toremove :test 'string=)
(progn
@@ -968,7 +968,7 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."

 (defun notmuch-search-remove-tag (tag)
   (interactive
-   (list (notmuch-select-tag-with-completion "Tag to remove: ")))
+   (list (notmuch-select-tag-with-completion "Tag to remove: " 
(notmuch-search-find-thread-id
   (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id))
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags

-- 
1.6.3.3



[notmuch] [PATCH 4/4] notmuch-new: New cmdline option --tag=.

2009-11-25 Thread Jan Janak
Hi Karl,

On Wed, Nov 25, 2009 at 7:21 AM, Karl Wiberg  wrote:
> On Tue, Nov 24, 2009 at 11:10 PM, Jan Janak  wrote:
>> The list of tags to be applied by 'notmuch new' can be configured in
>> the configuration file. This command line option can be used to
>> override the list of tags from the coonfiguration file on the command
>> line. You may repeat the option several times if you want to apply
>> more than one tag:
>>
>> ?notmuch new --tag=apple --tag=orange
>
> This leaves no way to skip the tags in the config file without adding
> at least one tag on the command line, right?

Right.

> It might be more flexible
> to e.g. have the commandline tags applied in _addition_ to the tags in
> the config, and have a --no-config-tags flag to skip the tags in the
> config when desired.

Yeah, I think that's a very good idea. I'll submit another patch for
that. Thanks for the suggestion!

  -- Jan


[notmuch] [PATCH] notmuch-new: Option to disable tags from the configuration file.

2009-11-25 Thread Jan Janak
This patch slightly changes behavior of the command line option --tag.
Any tags specified by the user on the command line will be added
*in addition* to tags configured in the configuration file.

This behavior can be changed with the new command line option
--no-config-tags. The user can use this option to ignore any tags from
the configuration file (i.e. only tags specified on the command line
will be applied).

With this new option the user can configure 'notmuch new' not to apply
any tags (and that was not possible before):

  notmuch new --no-config-tags

Suggested by Karl Wiberg.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   19 +++
 notmuch.c |   11 ++-
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 94036da..e988bf1 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -28,6 +28,7 @@ static notmuch_config_t *config = NULL;

 static char **cmdline_tags = NULL;
 static unsigned int cmdline_tags_count = 0;
+static int add_config_tags = 1;

 static void
 handle_sigalrm (unused (int signal))
@@ -79,19 +80,19 @@ apply_tags (notmuch_message_t *message)
 char** tags;
 unsigned int count, i;

+if (add_config_tags) {
+   tags = notmuch_config_get_new_tags (config, &count);
+   for (i = 0; tags && (i < count); i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+   }
+}
+
 if (cmdline_tags_count) {
for (i = 0; i < cmdline_tags_count; i++) {
if (cmdline_tags[i])
notmuch_message_add_tag (message, cmdline_tags[i]);
}
-} else {
-   if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
-   return;
-
-   for (i = 0; i < count; i++) {
-   if (tags[i])
-   notmuch_message_add_tag (message, tags[i]);
-   }
 }
 }

@@ -451,6 +452,8 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
}
tmp[cmdline_tags_count++] = opt;
cmdline_tags = tmp;
+   } else if (STRNCMP_LITERAL (argv[i], "--no-config-tags") == 0) {
+   add_config_tags = 0;
} else {
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
return 1;
diff --git a/notmuch.c b/notmuch.c
index 1bd3265..ff8d5bb 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -149,7 +149,16 @@ command_t commands[] = {
   "\n"
   "\t\t\tAdd the tag  to all messages newly added to the\n"
   "\t\t\tdatabase. You may repeat this option several times if\n"
-  "\t\t\tyou want to add more tags.\n"
+  "\t\t\tyou want to add more tags. Any tags configured in the\n"
+  "\t\t\tconfiguration file will still be added, unless you also\n"
+  "\t\t\tuse the option --no-config-tags.\n"
+  "\n"
+  "\t\t--no-config-tags\n"
+  "\n"
+  "\t\t\tDo not add tags configured in the configuration file.\n"
+  "\t\t\tUse this option if you only want to add tags specified\n"
+  "\t\t\ton the command line with --tag or if do not want to add\n"
+  "\t\t\tany tags at all.\n"
   "\n"
   "\t\tNote: \"notmuch new\" runs (other than the first run) will\n"
   "\t\tskip any read-only directories, so you can use that to mark\n"
-- 
1.6.3.3



[notmuch] [PATCH] notmuch-new: Test if directory looks like Maildir before skipping tmp.

2009-11-25 Thread Jan Janak
'notmuch new' skips directory entries with the name 'tmp'. This is to
prevent notmuch from processing possibly incomplete Maildir messages
stored in that directory.

This patch attempts to refine the feature. If "tmp" entry is found,
it first checks if the containing directory looks like a Maildir
directory. This is done by searching for other common Maildir
subdirectories. If they exist and if the entry "tmp" is a directory
then it is skipped.

Files and subdirectories with the name "tmp" that do not look like
Maildir will still be processed by 'notmuch new'.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   28 +++-
 1 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index e32b92a..3e1c9a7 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -80,6 +80,30 @@ static int ino_cmp(const struct dirent **a, const struct 
dirent **b)
 return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
 }

+/* Test if the directory looks like a Maildir directory.
+ *
+ * Search through the array of directory entries to see if we can find all
+ * three subdirectories typical for Maildir, that is "new", "cur", and "tmp".
+ *
+ * Return 1 if the directory looks like a Maildir and 0 otherwise.
+ */
+static int is_maildir (struct dirent **entries, int count)
+{
+int i, found = 0;
+
+for (i = 0; i < count; i++) {
+   if (entries[i]->d_type != DT_DIR) continue;
+   if (strcmp(entries[i]->d_name, "new") == 0 ||
+   strcmp(entries[i]->d_name, "cur") == 0 ||
+   strcmp(entries[i]->d_name, "tmp") == 0)
+   {
+   found++;
+   }
+}
+
+return found >= 3;
+}
+
 /* Examine 'path' recursively as follows:
  *
  *   o Ask the filesystem for the mtime of 'path' (path_mtime)
@@ -159,7 +183,9 @@ add_files_recursive (notmuch_database_t *notmuch,
 * user specify files to be ignored. */
if (strcmp (entry->d_name, ".") == 0 ||
strcmp (entry->d_name, "..") == 0 ||
-   strcmp (entry->d_name, "tmp") == 0 ||
+   (entry->d_type == DT_DIR &&
+(strcmp (entry->d_name, "tmp") == 0) &&
+is_maildir (namelist, num_entries)) ||
strcmp (entry->d_name, ".notmuch") ==0)
{
continue;
-- 
1.6.3.3



[notmuch] [PATCH] notmuch-new: Test if directory looks like Maildir before skipping tmp.

2009-11-25 Thread Jan Janak
'notmuch new' skips directory entries with the name 'tmp'. This is to
prevent notmuch from processing possibly incomplete Maildir messages
stored in that directory.

This patch attempts to refine the feature. If "tmp" entry is found,
it first checks if the containing directory looks like a Maildir
directory. This is done by searching for other common Maildir
subdirectories. If they exist and if the entry "tmp" is a directory
then it is skipped.

Files and subdirectories with the name "tmp" that do not look like
Maildir will still be processed by 'notmuch new'.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   29 -
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index e32b92a..10dc72b 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -80,6 +80,31 @@ static int ino_cmp(const struct dirent **a, const struct 
dirent **b)
 return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
 }

+/* Test if the directory looks like a Maildir directory.
+ *
+ * Search through the array of directory entries to see if we can find all
+ * three subdirectories typical for Maildir, that is "new", "cur", and "tmp".
+ *
+ * Return 1 if the directory looks like a Maildir and 0 otherwise.
+ */
+static int is_maildir (struct dirent **entries, int count)
+{
+int i, found = 0;
+
+for (i = 0; i < count; i++) {
+   if (entries[i]->d_type != DT_DIR) continue;
+   if (strcmp(entries[i]->d_name, "new") == 0 ||
+   strcmp(entries[i]->d_name, "cur") == 0 ||
+   strcmp(entries[i]->d_name, "tmp") == 0)
+   {
+   found++;
+   if (found == 3) return 1;
+   }
+}
+
+return 0;
+}
+
 /* Examine 'path' recursively as follows:
  *
  *   o Ask the filesystem for the mtime of 'path' (path_mtime)
@@ -159,7 +184,9 @@ add_files_recursive (notmuch_database_t *notmuch,
 * user specify files to be ignored. */
if (strcmp (entry->d_name, ".") == 0 ||
strcmp (entry->d_name, "..") == 0 ||
-   strcmp (entry->d_name, "tmp") == 0 ||
+   (entry->d_type == DT_DIR &&
+(strcmp (entry->d_name, "tmp") == 0) &&
+is_maildir (namelist, num_entries)) ||
strcmp (entry->d_name, ".notmuch") ==0)
{
continue;
-- 
1.6.3.3



[notmuch] [PATCH] notmuch-new: Test if directory looks like Maildir before skipping tmp.

2009-11-25 Thread Jan Janak
On 25-11 12:12, Scott Robinson wrote:
> Excerpts from Jan Janak's message of Wed Nov 25 11:43:15 -0800 2009:
> > +/* Test if the directory looks like a Maildir directory.
> > + *
> > + * Search through the array of directory entries to see if we can find all
> > + * three subdirectories typical for Maildir, that is "new", "cur", and 
> > "tmp".
> > + *
> > + * Return 1 if the directory looks like a Maildir and 0 otherwise.
> > + */
> > +static int is_maildir (struct dirent **entries, int count)
> > +{
> > +int i, found = 0;
> > +
> > +for (i = 0; i < count; i++) {
> > +if (entries[i]->d_type != DT_DIR) continue;
> > +if (strcmp(entries[i]->d_name, "new") == 0 ||
> > +strcmp(entries[i]->d_name, "cur") == 0 ||
> > +strcmp(entries[i]->d_name, "tmp") == 0)
> > +{
> > +found++;
> > +}
> > +}
> > +
> > +return found >= 3;
> > +}
> 
> Maybe put the "found >= 3" in the for loop's stop-condition?

You are right, of course. Resubmitted, thanks a lot!

  -- Jan


[notmuch] [PATCH] notmuch-new: Option to disable tags from the configuration file.

2009-11-25 Thread Jan Janak
Hi Bart,

On 25-11 14:55, Bart Trojanowski wrote:
> Jan,
> 
> I think your use of STRNCMP_LITERAL here is wrong...
> 
> > +   } else if (STRNCMP_LITERAL (argv[i], "--no-config-tags") == 0) {
> > +   add_config_tags = 0;
> 
> it will happily match "--no-config-tags-xxx".

Ahh, I actually stole the code from the part which parses the --verbose
command line option. And I didn't check it. That one suffers from the same
problem, so I'll just fix them both in one patch.

> Can I also suggest including --no-config-tags in the 'notmuch help'
> output?

Sure, I'll add it.

> Besides that I am very happy with this patch series.

Thanks a lot!

  -- Jan


[notmuch] [PATCH 2/4] notmuch: Config option to specify tags to be applied by 'notmuch new'.

2009-11-25 Thread Jan Janak
Hi Bart,

On 25-11 15:56, Bart Trojanowski wrote:
> Jan,
> 
> I really want this feature to get in, so I am going to do my best to
> review your code :)
> 
> Here are some more sticking points...
> 
> > +char **
> > +notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length);
> 
> If you are not giving over control of the pointer to the caller please
> return const char * const *.

I followed Carl's style there, in particular the following function:
notmuch_config_get_user_other_email

I can, of course, change that. But maybe we should wait for Carl to see
which way he prefers.

> Similarly...
> 
> > +char **new_tags;
> 
> ... this should probably be const char **.

That's the same story. I followed user_other_email there.

> Next...
> 
> > +char **
> > +notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
> 
> ... but ...
> 
> > +unsigned int count, i;
> > +
> > +if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
> > +   return;
> 
> size_t != unsigned int on all platforms.  Please stick with one or the
> other.  Note there are a few calls to fix here.

That's a good catch. I will fix that one. Thanks a lot for the review, I
really appreciate that!

  -- Jan



[notmuch] [PATCH 4/5] notmuch-new: New cmdline option --tag=.

2009-11-26 Thread Jan Janak
The list of tags to be applied by 'notmuch new' can be configured in
the configuration file. This command line option can be used to
override the list of tags from the coonfiguration file on the command
line. You may repeat the option several times if you want to apply
more than one tag:

  notmuch new --tag=apple --tag=orange

This is useful, for example, if you have an archive of messages you
would like to add to the database with a special tag so that they can
be easily identified later. To do that, you could simply copy the files
from the archive to the database directory and then index them all with:

  notmuch new --tag=prehistory

Tags to be applied every time 'notmuch new' is run can be specified in
the configuration file. One-time tags for individual runs can be
specified on the command line with this new option.

This revision of the patch includes suggestions from Bart Trojanowski.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   40 ++--
 notmuch.c |8 +++-
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index af717b7..cfbc6aa 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -26,6 +26,9 @@ static volatile sig_atomic_t do_add_files_print_progress = 0;

 static notmuch_config_t *config = NULL;

+static char **cmdline_tags = NULL;
+static size_t cmdline_tags_count = 0;
+
 static void
 handle_sigalrm (unused (int signal))
 {
@@ -76,12 +79,19 @@ apply_tags (notmuch_message_t *message)
 char** tags;
 size_t count, i;

-if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
-   return;
+if (cmdline_tags_count) {
+   for (i = 0; i < cmdline_tags_count; i++) {
+   if (cmdline_tags[i])
+   notmuch_message_add_tag (message, cmdline_tags[i]);
+   }
+} else {
+   if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
+   return;

-for (i = 0; i < count; i++) {
-   if (tags[i])
-   notmuch_message_add_tag (message, tags[i]);
+   for (i = 0; i < count; i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+   }
 }
 }

@@ -413,7 +423,8 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 int ret = 0;
 struct stat st;
 const char *db_path;
-char *dot_notmuch_path;
+char *dot_notmuch_path, *opt;
+char **tmp;
 struct sigaction action;
 int i;

@@ -423,6 +434,23 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 for (i = 0; i < argc && argv[i][0] == '-'; i++) {
if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {
add_files_state.verbose = 1;
+   } else if (STRNCMP_LITERAL (argv[i], "--tag=") == 0) {
+   opt = argv[i] + sizeof ("--tag=") - 1;
+   /* FIXME: We should check for leading and trailing white-space in
+* option value here and remove it.
+*/
+   if (*opt == '\0') {
+   fprintf (stderr, "Option value missing: %s\n", argv[i]);
+   return 1;
+   }
+   tmp = talloc_realloc (ctx, cmdline_tags, char*,
+ cmdline_tags_count + 1);
+   if (tmp == NULL) {
+   fprintf (stderr, "Notmuch ran out of memory.\n");
+   return 1;
+   }
+   tmp[cmdline_tags_count++] = opt;
+   cmdline_tags = tmp;
} else {
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
return 1;
diff --git a/notmuch.c b/notmuch.c
index f45b692..1bd3265 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -123,7 +123,7 @@ command_t commands[] = {
   "\t\tInvoking notmuch with no command argument will run setup if\n"
   "\t\tthe setup command has not previously been completed." },
 { "new", notmuch_new_command,
-  "[--verbose]",
+  "[--verbose] [--tag=]",
   "\t\tFind and import new messages to the notmuch database.",
   "\t\tScans all sub-directories of the mail directory, performing\n"
   "\t\tfull-text indexing on new messages that are found. Each new\n"
@@ -145,6 +145,12 @@ command_t commands[] = {
   "\t\t\tVerbose operation. Shows paths of message files as\n"
   "\t\t\tthey are being indexed.\n"
   "\n"
+  "\t\t--tag=\n"
+  "\n"
+  "\t\t\tAdd the tag  to all messages newly added to the\n"
+  "\t\t\tdatabase. You may repeat this option several times if\n"
+  "\t\t\tyou want to add more tags.\n"
+  "\n"
   "\t\tNote: \"notmuch new\" runs (other than the first run) will\n"
   "\t\tskip any read-only directories, so you can use that to mark\n"
   "\t\tdirectories that will not receive any new mail (and make\n"
-- 
1.6.3.3



[notmuch] [PATCH 2/5] notmuch: Config option to specify tags to be applied by 'notmuch new'.

2009-11-26 Thread Jan Janak
Add support for section [new] in the configuration file. This section
is supposed to contain options for 'notmuch new'. Currently there is
only one option called tags.

The tags option can be used to configure a set of tags to be applied
by 'notmuch new'. Individual tags are separated by semicolon.

'notmuch new' is modified not to apply 'inbox' and 'unread' by default,
but instead it obtains the set of tags to be applied from the new
configuration file option.

Signed-off-by: Jan Janak 

This revision of the patch includes suggestions from Bart Trojanowski.
---
 notmuch-client.h |3 +++
 notmuch-config.c |   43 +++
 notmuch-new.c|   19 ++-
 3 files changed, 64 insertions(+), 1 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index c04eaeb..0fb9c19 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -184,6 +184,9 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 const char *other_email[],
 size_t length);

+char **
+notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length);
+
 notmuch_bool_t
 debugger_is_active (void);

diff --git a/notmuch-config.c b/notmuch-config.c
index fc65d6b..57072ce 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -22,6 +22,7 @@

 #include 
 #include 
+#include 

 static const char toplevel_config_comment[] =
 " .notmuch-config - Configuration file for the notmuch mail system\n"
@@ -62,6 +63,9 @@ struct _notmuch_config {
 char *user_primary_email;
 char **user_other_email;
 size_t user_other_email_length;
+
+char **new_tags;
+size_t new_tags_length;
 };

 static int
@@ -199,6 +203,8 @@ notmuch_config_open (void *ctx,
 config->user_primary_email = NULL;
 config->user_other_email = NULL;
 config->user_other_email_length = 0;
+config->new_tags = NULL;
+config->new_tags_length = 0;

 if (! g_key_file_load_from_file (config->key_file,
 config->filename,
@@ -450,3 +456,40 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 talloc_free (config->user_other_email);
 config->user_other_email = NULL;
 }
+
+char **
+notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
+{
+char **tags;
+size_t i, len;
+char *start, *end;
+
+if (config->new_tags == NULL) {
+   config->new_tags_length = 0;
+   tags = g_key_file_get_string_list (config->key_file, "new", "tags",
+  &len, NULL);
+
+   if (tags) {
+   config->new_tags = talloc_size (config, sizeof(char*) *
+   (len + 1));
+   for (i = 0; i < len; i++) {
+   /* Remove leading and trailing white space around the tag and
+* filter out empty tags. */
+   start = tags[i];
+   end = start + strlen (start) - 1;
+   while (isspace (*start)) start++;
+   while (end > start && isspace (*end)) end--;
+   if (end >= start) {
+   config->new_tags[config->new_tags_length++] =
+   talloc_strndup (config->new_tags, start,
+   end - start + 1);
+   }
+   }
+   config->new_tags[config->new_tags_length] = NULL;
+   g_strfreev (tags);
+   }
+}
+
+*length = config->new_tags_length;
+return config->new_tags;
+}
diff --git a/notmuch-new.c b/notmuch-new.c
index 9970407..af717b7 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -24,6 +24,8 @@

 static volatile sig_atomic_t do_add_files_print_progress = 0;

+static notmuch_config_t *config = NULL;
+
 static void
 handle_sigalrm (unused (int signal))
 {
@@ -68,6 +70,21 @@ add_files_print_progress (add_files_state_t *state)
 fflush (stdout);
 }

+static void
+apply_tags (notmuch_message_t *message)
+{
+char** tags;
+size_t count, i;
+
+if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
+   return;
+
+for (i = 0; i < count; i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+}
+}
+
 static int ino_cmp(const struct dirent **a, const struct dirent **b)
 {
 return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
@@ -191,6 +208,7 @@ add_files_recursive (notmuch_database_t *notmuch,
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
+   apply_tags (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
@@ -388,7 +406,6 @@ count_files (co

[notmuch] [PATCH 3/5] notmuch-setup: Copy/create the new section with tags for 'notmuch-new'.

2009-11-26 Thread Jan Janak
If the user runs 'notmuch setup' and there is no configuration file yet
then we also add the new section [new] to the configuration file and
set the tags option as:

  tags=inbox;unread

This will be picked up by 'notmuch new' and all new mail added to the
database will be tagged with the two tags as before.

If the user already has a configuration file and runs 'notmuch setup'
then we just copy whatever tags we find in the old configuration file
to the new one. If there are no tags in the old configuration file then
we assume that the user configured notmuch that way and the new config
file would also have no tags in the section [new].

We never ask the user interactively for the list of tags to be used by
'notmuch new', it is assumed that beginners would want to stick to the
defaults and advanced users can edit the configuration manually.

This revision of the patch includes suggestions from Bart Trojanowski.

Signed-off-by: Jan Janak 
---
 notmuch-client.h |4 
 notmuch-config.c |   40 
 notmuch-setup.c  |   18 ++
 3 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 0fb9c19..bb7d3d4 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -187,6 +187,10 @@ notmuch_config_set_user_other_email (notmuch_config_t 
*config,
 char **
 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length);

+void
+notmuch_config_set_new_tags (notmuch_config_t *config, const char *tags[],
+size_t length);
+
 notmuch_bool_t
 debugger_is_active (void);

diff --git a/notmuch-config.c b/notmuch-config.c
index 57072ce..2bbeb20 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -54,6 +54,16 @@ static const char user_config_comment[] =
 " recipient list of replies, and will set the From address based on the\n"
 " address to which the original email was addressed.\n";

+static const char new_config_comment[] =
+" Configuration section for 'notmuch new'\n"
+"\n"
+" The only supported value at the moment is 'tags. This option contains 
a\n"
+" list of tags (separated by ';') that should be  automatically applied 
to\n"
+" newly added messages.\n"
+"\n"
+" Note that 'notmuch new' also has a command line option which can be 
used\n"
+" to add additional tags to the ones configured here.\n";
+
 struct _notmuch_config {
 char *filename;
 GKeyFile *key_file;
@@ -174,6 +184,7 @@ notmuch_config_open (void *ctx,
 GError *error = NULL;
 int is_new = 0;
 char *notmuch_config_env = NULL;
+const char* def_new_tags[2] = {"inbox", "unread"};

 if (is_new_ret)
*is_new_ret = 0;
@@ -270,6 +281,20 @@ notmuch_config_open (void *ctx,
}
 }

+/* If we have no configuration file then we configure "inbox" and "unread"
+ * tags by default for 'notmuch new'. This ensures that the Emacs mode
+ * would still work as expected.
+ *
+ * We do not ask the user for tags to be used by 'notmuch new'. That's too
+ * much detail for beginners and others can edit the configuration file by
+ * hand.
+ */
+if (is_new) {
+   notmuch_config_set_new_tags (config, def_new_tags,
+sizeof(def_new_tags) /
+sizeof(const char*));
+}
+
 /* When we create a new configuration file here, we  add some
  * comments to help the user understand what can be done. */
 if (is_new) {
@@ -279,6 +304,8 @@ notmuch_config_open (void *ctx,
database_config_comment, NULL);
g_key_file_set_comment (config->key_file, "user", NULL,
user_config_comment, NULL);
+   g_key_file_set_comment (config->key_file, "new", NULL,
+   new_config_comment, NULL);
 }

 if (is_new_ret)
@@ -493,3 +520,16 @@ notmuch_config_get_new_tags (notmuch_config_t *config, 
size_t *length)
 *length = config->new_tags_length;
 return config->new_tags;
 }
+
+void
+notmuch_config_set_new_tags (notmuch_config_t *config,
+const char *tags[],
+size_t length)
+{
+g_key_file_set_string_list (config->key_file,
+   "new", "tags",
+   tags, length);
+
+talloc_free (config->new_tags);
+config->user_other_email = NULL;
+}
diff --git a/notmuch-setup.c b/notmuch-setup.c
index d06fbf8..aeffb88 100644
--- a/notmuch-setup.c
+++ b/notmuch-setup.c
@@ -92,12 +92,10 @@ notmuch_setup_command (unused (void *ctx),
   unused (int argc

[notmuch] [PATCH 1/5] notmuch-new: Remove tag_add_inbox_unread in favor of a generic solution.

2009-11-26 Thread Jan Janak
Instead of adding 'inbox' and 'unread' tags directly in the code of
'notmuch-new', we can specify a list of tags to be added to newly
created messages with a configuration file option or a command line
option. That's more flexible, it allows the user to select which tags
should be added.

Signed-off-by: Jan Janak 
---
 notmuch-new.c |8 
 1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index e32b92a..9970407 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -41,13 +41,6 @@ handle_sigint (unused (int sig))
 }

 static void
-tag_inbox_and_unread (notmuch_message_t *message)
-{
-notmuch_message_add_tag (message, "inbox");
-notmuch_message_add_tag (message, "unread");
-}
-
-static void
 add_files_print_progress (add_files_state_t *state)
 {
 struct timeval tv_now;
@@ -198,7 +191,6 @@ add_files_recursive (notmuch_database_t *notmuch,
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
-   tag_inbox_and_unread (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-- 
1.6.3.3



[notmuch] [PATCH 5/5] notmuch-new: Option to disable tags from the configuration file.

2009-11-26 Thread Jan Janak
This patch slightly changes behavior of the command line option --tag.
Any tags specified by the user on the command line will be added
*in addition* to tags configured in the configuration file.

This behavior can be changed with the new command line option
--no-config-tags. The user can use this option to ignore any tags from
the configuration file (i.e. only tags specified on the command line
will be applied).

With this new option the user can configure 'notmuch new' not to apply
any tags (and that was not possible before):

  notmuch new --no-config-tags

Suggested by Karl Wiberg.

Bugfix: Fix parsing of --verbose cmdline option.

This is a revised version of the patch, incorporating suggestions made
by Bart Trojanowski. Thanks Bart!

Signed-off-by: Jan Janak 
---
 notmuch-new.c |   21 -
 notmuch.c |   13 +++--
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index cfbc6aa..eaed701 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -28,6 +28,7 @@ static notmuch_config_t *config = NULL;

 static char **cmdline_tags = NULL;
 static size_t cmdline_tags_count = 0;
+static int add_config_tags = 1;

 static void
 handle_sigalrm (unused (int signal))
@@ -79,19 +80,19 @@ apply_tags (notmuch_message_t *message)
 char** tags;
 size_t count, i;

+if (add_config_tags) {
+   tags = notmuch_config_get_new_tags (config, &count);
+   for (i = 0; tags && (i < count); i++) {
+   if (tags[i])
+   notmuch_message_add_tag (message, tags[i]);
+   }
+}
+
 if (cmdline_tags_count) {
for (i = 0; i < cmdline_tags_count; i++) {
if (cmdline_tags[i])
notmuch_message_add_tag (message, cmdline_tags[i]);
}
-} else {
-   if ((tags = notmuch_config_get_new_tags (config, &count)) == NULL)
-   return;
-
-   for (i = 0; i < count; i++) {
-   if (tags[i])
-   notmuch_message_add_tag (message, tags[i]);
-   }
 }
 }

@@ -432,7 +433,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 add_files_state.output_is_a_tty = isatty (fileno (stdout));

 for (i = 0; i < argc && argv[i][0] == '-'; i++) {
-   if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {
+   if (strcmp (argv[i], "--verbose") == 0) {
add_files_state.verbose = 1;
} else if (STRNCMP_LITERAL (argv[i], "--tag=") == 0) {
opt = argv[i] + sizeof ("--tag=") - 1;
@@ -451,6 +452,8 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
}
tmp[cmdline_tags_count++] = opt;
cmdline_tags = tmp;
+   } else if (strcmp (argv[i], "--no-config-tags") == 0) {
+   add_config_tags = 0;
} else {
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
return 1;
diff --git a/notmuch.c b/notmuch.c
index 1bd3265..2bb38f3 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -123,7 +123,7 @@ command_t commands[] = {
   "\t\tInvoking notmuch with no command argument will run setup if\n"
   "\t\tthe setup command has not previously been completed." },
 { "new", notmuch_new_command,
-  "[--verbose] [--tag=]",
+  "[--verbose] [--tag=] [--no-config-tags]",
   "\t\tFind and import new messages to the notmuch database.",
   "\t\tScans all sub-directories of the mail directory, performing\n"
   "\t\tfull-text indexing on new messages that are found. Each new\n"
@@ -149,7 +149,16 @@ command_t commands[] = {
   "\n"
   "\t\t\tAdd the tag  to all messages newly added to the\n"
   "\t\t\tdatabase. You may repeat this option several times if\n"
-  "\t\t\tyou want to add more tags.\n"
+  "\t\t\tyou want to add more tags. Any tags configured in the\n"
+  "\t\t\tconfiguration file will still be added, unless you also\n"
+  "\t\t\tuse the option --no-config-tags.\n"
+  "\n"
+  "\t\t--no-config-tags\n"
+  "\n"
+  "\t\t\tDo not add tags configured in the configuration file.\n"
+  "\t\t\tUse this option if you only want to add tags specified\n"
+  "\t\t\ton the command line with --tag or if do not want to add\n"
+  "\t\t\tany tags at all.\n"
   "\n"
   "\t\tNote: \"notmuch new\" runs (other than the first run) will\n"
   "\t\tskip any read-only directories, so you can use that to mark\n"
-- 
1.6.3.3



[notmuch] [PATCH 0/4] Make tags applied by 'notmuch new' configurable.

2009-11-26 Thread Jan Janak
Hello,

On 24-11 23:10, Jan Janak wrote:
> I would like to propose that we make the list of tags applied by 'notmuch new'
> configurable. Right now notmuch applies two tags to all new messages added to
> the database, 'inbox' and 'unread'. The two tags are added by the C code in
> notmuch-new.c and they cannot be changed without editing the source file and
> recompiling notmuch.
> 
> The four patches that follow this email allow for configuring the tags to be
> added by 'notmuch new' either in the configuration file or on the command
> line.
> 
> This change was motivated by my desire to remove both tags from newly added
> messages. My rules for adding these two tags are more complex and I do it in
> a script run after 'notmuch new'. Instead of 'inbox' and 'unread', I configure
> 'notmuch new' to add a new tag called 'new' (and only that one). This tag
> marks newly added messages that haven't been properly tagged yet by my 
> auto-tagging scripts. The last script I run after 'notmuch new' removes that
> tag. My auto-tagging scripts process only messages with the tag 'new'.
> 
> On a side note; It may seem logical to add/omit the tag 'unread' directly in 
> 'notmuch new' based on the Maildir flags extracted from the filename of the
> message. I suggest that we don't do that in 'notmuch new'. A better way would
> be writing a small script or command that can be run *after* 'notmuch new'.
> We could then distribute it with notmuch (maybe with other small tagging
> scripts for common situations). 
> 
> I think Maildir flags should be processed after 'notmuch new' is because if
> there are multiple copies of a message with different flags, we may need to
> see all flags from all filenames to set corresponding tags properly and we may
> also need to take the directory part into consideration (i.e. the new mail is
> in 'new', not 'cur').
> 
> The list of tags to be applied by notmuch can be configured in the
> configuration file. There is a new section [new] which contains configuration
> options for 'notmuch new'. There is only one option called 'tags'. The option
> contains a semicolon separated list of tags:
> 
>   [new]
>   tags=inbox;unread  # Emulate the original behavior
> 
> One of the patches updates 'notmuch setup' to create the section and add
> the tags option with tags 'inbox' and 'unread', but only if a new
> configuration file is being created. If the configuration file already exists
> then it just copies the contents from the old configuration file to the new
> one.
> 
> We do not ask the user for the list of tags in the interactive part, that 
> would
> have been too much. Users can edit the configuration file manually if they 
> want
> to change the list of tags. If they create a new configuration file then they
> probably want to accept the default anyway.
> 
> There is one catch for users who already have a configuration file and start
> using the patches. They will need to add the new section and the tags option
> manually if they want to preserve current behavior of applying 'inbox' and
> 'unread' automatically by 'notmuch new'.
> 
> The last patch in the set adds a new command line option to 'notmuch new'.
> The name of the option is --tag and it can be used to override any tags
> configured in the configuration file. For example:
> 
>   notmuch new --tag=outbox --tag=read
> 
> adds the tags 'outbox' and 'read' and ignores any tags from the configuration
> file.
> 
> Comments and opinions are welcome!

I updated this patch series, adding features and bug fixes suggested by others
on the list.

The command line option --tag now *adds* tags, so the tags configured in the
configuration file are still applied...unless you use the new option
--no-config-tag. With this option only the tags specified on the command line
will be applied by 'notmuch-new'.

  -- Jan


[notmuch] [PATCH] Makefile: Enable backslash escapes for echo.

2009-11-26 Thread Jan Janak
Hi Stefan,

On 26-11 09:17, Stefan Schmidt wrote:
> This fixes a visual glitch during a silent compile.
> Before:
> Use "make V=1" to see the verbose compile lines.\n  CC  debugger.o
>   CCgmime-filter-reply.o
> 
> After:
> Use "make V=1" to see the verbose compile lines.
>   CCdebugger.o
>   CCgmime-filter-reply.o
> 
> Signed-off-by: Stefan Schmidt 
> ---
>  Makefile |2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 2cd1b1b..2d19a6e 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -41,7 +41,7 @@ include Makefile.config
>  # user how to enable verbose compiles.
>  ifeq ($(V),)
>  quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
> -quiet = @echo $(quiet_DOC)$(eval quiet_DOC:=)"  $1   $@"; $($1)
> +quiet = @echo -e $(quiet_DOC)$(eval quiet_DOC:=)"  $1$@"; $($1)
>  endif
>  # The user has explicitly enabled quiet compilation.
>  ifeq ($(V),0)

I sent exactly the same patch a couple of days ago and it was rejected because
it does not work everywhere, see:

http://notmuchmail.org/pipermail/notmuch/2009/000370.html

  -- Jan


[notmuch] [PATCH 3/3] notmuch.el: Select tag names with completion.

2009-11-27 Thread Jan Janak
Hi Carl,

On 26-11 07:15, Carl Worth wrote:
> On Mon, 23 Nov 2009 01:10:56 +0100, Jan Janak  wrote:
> > Several commands ask the user for a tag name. With this feature the
> > user can just press tab and Emacs automatically retrieves the list of
> > all existing tags from notmuch database with 'notmuch search-tags' and
> > presents a completion buffer to the user.
> > 
> > This feature is very useful for users who have a large number of tags
> > because it saves typing and minimizes the risk of typos.
> 
> Jan,
> 
> This feature is incredibly useful. Thanks so much for coding it!

You are welcome!

> I've had a bunch of messages that were effectively "lost" to me since
> switching from sup. I had been experimenting with different tag
> schemes, renaming tags, etc. within sup. But in sup there was no
> global-search-based tag manipulation command, so no easy way to update
> the tag names for messages tagged under the old scheme.
> 
> I'd been aware of the problem and knew I could just code something up to
> search for those old tags. But now I get to see the full list every time
> I hit TAB in emacs. So thanks!
> 
> I do still want to unify search, search-messages, search-tags, count,
> etc. But I've gone ahead and merged this whole series as-is to get the
> functionality out there for now.

Oh, that's great, my first bigger contribution to nutmuch is in the
repository, thanks so much! 

I was just thinking about giving you some time to catch up and review all the
patches, but now I have a reason to send more again ;-).

> I assume that everyone is aware that I'm reserving the right to change
> the library and command-line interface as much as I want right now.

Yeah, I personally have no problem with that. In fact I like it.

I think that not having the user interface fixed is a good thing at this early
stage. This is what makes notmuch so hackable :-), contributors like me don't
have to worry about breaking things (at least not too much).

>From my point of view, notmuch is still missing some important features. Also,
there is a bunch of people writing front-ends and they'll probably ask for
more, too. Personally, I think it would make sense to add what is missing and,
once you feel that notuch is reasonably feature-complete, you can design nice
and intuitive user interface for it.

I'd be happy to help you update the code that I contributed once you decide to
change the command-line interface.

> If you've got code or scripts that depend on these interfaces, I highly
> recommend that you get them contributed to the notmuch repository so
> that we can fix them up as we rework the library and command line.

Yeah, I will.

> (So, Bart, I'll merge the vim stuff which is using "notmuch count"
> before I change that, so I can fixup the vim stuff at the same time.)
> 
> Thanks again, Jan! Well done.

Thanks for starting notmuch! I've been working on converting my 4GB mailbox
with about a hundred tags from gmail to notmuch and while I am not there yet,
I've made some good progress recently. That makes me really optimistic; I
tried various other mail indexing tools before and never got that far.

-Jan


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

2009-11-27 Thread Jan Janak
On 26-11 22:53, Ingmar Vanhassel wrote:
> Excerpts from Michiel Buddingh''s message of Thu Nov 26 22:12:02 +0100 2009:
> > Haven't tested it, but it seems you can put
> > 
> > [core]
> > whitespace = trailing-space,space-before-tab
> > 
> > into your ~/.gitconfig now.  I've also set emacs to mark trailing
> > whitespace with big red markers.
> 
> I think it should be in notmuch/.gitattributes, which doesn't relies on
> new contributors to set that up. It also doesn't force this on for every
> git repo one has.

This enforces the restrictions also on people's local commits, even those they
may never want to submit for inclusion into the official repository.

Asking people to follow certain rules when submitting patches for inclusion is
sensible, but I don't think notmuch should enforce this on all local commits
with notmuch/.gitattributes.

  -- Jan



[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jan Janak
On 02-12 11:59, Jed Brown wrote:
> A patch for notmuch-search-filter follows, my change to
> notmuch-search-filter-by-tag is not very useful since
> notmuch-select-tag-with-completion does not allow a space to be
> inserted.  I don't know how to get completion on multiple
> space-separated terms.

notmuch-select-tag-with-completion uses "\n" as tag separator. This is because
it gets the output of 'notmuch search-tags' as input and there is one tag on a
line.

I haven't been really following this thread in detail. What is that you need
from notmuch-select-tag-with-completion? To be able to process a list of tags
separated by spaces? Maybe I could help you with that.

-Jan


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jan Janak
Jed,

On 02-12 14:46, Jed Brown wrote:
> On Wed, 2 Dec 2009 14:18:08 +0100, Jan Janak  wrote:
> > I haven't been really following this thread in detail. What is that you need
> > from notmuch-select-tag-with-completion? To be able to process a list of 
> > tags
> > separated by spaces? Maybe I could help you with that.
> 
> No, it would need to take input separated by spaces, now I just get `[No
> match]' when I try to enter a space.  I think it's just not how
> completing-read works, the idea would be for the user to be able to type
> 
>   shorttag and not long
> 
> which would complete to
> 
>   shorttag and not longboringtagname

I see.

> The point of my patch was to be able to filter using arbitrary
> expressions where every non-operator, i.e. `and', `or', `not', `(', and
> `)', is interpreted as a tag name.  Is there an easy way to accept this
> input without sacrificing completion?

I am not completely sure, but there might be a way to do this with some of the
low-level completion functions. For example, the documentation on completion
styles:

http://www.gnu.org/software/emacs/elisp/html_node/Completion-Styles.html#Completion-Styles

mentions in the last paragraph that there is a style which completes each word
in the input separately. This can be enabled with (partial-completion-mode),
and indeed, if I enable this mode, try to visit a file and type ~/.n-c 
then it correctly completes ~/.notmuch-config. 

This seems close enough to what you want and maybe we could somehow make it
work with notmuch, too. This would be interesting to have, because then we
could complete multiple tag names with a single TAB press not only in your
expressions, but everywhere.

Right now we can only add one tag at a time with notmuch-search-add-tag and
similar functions. If we could make partial completion work, we could add
several tags with one command and still have their names completed.

Let me know if you do not plan to work on this and I'll see if I can make it
work.

-Jan


Re: [notmuch] [PATCH] Makefile: Enable backslash escapes for echo.

2009-11-26 Thread Jan Janak
Hi Stefan,

On 26-11 09:17, Stefan Schmidt wrote:
> This fixes a visual glitch during a silent compile.
> Before:
> Use "make V=1" to see the verbose compile lines.\n  CC  debugger.o
>   CCgmime-filter-reply.o
> 
> After:
> Use "make V=1" to see the verbose compile lines.
>   CCdebugger.o
>   CCgmime-filter-reply.o
> 
> Signed-off-by: Stefan Schmidt 
> ---
>  Makefile |2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 2cd1b1b..2d19a6e 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -41,7 +41,7 @@ include Makefile.config
>  # user how to enable verbose compiles.
>  ifeq ($(V),)
>  quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
> -quiet = @echo $(quiet_DOC)$(eval quiet_DOC:=)"  $1   $@"; $($1)
> +quiet = @echo -e $(quiet_DOC)$(eval quiet_DOC:=)"  $1$@"; $($1)
>  endif
>  # The user has explicitly enabled quiet compilation.
>  ifeq ($(V),0)

I sent exactly the same patch a couple of days ago and it was rejected because
it does not work everywhere, see:

http://notmuchmail.org/pipermail/notmuch/2009/000370.html

  -- Jan
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] [PATCH 3/3] notmuch.el: Select tag names with completion.

2009-11-27 Thread Jan Janak
Hi Carl,

On 26-11 07:15, Carl Worth wrote:
> On Mon, 23 Nov 2009 01:10:56 +0100, Jan Janak  wrote:
> > Several commands ask the user for a tag name. With this feature the
> > user can just press tab and Emacs automatically retrieves the list of
> > all existing tags from notmuch database with 'notmuch search-tags' and
> > presents a completion buffer to the user.
> > 
> > This feature is very useful for users who have a large number of tags
> > because it saves typing and minimizes the risk of typos.
> 
> Jan,
> 
> This feature is incredibly useful. Thanks so much for coding it!

You are welcome!

> I've had a bunch of messages that were effectively "lost" to me since
> switching from sup. I had been experimenting with different tag
> schemes, renaming tags, etc. within sup. But in sup there was no
> global-search-based tag manipulation command, so no easy way to update
> the tag names for messages tagged under the old scheme.
> 
> I'd been aware of the problem and knew I could just code something up to
> search for those old tags. But now I get to see the full list every time
> I hit TAB in emacs. So thanks!
> 
> I do still want to unify search, search-messages, search-tags, count,
> etc. But I've gone ahead and merged this whole series as-is to get the
> functionality out there for now.

Oh, that's great, my first bigger contribution to nutmuch is in the
repository, thanks so much! 

I was just thinking about giving you some time to catch up and review all the
patches, but now I have a reason to send more again ;-).

> I assume that everyone is aware that I'm reserving the right to change
> the library and command-line interface as much as I want right now.

Yeah, I personally have no problem with that. In fact I like it.

I think that not having the user interface fixed is a good thing at this early
stage. This is what makes notmuch so hackable :-), contributors like me don't
have to worry about breaking things (at least not too much).

>From my point of view, notmuch is still missing some important features. Also,
there is a bunch of people writing front-ends and they'll probably ask for
more, too. Personally, I think it would make sense to add what is missing and,
once you feel that notuch is reasonably feature-complete, you can design nice
and intuitive user interface for it.

I'd be happy to help you update the code that I contributed once you decide to
change the command-line interface.

> If you've got code or scripts that depend on these interfaces, I highly
> recommend that you get them contributed to the notmuch repository so
> that we can fix them up as we rework the library and command line.

Yeah, I will.

> (So, Bart, I'll merge the vim stuff which is using "notmuch count"
> before I change that, so I can fixup the vim stuff at the same time.)
> 
> Thanks again, Jan! Well done.

Thanks for starting notmuch! I've been working on converting my 4GB mailbox
with about a hundred tags from gmail to notmuch and while I am not there yet,
I've made some good progress recently. That makes me really optimistic; I
tried various other mail indexing tools before and never got that far.

-Jan
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


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

2009-11-27 Thread Jan Janak
On 26-11 22:53, Ingmar Vanhassel wrote:
> Excerpts from Michiel Buddingh''s message of Thu Nov 26 22:12:02 +0100 2009:
> > Haven't tested it, but it seems you can put
> > 
> > [core]
> > whitespace = trailing-space,space-before-tab
> > 
> > into your ~/.gitconfig now.  I've also set emacs to mark trailing
> > whitespace with big red markers.
> 
> I think it should be in notmuch/.gitattributes, which doesn't relies on
> new contributors to set that up. It also doesn't force this on for every
> git repo one has.

This enforces the restrictions also on people's local commits, even those they
may never want to submit for inclusion into the official repository.

Asking people to follow certain rules when submitting patches for inclusion is
sensible, but I don't think notmuch should enforce this on all local commits
with notmuch/.gitattributes.

  -- Jan

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jan Janak
On 02-12 11:59, Jed Brown wrote:
> A patch for notmuch-search-filter follows, my change to
> notmuch-search-filter-by-tag is not very useful since
> notmuch-select-tag-with-completion does not allow a space to be
> inserted.  I don't know how to get completion on multiple
> space-separated terms.

notmuch-select-tag-with-completion uses "\n" as tag separator. This is because
it gets the output of 'notmuch search-tags' as input and there is one tag on a
line.

I haven't been really following this thread in detail. What is that you need
from notmuch-select-tag-with-completion? To be able to process a list of tags
separated by spaces? Maybe I could help you with that.

-Jan
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jan Janak
Jed,

On 02-12 14:46, Jed Brown wrote:
> On Wed, 2 Dec 2009 14:18:08 +0100, Jan Janak  wrote:
> > I haven't been really following this thread in detail. What is that you need
> > from notmuch-select-tag-with-completion? To be able to process a list of 
> > tags
> > separated by spaces? Maybe I could help you with that.
> 
> No, it would need to take input separated by spaces, now I just get `[No
> match]' when I try to enter a space.  I think it's just not how
> completing-read works, the idea would be for the user to be able to type
> 
>   shorttag and not long
> 
> which would complete to
> 
>   shorttag and not longboringtagname

I see.

> The point of my patch was to be able to filter using arbitrary
> expressions where every non-operator, i.e. `and', `or', `not', `(', and
> `)', is interpreted as a tag name.  Is there an easy way to accept this
> input without sacrificing completion?

I am not completely sure, but there might be a way to do this with some of the
low-level completion functions. For example, the documentation on completion
styles:

http://www.gnu.org/software/emacs/elisp/html_node/Completion-Styles.html#Completion-Styles

mentions in the last paragraph that there is a style which completes each word
in the input separately. This can be enabled with (partial-completion-mode),
and indeed, if I enable this mode, try to visit a file and type ~/.n-c 
then it correctly completes ~/.notmuch-config. 

This seems close enough to what you want and maybe we could somehow make it
work with notmuch, too. This would be interesting to have, because then we
could complete multiple tag names with a single TAB press not only in your
expressions, but everywhere.

Right now we can only add one tag at a time with notmuch-search-add-tag and
similar functions. If we could make partial completion work, we could add
several tags with one command and still have their names completed.

Let me know if you do not plan to work on this and I'll see if I can make it
work.

-Jan
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch