Re: [PATCH 2/6] cli: sanitize tabs to spaces in notmuch search

2013-10-17 Thread Jani Nikula
On Thu, 17 Oct 2013, Mark Walters markwalters1...@gmail.com wrote:
 Hi

 I have looked at the whole series and broadly it looks good. However, I
 don't know this code so this is not a full review. I do have a few
 comments: some of these may be plain wrong in which case my apologies!

Thanks for the review!

 On Wed, 16 Oct 2013, Jani Nikula j...@nikula.org wrote:

 This is in preparation of switching to gmime header parsing, but
 arguably converting tabs to spaces rather than question marks is the
 right thing to do anyway.
 ---

 I think it would be worth saying in the commit message that this is only
 for text summary output.

Agreed.

 Also why only tabs to spaces but \n to a '?'

The notmuch header parser converts the tabs in header folding to spaces,
gmime keeps them as tabs. AFAICT that is the only difference between
headers indexed by notmuch and gmime, and causes tests to fail. So we do
the tabs to spaces conversion here to produce same output from cli. This
patch just does the minimal change required for tests to pass; other
changes might be good too, but they were not relevant for this series.

BR,
Jani.


 Best wishes

 Mark




  notmuch-search.c | 4 +++-
  1 file changed, 3 insertions(+), 1 deletion(-)

 diff --git a/notmuch-search.c b/notmuch-search.c
 index d9d39ec..eab314f 100644
 --- a/notmuch-search.c
 +++ b/notmuch-search.c
 @@ -40,7 +40,9 @@ sanitize_string (const void *ctx, const char *str)
  loop = out = talloc_strdup (ctx, str);
  
  for (; *loop; loop++) {
 -if ((unsigned char)(*loop)  32)
 +if (*loop == '\t')
 +*loop = ' ';
 +else if ((unsigned char)(*loop)  32)
  *loop = '?';
  }
  return out;
 -- 
 1.8.4.rc3

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


Re: [PATCH 3/6] cli: make the hacky from guessing more liberal

2013-10-17 Thread Jani Nikula
On Thu, 17 Oct 2013, Mark Walters markwalters1...@gmail.com wrote:
 On Wed, 16 Oct 2013, Jani Nikula j...@nikula.org wrote:
 This is in preparation of switching to gmime header parsing. Accept
 for and by preceded by tabs in the received header. This is a bit
 flaky, but so is the whole guessing code.

 I am happy with the change but I think a little more explanation of the
 problem it fixes would be helpful. Is it that there could be a \n \t
 before the for/by or something else?

It's the same header folding by tabs here too. In your mail that I'm
replying to, the received headers are folded with tabs. (This may be due
to mailman doing bad things, but that's irrelevant.) There may be a tab
preceding the for/by instead of a space. Obviously this could be
made more robust, but if you look at what the from guessing does, you
realize it's quite hacky anyway, and a last resort. So I didn't bother,
at least not for now, for this series. Minimal change to make tests
pass.

 ---
  notmuch-reply.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

 diff --git a/notmuch-reply.c b/notmuch-reply.c
 index 9d6f843..4b67e66 100644
 --- a/notmuch-reply.c
 +++ b/notmuch-reply.c
 @@ -423,7 +423,7 @@ guess_from_received_header (notmuch_config_t *config, 
 notmuch_message_t *message
  /* First we look for a  for em...@add.res in the received
   * header
   */
 -ptr = strstr (received,  for );
 +ptr = strstr (received, for );

 The comment should be updated to match the code (and depending on the
 answer to the above maybe explain that too)

Agreed.

BR,
Jani.


 Best wishes

 Mark
  
  /* Note: ptr potentially contains a list of email addresses. */
  addr = user_address_in_string (ptr, config);
 @@ -440,7 +440,7 @@ guess_from_received_header (notmuch_config_t *config, 
 notmuch_message_t *message
   * system in this step of the receive chain
   */
  by = received;
 -while((by = strstr (by,  by )) != NULL) {
 +while((by = strstr (by, by )) != NULL) {
  by += 4;
  if (*by == '\0')
  break;
 -- 
 1.8.4.rc3

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


Re: [PATCH 3/6] cli: make the hacky from guessing more liberal

2013-10-17 Thread Jani Nikula
On Thu, 17 Oct 2013, Moritz Wilhelmy mw+notm...@barfooze.de wrote:
 Hello,

 On Wed, Oct 16, 2013 at 22:00:10 +0300, Jani Nikula wrote:
 This is in preparation of switching to gmime header parsing. Accept
 for and by preceded by tabs in the received header. This is a bit
 flaky, but so is the whole guessing code.
 ---
  notmuch-reply.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/notmuch-reply.c b/notmuch-reply.c
 index 9d6f843..4b67e66 100644
 --- a/notmuch-reply.c
 +++ b/notmuch-reply.c
 @@ -423,7 +423,7 @@ guess_from_received_header (notmuch_config_t *config, 
 notmuch_message_t *message
  /* First we look for a  for em...@add.res in the received
   * header
   */
 -ptr = strstr (received,  for );
 +ptr = strstr (received, for );
  
  /* Note: ptr potentially contains a list of email addresses. */
  addr = user_address_in_string (ptr, config);
 @@ -440,7 +440,7 @@ guess_from_received_header (notmuch_config_t *config, 
 notmuch_message_t *message
   * system in this step of the receive chain
   */
  by = received;
 -while((by = strstr (by,  by )) != NULL) {
 +while((by = strstr (by, by )) != NULL) {
  by += 4;

 FWIW, I didn't read the rest of the code, but shouldn't the last line
 be changed to by += 3 when you're dropping a space from the strstr?

Absolutely, same in the for case. Thanks.

Jani.




 Best,

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


Re: [PATCH] lib: Add a new prefix list to the search-terms syntax

2013-10-17 Thread Jani Nikula
On Wed, 10 Apr 2013, Alexey I. Froloff ra...@raorn.name wrote:
 From: Alexey I. Froloff ra...@raorn.name

 Add support for indexing and searching the message's List-Id header.
 This is useful when matching all the messages belonging to a particular
 mailing list.

There's an issue with our duplicate message-id handling that is likely
to cause confusion with List-Id: searches. If you receive several
duplicates of the same message (judged by the message-id), only the
first one of them gets indexed, and the rest are ignored. This means
that for messages you receive both directly and through a list, it will
be arbitrary whether the List-Id: gets indexed or not. Therefore a list:
search might not return all the messages you'd expect.

BR,
Jani.


 Rework of the patch by Pablo Oliveira pa...@sifflez.org

 Differences from original patch:

 The whole list ID indexed as boolean term, not split by words.
 List description is not indexed at all.

 Thanks to ojwb and amdragon from irc://irc.freenode.net/notmuch

 Signed-off-by: Alexey I. Froloff ra...@raorn.name
 ---
  lib/database.cc |  1 +
  lib/index.cc| 45 
 -
  man/man7/notmuch-search-terms.7 |  8 
  3 files changed, 53 insertions(+), 1 deletion(-)

 diff --git a/lib/database.cc b/lib/database.cc
 index 91d4329..6313913 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -203,6 +203,7 @@ static prefix_t BOOLEAN_PREFIX_INTERNAL[] = {
  };
  
  static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
 +{ list,XLIST},
  { thread,  G },
  { tag, K },
  { is,  K },
 diff --git a/lib/index.cc b/lib/index.cc
 index a2edd6d..8b97ec3 100644
 --- a/lib/index.cc
 +++ b/lib/index.cc
 @@ -304,6 +304,46 @@ _index_address_list (notmuch_message_t *message,
  }
  }
  
 +static void
 +_index_list_id (notmuch_message_t *message,
 +   const char *list_id_header)
 +{
 +const char *begin_list_id, *end_list_id;
 +
 +if (list_id_header == NULL)
 + return;
 +
 +/* RFC2919 says that the list-id is found at the end of the header
 + * and enclosed between angle brackets. If we cannot find a
 + * matching pair of brackets containing at least one character,
 + * we ignore the list id header. */
 +begin_list_id = strrchr (list_id_header, '');
 +if (!begin_list_id) {
 + fprintf (stderr, Warning: Not indexing mailformed List-Id tag.\n);
 + return;
 +}
 +
 +end_list_id = strrchr(begin_list_id, '');
 +if (!end_list_id || (end_list_id - begin_list_id  2)) {
 + fprintf (stderr, Warning: Not indexing mailformed List-Id tag.\n);
 + return;
 +}
 +
 +void *local = talloc_new (message);
 +
 +/* We extract the list id between the angle brackets */
 +const char *list_id = talloc_strndup (local, begin_list_id + 1,
 +   end_list_id - begin_list_id - 1);
 +
 +/* _notmuch_message_add_term() may return
 + * NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG here.  We can't fix it, but
 + * this is not a reason to exit with error... */
 +if (_notmuch_message_add_term (message, list, list_id))
 + fprintf (stderr, Warning: Not indexing List-Id: %s\n, list_id);
 +
 +talloc_free (local);
 +}
 +
  /* Callback to generate terms for each mime part of a message. */
  static void
  _index_mime_part (notmuch_message_t *message,
 @@ -432,7 +472,7 @@ _notmuch_message_index_file (notmuch_message_t *message,
  GMimeMessage *mime_message = NULL;
  InternetAddressList *addresses;
  FILE *file = NULL;
 -const char *from, *subject;
 +const char *from, *subject, *list_id;
  notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
  static int initialized = 0;
  char from_buf[5];
 @@ -500,6 +540,9 @@ mboxes is deprecated and may be removed in the 
 future.\n, filename);
  subject = g_mime_message_get_subject (mime_message);
  _notmuch_message_gen_terms (message, subject, subject);
  
 +list_id = g_mime_object_get_header (GMIME_OBJECT (mime_message), 
 List-Id);
 +_index_list_id (message, list_id);
 +
  _index_mime_part (message, g_mime_message_get_mime_part (mime_message));
  
DONE:
 diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7
 index eb417ba..9cae107 100644
 --- a/man/man7/notmuch-search-terms.7
 +++ b/man/man7/notmuch-search-terms.7
 @@ -52,6 +52,8 @@ terms to match against specific portions of an email, (where
  
   thread:thread-id
  
 + list:list-id
 +
   folder:directory-path
  
   date:since..until
 @@ -100,6 +102,12 @@ thread ID values can be seen in the first column of 
 output from
  .B notmuch search
  
  The
 +.BR list: ,
 +is used to match mailing list ID of an email message \- contents of the
 +List\-Id: header without the '', '' delimiters or decoded list
 +description.
 +
 +The
  .B folder:
  prefix can be used to 

Re: Build broken on OS X 10.9

2013-10-26 Thread Jani Nikula
Please post the build log.

Jani.
On Oct 25, 2013 11:54 PM, Tad tadfis...@gmail.com wrote:

 Looks like notmuch 0.16 won't build on OS X 10.9 due to the switch to
 libc++. I don't know where to start with fixing this, but thought I'd
 let y'all know.
 ___
 notmuch mailing list
 notmuch@notmuchmail.org
 http://notmuchmail.org/mailman/listinfo/notmuch

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


[PATCH] lib: fix build on !HAVE_XAPIAN_COMPACT

2013-10-28 Thread Jani Nikula
Minimal change to build notmuch against xapian that doesn't have
compaction support.
---
 lib/database.cc |4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 06f1c0a..20e5ec2 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -944,7 +944,9 @@ DONE:
 }
 #else
 notmuch_status_t
-notmuch_database_compact_close (unused (notmuch_database_t *notmuch))
+notmuch_database_compact (unused (const char* path),
+ unused (const char* backup_path),
+ unused (notmuch_compact_status_cb_t status_cb))
 {
 fprintf (stderr, notmuch was compiled against a xapian version lacking 
compaction support.\n);
 return NOTMUCH_STATUS_UNSUPPORTED_OPERATION;
-- 
1.7.2.5

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


[PATCH 3/6] lib: use the backup path provided by the user, don't add anything to it

2013-11-01 Thread Jani Nikula
Adding another level is just useless cruft.
---
 lib/database.cc   |   14 --
 notmuch-compact.c |4 ++--
 2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index da549b4..9c99ac6 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -868,7 +868,6 @@ notmuch_database_compact (const char* path,
 {
 void *local = talloc_new (NULL);
 char *notmuch_path, *xapian_path, *compact_xapian_path;
-char *old_xapian_path = NULL;
 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
 notmuch_database_t *notmuch = NULL;
 struct stat statbuf;
@@ -894,13 +893,8 @@ notmuch_database_compact (const char* path,
 }
 
 if (backup_path != NULL) {
-   if (! (old_xapian_path = talloc_asprintf (local, %s/xapian.old, 
backup_path))) {
-   ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
-   goto DONE;
-   }
-
-   if (stat(old_xapian_path, statbuf) != -1) {
-   fprintf (stderr, Backup path already exists: %s\n, 
old_xapian_path);
+   if (stat(backup_path, statbuf) != -1) {
+   fprintf (stderr, Backup path already exists: %s\n, backup_path);
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
}
@@ -924,8 +918,8 @@ notmuch_database_compact (const char* path,
goto DONE;
 }
 
-if (old_xapian_path != NULL) {
-   if (rename(xapian_path, old_xapian_path)) {
+if (backup_path) {
+   if (rename(xapian_path, backup_path)) {
fprintf (stderr, Error moving old database out of the way\n);
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
diff --git a/notmuch-compact.c b/notmuch-compact.c
index ee7afcf..043710f 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -42,11 +42,11 @@ notmuch_compact_command (notmuch_config_t *config,
 } else {
printf (\n);
printf (\n);
-   printf (The old database has been moved to %s/xapian.old, 
backup_path);
+   printf (The old database has been moved to %s, backup_path);
printf (\n);
printf (To delete run,\n);
printf (\n);
-   printf (rm -R %s/xapian.old\n, backup_path);
+   printf (rm -R %s\n, backup_path);
printf (\n);
 }
 
-- 
1.7.2.5

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


[PATCH 4/6] cli: return error status if compaction fails

2013-11-01 Thread Jani Nikula
---
 notmuch-compact.c |   19 ++-
 1 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 043710f..2afa725 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -39,16 +39,17 @@ notmuch_compact_command (notmuch_config_t *config,
 ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
-} else {
-   printf (\n);
-   printf (\n);
-   printf (The old database has been moved to %s, backup_path);
-   printf (\n);
-   printf (To delete run,\n);
-   printf (\n);
-   printf (rm -R %s\n, backup_path);
-   printf (\n);
+   return 1;
 }
 
+printf (\n);
+printf (\n);
+printf (The old database has been moved to %s, backup_path);
+printf (\n);
+printf (To delete run,\n);
+printf (\n);
+printf (rm -R %s\n, backup_path);
+printf (\n);
+
 return 0;
 }
-- 
1.7.2.5

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


[PATCH 0/6] compactor changes

2013-11-01 Thread Jani Nikula
David was a bit hasty with pushing compact, so I missed the
review. Instead of just whining about it, here's a few changes I'd
really like to see merged before release. Completely untested, needs man
page updates and probably test changes too, so there's a bit more to do
still. Hint, if you have the time, just pick up from here. ;)

Cheers,
Jani.


Jani Nikula (6):
  lib: construct compactor within try block to catch any exceptions
  lib: add closure parameter to compact status update callback
  lib: use the backup path provided by the user, don't add anything to
it
  cli: return error status if compaction fails
  cli: add compact --backup=FILE option, don't backup by default
  cli: add compact --verbose option and silence output without it

 lib/database.cc   |   29 ++---
 lib/notmuch.h |5 +++--
 notmuch-compact.c |   46 +++---
 3 files changed, 44 insertions(+), 36 deletions(-)

-- 
1.7.2.5

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


[PATCH 1/6] lib: construct compactor within try block to catch any exceptions

2013-11-01 Thread Jani Nikula
Constructors may also throw exceptions. Catch them.
---
 lib/database.cc |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 20e5ec2..3dfea0f 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -864,7 +864,6 @@ notmuch_database_compact (const char* path,
  notmuch_compact_status_cb_t status_cb)
 {
 void *local = talloc_new (NULL);
-NotmuchCompactor compactor(status_cb);
 char *notmuch_path, *xapian_path, *compact_xapian_path;
 char *old_xapian_path = NULL;
 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
@@ -910,6 +909,8 @@ notmuch_database_compact (const char* path,
 }
 
 try {
+   NotmuchCompactor compactor(status_cb);
+
compactor.set_renumber(false);
compactor.add_source(xapian_path);
compactor.set_destdir(compact_xapian_path);
-- 
1.7.2.5

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


[PATCH 5/6] cli: add compact --backup=FILE option, don't backup by default

2013-11-01 Thread Jani Nikula
It's the user's decision. The recommended way is to do a database dump
anyway. Clean up the relevant printfs too.
---
 notmuch-compact.c |   27 +++
 1 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 2afa725..ecac86a 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -27,13 +27,20 @@ status_update_cb (const char *msg, unused (void *closure))
 }
 
 int
-notmuch_compact_command (notmuch_config_t *config,
-unused (int argc),
-unused (char *argv[]))
+notmuch_compact_command (notmuch_config_t *config, int argc, char *argv[])
 {
 const char *path = notmuch_config_get_database_path (config);
-const char *backup_path = path;
+const char *backup_path = NULL;
 notmuch_status_t ret;
+int opt_index;
+
+notmuch_opt_desc_t options[] = {
+   { NOTMUCH_OPT_STRING, backup_path, backup, 0, 0 },
+};
+
+opt_index = parse_arguments (argc, argv, options, 1);
+if (opt_index  0)
+   return 1;
 
 printf (Compacting database...\n);
 ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
@@ -42,14 +49,10 @@ notmuch_compact_command (notmuch_config_t *config,
return 1;
 }
 
-printf (\n);
-printf (\n);
-printf (The old database has been moved to %s, backup_path);
-printf (\n);
-printf (To delete run,\n);
-printf (\n);
-printf (rm -R %s\n, backup_path);
-printf (\n);
+printf (Done.\n);
+
+if (backup_path)
+   printf (The old database has been moved to %s.\n, backup_path);
 
 return 0;
 }
-- 
1.7.2.5

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


[PATCH 6/6] cli: add compact --verbose option and silence output without it

2013-11-01 Thread Jani Nikula
If there's nothing surprising to say, don't say anything. Unless asked
for by the user.
---
 notmuch-compact.c |   16 +++-
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index ecac86a..c0ae22e 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -32,27 +32,33 @@ notmuch_compact_command (notmuch_config_t *config, int 
argc, char *argv[])
 const char *path = notmuch_config_get_database_path (config);
 const char *backup_path = NULL;
 notmuch_status_t ret;
+notmuch_bool_t verbose;
 int opt_index;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, backup_path, backup, 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN,  verbose, verbose, 'v', 0 },
 };
 
 opt_index = parse_arguments (argc, argv, options, 1);
 if (opt_index  0)
return 1;
 
-printf (Compacting database...\n);
-ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
+if (verbose)
+   printf (Compacting database...\n);
+ret = notmuch_database_compact (path, backup_path,
+   verbose ? status_update_cb : NULL, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
return 1;
 }
 
-printf (Done.\n);
+if (verbose) {
+   printf (Done.\n);
 
-if (backup_path)
-   printf (The old database has been moved to %s.\n, backup_path);
+   if (backup_path)
+   printf (The old database has been moved to %s.\n, backup_path);
+}
 
 return 0;
 }
-- 
1.7.2.5

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


Re: [PATCH] lib: update documentation of callback functions for database_compact and database_upgrade.

2013-11-01 Thread Jani Nikula
The point was, we can do this *now* without soname bumps, because we
haven't released this yet.
 On Nov 2, 2013 1:16 AM, da...@tethera.net wrote:

 From: David Bremner brem...@debian.org

 Compact was missing callback documentation entirely, and upgrade did not
 discuss the
 closure parameter.
 ---
 This patch depends on


 id:2a58adbdc1257f16579692544b4bcbadca3d3045.1383315568.git.j...@nikula.org

 BTW, I didn't completely understand the remark about SONAME bumps;
 since we're providing new symbols, it doesn't really matter what the
 signature is?

  lib/notmuch.h | 6 +-
  1 file changed, 5 insertions(+), 1 deletion(-)

 diff --git a/lib/notmuch.h b/lib/notmuch.h
 index cd301a4..82fd599 100644
 --- a/lib/notmuch.h
 +++ b/lib/notmuch.h
 @@ -227,6 +227,9 @@ typedef void (*notmuch_compact_status_cb_t)(const char
 *message, void *closure);
   * The database will be opened with NOTMUCH_DATABASE_MODE_READ_WRITE
   * during the compaction process to ensure no writes are made.
   *
 + * If the optional callback function 'status_cb' is non-NULL, it will
 + * be called with diagnostic and informational messages. The argument
 + * 'closure' is passed verbatim to any callback invoked.
   */
  notmuch_status_t
  notmuch_database_compact (const char* path,
 @@ -270,7 +273,8 @@ notmuch_database_needs_upgrade (notmuch_database_t
 *database);
   * provide progress indication to the user. If non-NULL it will be
   * called periodically with 'progress' as a floating-point value in
   * the range of [0.0 .. 1.0] indicating the progress made so far in
 - * the upgrade process.
 + * the upgrade process.  The argument 'closure' is passed verbatim to
 + * any callback invoked.
   */
  notmuch_status_t
  notmuch_database_upgrade (notmuch_database_t *database,
 --
 1.8.4.rc3

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

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


Re: [PATCH 3/6] lib: use the backup path provided by the user, don't add anything to it

2013-11-02 Thread Jani Nikula
On Nov 2, 2013 2:14 PM, David Bremner da...@tethera.net wrote:

 Jani Nikula j...@nikula.org writes:

  Adding another level is just useless cruft.
  ---
   lib/database.cc   |   14 --
   notmuch-compact.c |4 ++--
   2 files changed, 6 insertions(+), 12 deletions(-)

 The first two patches are fine, modulo my comments about documentation.
 I think the backup path needs to be updated in notmuch-compact.c, and
 possible the test updated (after applying
 id:1383350515-24320-1-git-send-email-da...@tethera.net)

 d

Ah, right, I was juggling the patch order back and forth a bit, and I
missed this (as I drop the path completely in a later patch).

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


Re: Getting the right root mail of the thread

2013-11-02 Thread Jani Nikula
On Sat, 02 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:
 I often wondered why when browsing threads, I often see a message that doesn't
 describe at all the thread, for example:

   notmuch search ...
   thread:826a 18 mins. ago [45/45] Felipe Contreras; [PATCH/TEST 
 44/44]

 I can reverse the order of the search:

   notmuch search --sort=oldest-first
   thread:826a 23 mins. ago [45/45] Felipe Contreras; [PATCH/TEST 
 00/44]

 Then I get the correct summary, but now the order of the search is the other
 way around, and there doesn't seem to be a way to specify the order of the
 messages independently of the order of the threads.

I think it's actually worse than what your example demonstrates. It's
the subject of the newest/oldest *matching* message that gets used. In
your example, the first/last messages in the thread apparently match
your query.

 Either way this doesn't make any sense to me. Each thread has a single origin
 mail, why would anybody would like to show a message other than that while
 displaying the summary of the tread? Even more, why isn't there an option to
 fetch that information easily?

 I am forced to get the list of messages, and then grab the first one, even
 though it's not efficient, probably unnecessary, and potentiall wrong. For
 example, it's possible that multiple mails arrived at the same time, then how
 am I supposed to display the one that originated the thread?

 I think there should be a way to get the root mail of a thread,
 irrespective of the search order.

Largely agreed. It's just that nobody's gotten around to doing this
yet. At the cli level I think the consensus is that the structured
(sexp/json) output format should contain multiple (or all) subjects.


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


Re: Getting the right root mail of the thread

2013-11-02 Thread Jani Nikula
On Sat, 02 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:
 On Sat, Nov 2, 2013 at 7:50 AM, Jani Nikula j...@nikula.org wrote:
 On Sat, 02 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:

 I think there should be a way to get the root mail of a thread,
 irrespective of the search order.

 Largely agreed. It's just that nobody's gotten around to doing this
 yet. At the cli level I think the consensus is that the structured
 (sexp/json) output format should contain multiple (or all) subjects.

 What about the default? (--format=text). What about user-interfaces
 that must display a summary of a thread?

To be honest, we haven't had much interest in adding new content or
features to the text output formats. It's just much easier to do this in
a backwards compatible way in the structured output formats, for which
we also have the format versioning. The emacs ui uses the sexp format
for the thread summaries.

That said, if someone were interested in amending notmuch search
--format=text --output=summary, I don't think we'd have anything against
it. I'd say a new option to specify a format string would be the way to
go.


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


[PATCH v2 01/11] test: fix compact backup / restore test

2013-11-03 Thread Jani Nikula
From: David Bremner da...@tethera.net

It was looking in completely the wrong place for the backup and the
(test) xapian database. Unfortunately test_begin_subtest hides the
relevant errors.
---
 test/compact | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/test/compact b/test/compact
index 5bb5cea..afab537 100755
--- a/test/compact
+++ b/test/compact
@@ -19,10 +19,11 @@ thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One 
(inbox tag1 unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)
 
-test_begin_subtest Restoring backup
-rm -Rf ${TEST_TMPDIR}/mail/xapian
-mv ${TEST_TMPDIR}/mail/xapian.old ${TEST_TMPDIR}/mail/xapian
+test_expect_success 'Restoring Backup' \
+'rm -Rf ${MAIL_DIR}/.notmuch/xapian 
+ mv ${MAIL_DIR}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
 
+test_begin_subtest Checking restored backup
 output=$(notmuch search \* | notmuch_search_sanitize)
 test_expect_equal $output \
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
-- 
1.8.4.rc3

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


[PATCH v2 00/11] compactor changes v2

2013-11-03 Thread Jani Nikula
Hi all, this is v2 of [1], incorporating compact related patches from
David, some changes from David's review, some new patches, man page
update, test update.

Cheers,
Jani.


[1] id:cover.1383315568.git.j...@nikula.org


David Bremner (2):
  test: fix compact backup / restore test
  lib: update documentation of callback functions for database_compact
and database_upgrade.

Jani Nikula (9):
  lib: construct compactor within try block to catch any exceptions
  lib: check talloc success in compact
  lib: do not leak the database in compaction
  lib: add closure parameter to compact status update callback
  lib: use the compaction backup path provided by the caller
  cli: return error status if compaction fails
  cli: add compact --backup=DIRECTORY option, don't backup by default
  cli: add compact --verbose option and silence output without it
  man: document notmuch compact --verbose and --backup=DIRECTORY options

 lib/database.cc| 41 +++--
 lib/notmuch.h  | 11 ---
 man/man1/notmuch-compact.1 | 28 +++-
 notmuch-compact.c  | 46 +++---
 test/compact   |  9 +
 5 files changed, 90 insertions(+), 45 deletions(-)

-- 
1.8.4.rc3

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


[PATCH v2 03/11] lib: check talloc success in compact

2013-11-03 Thread Jani Nikula
In line with the allocation checks all around.
---
 lib/database.cc | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/database.cc b/lib/database.cc
index 3dfea0f..7a8702e 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -863,13 +863,17 @@ notmuch_database_compact (const char* path,
  const char* backup_path,
  notmuch_compact_status_cb_t status_cb)
 {
-void *local = talloc_new (NULL);
+void *local;
 char *notmuch_path, *xapian_path, *compact_xapian_path;
 char *old_xapian_path = NULL;
 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
 notmuch_database_t *notmuch = NULL;
 struct stat statbuf;
 
+local = talloc_new (NULL);
+if (! local)
+   return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
 ret = notmuch_database_open(path, NOTMUCH_DATABASE_MODE_READ_WRITE, 
notmuch);
 if (ret) {
goto DONE;
-- 
1.8.4.rc3

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


[PATCH v2 02/11] lib: construct compactor within try block to catch any exceptions

2013-11-03 Thread Jani Nikula
Constructors may also throw exceptions. Catch them.
---
 lib/database.cc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/database.cc b/lib/database.cc
index 20e5ec2..3dfea0f 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -864,7 +864,6 @@ notmuch_database_compact (const char* path,
  notmuch_compact_status_cb_t status_cb)
 {
 void *local = talloc_new (NULL);
-NotmuchCompactor compactor(status_cb);
 char *notmuch_path, *xapian_path, *compact_xapian_path;
 char *old_xapian_path = NULL;
 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
@@ -910,6 +909,8 @@ notmuch_database_compact (const char* path,
 }
 
 try {
+   NotmuchCompactor compactor(status_cb);
+
compactor.set_renumber(false);
compactor.add_source(xapian_path);
compactor.set_destdir(compact_xapian_path);
-- 
1.8.4.rc3

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


[PATCH v2 05/11] lib: add closure parameter to compact status update callback

2013-11-03 Thread Jani Nikula
This provides much more flexibility for the caller.
---
 lib/database.cc   | 14 +-
 lib/notmuch.h |  5 +++--
 notmuch-compact.c |  8 +++-
 3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index eadf8a7..5a01703 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -821,9 +821,11 @@ static int rmtree (const char *path)
 class NotmuchCompactor : public Xapian::Compactor
 {
 notmuch_compact_status_cb_t status_cb;
+void *status_closure;
 
 public:
-NotmuchCompactor(notmuch_compact_status_cb_t cb) : status_cb(cb) { }
+NotmuchCompactor(notmuch_compact_status_cb_t cb, void *closure) :
+   status_cb(cb), status_closure(closure) { }
 
 virtual void
 set_status (const std::string table, const std::string status)
@@ -842,7 +844,7 @@ public:
return;
}
 
-   status_cb(msg);
+   status_cb(msg, status_closure);
talloc_free(msg);
 }
 };
@@ -861,7 +863,8 @@ public:
 notmuch_status_t
 notmuch_database_compact (const char* path,
  const char* backup_path,
- notmuch_compact_status_cb_t status_cb)
+ notmuch_compact_status_cb_t status_cb,
+ void *closure)
 {
 void *local;
 char *notmuch_path, *xapian_path, *compact_xapian_path;
@@ -913,7 +916,7 @@ notmuch_database_compact (const char* path,
 }
 
 try {
-   NotmuchCompactor compactor(status_cb);
+   NotmuchCompactor compactor(status_cb, closure);
 
compactor.set_renumber(false);
compactor.add_source(xapian_path);
@@ -953,7 +956,8 @@ DONE:
 notmuch_status_t
 notmuch_database_compact (unused (const char* path),
  unused (const char* backup_path),
- unused (notmuch_compact_status_cb_t status_cb))
+ unused (notmuch_compact_status_cb_t status_cb),
+ unused (void *closure))
 {
 fprintf (stderr, notmuch was compiled against a xapian version lacking 
compaction support.\n);
 return NOTMUCH_STATUS_UNSUPPORTED_OPERATION;
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 9dab555..cd301a4 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -219,7 +219,7 @@ notmuch_database_close (notmuch_database_t *database);
 /* A callback invoked by notmuch_database_compact to notify the user
  * of the progress of the compaction process.
  */
-typedef void (*notmuch_compact_status_cb_t)(const char*);
+typedef void (*notmuch_compact_status_cb_t)(const char *message, void 
*closure);
 
 /* Compact a notmuch database, backing up the original database to the
  * given path.
@@ -231,7 +231,8 @@ typedef void (*notmuch_compact_status_cb_t)(const char*);
 notmuch_status_t
 notmuch_database_compact (const char* path,
  const char* backup_path,
- notmuch_compact_status_cb_t status_cb);
+ notmuch_compact_status_cb_t status_cb,
+ void *closure);
 
 /* Destroy the notmuch database, closing it if necessary and freeing
  * all associated resources.
diff --git a/notmuch-compact.c b/notmuch-compact.c
index bfda40e..ee7afcf 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -20,10 +20,8 @@
 
 #include notmuch-client.h
 
-void status_update_cb (const char *msg);
-
-void
-status_update_cb (const char *msg)
+static void
+status_update_cb (const char *msg, unused (void *closure))
 {
 printf(%s\n, msg);
 }
@@ -38,7 +36,7 @@ notmuch_compact_command (notmuch_config_t *config,
 notmuch_status_t ret;
 
 printf (Compacting database...\n);
-ret = notmuch_database_compact (path, backup_path, status_update_cb);
+ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
 } else {
-- 
1.8.4.rc3

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


[PATCH v2 06/11] lib: update documentation of callback functions for database_compact and database_upgrade.

2013-11-03 Thread Jani Nikula
From: David Bremner brem...@debian.org

Compact was missing callback documentation entirely, and upgrade did not 
discuss the
closure parameter.
---
 lib/notmuch.h | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index cd301a4..82fd599 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -227,6 +227,9 @@ typedef void (*notmuch_compact_status_cb_t)(const char 
*message, void *closure);
  * The database will be opened with NOTMUCH_DATABASE_MODE_READ_WRITE
  * during the compaction process to ensure no writes are made.
  *
+ * If the optional callback function 'status_cb' is non-NULL, it will
+ * be called with diagnostic and informational messages. The argument
+ * 'closure' is passed verbatim to any callback invoked.
  */
 notmuch_status_t
 notmuch_database_compact (const char* path,
@@ -270,7 +273,8 @@ notmuch_database_needs_upgrade (notmuch_database_t 
*database);
  * provide progress indication to the user. If non-NULL it will be
  * called periodically with 'progress' as a floating-point value in
  * the range of [0.0 .. 1.0] indicating the progress made so far in
- * the upgrade process.
+ * the upgrade process.  The argument 'closure' is passed verbatim to
+ * any callback invoked.
  */
 notmuch_status_t
 notmuch_database_upgrade (notmuch_database_t *database,
-- 
1.8.4.rc3

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


[PATCH v2 10/11] cli: add compact --verbose option and silence output without it

2013-11-03 Thread Jani Nikula
If there's nothing surprising to say, don't say anything. Unless asked
for by the user.
---
 notmuch-compact.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 359acfc..1e7808c 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -32,27 +32,33 @@ notmuch_compact_command (notmuch_config_t *config, int 
argc, char *argv[])
 const char *path = notmuch_config_get_database_path (config);
 const char *backup_path = NULL;
 notmuch_status_t ret;
+notmuch_bool_t verbose;
 int opt_index;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, backup_path, backup, 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN,  verbose, verbose, 'v', 0 },
 };
 
 opt_index = parse_arguments (argc, argv, options, 1);
 if (opt_index  0)
return 1;
 
-printf (Compacting database...\n);
-ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
+if (verbose)
+   printf (Compacting database...\n);
+ret = notmuch_database_compact (path, backup_path,
+   verbose ? status_update_cb : NULL, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
return 1;
 }
 
-if (backup_path)
-   printf (The old database has been moved to %s.\n, backup_path);
+if (verbose) {
+   if (backup_path)
+   printf (The old database has been moved to %s.\n, backup_path);
 
-printf (Done.\n);
+   printf (Done.\n);
+}
 
 return 0;
 }
-- 
1.8.4.rc3

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


[PATCH v2 08/11] cli: return error status if compaction fails

2013-11-03 Thread Jani Nikula
As is customary for any tool.
---
 notmuch-compact.c | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 55dc731..b9461c2 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -43,16 +43,17 @@ notmuch_compact_command (notmuch_config_t *config,
 ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
-} else {
-   printf (\n);
-   printf (\n);
-   printf (The old database has been moved to %s, backup_path);
-   printf (\n);
-   printf (To delete run,\n);
-   printf (\n);
-   printf (rm -R %s\n, backup_path);
-   printf (\n);
+   return 1;
 }
 
+printf (\n);
+printf (\n);
+printf (The old database has been moved to %s, backup_path);
+printf (\n);
+printf (To delete run,\n);
+printf (\n);
+printf (rm -R %s\n, backup_path);
+printf (\n);
+
 return 0;
 }
-- 
1.8.4.rc3

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


[PATCH v2 07/11] lib: use the compaction backup path provided by the caller

2013-11-03 Thread Jani Nikula
The extra path component added by the lib is a magic value that the
caller just has to know. This is demonstrated by the current code,
which indeed has xapian.old both sides of the interface. Use the
backup path provided by the lib caller verbatim, without adding
anything to it.

---

v2: add xapian.old in cli
---
 lib/database.cc   | 14 --
 notmuch-compact.c | 10 +++---
 2 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 5a01703..a021bf1 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -868,7 +868,6 @@ notmuch_database_compact (const char* path,
 {
 void *local;
 char *notmuch_path, *xapian_path, *compact_xapian_path;
-char *old_xapian_path = NULL;
 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
 notmuch_database_t *notmuch = NULL;
 struct stat statbuf;
@@ -898,13 +897,8 @@ notmuch_database_compact (const char* path,
 }
 
 if (backup_path != NULL) {
-   if (! (old_xapian_path = talloc_asprintf (local, %s/xapian.old, 
backup_path))) {
-   ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
-   goto DONE;
-   }
-
-   if (stat(old_xapian_path, statbuf) != -1) {
-   fprintf (stderr, Backup path already exists: %s\n, 
old_xapian_path);
+   if (stat(backup_path, statbuf) != -1) {
+   fprintf (stderr, Backup path already exists: %s\n, backup_path);
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
}
@@ -928,8 +922,8 @@ notmuch_database_compact (const char* path,
goto DONE;
 }
 
-if (old_xapian_path != NULL) {
-   if (rename(xapian_path, old_xapian_path)) {
+if (backup_path) {
+   if (rename(xapian_path, backup_path)) {
fprintf (stderr, Error moving old database out of the way\n);
ret = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
diff --git a/notmuch-compact.c b/notmuch-compact.c
index ee7afcf..55dc731 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -32,9 +32,13 @@ notmuch_compact_command (notmuch_config_t *config,
 unused (char *argv[]))
 {
 const char *path = notmuch_config_get_database_path (config);
-const char *backup_path = path;
+const char *backup_path;
 notmuch_status_t ret;
 
+backup_path = talloc_asprintf (config, %s/xapian.old, path);
+if (! backup_path)
+   return 1;
+
 printf (Compacting database...\n);
 ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
 if (ret) {
@@ -42,11 +46,11 @@ notmuch_compact_command (notmuch_config_t *config,
 } else {
printf (\n);
printf (\n);
-   printf (The old database has been moved to %s/xapian.old, 
backup_path);
+   printf (The old database has been moved to %s, backup_path);
printf (\n);
printf (To delete run,\n);
printf (\n);
-   printf (rm -R %s/xapian.old\n, backup_path);
+   printf (rm -R %s\n, backup_path);
printf (\n);
 }
 
-- 
1.8.4.rc3

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


[PATCH v2 09/11] cli: add compact --backup=DIRECTORY option, don't backup by default

2013-11-03 Thread Jani Nikula
It's the user's decision. The recommended way is to do a database dump
anyway. Clean up the relevant printfs too.

---

v2: reorder prints
---
 notmuch-compact.c | 27 +--
 test/compact  |  4 ++--
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index b9461c2..359acfc 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -27,16 +27,19 @@ status_update_cb (const char *msg, unused (void *closure))
 }
 
 int
-notmuch_compact_command (notmuch_config_t *config,
-unused (int argc),
-unused (char *argv[]))
+notmuch_compact_command (notmuch_config_t *config, int argc, char *argv[])
 {
 const char *path = notmuch_config_get_database_path (config);
-const char *backup_path;
+const char *backup_path = NULL;
 notmuch_status_t ret;
+int opt_index;
 
-backup_path = talloc_asprintf (config, %s/xapian.old, path);
-if (! backup_path)
+notmuch_opt_desc_t options[] = {
+   { NOTMUCH_OPT_STRING, backup_path, backup, 0, 0 },
+};
+
+opt_index = parse_arguments (argc, argv, options, 1);
+if (opt_index  0)
return 1;
 
 printf (Compacting database...\n);
@@ -46,14 +49,10 @@ notmuch_compact_command (notmuch_config_t *config,
return 1;
 }
 
-printf (\n);
-printf (\n);
-printf (The old database has been moved to %s, backup_path);
-printf (\n);
-printf (To delete run,\n);
-printf (\n);
-printf (rm -R %s\n, backup_path);
-printf (\n);
+if (backup_path)
+   printf (The old database has been moved to %s.\n, backup_path);
+
+printf (Done.\n);
 
 return 0;
 }
diff --git a/test/compact b/test/compact
index afab537..ac174ce 100755
--- a/test/compact
+++ b/test/compact
@@ -10,7 +10,7 @@ notmuch tag +tag1 \*
 notmuch tag +tag2 subject:Two
 notmuch tag -tag1 +tag3 subject:Three
 
-test_expect_success Running compact notmuch compact
+test_expect_success Running compact notmuch compact 
--backup=${TEST_DIRECTORY}/xapian.old
 
 test_begin_subtest Compact preserves database
 output=$(notmuch search \* | notmuch_search_sanitize)
@@ -21,7 +21,7 @@ thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Three 
(inbox tag3 unread)
 
 test_expect_success 'Restoring Backup' \
 'rm -Rf ${MAIL_DIR}/.notmuch/xapian 
- mv ${MAIL_DIR}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
+ mv ${TEST_DIRECTORY}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
 
 test_begin_subtest Checking restored backup
 output=$(notmuch search \* | notmuch_search_sanitize)
-- 
1.8.4.rc3

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


[PATCH v2 11/11] man: document notmuch compact --verbose and --backup=DIRECTORY options

2013-11-03 Thread Jani Nikula
---
 man/man1/notmuch-compact.1 | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/man/man1/notmuch-compact.1 b/man/man1/notmuch-compact.1
index 1aeed22..dfffccb 100644
--- a/man/man1/notmuch-compact.1
+++ b/man/man1/notmuch-compact.1
@@ -4,6 +4,8 @@ notmuch-compact \- compact the notmuch database
 .SH SYNOPSIS
 
 .B notmuch compact
+.RI [ --verbose ]
+.RI [ --backup= directory  ]
 
 .SH DESCRIPTION
 
@@ -14,11 +16,35 @@ the space required by the database and improve lookup 
performance.
 
 The compacted database is built in a temporary directory and is later
 moved into the place of the origin database. The original uncompacted
-database is preserved to be deleted by the user as desired.
+database is discarded, unless the
+.BR \-\-backup= directory
+option is used.
 
 Note that the database write lock will be held during the compaction
 process (which may be quite long) to protect data integrity.
 
+Supported options for
+.B compact
+include
+
+.RS 4
+.TP 4
+.BR \-\-backup= directory
+
+Save the current database to the given directory before replacing it
+with the compacted database. The backup directory must not exist and
+it must reside on the same mounted filesystem as the current database.
+
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-verbose
+
+Report database compaction progress to stdout.
+
+.RE
+
 .RE
 .SH ENVIRONMENT
 The following environment variables can be used to control the
-- 
1.8.4.rc3

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


Re: [PATCH] test: fix compact backup / restore test

2013-11-03 Thread Jani Nikula
On Sat, 02 Nov 2013, David Bremner da...@tethera.net wrote:
 It was looking in completely the wrong place for the backup and the
 (test) xapian database. Unfortunately test_begin_subtest hides the
 relevant errors.

I included this, unchanged, in my series [1] that depends on it. It
makes no difference which one is pushed.

BR,
Jani.

[1] id:cover.1383481295.git.j...@nikula.org


 ---

 I found this bug because 

   id:9ee3f2334a117b0a1b88650f44432423cbe95fd7.1383315568.git.j...@nikula.org

 did _not_ break any tests. Which was puzzling.

  test/compact | 7 ---
  1 file changed, 4 insertions(+), 3 deletions(-)

 diff --git a/test/compact b/test/compact
 index 5bb5cea..afab537 100755
 --- a/test/compact
 +++ b/test/compact
 @@ -19,10 +19,11 @@ thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One 
 (inbox tag1 unread)
  thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 
 unread)
  thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)
  
 -test_begin_subtest Restoring backup
 -rm -Rf ${TEST_TMPDIR}/mail/xapian
 -mv ${TEST_TMPDIR}/mail/xapian.old ${TEST_TMPDIR}/mail/xapian
 +test_expect_success 'Restoring Backup' \
 +'rm -Rf ${MAIL_DIR}/.notmuch/xapian 
 + mv ${MAIL_DIR}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
  
 +test_begin_subtest Checking restored backup
  output=$(notmuch search \* | notmuch_search_sanitize)
  test_expect_equal $output \
  thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
 -- 
 1.8.4.rc3

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


Re: Getting the right root mail of the thread

2013-11-03 Thread Jani Nikula
On Sun, 03 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:
 On Sat, Nov 2, 2013 at 8:58 AM, Jani Nikula j...@nikula.org wrote:
 On Sat, 02 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:
 On Sat, Nov 2, 2013 at 7:50 AM, Jani Nikula j...@nikula.org wrote:
 On Sat, 02 Nov 2013, Felipe Contreras felipe.contre...@gmail.com wrote:

 I think there should be a way to get the root mail of a thread,
 irrespective of the search order.

 Largely agreed. It's just that nobody's gotten around to doing this
 yet. At the cli level I think the consensus is that the structured
 (sexp/json) output format should contain multiple (or all) subjects.

 What about the default? (--format=text). What about user-interfaces
 that must display a summary of a thread?

 To be honest, we haven't had much interest in adding new content or
 features to the text output formats. It's just much easier to do this in
 a backwards compatible way in the structured output formats, for which
 we also have the format versioning. The emacs ui uses the sexp format
 for the thread summaries.

 How is this any better?

 (:thread 826a :timestamp 1383396519 :date_relative
 Yest. 06:48 :matched 45 :total 45 :authors Felipe Contreras
 :subject [PATCH/TEST 44/44] request-pull: rewrite to C :tags (sent
 to-me))

I made no claims it would contain more or better information *now*. But
if someone were to add new things, the structured output is where it
would likely be added. We could add :subject_first, :subject_oldest, or
whatever *in addition* to :subject.

BR,
Jani.

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


Re: Getting the right root mail of the thread

2013-11-03 Thread Jani Nikula
On Sun, 03 Nov 2013, Jesse Rosenthal jrosent...@jhu.edu wrote:
 The current behavior can be annoying, but the old behavior could make
 the MUA quite unusable in a number of circumstances. (And yes, an MUA
 that fails on reading mail from senders with bad emailing practices is
 unusable for me.)

I wouldn't have suggested changing the current default behaviour anyway,
but thanks for reminding us there are users depending on it!

 Maybe there should be a show original subject toggle? That wouldn't be
 too hard, though it would require another call to the library and
 regenerating the search results.

IMO the best approach would be including the first (or oldest, or
original) subject in the structured thread summary output, in addition
to the first matching subject that we have now.

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


Re: [PATCH v2 07/11] lib: use the compaction backup path provided by the caller

2013-11-05 Thread Jani Nikula
On Tue, 05 Nov 2013, David Bremner da...@tethera.net wrote:
 Jani Nikula j...@nikula.org writes:

 +backup_path = talloc_asprintf (config, %s/xapian.old, path);
 +if (! backup_path)
 +return 1;
 +

 Is it intentional that no message is printed here? A random glance at
 notmuch-search.c suggests we usually print a message on OOM in the CLI.

Oversight.

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


[PATCH 1/2] cli: add compact --quiet option and silence output with it

2013-11-06 Thread Jani Nikula
Provide a way to silence the output.

---

v2: --verbose - --quiet
---
 notmuch-compact.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 359acfc..8022dfe 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -32,27 +32,33 @@ notmuch_compact_command (notmuch_config_t *config, int 
argc, char *argv[])
 const char *path = notmuch_config_get_database_path (config);
 const char *backup_path = NULL;
 notmuch_status_t ret;
+notmuch_bool_t quiet;
 int opt_index;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, backup_path, backup, 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN,  quiet, quiet, 'q', 0 },
 };
 
 opt_index = parse_arguments (argc, argv, options, 1);
 if (opt_index  0)
return 1;
 
-printf (Compacting database...\n);
-ret = notmuch_database_compact (path, backup_path, status_update_cb, NULL);
+if (! quiet)
+   printf (Compacting database...\n);
+ret = notmuch_database_compact (path, backup_path,
+   quiet ? NULL : status_update_cb, NULL);
 if (ret) {
fprintf (stderr, Compaction failed: %s\n, 
notmuch_status_to_string(ret));
return 1;
 }
 
-if (backup_path)
-   printf (The old database has been moved to %s.\n, backup_path);
+if (! quiet) {
+   if (backup_path)
+   printf (The old database has been moved to %s.\n, backup_path);
 
-printf (Done.\n);
+   printf (Done.\n);
+}
 
 return 0;
 }
-- 
1.8.4.rc3

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


[RFC PATCH 2/2] lib: modify notmuch.h for automatic document generation

2013-11-06 Thread Jani Nikula
Minimal changes to produce a sensible result.
---
 lib/notmuch.h | 426 +++---
 1 file changed, 289 insertions(+), 137 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index 9dab555..6d91b17 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -18,9 +18,19 @@
  * Author: Carl Worth cwo...@cworth.org
  */
 
+/**
+ * @defgroup notmuch The notmuch API
+ *
+ * Not much of an email library, (just index and search)
+ *
+ * @{
+ */
+
 #ifndef NOTMUCH_H
 #define NOTMUCH_H
 
+#ifndef __DOXYGEN__
+
 #ifdef  __cplusplus
 # define NOTMUCH_BEGIN_DECLS  extern C {
 # define NOTMUCH_END_DECLS}
@@ -33,6 +43,8 @@ NOTMUCH_BEGIN_DECLS
 
 #include time.h
 
+#endif /* __DOXYGEN__ */
+
 #ifndef FALSE
 #define FALSE 0
 #endif
@@ -41,72 +53,87 @@ NOTMUCH_BEGIN_DECLS
 #define TRUE 1
 #endif
 
+/**
+ * Notmuch boolean type.
+ */
 typedef int notmuch_bool_t;
 
-/* Status codes used for the return values of most functions.
+/**
+ * Status codes used for the return values of most functions.
  *
  * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
- * completed without error. Any other value indicates an error as
- * follows:
- *
- * NOTMUCH_STATUS_SUCCESS: No error occurred.
- *
- * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory
- *
- * XXX: We don't really want to expose this lame XAPIAN_EXCEPTION
- * value. Instead we should map to things like DATABASE_LOCKED or
- * whatever.
- *
- * NOTMUCH_STATUS_READ_ONLY_DATABASE: An attempt was made to write to
- * a database opened in read-only mode.
+ * completed without error. Any other value indicates an error.
  *
- * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
- *
- * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to read or
- * write to a file (this could be file not found, permission
- * denied, etc.)
- *
- * NOTMUCH_STATUS_FILE_NOT_EMAIL: A file was presented that doesn't
- * appear to be an email message.
- *
- * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: A file contains a message ID
- * that is identical to a message already in the database.
- *
- * NOTMUCH_STATUS_NULL_POINTER: The user erroneously passed a NULL
- * pointer to a notmuch function.
- *
- * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds
- * NOTMUCH_TAG_MAX)
- *
- * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw
- * function has been called more times than notmuch_message_freeze.
- *
- * NOTMUCH_STATUS_UNBALANCED_ATOMIC: notmuch_database_end_atomic has
- * been called more times than notmuch_database_begin_atomic.
- *
- * And finally:
- *
- * NOTMUCH_STATUS_LAST_STATUS: Not an actual status value. Just a way
- * to find out how many valid status values there are.
  */
 typedef enum _notmuch_status {
+/**
+ * No error occurred.
+ */
 NOTMUCH_STATUS_SUCCESS = 0,
+/**
+ * Out of memory.
+ */
 NOTMUCH_STATUS_OUT_OF_MEMORY,
+/**
+ * An attempt was made to write to a database opened in read-only
+ * mode.
+ */
 NOTMUCH_STATUS_READ_ONLY_DATABASE,
+/**
+ * A Xapian exception occurred.
+ */
 NOTMUCH_STATUS_XAPIAN_EXCEPTION,
+/**
+ * An error occurred trying to read or write to a file (this could
+ * be file not found, permission denied, etc.)
+ *
+ * @todo We don't really want to expose this lame XAPIAN_EXCEPTION
+ * value. Instead we should map to things like DATABASE_LOCKED or
+ * whatever.
+ */
 NOTMUCH_STATUS_FILE_ERROR,
+/**
+ * A file was presented that doesn't appear to be an email
+ * message.
+ */
 NOTMUCH_STATUS_FILE_NOT_EMAIL,
+/**
+ * A file contains a message ID that is identical to a message
+ * already in the database.
+ */
 NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,
+/**
+ * The user erroneously passed a NULL pointer to a notmuch
+ * function.
+ */
 NOTMUCH_STATUS_NULL_POINTER,
+/**
+ * A tag value is too long (exceeds NOTMUCH_TAG_MAX).
+ */
 NOTMUCH_STATUS_TAG_TOO_LONG,
+/**
+ * The notmuch_message_thaw function has been called more times
+ * than notmuch_message_freeze.
+ */
 NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW,
+/**
+ * notmuch_database_end_atomic has been called more times than
+ * notmuch_database_begin_atomic.
+ */
 NOTMUCH_STATUS_UNBALANCED_ATOMIC,
+/**
+ * The operation is not supported.
+ */
 NOTMUCH_STATUS_UNSUPPORTED_OPERATION,
-
+/**
+ * Not an actual status value. Just a way to find out how many
+ * valid status values there are.
+ */
 NOTMUCH_STATUS_LAST_STATUS
 } notmuch_status_t;
 
-/* Get a string representation of a notmuch_status_t value.
+/**
+ * Get a string representation of a notmuch_status_t value.
  *
  * The result is read-only.
  */
@@ -125,7 +152,8 @@ typedef struct _notmuch_tags notmuch_tags_t;
 typedef struct _notmuch_directory notmuch_directory_t;
 typedef struct 

[PATCH 2/2] man: document notmuch compact --quiet and --backup=DIRECTORY options

2013-11-06 Thread Jani Nikula
---

v2: --verbose - --quiet
---
 man/man1/notmuch-compact.1 | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/man/man1/notmuch-compact.1 b/man/man1/notmuch-compact.1
index 1aeed22..0c95873 100644
--- a/man/man1/notmuch-compact.1
+++ b/man/man1/notmuch-compact.1
@@ -4,6 +4,8 @@ notmuch-compact \- compact the notmuch database
 .SH SYNOPSIS
 
 .B notmuch compact
+.RI [ --quiet ]
+.RI [ --backup= directory  ]
 
 .SH DESCRIPTION
 
@@ -14,11 +16,35 @@ the space required by the database and improve lookup 
performance.
 
 The compacted database is built in a temporary directory and is later
 moved into the place of the origin database. The original uncompacted
-database is preserved to be deleted by the user as desired.
+database is discarded, unless the
+.BR \-\-backup= directory
+option is used.
 
 Note that the database write lock will be held during the compaction
 process (which may be quite long) to protect data integrity.
 
+Supported options for
+.B compact
+include
+
+.RS 4
+.TP 4
+.BR \-\-backup= directory
+
+Save the current database to the given directory before replacing it
+with the compacted database. The backup directory must not exist and
+it must reside on the same mounted filesystem as the current database.
+
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-quiet
+
+Do not report database compaction progress to stdout.
+
+.RE
+
 .RE
 .SH ENVIRONMENT
 The following environment variables can be used to control the
-- 
1.8.4.rc3

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


[PATCH] lib: add library version check macro

2013-11-06 Thread Jani Nikula
There have been some plans for making build incompatible changes to
the library API. This is inconvenient, but it is much more so without
a way to easily conditional build against multiple versions of
notmuch.

The macro has been lifted from glib.
---
 lib/notmuch.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index 9dab555..d109a2c 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -41,6 +41,30 @@ NOTMUCH_BEGIN_DECLS
 #define TRUE 1
 #endif
 
+#define NOTMUCH_MAJOR_VERSION  0
+#define NOTMUCH_MINOR_VERSION  17
+#define NOTMUCH_MICRO_VERSION  0
+
+/*
+ * Check the version of the notmuch library being compiled against.
+ *
+ * Return true if the library being compiled against is of the
+ * specified version or above. For example:
+ *
+ * #if NOTMUCH_CHECK_VERSION(0, 18, 0)
+ * (code requiring notmuch 0.18 or above)
+ * #endif
+ *
+ * NOTMUCH_CHECK_VERSION has been defined since version 0.17.0; you
+ * can use #if !defined(NOTMUCH_CHECK_VERSION) to check for versions
+ * prior to that.
+ */
+#define NOTMUCH_CHECK_VERSION (major, minor, micro)\
+(NOTMUCH_MAJOR_VERSION  (major) ||
\
+ (NOTMUCH_MAJOR_VERSION == (major)  NOTMUCH_MINOR_VERSION  (minor)) || \
+ (NOTMUCH_MAJOR_VERSION == (major)  NOTMUCH_MINOR_VERSION == (minor)  \
+  NOTMUCH_MICRO_VERSION = (micro)))
+
 typedef int notmuch_bool_t;
 
 /* Status codes used for the return values of most functions.
-- 
1.8.4.rc3

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


[PATCH] completion: update bash completion

2013-11-06 Thread Jani Nikula
Update bash completion to cover new commands and options:

notmuch compact --quiet --backup=DIR
notmuch count --output=files --batch --input=FILE
notmuch insert --folder=DIR --create-folder
notmuch search --exclude=all --duplicate=N
notmuch show --include-html
notmuch tag --batch --input=FILE --remove-all

---

This logically depends on id:cover.1383481295.git.j...@nikula.org
which adds --quiet and --backup=DIR parameters to compact.
---
 completion/notmuch-completion.bash | 89 +++---
 1 file changed, 82 insertions(+), 7 deletions(-)

diff --git a/completion/notmuch-completion.bash 
b/completion/notmuch-completion.bash
index 7bd7745..04324bb 100644
--- a/completion/notmuch-completion.bash
+++ b/completion/notmuch-completion.bash
@@ -59,6 +59,29 @@ _notmuch_search_terms()
 __ltrim_colon_completions ${cur}
 }
 
+_notmuch_compact()
+{
+local cur prev words cword split
+_init_completion -s || return
+
+$split 
+case ${prev} in
+   --backup)
+   _filedir
+   return
+   ;;
+esac
+
+! $split 
+case ${cur} in
+   -*)
+   local options=--backup= --quiet
+   compopt -o nospace
+   COMPREPLY=( $(compgen -W $options -- ${cur}) )
+   ;;
+esac
+}
+
 _notmuch_config()
 {
 local cur prev words cword split
@@ -89,19 +112,23 @@ _notmuch_count()
 $split 
 case ${prev} in
--output)
-   COMPREPLY=( $( compgen -W messages threads -- ${cur} ) )
+   COMPREPLY=( $( compgen -W messages threads files -- ${cur} ) )
return
;;
--exclude)
COMPREPLY=( $( compgen -W true false -- ${cur} ) )
return
;;
+   --input)
+   _filedir
+   return
+   ;;
 esac
 
 ! $split 
 case ${cur} in
-*)
-   local options=--output= --exclude=
+   local options=--output= --exclude= --batch --input=
compopt -o nospace
COMPREPLY=( $(compgen -W $options -- ${cur}) )
;;
@@ -141,6 +168,39 @@ _notmuch_dump()
 esac
 }
 
+_notmuch_insert()
+{
+local cur prev words cword split
+# handle tags with colons and equal signs
+_init_completion -s -n := || return
+
+$split 
+case ${prev} in
+   --folder)
+   _filedir
+   return
+   ;;
+esac
+
+! $split 
+case ${cur} in
+   --*)
+   local options=--create-folder --folder=
+   compopt -o nospace
+   COMPREPLY=( $(compgen -W $options -- ${cur}) )
+   return
+   ;;
+   +*)
+   COMPREPLY=( $(compgen -P + -W `notmuch search --output=tags \*` 
-- ${cur##+}) )
+   ;;
+   -*)
+   COMPREPLY=( $(compgen -P - -W `notmuch search --output=tags \*` 
-- ${cur##-}) )
+   ;;
+esac
+# handle tags with colons
+__ltrim_colon_completions ${cur}
+}
+
 _notmuch_new()
 {
 local cur prev words cword split
@@ -231,7 +291,7 @@ _notmuch_search()
return
;;
--exclude)
-   COMPREPLY=( $( compgen -W true false flag -- ${cur} ) )
+   COMPREPLY=( $( compgen -W true false flag all -- ${cur} ) )
return
;;
 esac
@@ -239,7 +299,7 @@ _notmuch_search()
 ! $split 
 case ${cur} in
-*)
-   local options=--format= --output= --sort= --offset= --limit= 
--exclude=
+   local options=--format= --output= --sort= --offset= --limit= 
--exclude= --duplicate=
compopt -o nospace
COMPREPLY=( $(compgen -W $options -- ${cur}) )
;;
@@ -273,7 +333,7 @@ _notmuch_show()
 ! $split 
 case ${cur} in
-*)
-   local options=--entire-thread= --format= --exclude= --body= 
--format-version= --part= --verify --decrypt
+   local options=--entire-thread= --format= --exclude= --body= 
--format-version= --part= --verify --decrypt --include-html
compopt -o nospace
COMPREPLY=( $(compgen -W $options -- ${cur}) )
;;
@@ -287,9 +347,24 @@ _notmuch_tag()
 {
 local cur prev words cword split
 # handle tags with colons and equal signs
-_init_completion -n := || return
+_init_completion -s -n := || return
+
+$split 
+case ${prev} in
+   --input)
+   _filedir
+   return
+   ;;
+esac
 
+! $split 
 case ${cur} in
+   --*)
+   local options=--batch --input= --remove-all
+   compopt -o nospace
+   COMPREPLY=( $(compgen -W $options -- ${cur}) )
+   return
+   ;;
+*)
COMPREPLY=( $(compgen -P + -W `notmuch search --output=tags \*` 
-- ${cur##+}) )
;;
@@ -307,7 +382,7 @@ _notmuch_tag()
 
 _notmuch()
 {
-local _notmuch_commands=config count dump help new reply restore search 
setup show tag
+local _notmuch_commands=compact config count dump help insert new reply 
restore search 

Re: fix for failing tests with gmime 2.6.19

2013-11-11 Thread Jani Nikula
Gmime doesn't do anything standards incompliant, so I'd prefer patching the
test suite. Which is also why I'd like to work around this in notmuch.
On Nov 11, 2013 4:59 PM, Tomi Ollila tomi.oll...@iki.fi wrote:

 On Mon, Nov 11 2013, David Bremner da...@tethera.net wrote:

  Daniel Kahn Gillmor d...@fifthhorseman.net writes:
 
 
  Please don't introduce this cruft into the notmuch codebase.  It should
  be fixed in gmime, not worked-around notmuch.
 
  I've just uploaded gmime 2.6.19-2 to unstable to address this issue.
 
 
  Hi Daniel;
 
  Thanks a lot for that.
 
  What I (still) wonder about is all the people not running Debian, in the
  interval between the release of notmuch 0.17 and the next upstream
  release of gmime (and propagation to various distros).  Even on Debian,
  building on testing and backports complicates things a bit.

 Something like this could also be used...

 diff --git a/notmuch-reply.c b/notmuch-reply.c
 index 9d6f843..2ab0f6e 100644
 --- a/notmuch-reply.c
 +++ b/notmuch-reply.c
 @@ -26,6 +26,7 @@
  static void
  show_reply_headers (GMimeMessage *message)
  {
 +#if ! GMIME_CHECK_VERSION(2,6,19)
  GMimeStream *stream_stdout = NULL;

  stream_stdout = g_mime_stream_file_new (stdout);
 @@ -35,6 +36,17 @@ show_reply_headers (GMimeMessage *message)
 g_mime_object_write_to_stream (GMIME_OBJECT(message),
 stream_stdout);
 g_object_unref(stream_stdout);
  }
 +#else
 +char * msg = g_mime_object_to_string (GMIME_OBJECT(message));
 +char * rp = strstr (msg, References:  );
 +if (rp) {
 +   fwrite (msg, 1, rp - msg + 12, stdout); // Up to 'References: '
 +   fputs (rp + 13, stdout);
 +}
 +else {
 +   fputs (msg, stdout);
 +}
 +#endif
  }

  static void


 
  d

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

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


Re: [PATCH] notmuch: Add maildir: search option

2013-11-12 Thread Jani Nikula
On Tue, 12 Nov 2013, Peter Zijlstra pet...@infradead.org wrote:
 On Tue, Nov 12, 2013 at 02:31:25PM -0500, Austin Clements wrote:
  +/* Strip the maildir cur, new directory entries. */
  +i = strlen(maildir);
  +if (strncmp(maildir + i - 3, cur, 3) == 0 ||
  +  strncmp(maildir + i - 3, new, 3) == 0) {
 
 This is unsafe if directory is less than three characters, which I
 believe could happen if the message is in the root mail directory (which
 shouldn't happen with a well-formed maildir, but notmuch doesn't require
 maildir, and, regardless, we should be defensive).
 
 Also, we have a STRNCMP_LITERAL macro that we often use for comparisons
 with string literals, but I'm good with this, too.

 Quite so, I haven't actually seen that, but you're quite right.

FWIW, in this particular case you can just strcmp because you are
looking at the end of maildir.

BR,
Jani.

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


Re: [PATCH v2 4/5] compact: unconditionally attempt to remove old wip database compact directory

2013-11-14 Thread Jani Nikula
On Wed, 13 Nov 2013, Tomi Ollila tomi.oll...@iki.fi wrote:
 In case previous notmuch compact has been interrupted there is old
 work-in-progress database compact directory partially filled. Remove
 it just before starting to fill the directory with new files.
 ---
  lib/database.cc | 5 +
  1 file changed, 5 insertions(+)

 diff --git a/lib/database.cc b/lib/database.cc
 index ee09c5e..4b5ac64 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -920,6 +920,11 @@ notmuch_database_compact (const char *path,
   goto DONE;
  }
  
 +// Unconditionally attempt to remove old work-in-progress database (if 
 any).
 +// This is protected by database lock. If this fails due to write 
 errors
 +// (etc), the following code will fail and provide error message.
 +(void) rmtree (compact_xapian_path);

I thought we avoid using // comments. Otherwise LGTM.

 +
  try {
   NotmuchCompactor compactor (status_cb, closure);
  
 -- 
 1.8.3.1

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


Re: [PATCH v2 2/5] compact: catch Xapian::Error consistently

2013-11-14 Thread Jani Nikula

The first two patches LGTM.

On Wed, 13 Nov 2013, Tomi Ollila tomi.oll...@iki.fi wrote:
 catch Xapian::Error in compact code in lib/database.cc to be consistent
 with other code in addition to not making software crash on uncaught
 other Xapian error.
 ---
  lib/database.cc | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

 diff --git a/lib/database.cc b/lib/database.cc
 index 3c008d6..3530cb6 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -918,8 +918,8 @@ notmuch_database_compact (const char *path,
   compactor.add_source (xapian_path);
   compactor.set_destdir (compact_xapian_path);
   compactor.compact ();
 -} catch (Xapian::InvalidArgumentError e) {
 - fprintf (stderr, Error while compacting: %s\n, e.get_msg().c_str());
 +} catch (const Xapian::Error error) {
 + fprintf (stderr, Error while compacting: %s\n, 
 error.get_msg().c_str());
   ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
   goto DONE;
  }
 -- 
 1.8.3.1

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


Re: [PATCH v2 5/5] compact: provide user more information on after-compaction failures

2013-11-14 Thread Jani Nikula
On Wed, 13 Nov 2013, Tomi Ollila tomi.oll...@iki.fi wrote:
 After database has been compacted, there are steps to put the new
 database into place -- and these steps may fail. In case such
 failure happens, provide better information how to resolve it.

I disagree with having a library spew all this information out. For each
case, I think it should be sufficient to just say what happened
(e.g. rename a - b failed + strerror). I don't think a library's
error messages should be a tutorial on how to fix things.

We may need to amend notmuch compact man page though.

BR,
Jani.




 Thanks to Ben Gamari for most of the information content.
 ---
  lib/database.cc | 39 +++
  1 file changed, 35 insertions(+), 4 deletions(-)

 diff --git a/lib/database.cc b/lib/database.cc
 index 4b5ac64..a6daac6 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -939,19 +939,50 @@ notmuch_database_compact (const char *path,
  }
  
  if (rename (xapian_path, backup_path)) {
 - fprintf (stderr, Error moving old database out of the way\n);
 + fprintf (stderr, Error moving old database out of the way:\n
 +  Old database: %s\n
 +  Backup database: %s\n
 +  Error: %s\n, xapian_path, backup_path, strerror (errno));
   ret = NOTMUCH_STATUS_FILE_ERROR;
   goto DONE;
  }
  
  if (rename (compact_xapian_path, xapian_path)) {
 - fprintf (stderr, Error moving compacted database\n);
 + fprintf (stderr, Error moving compacted database into place: %s\n,
 +  strerror (errno));
 + fprintf (stderr, \n
 +  Encountered error while moving the compacted database\n
 +  \n
 +  %s\n
 +  \n
 +  to\n
 +  \n
 +  %s\n
 +  \n
 +  Please identify the reason for this and move the compacted 
 database\n
 +  into place manually.\n
 +  \n
 +  Alternatively you can revert to the uncompacted database 
 with\n
 +  \n
 +  mv '%s' '%s'\n
 +  \n, compact_xapian_path, xapian_path,
 +  backup_path, xapian_path);
   ret = NOTMUCH_STATUS_FILE_ERROR;
   goto DONE;
  }
  
 -if (! keep_backup)
 - rmtree (backup_path);
 +if (! keep_backup) {
 + if (rmtree (backup_path)) {
 + fprintf (stderr, Error removing backup database: %s\n,
 +  strerror (errno));
 + fprintf (stderr, \n
 +  Please remove the backup database with\n
 +  \n
 + rm -rf '%s'\n \n, backup_path);
 + ret = NOTMUCH_STATUS_FILE_ERROR;
 + goto DONE;
 + }
 +}
  
DONE:
  if (notmuch)
 -- 
 1.8.3.1

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


Re: [PATCH v2 3/5] compact: preserve backup database until compacted database is in place

2013-11-14 Thread Jani Nikula
On Wed, 13 Nov 2013, Tomi Ollila tomi.oll...@iki.fi wrote:
 It is less error prone and window of failure opportunity is smaller
 if the old (backup) database is always renamed (instead of sometimes
 rmtree'd) before new (compacted) database is put into its place.
 Finally rmtree() old database in case old database backup is not kept.
 ---
  lib/database.cc | 42 +-
  1 file changed, 25 insertions(+), 17 deletions(-)

 diff --git a/lib/database.cc b/lib/database.cc
 index 3530cb6..ee09c5e 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -873,6 +873,7 @@ notmuch_database_compact (const char *path,
  notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
  notmuch_database_t *notmuch = NULL;
  struct stat statbuf;
 +notmuch_bool_t keep_backup;
  
  local = talloc_new (NULL);
  if (! local)
 @@ -898,17 +899,25 @@ notmuch_database_compact (const char *path,
   goto DONE;
  }
  
 -if (backup_path != NULL) {
 - if (stat (backup_path, statbuf) != -1) {
 - fprintf (stderr, Backup path already exists: %s\n, backup_path);
 - ret = NOTMUCH_STATUS_FILE_ERROR;
 - goto DONE;
 - }
 - if (errno != ENOENT) {
 - fprintf (stderr, Unknown error while stat()ing backup path: %s\n,
 -  strerror (errno));
 +if (backup_path == NULL) {
 + if (! (backup_path = talloc_asprintf (local, %s.old, xapian_path))) {
 + ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
   goto DONE;
   }
 + keep_backup = FALSE;
 +}
 +else
 + keep_backup = TRUE;

*cough* I thought you were the style police around here *cough*

 +
 +if (stat (backup_path, statbuf) != -1) {
 + fprintf (stderr, Backup path already exists: %s\n, backup_path);

The user will be confused if he specifically didn't add --backup and
happens to get this. But maybe it's a corner case. *shrug*.

 + ret = NOTMUCH_STATUS_FILE_ERROR;
 + goto DONE;
 +}
 +if (errno != ENOENT) {
 + fprintf (stderr, Unknown error while stat()ing backup path: %s\n,
 +  strerror (errno));

ret = ?

 + goto DONE;
  }
  
  try {
 @@ -924,14 +933,10 @@ notmuch_database_compact (const char *path,
   goto DONE;
  }
  
 -if (backup_path) {
 - if (rename (xapian_path, backup_path)) {
 - fprintf (stderr, Error moving old database out of the way\n);
 - ret = NOTMUCH_STATUS_FILE_ERROR;
 - goto DONE;
 - }
 -} else {
 - rmtree (xapian_path);
 +if (rename (xapian_path, backup_path)) {
 + fprintf (stderr, Error moving old database out of the way\n);
 + ret = NOTMUCH_STATUS_FILE_ERROR;
 + goto DONE;
  }
  
  if (rename (compact_xapian_path, xapian_path)) {
 @@ -940,6 +945,9 @@ notmuch_database_compact (const char *path,
   goto DONE;
  }
  
 +if (! keep_backup)
 + rmtree (backup_path);
 +
DONE:
  if (notmuch)
   notmuch_database_destroy (notmuch);
 -- 
 1.8.3.1

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


[PATCH] NEWS: insert quotable parts in reply as they are displayed in show view

2013-11-17 Thread Jani Nikula
News for
commit 5c19eb46a906819744a022463ee3fd7cdfaabbb9
Author: Jani Nikula j...@nikula.org
Date:   Sun Sep 1 20:59:53 2013 +0300

emacs: insert quotable parts in reply as they are displayed in show view
---
 NEWS | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/NEWS b/NEWS
index d0d5300..dbbbe9f 100644
--- a/NEWS
+++ b/NEWS
@@ -91,6 +91,12 @@ Built-in help improvements
   `notmuch-help` (usually bound to ?).  The bindings listed by
   `notmuch-help` also now include descriptions of prefixed commands.
 
+Quote replies as they are displayed in show view
+
+  We now render the parts for reply quoting the same way they are
+  rendered for show. At this time, the notable change is that replies
+  to text/calendar are now pretty instead of raw vcalendar.
+
 Fixed inconsistent use of configured search order
 
   All ways of interactively invoking search now honor the value of
-- 
1.8.4.2

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


Re: notmuch-lib questions and observations

2013-11-19 Thread Jani Nikula
On Mon, 18 Nov 2013, Tomi Valkeinen tomi.valkei...@iki.fi wrote:
 Hi,

 I found out about notmuch quite recently, and now I've been tinkering
 with it, prototyping a GUI client. I have some questions and observations:

Hello Tomi, glad you've found notmuch too! ;)

Your mail would deserve a more thorough answer that I have time for
right now, but hopefully someone(tm) will fill in.

 1.

 The API seems to be a bit broken. I think many of the functions should
 return notmuch_status_t. I encountered this issue with get_header() and
 get_date(), which I happened to call after the DB had been changed
 twice, leading to Xapian::DatabaseModifiedError.

 Neither function handle the exception, causing a crash, which is
 obviously a bug, but even if they did handle the exception they don't
 return any sensible error information. Even worse, consider
 count_messages(), for which return value of 0 is valid.

We should never leak exceptions or do INTERNAL_ERROR() on things that
are not internal errors. So agreed those are bugs.

 So, as far as I see, many of the funcs should be changed to something like:

 notmuch_status_t
 notmuch_query_count_messages (notmuch_query_t *query, unsigned *count);

We're about to release 0.17, and we expect to have to break the API a
bit after the release anyway. IMO it would be a good time to review this
kind of stuff.

The bug fixes you sent for not crashing should probably be considered
for 0.17.

 2.

 This is more about Xapian, I guess. The behavior that a db reader will
 start failing if the db has been changed twice is rather bad. If I'm not
 mistaken, having a rather long read-only query could be blocked (or,
 well, re-tried) forever, if there just happens to be a few db writes
 during the read.

 I think a better approach would be to allow only one change to the db if
 there are open db readers. If a second db writer tries to open the db,
 it would get a failure (instead of the readers).

 Anyone know if this has been discussed, or if my suggestion is plain silly?

 3.

 How is a client using notmuch supposed to find out there are new
 messages, and which messages are new?

'notmuch new' tags any new messages it finds with tags specified in
new.tags config option (man notmuch-config), inbox and unread by
default. Some people like to change that to new, and run a post-new
hook (man notmuch-hooks) that looks at messages matching tag:new,
retagging as desired.

 My current thought is to make 'notmuch new' run a script that tags the
 messages, and make it add a 'new-gui' or such tag to all new messages.
 The client would then periodically make a query for that tag, and at the
 same time remove the tag for any returned messages.

As said, 'notmuch new' does that, and it can also run a script for you.

 4.

 Has there been discussion on returning integer IDs instead of strings
 from various functions like notmuch_message_get_message_id() and
 notmuch_tags_get()?

 I have two things behind this question:

 - Marshaling strings from native code to managed code requires
 allocating memory and copying the string, whereas returning an int is
 more or less a no-op [1][2]. E.g. at the moment if I fetch tag 'inbox'
 for 10k messages, I'm creating a new 'inbox' string 10k times. I'd
 rather fetch an int 10k times, and the 'inbox' string once.

 - My prototype fetches the message ids for all the messages returned by
 the query, so that it can later load the message if the user wants to
 read it. Fetching and storing only an int per message versus a long-ish
 string per message would most likely be good for performance with large
 queries.

 5.

 This one is just a vague thought that came to my mind. At the moment
 notmuch hides Xapian totally behind notmuch's interface, which probably
 makes things simpler (and gives a nice C API), but also (afaik) prevents
 using Xapian features that are not at the moment supported in the
 notmuch API.

 I wonder how would an approach work where notmuch would be a bit more
 like a helper library, allowing full use of Xapian's features but making
 it simple to manage notmuch database. So, for example, when making a
 query, you'd create a Xapian query with notmuch, and then use Xapian to
 run the query.

 I don't have anything clear in mind, and obviously Xapian being C++
 might make the whole idea unimplementable.

I think the database implementation has been abstracted on purpose, so
we could, at least in theory, switch from xapian to something else. I
don't know how feasible that would be though. I think Austin has
experimented with that.


Cheers,
Jani.


  Tomi


 [1] That's on C#. I wouldn't be surprised if it's also the same with
 other higher level languages.

 [2] That's not entirely true, as strings can be passed as is, if the
 managed code is given the ownership of the string, and the managed code
 will free the string eventually.

 ___
 notmuch mailing list
 notmuch@notmuchmail.org
 

[PATCH v2 1/7] cli: sanitize tabs and newlines to spaces in notmuch search

2013-11-30 Thread Jani Nikula
Sanitize tabs and newlines to spaces rather than question marks in
--output=summary --format=text output.

This will also hide any difference in unfolding a header that has been
folded with a tab. Our own header parser replaces tabs with spaces,
while gmime would retain the tab.
---
 notmuch-search.c   | 4 +++-
 test/search-output | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 7c973b3..11cd6ee 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -41,7 +41,9 @@ sanitize_string (const void *ctx, const char *str)
 loop = out = talloc_strdup (ctx, str);
 
 for (; *loop; loop++) {
-   if ((unsigned char)(*loop)  32)
+   if (*loop == '\t' || *loop == '\n')
+   *loop = ' ';
+   else if ((unsigned char)(*loop)  32)
*loop = '?';
 }
 return out;
diff --git a/test/search-output b/test/search-output
index 5ccfeaf..86544ac 100755
--- a/test/search-output
+++ b/test/search-output
@@ -388,7 +388,7 @@ add_message [subject]='two =?ISO-8859-1?Q?line=0A_subject?=
headers'
 notmuch search id:$gen_msg_id | notmuch_search_sanitize OUTPUT
 cat EOF EXPECTED
-thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; two line? subject headers 
(inbox unread)
+thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; two line  subject headers 
(inbox unread)
 EOF
 test_expect_equal_file OUTPUT EXPECTED
 
-- 
1.8.4.2

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


[PATCH v2 0/7] lib: replace the message header parser with gmime

2013-11-30 Thread Jani Nikula
This is v2 of id:cover.1381948853.git.j...@nikula.org with more polish.

Patches 1-4 do prep work to fix some of the differences in the parsers
in advance. Arguably they are not that bad regardless of the parser
change.

Patches 5-6 actually make the change. Having two patches is a somewhat
artificial division, but perhaps makes it easier to review.

Patch 7 is just a hack to make perf tests not ignore so many mails... we
have quite a bit of non-emails in the corpus by gmime parser
standards. And this illustrates one of the differences in the parsers.


BR,
Jani.

Jani Nikula (7):
  cli: sanitize tabs and newlines to spaces in notmuch search
  cli: refactor reply from guessing
  util: make sanitize string available in string util for reuse
  cli: sanitize the received header before scanning for replies
  lib: replace the header parser with gmime
  lib: parse messages only once
  HACK: fix broken messages in the perf test corpus

 lib/database.cc   |   6 +-
 lib/index.cc  |  70 +---
 lib/message-file.c| 351 +-
 lib/message.cc|   6 +
 lib/notmuch-private.h |  20 ++-
 notmuch-reply.c   | 186 
 notmuch-search.c  |  17 --
 performance-test/perf-test-lib.sh |   4 +
 test/search-output|   2 +-
 util/string-util.c|  22 +++
 util/string-util.h|   7 +
 11 files changed, 297 insertions(+), 394 deletions(-)

-- 
1.8.4.2

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


[PATCH v2 3/7] util: make sanitize string available in string util for reuse

2013-11-30 Thread Jani Nikula
No functional changes.
---
 notmuch-search.c   | 19 ---
 util/string-util.c | 22 ++
 util/string-util.h |  7 +++
 3 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index 11cd6ee..8b6940a 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -30,25 +30,6 @@ typedef enum {
 OUTPUT_TAGS
 } output_t;
 
-static char *
-sanitize_string (const void *ctx, const char *str)
-{
-char *out, *loop;
-
-if (NULL == str)
-   return NULL;
-
-loop = out = talloc_strdup (ctx, str);
-
-for (; *loop; loop++) {
-   if (*loop == '\t' || *loop == '\n')
-   *loop = ' ';
-   else if ((unsigned char)(*loop)  32)
-   *loop = '?';
-}
-return out;
-}
-
 /* Return two stable query strings that identify exactly the matched
  * and unmatched messages currently in thread.  If there are no
  * matched or unmatched messages, the returned buffers will be
diff --git a/util/string-util.c b/util/string-util.c
index a5622d7..9e2f728 100644
--- a/util/string-util.c
+++ b/util/string-util.c
@@ -37,6 +37,28 @@ strtok_len (char *s, const char *delim, size_t *len)
 return *len ? s : NULL;
 }
 
+char *
+sanitize_string (const void *ctx, const char *str)
+{
+char *out, *loop;
+
+if (! str)
+   return NULL;
+
+out = talloc_strdup (ctx, str);
+if (! out)
+   return NULL;
+
+for (loop = out; *loop; loop++) {
+   if (*loop == '\t' || *loop == '\n')
+   *loop = ' ';
+   else if ((unsigned char)(*loop)  32)
+   *loop = '?';
+}
+
+return out;
+}
+
 static int
 is_unquoted_terminator (unsigned char c)
 {
diff --git a/util/string-util.h b/util/string-util.h
index 0194607..228420d 100644
--- a/util/string-util.h
+++ b/util/string-util.h
@@ -19,6 +19,13 @@
 
 char *strtok_len (char *s, const char *delim, size_t *len);
 
+/* Return a talloced string with str sanitized.
+ *
+ * Whitespace (tabs and newlines) is replaced with spaces,
+ * non-printable characters with question marks.
+ */
+char *sanitize_string (const void *ctx, const char *str);
+
 /* Construct a boolean term query with the specified prefix (e.g.,
  * id) and search term, quoting term as necessary.  Specifically, if
  * term contains any non-printable ASCII characters, non-ASCII
-- 
1.8.4.2

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


[PATCH v2 2/7] cli: refactor reply from guessing

2013-11-30 Thread Jani Nikula
The guess_from_received_header() function had grown quite big. Chop it
up into smaller functions.

No functional changes.
---
 notmuch-reply.c | 178 +---
 1 file changed, 105 insertions(+), 73 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9d6f843..ca41405 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -369,78 +369,44 @@ add_recipients_from_message (GMimeMessage *reply,
 return from_addr;
 }
 
+/*
+ * Look for the user's address in  for em...@add.res in the
+ * received headers.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
 static const char *
-guess_from_received_header (notmuch_config_t *config, notmuch_message_t 
*message)
+guess_from_received_for (notmuch_config_t *config, const char *received)
 {
-const char *addr, *received, *by;
-char *mta,*ptr,*token;
-char *domain=NULL;
-char *tld=NULL;
-const char *delim=. \t;
-size_t i;
-
-const char *to_headers[] = {
-   Envelope-to,
-   X-Original-To,
-   Delivered-To,
-};
-
-/* sadly, there is no standard way to find out to which email
- * address a mail was delivered - what is in the headers depends
- * on the MTAs used along the way. So we are trying a number of
- * heuristics which hopefully will answer this question.
-
- * We only got here if none of the users email addresses are in
- * the To: or Cc: header. From here we try the following in order:
- * 1) check for an Envelope-to: header
- * 2) check for an X-Original-To: header
- * 3) check for a Delivered-To: header
- * 4) check for a (for em...@add.res) clause in Received: headers
- * 5) check for the domain part of known email addresses in the
- *'by' part of Received headers
- * If none of these work, we give up and return NULL
- */
-for (i = 0; i  ARRAY_SIZE (to_headers); i++) {
-   const char *tohdr = notmuch_message_get_header (message, to_headers[i]);
-
-   /* Note: tohdr potentially contains a list of email addresses. */
-   addr = user_address_in_string (tohdr, config);
-   if (addr)
-   return addr;
-}
+const char *ptr;
 
-/* We get the concatenated Received: headers and search from the
- * front (last Received: header added) and try to extract from
- * them indications to which email address this message was
- * delivered.
- * The Received: header is special in our get_header function
- * and is always concatenated.
- */
-received = notmuch_message_get_header (message, received);
-if (received == NULL)
+ptr = strstr (received,  for );
+if (! ptr)
return NULL;
 
-/* First we look for a  for em...@add.res in the received
- * header
- */
-ptr = strstr (received,  for );
+return user_address_in_string (ptr, config);
+}
 
-/* Note: ptr potentially contains a list of email addresses. */
-addr = user_address_in_string (ptr, config);
-if (addr)
-   return addr;
-
-/* Finally, we parse all the  by MTA ... headers to guess the
- * email address that this was originally delivered to.
- * We extract just the MTA here by removing leading whitespace and
- * assuming that the MTA name ends at the next whitespace.
- * We test for *(by+4) to be non-'\0' to make sure there's
- * something there at all - and then assume that the first
- * whitespace delimited token that follows is the receiving
- * system in this step of the receive chain
- */
-by = received;
-while((by = strstr (by,  by )) != NULL) {
+/*
+ * Parse all the  by MTA ... parts in received headers to guess the
+ * email address that this was originally delivered to.
+ *
+ * Extract just the MTA here by removing leading whitespace and
+ * assuming that the MTA name ends at the next whitespace. Test for
+ * *(by+4) to be non-'\0' to make sure there's something there at all
+ * - and then assume that the first whitespace delimited token that
+ * follows is the receiving system in this step of the receive chain.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+guess_from_received_by (notmuch_config_t *config, const char *received)
+{
+const char *addr;
+const char *by = received;
+char *domain, *tld, *mta, *ptr, *token;
+
+while ((by = strstr (by,  by )) != NULL) {
by += 4;
if (*by == '\0')
break;
@@ -454,7 +420,7 @@ guess_from_received_header (notmuch_config_t *config, 
notmuch_message_t *message
 * as domain and tld.
 */
domain = tld = NULL;
-   while ((ptr = strsep (token, delim)) != NULL) {
+   while ((ptr = strsep (token, . \t)) != NULL) {
if (*ptr == '\0')
continue;
domain = tld;
@@ -462,13 +428,13 @@ guess_from_received_header (notmuch_config_t *config, 
notmuch_message_t *message
}
 
if 

[PATCH v2 4/7] cli: sanitize the received header before scanning for replies

2013-11-30 Thread Jani Nikula
This makes the from guessing agnostic to header folding by spaces or
tabs.
---
 notmuch-reply.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index ca41405..a2eee17 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -21,6 +21,7 @@
  */
 
 #include notmuch-client.h
+#include string-util.h
 #include sprinter.h
 
 static void
@@ -463,14 +464,21 @@ guess_from_received_header (notmuch_config_t *config,
notmuch_message_t *message)
 {
 const char *received, *addr;
+char *sanitized;
 
 received = notmuch_message_get_header (message, received);
 if (! received)
return NULL;
 
-addr = guess_from_received_for (config, received);
+sanitized = sanitize_string (config, received);
+if (! sanitized)
+   return NULL;
+
+addr = guess_from_received_for (config, sanitized);
 if (! addr)
-   addr = guess_from_received_by (config, received);
+   addr = guess_from_received_by (config, sanitized);
+
+talloc_free (sanitized);
 
 return addr;
 }
-- 
1.8.4.2

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


[PATCH v2 6/7] lib: parse messages only once

2013-11-30 Thread Jani Nikula
Make the necessary changes to only do one gmime parse pass during
indexing.
---
 lib/database.cc   |  2 +-
 lib/index.cc  | 59 ++-
 lib/message-file.c|  9 
 lib/notmuch-private.h | 16 --
 4 files changed, 30 insertions(+), 56 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index d1bea88..3a29fe7 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -2029,7 +2029,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
date = notmuch_message_file_get_header (message_file, date);
_notmuch_message_set_header_values (message, date, from, subject);
 
-   ret = _notmuch_message_index_file (message, filename);
+   ret = _notmuch_message_index_file (message, message_file);
if (ret)
goto DONE;
} else {
diff --git a/lib/index.cc b/lib/index.cc
index 976e49f..71397da 100644
--- a/lib/index.cc
+++ b/lib/index.cc
@@ -425,52 +425,15 @@ _index_mime_part (notmuch_message_t *message,
 
 notmuch_status_t
 _notmuch_message_index_file (notmuch_message_t *message,
-const char *filename)
+notmuch_message_file_t *message_file)
 {
-GMimeStream *stream = NULL;
-GMimeParser *parser = NULL;
-GMimeMessage *mime_message = NULL;
+GMimeMessage *mime_message;
 InternetAddressList *addresses;
-FILE *file = NULL;
 const char *from, *subject;
-notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
-static int initialized = 0;
-char from_buf[5];
-bool is_mbox = false;
-
-if (! initialized) {
-   g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS);
-   initialized = 1;
-}
-
-file = fopen (filename, r);
-if (! file) {
-   fprintf (stderr, Error opening %s: %s\n, filename, strerror (errno));
-   ret = NOTMUCH_STATUS_FILE_ERROR;
-   goto DONE;
-}
-
-/* Is this mbox? */
-if (fread (from_buf, sizeof (from_buf), 1, file) == 1 
-   strncmp (from_buf, From , 5) == 0)
-   is_mbox = true;
-rewind (file);
-
-/* Evil GMime steals my FILE* here so I won't fclose it. */
-stream = g_mime_stream_file_new (file);
-
-parser = g_mime_parser_new_with_stream (stream);
-g_mime_parser_set_scan_from (parser, is_mbox);
 
-mime_message = g_mime_parser_construct_message (parser);
-
-if (is_mbox) {
-   if (!g_mime_parser_eos (parser)) {
-   /* This is a multi-message mbox. */
-   ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
-   goto DONE;
-   }
-}
+mime_message = notmuch_message_file_get_mime_message (message_file);
+if (! mime_message)
+   return NOTMUCH_STATUS_FILE_NOT_EMAIL; /* more like internal error */
 
 from = g_mime_message_get_sender (mime_message);
 
@@ -491,15 +454,5 @@ _notmuch_message_index_file (notmuch_message_t *message,
 
 _index_mime_part (message, g_mime_message_get_mime_part (mime_message));
 
-  DONE:
-if (mime_message)
-   g_object_unref (mime_message);
-
-if (parser)
-   g_object_unref (parser);
-
-if (stream)
-   g_object_unref (stream);
-
-return ret;
+return NOTMUCH_STATUS_SUCCESS;
 }
diff --git a/lib/message-file.c b/lib/message-file.c
index 3c653d1..0bd8c2e 100644
--- a/lib/message-file.c
+++ b/lib/message-file.c
@@ -247,6 +247,15 @@ mboxes is deprecated and may be removed in the future.\n, 
message-filename);
 return NOTMUCH_STATUS_SUCCESS;
 }
 
+GMimeMessage *
+notmuch_message_file_get_mime_message (notmuch_message_file_t *message)
+{
+if (! message-parsed)
+   return NULL;
+
+return message-message;
+}
+
 /* return NULL on errors, empty string for non-existing headers */
 const char *
 notmuch_message_file_get_header (notmuch_message_file_t *message,
diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
index 7277df1..7559521 100644
--- a/lib/notmuch-private.h
+++ b/lib/notmuch-private.h
@@ -46,6 +46,8 @@ NOTMUCH_BEGIN_DECLS
 
 #include talloc.h
 
+#include gmime/gmime.h
+
 #include xutil.h
 #include error_util.h
 
@@ -320,9 +322,11 @@ notmuch_message_get_author (notmuch_message_t *message);
 
 /* index.cc */
 
+typedef struct _notmuch_message_file notmuch_message_file_t;
+
 notmuch_status_t
 _notmuch_message_index_file (notmuch_message_t *message,
-const char *filename);
+notmuch_message_file_t *message_file);
 
 /* message-file.c */
 
@@ -330,7 +334,6 @@ _notmuch_message_index_file (notmuch_message_t *message,
  * into the public interface in notmuch.h
  */
 
-typedef struct _notmuch_message_file notmuch_message_file_t;
 
 /* Open a file containing a single email message.
  *
@@ -377,6 +380,15 @@ void
 notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,
va_list va_headers);
 
+/* Get the gmime message of a parsed message file.
+ *
+ * Returns NULL if the message file has not 

[PATCH v2 5/7] lib: replace the header parser with gmime

2013-11-30 Thread Jani Nikula
The notmuch library includes a full blown message header parser. Yet
the same message headers are parsed by gmime during indexing. Switch
to gmime parsing completely.

These are the main differences between the parsers:

* Gmime stops header parsing at the first invalid header, and presumes
  the message body starts from there. The current parser is quite
  liberal in accepting broken headers. The change means we will be
  much pickier about accepting invalid messages. For example the
  performance test suite contains plenty of email that does not pass
  as valid email. (Note that the mail body would not have been indexed
  before the change anyway, as we use gmime for that.)

* The current parser converts tabs used in header folding to
  spaces. Gmime preserve the tabs. Due to a broken python library used
  in mailman, there are plenty of mailing lists that produce headers
  with tabs in header folding, we'll see plenty of tabs.

At this step, we only switch the header parsing to gmime.
---
 lib/database.cc   |   4 +
 lib/index.cc  |  11 --
 lib/message-file.c| 346 --
 lib/message.cc|   6 +
 lib/notmuch-private.h |   4 +
 5 files changed, 122 insertions(+), 249 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index f395061..d1bea88 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1940,6 +1940,10 @@ notmuch_database_add_message (notmuch_database_t 
*notmuch,
   to,
   (char *) NULL);
 
+ret = notmuch_message_file_parse (message_file);
+if (ret)
+   goto DONE;
+
 try {
/* Before we do any real work, (especially before doing a
 * potential SHA-1 computation on the entire file's contents),
diff --git a/lib/index.cc b/lib/index.cc
index 78c18cf..976e49f 100644
--- a/lib/index.cc
+++ b/lib/index.cc
@@ -437,7 +437,6 @@ _notmuch_message_index_file (notmuch_message_t *message,
 static int initialized = 0;
 char from_buf[5];
 bool is_mbox = false;
-static bool mbox_warning = false;
 
 if (! initialized) {
g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS);
@@ -471,16 +470,6 @@ _notmuch_message_index_file (notmuch_message_t *message,
ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
goto DONE;
}
-   /* For historical reasons, we support single-message mboxes,
-* but this behavior is likely to change in the future, so
-* warn. */
-   if (!mbox_warning) {
-   mbox_warning = true;
-   fprintf (stderr, \
-Warning: %s is an mbox containing a single message,\n\
-likely caused by misconfigured mail delivery.  Support for single-message\n\
-mboxes is deprecated and may be removed in the future.\n, filename);
-   }
 }
 
 from = g_mime_message_get_sender (mime_message);
diff --git a/lib/message-file.c b/lib/message-file.c
index a2850c2..3c653d1 100644
--- a/lib/message-file.c
+++ b/lib/message-file.c
@@ -26,30 +26,19 @@
 
 #include glib.h /* GHashTable */
 
-typedef struct {
-char *str;
-size_t size;
-size_t len;
-} header_value_closure_t;
-
 struct _notmuch_message_file {
 /* File object */
 FILE *file;
+char *filename;
 
 /* Header storage */
 int restrict_headers;
 GHashTable *headers;
-int broken_headers;
-int good_headers;
-size_t header_size; /* Length of full message header in bytes. */
-
-/* Parsing state */
-char *line;
-size_t line_size;
-header_value_closure_t value;
 
-int parsing_started;
-int parsing_finished;
+GMimeStream *stream;
+GMimeParser *parser;
+GMimeMessage *message;
+notmuch_bool_t parsed;
 };
 
 static int
@@ -76,16 +65,18 @@ strcase_hash (const void *ptr)
 static int
 _notmuch_message_file_destructor (notmuch_message_file_t *message)
 {
-if (message-line)
-   free (message-line);
-
-if (message-value.size)
-   free (message-value.str);
-
 if (message-headers)
g_hash_table_destroy (message-headers);
 
-if (message-file)
+if (message-message)
+   g_object_unref (message-message);
+
+if (message-parser)
+   g_object_unref (message-parser);
+
+if (message-stream)
+   g_object_unref (message-stream);
+else if (message-file) /* GMimeStream takes over the FILE* */
fclose (message-file);
 
 return 0;
@@ -102,19 +93,21 @@ _notmuch_message_file_open_ctx (void *ctx, const char 
*filename)
 if (unlikely (message == NULL))
return NULL;
 
+/* only needed for error messages during parsing */
+message-filename = talloc_strdup (message, filename);
+if (message-filename == NULL)
+   goto FAIL;
+
 talloc_set_destructor (message, _notmuch_message_file_destructor);
 
 message-file = fopen (filename, r);
 if (message-file == NULL)
goto FAIL;
 
-message-headers = g_hash_table_new_full (strcase_hash,
-  

[PATCH v2 7/7] HACK: fix broken messages in the perf test corpus

2013-11-30 Thread Jani Nikula
The gmime header parser rejects a lot of messages in the perf test
corpus which have this in the middle of headers:

Microsoft Mail Internet Headers Version 2.0

The header parsing stops right there. This illustrates a change in the
parsing. The message is clearly broken, but previously notmuch
accepted it anyway.

This patch fixes the messages in the perf test corpus to be able to
do fair comparisons of the parsers.

NOT TO BE MERGED, if that isn't obvious. This is just a quick hack.
---
 performance-test/perf-test-lib.sh | 4 
 1 file changed, 4 insertions(+)

diff --git a/performance-test/perf-test-lib.sh 
b/performance-test/perf-test-lib.sh
index 9ee7661..caec0d0 100644
--- a/performance-test/perf-test-lib.sh
+++ b/performance-test/perf-test-lib.sh
@@ -84,7 +84,11 @@ add_email_corpus ()
${args[@]}
 
printf \n
+   printf Fix broken messages in corpus...
 
+   find ${TEST_DIRECTORY}/corpus -type f -print0 | xargs -0 sed -i -e 
's/^Microsoft Mail Internet Headers Version 2\.0/X-Crap: /'
+
+   printf \n
 fi
 
 cp -lr $TAG_CORPUS $TMP_DIRECTORY/corpus.tags
-- 
1.8.4.2

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


[PATCH 0/2] library reference man page

2013-11-30 Thread Jani Nikula
v1 after RFC at id:cover.1383758666.git.j...@nikula.org.

These two patches add a doxygen configuration file and minimal changes
to lib/notmuch.h to produce man/man3/notmuch.3 library reference.

Apply patches, and run
 $ doxygen devel/doxygen.cfg
 $ man man/man3/notmuch.3

There's still plenty to do, but perhaps we could get started with
merging this? There's no harm done, and would help collaboration on
this.

TODO:

* make this part of the build/install process
* check version in release checks
* figure out how to *not* create a file list man page
* upload the man page to the web site
* generate html pages too, and upload to web site also
* start using doxygen/javadoc tags to produce nicer output

Cheers,
Jani.


Jani Nikula (2):
  devel: add doxygen configuration file
  lib: modify notmuch.h for automatic document generation

 devel/doxygen.cfg | 1890 +
 lib/notmuch.h |  436 
 2 files changed, 2186 insertions(+), 140 deletions(-)
 create mode 100644 devel/doxygen.cfg

-- 
1.8.4.2

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


[PATCH 2/2] lib: modify notmuch.h for automatic document generation

2013-11-30 Thread Jani Nikula
Minimal changes to produce a sensible result.
---
 lib/notmuch.h | 436 +++---
 1 file changed, 296 insertions(+), 140 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index 7c3a30c..708b603 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -18,9 +18,19 @@
  * Author: Carl Worth cwo...@cworth.org
  */
 
+/**
+ * @defgroup notmuch The notmuch API
+ *
+ * Not much of an email library, (just index and search)
+ *
+ * @{
+ */
+
 #ifndef NOTMUCH_H
 #define NOTMUCH_H
 
+#ifndef __DOXYGEN__
+
 #ifdef  __cplusplus
 # define NOTMUCH_BEGIN_DECLS  extern C {
 # define NOTMUCH_END_DECLS}
@@ -45,18 +55,20 @@ NOTMUCH_BEGIN_DECLS
 #define NOTMUCH_MINOR_VERSION  17
 #define NOTMUCH_MICRO_VERSION  0
 
-/*
+#endif /* __DOXYGEN__ */
+
+/**
  * Check the version of the notmuch library being compiled against.
  *
  * Return true if the library being compiled against is of the
  * specified version or above. For example:
  *
- * #if NOTMUCH_CHECK_VERSION(0, 18, 0)
+ * \#if NOTMUCH_CHECK_VERSION(0, 18, 0)
  * (code requiring notmuch 0.18 or above)
- * #endif
+ * \#endif
  *
  * NOTMUCH_CHECK_VERSION has been defined since version 0.17.0; you
- * can use #if !defined(NOTMUCH_CHECK_VERSION) to check for versions
+ * can use \#if !defined(NOTMUCH_CHECK_VERSION) to check for versions
  * prior to that.
  */
 #define NOTMUCH_CHECK_VERSION (major, minor, micro)\
@@ -65,80 +77,97 @@ NOTMUCH_BEGIN_DECLS
  (NOTMUCH_MAJOR_VERSION == (major)  NOTMUCH_MINOR_VERSION == (minor)  \
   NOTMUCH_MICRO_VERSION = (micro)))
 
+/**
+ * Notmuch boolean type.
+ */
 typedef int notmuch_bool_t;
 
-/* Status codes used for the return values of most functions.
+/**
+ * Status codes used for the return values of most functions.
  *
  * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
- * completed without error. Any other value indicates an error as
- * follows:
- *
- * NOTMUCH_STATUS_SUCCESS: No error occurred.
- *
- * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory
- *
- * XXX: We don't really want to expose this lame XAPIAN_EXCEPTION
- * value. Instead we should map to things like DATABASE_LOCKED or
- * whatever.
- *
- * NOTMUCH_STATUS_READ_ONLY_DATABASE: An attempt was made to write to
- * a database opened in read-only mode.
+ * completed without error. Any other value indicates an error.
  *
- * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
- *
- * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to read or
- * write to a file (this could be file not found, permission
- * denied, etc.)
- *
- * NOTMUCH_STATUS_FILE_NOT_EMAIL: A file was presented that doesn't
- * appear to be an email message.
- *
- * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: A file contains a message ID
- * that is identical to a message already in the database.
- *
- * NOTMUCH_STATUS_NULL_POINTER: The user erroneously passed a NULL
- * pointer to a notmuch function.
- *
- * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds
- * NOTMUCH_TAG_MAX)
- *
- * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw
- * function has been called more times than notmuch_message_freeze.
- *
- * NOTMUCH_STATUS_UNBALANCED_ATOMIC: notmuch_database_end_atomic has
- * been called more times than notmuch_database_begin_atomic.
- *
- * And finally:
- *
- * NOTMUCH_STATUS_LAST_STATUS: Not an actual status value. Just a way
- * to find out how many valid status values there are.
  */
 typedef enum _notmuch_status {
+/**
+ * No error occurred.
+ */
 NOTMUCH_STATUS_SUCCESS = 0,
+/**
+ * Out of memory.
+ */
 NOTMUCH_STATUS_OUT_OF_MEMORY,
+/**
+ * An attempt was made to write to a database opened in read-only
+ * mode.
+ */
 NOTMUCH_STATUS_READ_ONLY_DATABASE,
+/**
+ * A Xapian exception occurred.
+ */
 NOTMUCH_STATUS_XAPIAN_EXCEPTION,
+/**
+ * An error occurred trying to read or write to a file (this could
+ * be file not found, permission denied, etc.)
+ *
+ * @todo We don't really want to expose this lame XAPIAN_EXCEPTION
+ * value. Instead we should map to things like DATABASE_LOCKED or
+ * whatever.
+ */
 NOTMUCH_STATUS_FILE_ERROR,
+/**
+ * A file was presented that doesn't appear to be an email
+ * message.
+ */
 NOTMUCH_STATUS_FILE_NOT_EMAIL,
+/**
+ * A file contains a message ID that is identical to a message
+ * already in the database.
+ */
 NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,
+/**
+ * The user erroneously passed a NULL pointer to a notmuch
+ * function.
+ */
 NOTMUCH_STATUS_NULL_POINTER,
+/**
+ * A tag value is too long (exceeds NOTMUCH_TAG_MAX).
+ */
 NOTMUCH_STATUS_TAG_TOO_LONG,
+/**
+ * The notmuch_message_thaw function has been called more times
+ * than notmuch_message_freeze.
+ */
 

Re: [PATCH 0/2] library reference man page

2013-11-30 Thread Jani Nikula
On Sat, 30 Nov 2013, David Bremner da...@tethera.net wrote:
 Jani Nikula j...@nikula.org writes:

  devel/doxygen.cfg | 1890 
 +
  lib/notmuch.h |  436 

 A 2K line config file is kindof gross, but other than that, I think the
 idea has merit. Do we really need that much configuration info?

The config file is basically a template generated with 'doxygen -g' and
adjusted to our needs. It could be significantly reduced by dropping
comments, defaults, and unused settings. Maybe that would be the right
thing to do, even if the comments and defaults that are set explicitly
serve as documentation.

 Perhaps a quibble, but at least for me the summary part of the resulting
 manpage is almost unreadable because of the amount of underlining.

Agreed, it's not optimal. I was hoping someone more experienced with
doxygen would fix that after I shared this initial work. ;)

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


[PATCH 1/2] lib: add return status to database close and destroy

2013-12-01 Thread Jani Nikula
notmuch_database_close may fail in Xapian -flush() or -close(), so
report the status. Similarly for notmuch_database_destroy which calls
close.

This is required for notmuch insert to report error status if message
indexing failed.

Bump the notmuch version to allow clients to conditional build against
both the current release and the next release (current git master).
---
 lib/database.cc | 18 ++
 lib/notmuch.h   | 17 ++---
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index f395061..98e2c31 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -767,14 +767,17 @@ notmuch_database_open (const char *path,
 return status;
 }
 
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *notmuch)
 {
+notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
 try {
if (notmuch-xapian_db != NULL 
notmuch-mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
(static_cast Xapian::WritableDatabase * 
(notmuch-xapian_db))-flush ();
 } catch (const Xapian::Error error) {
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
if (! notmuch-exception_reported) {
fprintf (stderr, Error: A Xapian exception occurred flushing 
database: %s\n,
 error.get_msg().c_str());
@@ -789,6 +792,7 @@ notmuch_database_close (notmuch_database_t *notmuch)
notmuch-xapian_db-close();
} catch (const Xapian::Error error) {
/* do nothing */
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
 }
 
@@ -802,6 +806,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
 notmuch-value_range_processor = NULL;
 delete notmuch-date_range_processor;
 notmuch-date_range_processor = NULL;
+
+return status;
 }
 
 #if HAVE_XAPIAN_COMPACT
@@ -966,7 +972,7 @@ notmuch_database_compact (const char *path,
 
   DONE:
 if (notmuch)
-   notmuch_database_destroy (notmuch);
+   ret = notmuch_database_destroy (notmuch);
 
 talloc_free (local);
 
@@ -984,11 +990,15 @@ notmuch_database_compact (unused (const char *path),
 }
 #endif
 
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *notmuch)
 {
-notmuch_database_close (notmuch);
+notmuch_status_t status;
+
+status = notmuch_database_close (notmuch);
 talloc_free (notmuch);
+
+return status;
 }
 
 const char *
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 7c3a30c..dbdce86 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -42,7 +42,7 @@ NOTMUCH_BEGIN_DECLS
 #endif
 
 #define NOTMUCH_MAJOR_VERSION  0
-#define NOTMUCH_MINOR_VERSION  17
+#define NOTMUCH_MINOR_VERSION  18
 #define NOTMUCH_MICRO_VERSION  0
 
 /*
@@ -236,8 +236,16 @@ notmuch_database_open (const char *path,
  *
  * notmuch_database_close can be called multiple times.  Later calls
  * have no effect.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successfully closed the database.
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the
+ * database has been closed but there are no guarantees the
+ * changes to the database, if any, have been flushed to disk.
  */
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *database);
 
 /* A callback invoked by notmuch_database_compact to notify the user
@@ -263,8 +271,11 @@ notmuch_database_compact (const char* path,
 
 /* Destroy the notmuch database, closing it if necessary and freeing
  * all associated resources.
+ *
+ * Return value as in notmuch_database_close if the database was open;
+ * notmuch_database_destroy itself has no failure modes.
  */
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *database);
 
 /* Return the database path of the given database.
-- 
1.8.4.2

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


[PATCH 0/2] lib: introduce notmuch_database_new

2013-12-01 Thread Jani Nikula
Hi all -

In preparation of adding some logging hooks into the library (instead of
printing everything to stdout/stderr) we need a way to set that kind of
options before opening/creating the database. Here's a proposed API
change to make that possible in the future.

N.B. This breaks bindings and contrib/notmuch-deliver.

BR,
Jani.


Jani Nikula (2):
  lib: add return status to database close and destroy
  lib: introduce notmuch_database_new for initializing a database handle

 lib/database.cc  | 80 ++--
 lib/notmuch.h| 69 ++--
 notmuch-compact.c| 11 +++-
 notmuch-count.c  | 10 +--
 notmuch-dump.c   | 10 +--
 notmuch-insert.c | 10 +--
 notmuch-new.c| 14 +
 notmuch-reply.c  | 10 +--
 notmuch-restore.c| 10 +--
 notmuch-search.c | 10 +--
 notmuch-show.c   | 10 +--
 notmuch-tag.c| 10 +--
 test/random-corpus.c | 10 +--
 test/symbol-test.cc  |  3 +-
 14 files changed, 193 insertions(+), 74 deletions(-)

-- 
1.8.4.2

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


[PATCH 2/2] lib: introduce notmuch_database_new for initializing a database handle

2013-12-01 Thread Jani Nikula
There is a need for setting options before opening a database, such as
setting a logging function to use instead of writing to stdout or
stderr. It would be possible to do this by adding new parameters to
notmuch_database_create and notmuch_database_open, but maintaining a
backwards compatible API and ABI when new options are added becomes
burdensome.

Instead, split the opaque database object creation from
notmuch_database_create and notmuch_database_open into a new
notmuch_database_new call, to allow operations on the handle before
create and open. This creates API and ABI breakage now, but allows
easier future extensions.

The notmuch_database_new call becomes a natural pair to the already
existing notmuch_database_destroy, and it should be possible to call
open/close multiple times using an initialized handle.
---
 lib/database.cc  | 64 
 lib/notmuch.h| 52 --
 notmuch-compact.c| 11 -
 notmuch-count.c  | 10 ++--
 notmuch-dump.c   | 10 ++--
 notmuch-insert.c | 10 ++--
 notmuch-new.c| 14 +++-
 notmuch-reply.c  | 10 ++--
 notmuch-restore.c| 10 ++--
 notmuch-search.c | 10 ++--
 notmuch-show.c   | 10 ++--
 notmuch-tag.c| 10 ++--
 test/random-corpus.c | 10 ++--
 test/symbol-test.cc  |  3 ++-
 14 files changed, 166 insertions(+), 68 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 98e2c31..386b93a 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -539,10 +539,21 @@ parse_references (void *ctx,
 }
 
 notmuch_status_t
-notmuch_database_create (const char *path, notmuch_database_t **database)
+notmuch_database_new (notmuch_database_t **notmuch)
+{
+/* Note: try to avoid error conditions! No error printing! */
+
+*notmuch = talloc_zero (NULL, notmuch_database_t);
+if (! *notmuch)
+   return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+return NOTMUCH_STATUS_SUCCESS;
+}
+
+notmuch_status_t
+notmuch_database_create (notmuch_database_t *notmuch, const char *path)
 {
 notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
-notmuch_database_t *notmuch = NULL;
 char *notmuch_path = NULL;
 struct stat st;
 int err;
@@ -579,25 +590,18 @@ notmuch_database_create (const char *path, 
notmuch_database_t **database)
goto DONE;
 }
 
-status = notmuch_database_open (path,
-   NOTMUCH_DATABASE_MODE_READ_WRITE,
-   notmuch);
+status = notmuch_database_open (notmuch, path,
+   NOTMUCH_DATABASE_MODE_READ_WRITE);
 if (status)
goto DONE;
 status = notmuch_database_upgrade (notmuch, NULL, NULL);
-if (status) {
+if (status)
notmuch_database_close(notmuch);
-   notmuch = NULL;
-}
 
   DONE:
 if (notmuch_path)
talloc_free (notmuch_path);
 
-if (database)
-   *database = notmuch;
-else
-   talloc_free (notmuch);
 return status;
 }
 
@@ -612,14 +616,15 @@ _notmuch_database_ensure_writable (notmuch_database_t 
*notmuch)
 return NOTMUCH_STATUS_SUCCESS;
 }
 
+/*
+ * XXX: error handling should clean up *all* state created!
+ */
 notmuch_status_t
-notmuch_database_open (const char *path,
-  notmuch_database_mode_t mode,
-  notmuch_database_t **database)
+notmuch_database_open (notmuch_database_t *notmuch, const char *path,
+  notmuch_database_mode_t mode)
 {
 notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
 void *local = talloc_new (NULL);
-notmuch_database_t *notmuch = NULL;
 char *notmuch_path, *xapian_path;
 struct stat st;
 int err;
@@ -663,7 +668,6 @@ notmuch_database_open (const char *path,
initialized = 1;
 }
 
-notmuch = talloc_zero (NULL, notmuch_database_t);
 notmuch-exception_reported = FALSE;
 notmuch-path = talloc_strdup (notmuch, path);
 
@@ -689,8 +693,7 @@ notmuch_database_open (const char *path,
read-write mode.\n,
 notmuch_path, version, NOTMUCH_DATABASE_VERSION);
notmuch-mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
-   notmuch_database_destroy (notmuch);
-   notmuch = NULL;
+   notmuch_database_close (notmuch);
status = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
}
@@ -752,21 +755,19 @@ notmuch_database_open (const char *path,
 } catch (const Xapian::Error error) {
fprintf (stderr, A Xapian exception occurred opening database: %s\n,
 error.get_msg().c_str());
-   notmuch_database_destroy (notmuch);
-   notmuch = NULL;
+   notmuch_database_close (notmuch);
status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
 }
 
   DONE:
 talloc_free (local);
 
-if (database)
-   *database = notmuch;
-else
-  

Re: [PATCH 2/2] lib: introduce notmuch_database_new for initializing a database handle

2013-12-03 Thread Jani Nikula
On Tue, 03 Dec 2013, David Bremner da...@tethera.net wrote:
 The first patch looks ok. I like the new API overall.

Happy to hear that.

 As far as breaking contrib/notmuch-deliver, I'd rather fix
 notmuch-insert than put effort into notmuch-deliver at this point. I
 guess it could be a rough transition for people running notmuch-deliver
 from git.

Agreed. We could fix notmuch insert with patch 1/2 alone.

 Jani Nikula j...@nikula.org writes:

 +/*
 + * XXX: error handling should clean up *all* state created!
 + */
 is this a warning to future hackers or some current problem?

It's a note to self and reviewers that we need to be sure this
happens... I'm just saying I'm not 100% sure we're doing all of that
now.

  notmuch_status_t
 -notmuch_database_open (const char *path,
 -   notmuch_database_mode_t mode,
 -   notmuch_database_t **database)
 +notmuch_database_open (notmuch_database_t *notmuch, const char *path,
 +   notmuch_database_mode_t mode)
  
 +/* Initialize a new, empty database handle.
 + *

 I wondered about making the new documentation adhere to doxygen?

I was thinking of fixing either series depending on them getting
merged. I wasn't sure we'd reached consensus on doxygen yet.

 +if (notmuch_database_open (notmuch,
 +   notmuch_config_get_database_path (config),
 +   NOTMUCH_DATABASE_MODE_READ_ONLY))

 Would it make any sense to migrate the mode argument to an option
 setting while we're messing with the API?  

My gut feeling says no. Same for the path argument suggested by Tomi.

What would it mean to change the mode while the database is open? Or the
path? I think we'd have to check for this, and fail. Mode is only
meaningful for open, and path for open, create and compact. I think
adding such state modifiers would make the interface feel more complex,
but I'm open to arguments to the contrary.


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


Re: [PATCH WIP v2 0/5] emacs: show: redesign unread/read logic

2013-12-04 Thread Jani Nikula
On Sun, 01 Dec 2013, Mark Walters markwalters1...@gmail.com wrote:
 This is further wip of the message at
 id:1385285551-5158-1-git-send-email-markwalters1...@gmail.com
 see there for some discussion of the design.

 This series is still definitely wip: one reason for posting is so
 people can play with different strategies for marking read
 easily. (As WIP tree's unread handling is broken and the tests need updating.)

 The series consists of three parts: the first 4 patches add the notion
 of seen: this means the user has seen the message but the message has
 typically not been marked read yet. The seen messages are marked read
 when the user quits the show buffer unless the user quits with
 prefix-arg quit. In all cases an informative message is shown.

 The fifth patch adds a psot-command-hook stub for updating the seen
 status. This seems a natural place to do the update as it means
 however the user navugates around the buffer (eg next-message or
 page-down etc) the update gets done.

 This is intended to be an easy place for other people to try out their
 own mark read strategies.

 The final patch implements something pretty close to what I would like
 for marking seen/read. A message is deemed seen provided the user has
 seen the top of the message, and has seen either the bottom of the
 message or a point at least some customisable number of lines into the
 message. The customisable number of lines can either be a fixed number
 e.g. 20, or a number depending on the height of the current window
 e.g. the default is 3/4 of the window height.

 The idea is a message seen if the user has seen the entire message, or
 enough of it they have to have noticed it. The figure of 3/4 also
 means that the notmuch commands like next-message which place the top
 of the message at the top of the window automatically mark the message
 seen as either the whole message or at least one window full must be
 visible.

 I would be very grateful for any comments on whether this behaves as
 people would expect, what they would want instead etc

Hi Mark, thanks for working on this.

I had tons of mail reading to catch up, so this was a good opportunity
to try the patches. I'll try to be objective and constructive next, but
up front, just so there's no doubt: I don't like it.

I think my issues boil down to the series containing two pretty
significant changes at once: how to decide if a message was read and
when to apply the tag changes to reflect that.

I found it confusing that messages were not being tagged -unread while I
was viewing the thread. I found it even more confusing to get a message
Marked N messages read on quitting show view with no feedback on
*which* messages were read, and often the N didn't feel right
either. And I think that's the problem: I wanted to see the new
heuristics on deciding whether a message was read in action, but I got
zero immediate feedback on it!

My suggestion is to drop the delay in tag changes for now, and focus on
the part that decides whether a message was read or not. Do the tag
changes immediately when you consider a message seen. I think this way
we get a better feel of how well the heuristics really work, and we can
make it just right. I think that's the bug in we currently have in
notmuch, and delaying the tag changes doesn't contribute to fixing
it. Indeed I think the delay makes it *harder* to fix.

Afterwards, we could add the delayed tag changes (although hopefully as
an option) if desired. And keeping that in mind, AFAICT you wouldn't
need to rework your patches all that much.

How does that sound?


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


Re: [PATCH 1/3] lib: Make VERSION macros agree with soname version

2013-12-04 Thread Jani Nikula
On Wed, 04 Dec 2013, Austin Clements amdra...@mit.edu wrote:
 We have two distinct library version numbers: the soname version and
 the version macros.  We need both for different reasons: the version
 macros enable easy compile-time version detection (and conditional
 compilation), while the soname version enables runtime version
 detection (which includes the version checking done by things like the
 Python bindings).

 However, currently, these two version numbers are different, which is
 unnecessary and can lead to confusion (especially in things like
 Debian, which include the soname version in the package name).  This
 patch makes them the same by bumping the version macros up to agree
 with the soname version.

The patches look good to me. Thanks for spotting and fixing this in the
nick of time before releasing.

BR,
Jani.



 (We should probably keep the version number in just one place so they
 can't get out of sync, but that can be done in another patch.)
 ---
  lib/Makefile.local | 3 +++
  lib/notmuch.h  | 8 ++--
  2 files changed, 9 insertions(+), 2 deletions(-)

 diff --git a/lib/Makefile.local b/lib/Makefile.local
 index 155ac02..cd2c60d 100644
 --- a/lib/Makefile.local
 +++ b/lib/Makefile.local
 @@ -18,6 +18,9 @@ LIBNOTMUCH_VERSION_MINOR = 0
  # simply compatible changes to the implementation).
  LIBNOTMUCH_VERSION_RELEASE = 0
  
 +# Note: Don't forget to change the VERSION macros in notmuch.h when
 +# any of the above change.
 +
  ifeq ($(PLATFORM),MACOSX)
  LIBRARY_SUFFIX = dylib
  # On OS X, library version numbers go before suffix.
 diff --git a/lib/notmuch.h b/lib/notmuch.h
 index 7c3a30c..42188a8 100644
 --- a/lib/notmuch.h
 +++ b/lib/notmuch.h
 @@ -41,8 +41,12 @@ NOTMUCH_BEGIN_DECLS
  #define TRUE 1
  #endif
  
 -#define NOTMUCH_MAJOR_VERSION0
 -#define NOTMUCH_MINOR_VERSION17
 +/*
 + * The library version number.  This must agree with the soname
 + * version in Makefile.local.
 + */
 +#define NOTMUCH_MAJOR_VERSION3
 +#define NOTMUCH_MINOR_VERSION0
  #define NOTMUCH_MICRO_VERSION0
  
  /*
 -- 
 1.8.4.rc3
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/1] devel/release-checks.sh: adjust to LIBNOTMUCH version checks

2013-12-04 Thread Jani Nikula
On Wed, 04 Dec 2013, Tomi Ollila tomi.oll...@iki.fi wrote:
 NOTMUCH_VERSION_* macros in lib/notmuch.h are replaced with
 LIBNOTMUCH_VERSION_* macros. Check that the values of those
 match the LIBNOTMUCH_*_VERSION values in lib/Makefile.local.
 ---
  devel/release-checks.sh | 41 -
  1 file changed, 20 insertions(+), 21 deletions(-)

 diff --git a/devel/release-checks.sh b/devel/release-checks.sh
 index d6410ad..7be57df 100755
 --- a/devel/release-checks.sh
 +++ b/devel/release-checks.sh
 @@ -77,37 +77,36 @@ case $VERSION in
   *)  verfail '$VERSION' is a single number ;;
  esac
  
 -_set_version_components ()
 -{
 - VERSION_MAJOR=$1
 - VERSION_MINOR=$2
 - VERSION_MICRO=${3:-0} # set to 0 in case $3 is unset or null (string)
 -}
 +echo -n Checking that LIBNOTMUCH version macros  variables match ... 
 +# lib/notmuch.h
 +LIBNOTMUCH_MAJOR_VERSION=broken
 +LIBNOTMUCH_MINOR_VERSION=broken
 +LIBNOTMUCH_MICRO_VERSION=broken
 +# lib/Makefile.local
 +LIBNOTMUCH_VERSION_MAJOR=broken
 +LIBNOTMUCH_VERSION_MINOR=broken
 +LIBNOTMUCH_VERSION_RELEASE=broken

Does the test pass if both values are broken? Should the other set be
borken? Am I being too pessimistic? :)

At a glance, the patch looks good, but admittedly didn't spend too much
time on it.

BR,
Jani.


 +
 +eval `awk 'NF == 3  $1 == #define  $2 ~ /^LIBNOTMUCH_[A-Z]+_VERSION$/ \
 +  $3 ~ /^[0-9]+$/ { print $2 = $3 }' lib/notmuch.h`
  
 -IFS=.
 -_set_version_components $VERSION
 -IFS=$DEFAULT_IFS
 +eval `awk 'NF == 3  $1 ~ /^LIBNOTMUCH_VERSION_[A-Z]+$/  $2 == = \
 +  $3 ~ /^[0-9]+$/ { print $1 = $3 }' lib/Makefile.local`
  
 -echo -n Checking that libnotmuch version macros match $VERSION... 
 -NOTMUCH_MAJOR_VERSION=broken
 -NOTMUCH_MINOR_VERSION=broken
 -NOTMUCH_MICRO_VERSION=broken
 -eval `awk 'NF == 3  $1 == #define  $2 ~ /^NOTMUCH_[A-Z]+_VERSION$/ \
 -  $3 ~ /^[0-9]+$/ { print $2 = $3 }' lib/notmuch.h`
  
  check_version_component ()
  {
 - eval local v1=\$VERSION_$1
 - eval local v2=\$NOTMUCH_$1_VERSION
 + eval local v1=\$LIBNOTMUCH_$1_VERSION
 + eval local v2=\$LIBNOTMUCH_VERSION_$2
   if [ $v1 != $v2 ]
 - thenappend_emsg NOTMUCH_$1_VERSION is defined as '$v2' in 
 lib/notmuch.h instead of '$v1'
 + thenappend_emsg LIBNOTMUCH_$1_VERSION ($v1) does not equal 
 LIBNOTMUCH_VERSION_$2 ($v2)
   fi
  }
  
  old_emsg_count=$emsg_count
 -check_version_component MAJOR
 -check_version_component MINOR
 -check_version_component MICRO
 +check_version_component MAJOR MAJOR
 +check_version_component MINOR MINOR
 +check_version_component MICRO RELEASE
  [ $old_emsg_count = $emsg_count ]  echo Yes. || echo No.
  
  echo -n Checking that this is Debian package for notmuch... 
 -- 
 1.8.0

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


Re: [PATCH 1/2] lib: add return status to database close and destroy

2013-12-04 Thread Jani Nikula
On Wed, 04 Dec 2013, Austin Clements amdra...@mit.edu wrote:
 Quoth Jani Nikula on Dec 01 at  3:13 pm:
 notmuch_database_close may fail in Xapian -flush() or -close(), so
 report the status. Similarly for notmuch_database_destroy which calls
 close.
 
 This is required for notmuch insert to report error status if message
 indexing failed.
 
 Bump the notmuch version to allow clients to conditional build against
 both the current release and the next release (current git master).
 ---
  lib/database.cc | 18 ++
  lib/notmuch.h   | 17 ++---
  2 files changed, 28 insertions(+), 7 deletions(-)
 
 diff --git a/lib/database.cc b/lib/database.cc
 index f395061..98e2c31 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -767,14 +767,17 @@ notmuch_database_open (const char *path,
  return status;
  }
  
 -void
 +notmuch_status_t
  notmuch_database_close (notmuch_database_t *notmuch)
  {
 +notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
 +
  try {
  if (notmuch-xapian_db != NULL 
  notmuch-mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
  (static_cast Xapian::WritableDatabase * 
 (notmuch-xapian_db))-flush ();
  } catch (const Xapian::Error error) {
 +status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
  if (! notmuch-exception_reported) {
  fprintf (stderr, Error: A Xapian exception occurred flushing 
 database: %s\n,
   error.get_msg().c_str());
 @@ -789,6 +792,7 @@ notmuch_database_close (notmuch_database_t *notmuch)
  notmuch-xapian_db-close();
  } catch (const Xapian::Error error) {
  /* do nothing */
 +status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
  }
  }
  
 @@ -802,6 +806,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
  notmuch-value_range_processor = NULL;
  delete notmuch-date_range_processor;
  notmuch-date_range_processor = NULL;
 +
 +return status;
  }
  
  #if HAVE_XAPIAN_COMPACT
 @@ -966,7 +972,7 @@ notmuch_database_compact (const char *path,
  
DONE:
  if (notmuch)
 -notmuch_database_destroy (notmuch);
 +ret = notmuch_database_destroy (notmuch);

 This will clobber the error code on most of the error paths.  Maybe
 you want to only set ret if it's currently NOTMUCH_STATUS_SUCCESS?

Good point, will fix.

BR,
Jani.



  
  talloc_free (local);
  
 @@ -984,11 +990,15 @@ notmuch_database_compact (unused (const char *path),
  }
  #endif
  
 -void
 +notmuch_status_t
  notmuch_database_destroy (notmuch_database_t *notmuch)
  {
 -notmuch_database_close (notmuch);
 +notmuch_status_t status;
 +
 +status = notmuch_database_close (notmuch);
  talloc_free (notmuch);
 +
 +return status;
  }
  
  const char *
 diff --git a/lib/notmuch.h b/lib/notmuch.h
 index 7c3a30c..dbdce86 100644
 --- a/lib/notmuch.h
 +++ b/lib/notmuch.h
 @@ -42,7 +42,7 @@ NOTMUCH_BEGIN_DECLS
  #endif
  
  #define NOTMUCH_MAJOR_VERSION   0
 -#define NOTMUCH_MINOR_VERSION   17
 +#define NOTMUCH_MINOR_VERSION   18
  #define NOTMUCH_MICRO_VERSION   0

 This is actually what got me thinking about
 id:1386173986-9624-1-git-send-email-amdra...@mit.edu (which obviously
 conflicts).  In particular, the Python bindings don't have access to
 these macros, and can only use the soname version.  (I think the Go
 ones can use the macros; the Ruby ones certainly can.)

  
  /*
 @@ -236,8 +236,16 @@ notmuch_database_open (const char *path,
   *
   * notmuch_database_close can be called multiple times.  Later calls
   * have no effect.
 + *
 + * Return value:
 + *
 + * NOTMUCH_STATUS_SUCCESS: Successfully closed the database.
 + *
 + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the
 + *  database has been closed but there are no guarantees the
 + *  changes to the database, if any, have been flushed to disk.
   */
 -void
 +notmuch_status_t
  notmuch_database_close (notmuch_database_t *database);
  
  /* A callback invoked by notmuch_database_compact to notify the user
 @@ -263,8 +271,11 @@ notmuch_database_compact (const char* path,
  
  /* Destroy the notmuch database, closing it if necessary and freeing
   * all associated resources.
 + *
 + * Return value as in notmuch_database_close if the database was open;
 + * notmuch_database_destroy itself has no failure modes.
   */
 -void
 +notmuch_status_t
  notmuch_database_destroy (notmuch_database_t *database);
  
  /* Return the database path of the given database.

 Regarding bindings (since you asked me to think about them), these
 should be a safe changes from an ABI perspective (though obviously the
 bindings will need changes to take advantage of the new return code).
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 2/2] lib: introduce notmuch_database_new for initializing a database handle

2013-12-05 Thread Jani Nikula
On Thu, 05 Dec 2013, Austin Clements amdra...@mit.edu wrote:
 Quoth Jani Nikula on Dec 01 at  3:14 pm:
 There is a need for setting options before opening a database, such as
 setting a logging function to use instead of writing to stdout or
 stderr. It would be possible to do this by adding new parameters to
 notmuch_database_create and notmuch_database_open, but maintaining a
 backwards compatible API and ABI when new options are added becomes
 burdensome.
 
 Instead, split the opaque database object creation from
 notmuch_database_create and notmuch_database_open into a new
 notmuch_database_new call, to allow operations on the handle before
 create and open. This creates API and ABI breakage now, but allows
 easier future extensions.
 
 The notmuch_database_new call becomes a natural pair to the already
 existing notmuch_database_destroy, and it should be possible to call
 open/close multiple times using an initialized handle.

 A high-level comment about the API: Currently, an allocated
 notmuch_database_t has two memory states, if you will: open and
 closed.  (I wish it didn't have any memory states, and was on the
 fence about this API for a while until I realized that the ship had
 already sailed.) 

Just to confirm, are you referring to the state between close and
destroy/open?

Btw what is the use case we have separate close and destroy for? To be
able to access the data cached in memory after the db has been closed?

 It's pretty clear how all of the notmuch APIs will
 behave in both states (modulo some bounded non-determinism in the
 closed state).  I think this patch introduces a new pre-open state,
 and I don't know how most of the notmuch APIs behave in that state.
 My guess is poorly.  If it's feasible, I'd much rather a fresh baked
 notmuch_database_t act like it's in the closed state, including that
 notmuch_database_{create,open} are well-defined as transitions from
 closed state to open state (even if the closed state was reached by
 calling notmuch_database_close).  Or, if we do have a pre-open
 state, it should at least be well-specified what that means
 (preferably the specification is *not* most APIs segfault).

Agreed.

 Orthogonally -- and this may be a complete pipe dream of mine -- if we
 just had a way to return more detailed error information than a simple
 error code from notmuch_database_{create,open}, I think we wouldn't
 need any of this.  Everything that these functions currently log
 (modulo one warning) is error details, so if we could return the error
 details *with the error* or somehow make them accessible, we wouldn't
 need a logger at this point (or at several other points in the
 library).

Agreed. I tried to look into this earlier, but was hitting dead ends
*if* we want to keep reporting user friendly error status in
open/create. Obviously any concrete suggestions would be most welcome!

 ---
  lib/database.cc  | 64 
 
  lib/notmuch.h| 52 --
  notmuch-compact.c| 11 -
  notmuch-count.c  | 10 ++--
  notmuch-dump.c   | 10 ++--
  notmuch-insert.c | 10 ++--
  notmuch-new.c| 14 +++-
  notmuch-reply.c  | 10 ++--
  notmuch-restore.c| 10 ++--
  notmuch-search.c | 10 ++--
  notmuch-show.c   | 10 ++--
  notmuch-tag.c| 10 ++--
  test/random-corpus.c | 10 ++--
  test/symbol-test.cc  |  3 ++-
  14 files changed, 166 insertions(+), 68 deletions(-)
 
 diff --git a/lib/database.cc b/lib/database.cc
 index 98e2c31..386b93a 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -539,10 +539,21 @@ parse_references (void *ctx,
  }
  
  notmuch_status_t
 -notmuch_database_create (const char *path, notmuch_database_t **database)
 +notmuch_database_new (notmuch_database_t **notmuch)

 The naming of this is unfortunate...  Other APIs use x_create to
 allocate objects (e.g., notmuch_query_create, several internal APIs).
 I would lean towards calling this function notmuch_database_create,
 but that leaves the question of what to call the other.  While we're
 breaking APIs, would it be completely crazy to merge open and create
 into one API with an extra mode to indicate creation (it can be its
 own mode because creation implies read/write)?  (Or, in UNIX
 tradition, we could call this function notmuch_database_create and the
 other notmuch_database_creat.)  notmuch_database_create is already
 just a shell around notmuch_database_open (we could keep it as a
 separate function, but just make it internal).

Agreed on the naming being unfortunate, though I'll dodge further
bikeshedding. ;) Merging open and create sounds all right, though it's a
minor detail in the bigger picture of this patch.

The comments below seemed valid too, thanks.

BR,
Jani.



 +{
 +/* Note: try to avoid error conditions! No error printing! */
 +
 +*notmuch = talloc_zero (NULL, notmuch_database_t

Re: [PATCH WIP v3 1/3] emacs: show: mark tags changed since buffer loaded

2013-12-09 Thread Jani Nikula
On Thu, 05 Dec 2013, Mark Walters markwalters1...@gmail.com wrote:
 This shows any tags changed in the show buffer since it was loaded or
 refreshed. By default a removed tag is displayed with strike-through
 in red and an added tag is displayed underlined in green.

 One nice feature is that this makes it clear when a message was unread
 when you first loaded the buffer (previously the unread tag could be
 removed before a user realised that it had been unread).

I really like how this works. Very nice!

I did notice a small wrinkle though. On a terminal the strike-through
does not work, and the appearance is that the tag was not removed (until
you refresh with '='). I don't know if you can easily adapt the face or
disable the whole feature when on terminal. Or make this an opt-in
feature. I guess some people might not like this in general, so a way to
disable might be a good idea too. Fine tuning.

BR,
Jani.




 ---
  emacs/notmuch-show.el |   34 +-
  emacs/notmuch-tag.el  |   30 --
  2 files changed, 49 insertions(+), 15 deletions(-)

 diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
 index 784644c..d64d407 100644
 --- a/emacs/notmuch-show.el
 +++ b/emacs/notmuch-show.el
 @@ -211,6 +211,18 @@ For example, if you wanted to remove an \unread\ tag 
 and add a
:type '(repeat string)
:group 'notmuch-show)
  
 +(defface notmuch-show-deleted-tag-face
 +  '((t :strike-through red :inherit 'notmuch-tag-face))
 +  Face for tags that have been removed
 +  :group 'notmuch-show
 +  :group 'notmuch-faces)
 +
 +(defface notmuch-show-added-tag-face
 +  '((t :underline green))
 +  Face for tags that have been added
 +  :group 'notmuch-show
 +  :group 'notmuch-faces)
 +
  
  (defmacro with-current-notmuch-show-message (rest body)
Evaluate body with current buffer set to the text of current message
 @@ -341,11 +353,21 @@ operation on the contents of the current buffer.
Update the displayed tags of the current message.
(save-excursion
  (goto-char (notmuch-show-message-top))
 -(if (re-search-forward (\\([^()]*\\))$ (line-end-position) t)
 - (let ((inhibit-read-only t))
 -   (replace-match (concat (
 -  (notmuch-tag-format-tags tags)
 -  )))
 +(let* ((orig-tags (notmuch-show-get-prop :orig-tags))
 +(all-tags (sort (delete-dups (append tags orig-tags)) #'string))
 +(display-tags (mapcar (lambda (tag) (cond ((and (member tag tags) 
 (member tag orig-tags))
 +   tag)
 +  ((not (member tag tags))
 +   (cons tag 'deleted))
 +  ((not (member tag 
 orig-tags))
 +   (cons tag 'added
 +  all-tags)))
 +
 +  (if (re-search-forward (\\([^()]*\\))$ (line-end-position) t)
 +   (let ((inhibit-read-only t))
 + (replace-match (concat (
 +(notmuch-tag-format-tags display-tags)
 +
  
  (defun notmuch-clean-address (address)
Try to clean a single email ADDRESS for display. Return a cons
 @@ -1167,6 +1189,8 @@ function is used.
  
(jit-lock-register #'notmuch-show-buttonise-links)
  
 +  (notmuch-show-mapc (lambda () (notmuch-show-set-prop :orig-tags 
 (notmuch-show-get-tags
 +
;; Set the header line to the subject of the first message.
(setq header-line-format (notmuch-sanitize (notmuch-show-strip-re 
 (notmuch-show-get-subject
  
 diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
 index b60f46c..fac2c3b 100644
 --- a/emacs/notmuch-tag.el
 +++ b/emacs/notmuch-tag.el
 @@ -137,16 +137,26 @@ This can be used with `notmuch-tag-format-image-data'.
  
  (defun notmuch-tag-format-tag (tag)
Format TAG by looking into `notmuch-tag-formats'.
 -  (let ((formats (assoc tag notmuch-tag-formats)))
 -(cond
 - ((null formats) ;; - Tag not in `notmuch-tag-formats',
 -  tag)   ;;   the format is the tag itself.
 - ((null (cdr formats))   ;; - Tag was deliberately hidden,
 -  nil)   ;;   no format must be returned
 - (t  ;; - Tag was found and has formats,
 -  (let ((tag tag))   ;;   we must apply all the formats.
 - (dolist (format (cdr formats) tag)
 -   (setq tag (eval format
 +  (let* ((status (if (consp tag) (cdr tag)))
 +  (tag (if (consp tag) (car tag) tag))
 +  (formats (append (assoc tag notmuch-tag-formats)))
 +  (tag
 +   (cond
 +((null formats)  ;; - Tag not in `notmuch-tag-formats',
 + tag);;   the format is the tag itself.
 +((null (cdr formats));; - Tag 

Re: [PATCH WIP v3 0/3] emacs: show: change the unread handling

2013-12-09 Thread Jani Nikula
On Thu, 05 Dec 2013, Mark Walters markwalters1...@gmail.com wrote:
 This is the next iteration of this WIP patch series. v2 was at
 id:1385892147-16994-1-git-send-email-markwalters1...@gmail.com

 I would just like to emphasise that *all* feedback is appreciated
 including I HATE IT etc. 

I LIKE IT. :)

It's not perfect, but IMHO it's a nice, incremental improvement over
what we have, and it's discoverable: you can see what it does and
when. If anything is surprising, the user has a better chance of
explaining what happened, and what he liked and didn't.

Good work, Mark!

BR,
Jani.


PS. I didn't look at the code, I only tried it.


 I have followed Jani's suggestion and removed the delayed updates to
 unread status: it makes it harder to see if the heuristics are doing
 what you want.

 The first patch is completely new: it makes all tag changes in a
 buffer (in particular the unread tag) clearly visible to the user: a
 deleted tag is displayed with red strike-through and an added tag is
 displayed underlined in green.  (This may have strange interactions with
 notmuch-tag-formats in some cases.)

 This makes the visual feedback when a message is marked unread very
 clear: the unread tag is struck-through.

 As always with the previous series lots of tests will fail for the
 obvious reason that marking read is done differently and displayed
 differently.

 Best wishes

 Mark




 Mark Walters (3):
   emacs: show: mark tags changed since buffer loaded
   emacs: show: add an update seen function to post-command-hook
   emacs: show: make `seen' mean user viewed whole message

  emacs/notmuch-show.el |  136 +---
  emacs/notmuch-tag.el  |   30 +++
  2 files changed, 136 insertions(+), 30 deletions(-)

 -- 
 1.7.9.1

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


Re: [PATCH] lib: Add a new prefix list to the search-terms syntax

2014-01-01 Thread Jani Nikula
On Tue, 17 Dec 2013, Kirill A. Shutemov kir...@shutemov.name wrote:
 On Thu, Oct 17, 2013 at 05:17:00PM +0300, Jani Nikula wrote:
 On Wed, 10 Apr 2013, Alexey I. Froloff ra...@raorn.name wrote:
  From: Alexey I. Froloff ra...@raorn.name
 
  Add support for indexing and searching the message's List-Id header.
  This is useful when matching all the messages belonging to a particular
  mailing list.
 
 There's an issue with our duplicate message-id handling that is likely
 to cause confusion with List-Id: searches. If you receive several
 duplicates of the same message (judged by the message-id), only the
 first one of them gets indexed, and the rest are ignored. This means
 that for messages you receive both directly and through a list, it will
 be arbitrary whether the List-Id: gets indexed or not. Therefore a list:
 search might not return all the messages you'd expect.

 I've tried to address this. The patch also adds few tests for the feature.

 There's still missing functionality: re-indexing existing messages for
 list-id, handling message removal, etc.

 Any comments?

Hi Kirill, sorry it took me so long to get to this!

I've looked into our duplicate message-id handling and indexing before,
and it's not very good.

First, we should pay more attention to checking whether the messages
really are duplicates or not. This is not trivial, but we should go a
bit further than just comparing the message-ids. Sadly, handling the
case of colliding message-ids on clearly different messages is not
trivial either, as we rely on the message-ids being unique all around.

Second, we should be more clever about indexing duplicates that we think
are the same message. This is orthogonal to the first point. Currently,
only the first duplicate gets indexed, and will remain indexed even if
it's deleted and other copies remain. A message that matches a search
might end up not having the matching search terms, for example. A
rebuild of the database might index a different duplicate from the last
time.

Having said that (partially just to write the thoughts down somewhere!),
I think your basic approach of indexing the list-id for duplicates is
sane, and we can grow more smarts to _notmuch_message_index_file() for
duplicate == true in the future, checking more headers etc. One thing I
wonder about though: what if more than one duplicate has list-id, and
_index_list_id() gets called multiple times on a message? (CC Austin, he
probably has more clues on this than me.)

For merging, you should also address the previous comments to the
original patch. There's been plenty of dropping the ball here it
seems... I think we've also agreed (perhaps only on IRC, I forget) that
we should use listid as the prefix, not list (sadly hyphens are not
allowed). Splitting the patch to code, test, and man parts might be a
good idea too.

BR,
Jani.



 diff --git a/lib/database.cc b/lib/database.cc
 index f395061e3a73..196243e15d1a 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -205,6 +205,7 @@ static prefix_t BOOLEAN_PREFIX_INTERNAL[] = {
  };
  
  static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
 +{ list,XLIST},
  { thread,  G },
  { tag, K },
  { is,  K },
 @@ -2025,10 +2026,13 @@ notmuch_database_add_message (notmuch_database_t 
 *notmuch,
   date = notmuch_message_file_get_header (message_file, date);
   _notmuch_message_set_header_values (message, date, from, subject);
  
 - ret = _notmuch_message_index_file (message, filename);
 + ret = _notmuch_message_index_file (message, filename, false);
   if (ret)
   goto DONE;
   } else {
 + ret = _notmuch_message_index_file (message, filename, true);
 + if (ret)
 + goto DONE;
   ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
   }
  
 diff --git a/lib/index.cc b/lib/index.cc
 index 78c18cf36d10..9fe1ad6502ed 100644
 --- a/lib/index.cc
 +++ b/lib/index.cc
 @@ -304,6 +304,47 @@ _index_address_list (notmuch_message_t *message,
  }
  }
  
 +static void
 +_index_list_id (notmuch_message_t *message,
 +   const char *list_id_header)
 +{
 +const char *begin_list_id, *end_list_id, *list_id;
 +void *local;
 +
 +if (list_id_header == NULL)
 + return;
 +
 +/* RFC2919 says that the list-id is found at the end of the header
 + * and enclosed between angle brackets. If we cannot find a
 + * matching pair of brackets containing at least one character,
 + * we ignore the list id header. */
 +begin_list_id = strrchr (list_id_header, '');
 +if (!begin_list_id) {
 + fprintf (stderr, Warning: Not indexing mailformed List-Id tag.\n);
 + return;
 +}
 +
 +end_list_id = strrchr(begin_list_id, '');
 +if (!end_list_id || (end_list_id - begin_list_id  2)) {
 + fprintf (stderr, Warning: Not indexing mailformed List-Id tag.\n);
 + return

Re: [PATCH] new: Detect dirent.d_type support at configure time

2014-01-01 Thread Jani Nikula
On Sun, 24 Nov 2013, Austin Clements amdra...@mit.edu wrote:
 Support for dirent.d_type is OS-specific.  Previously, we used
 _DIRENT_HAVE_D_TYPE to detect support for this, but this is apparently
 a glic-ism (FreeBSD, for example, supports d_type, but does not define
 this).  Since there's no cross-platform way to detect support for
 dirent.d_type, detect it using a test compile at configure time.
 ---
  compat/have_d_type.c | 10 ++
  configure| 16 
  notmuch-new.c|  2 +-
  3 files changed, 27 insertions(+), 1 deletion(-)
  create mode 100644 compat/have_d_type.c

 diff --git a/compat/have_d_type.c b/compat/have_d_type.c
 new file mode 100644
 index 000..9ca6c6e
 --- /dev/null
 +++ b/compat/have_d_type.c
 @@ -0,0 +1,10 @@
 +#include dirent.h
 +
 +int main()
 +{
 +struct dirent ent;
 +
 +(void) ent.d_type;
 +
 +return 0;
 +}
 diff --git a/configure b/configure
 index 1a8e939..d2d193c 100755
 --- a/configure
 +++ b/configure
 @@ -557,6 +557,17 @@ else
  fi
  rm -f compat/have_timegm
  
 +printf Checking for dirent.d_type... 
 +if ${CC} -o compat/have_d_type $srcdir/compat/have_d_type.c  /dev/null 
 21
 +then
 +printf Yes.\n
 +have_d_type=1
 +else
 +printf No (will use stat instead).\n
 +have_d_type=0
 +fi
 +rm -f compat/have_d_type
 +
  printf Checking for standard version of getpwuid_r... 
  if ${CC} -o compat/check_getpwuid $srcdir/compat/check_getpwuid.c  
 /dev/null 21
  then
 @@ -745,6 +756,9 @@ HAVE_STRCASESTR = ${have_strcasestr}
  # build its own version)
  HAVE_STRSEP = ${have_strsep}
  
 +# Whether struct dirent has d_type (if not, then notmuch will use stat)
 +HAVE_D_TYPE = ${have_d_type}
 +
  # Whether the Xapian version in use supports compaction
  HAVE_XAPIAN_COMPACT = ${have_xapian_compact}
  
 @@ -805,6 +819,7 @@ CONFIGURE_CFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) 
 \$(GMIME_CFLAGS)  \\
  \$(VALGRIND_CFLAGS)   \\
  -DHAVE_STRCASESTR=\$(HAVE_STRCASESTR) \\
  -DHAVE_STRSEP=\$(HAVE_STRSEP) \\
 +-DHAVE_D_TYPE=\$(HAVE_D_TYPE) \\
  -DSTD_GETPWUID=\$(STD_GETPWUID)   \\
  -DSTD_ASCTIME=\$(STD_ASCTIME) \\
  -DHAVE_XAPIAN_COMPACT=\$(HAVE_XAPIAN_COMPACT)
 @@ -813,6 +828,7 @@ CONFIGURE_CXXFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) 
 \$(GMIME_CFLAGS)\\
\$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS) \\
-DHAVE_STRCASESTR=\$(HAVE_STRCASESTR)   \\
-DHAVE_STRSEP=\$(HAVE_STRSEP)   \\
 +  -DHAVE_D_TYPE=\$(HAVE_D_TYPE)   \\
-DSTD_GETPWUID=\$(STD_GETPWUID) \\
-DSTD_ASCTIME=\$(STD_ASCTIME)   \\
-DHAVE_XAPIAN_COMPACT=\$(HAVE_XAPIAN_COMPACT)

The patch looks good, but the above two hunks no longer apply
cleanly. Please repost.

BR,
Jani.



 diff --git a/notmuch-new.c b/notmuch-new.c
 index ba05cb4..423e188 100644
 --- a/notmuch-new.c
 +++ b/notmuch-new.c
 @@ -167,7 +167,7 @@ dirent_type (const char *path, const struct dirent *entry)
  char *abspath;
  int err, saved_errno;
  
 -#ifdef _DIRENT_HAVE_D_TYPE
 +#if HAVE_D_TYPE
  /* Mapping from d_type to stat mode_t.  We omit DT_LNK so that
   * we'll fall through to stat and get the real file type. */
  static const mode_t modes[] = {
 -- 
 1.8.4.rc3

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


[PATCH 2/2] insert: respect maildir.synchronize_flags

2014-01-01 Thread Jani Nikula
Don't synchronize maildir flags if the user doesn't want it.
---
 notmuch-insert.c | 24 
 test/insert  |  1 -
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 2207b1e..55384e3 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -295,7 +295,7 @@ copy_stdin (int fdin, int fdout)
  * The file is renamed to encode notmuch tags as maildir flags. */
 static void
 add_file_to_database (notmuch_database_t *notmuch, const char *path,
- tag_op_list_t *tag_ops)
+ tag_op_list_t *tag_ops, notmuch_bool_t synchronize_flags)
 {
 notmuch_message_t *message;
 notmuch_status_t status;
@@ -323,11 +323,15 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 
 if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
/* Don't change tags of an existing message. */
-   status = notmuch_message_tags_to_maildir_flags (message);
-   if (status != NOTMUCH_STATUS_SUCCESS)
-   fprintf (stderr, Error: failed to sync tags to maildir flags\n);
+   if (synchronize_flags) {
+   status = notmuch_message_tags_to_maildir_flags (message);
+   if (status != NOTMUCH_STATUS_SUCCESS)
+   fprintf (stderr, Error: failed to sync tags to maildir 
flags\n);
+   }
 } else {
-   tag_op_list_apply (message, tag_ops, TAG_FLAG_MAILDIR_SYNC);
+   tag_op_flag_t flags = synchronize_flags ? TAG_FLAG_MAILDIR_SYNC : 0;
+
+   tag_op_list_apply (message, tag_ops, flags);
 }
 
 notmuch_message_destroy (message);
@@ -335,7 +339,8 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 
 static notmuch_bool_t
 insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
-   const char *dir, tag_op_list_t *tag_ops)
+   const char *dir, tag_op_list_t *tag_ops,
+   notmuch_bool_t synchronize_flags)
 {
 char *tmppath;
 char *newpath;
@@ -377,7 +382,7 @@ insert_message (void *ctx, notmuch_database_t *notmuch, int 
fdin,
 
 /* Even if adding the message to the notmuch database fails,
  * the message is on disk and we consider the delivery completed. */
-add_file_to_database (notmuch, newpath, tag_ops);
+add_file_to_database (notmuch, newpath, tag_ops, synchronize_flags);
 
 return TRUE;
 
@@ -400,6 +405,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 char *query_string = NULL;
 const char *folder = NULL;
 notmuch_bool_t create_folder = FALSE;
+notmuch_bool_t synchronize_flags;
 const char *maildir;
 int opt_index;
 unsigned int i;
@@ -420,6 +426,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 
 db_path = notmuch_config_get_database_path (config);
 new_tags = notmuch_config_get_new_tags (config, new_tags_length);
+synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
 
 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
@@ -471,7 +478,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
   NOTMUCH_DATABASE_MODE_READ_WRITE, notmuch))
return 1;
 
-ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops);
+ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops,
+ synchronize_flags);
 
 notmuch_database_destroy (notmuch);
 
diff --git a/test/insert b/test/insert
index 9283e70..e8dc4c0 100755
--- a/test/insert
+++ b/test/insert
@@ -114,7 +114,6 @@ dirname=$(dirname $output)
 test_expect_equal $dirname $MAIL_DIR/cur
 
 test_begin_subtest Insert message with maildir sync off goes to new/
-test_subtest_known_broken
 OLDCONFIG=$(notmuch config get maildir.synchronize_flags)
 notmuch config set maildir.synchronize_flags false
 gen_insert_msg
-- 
1.8.5.2

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


[PATCH v2 2/2] lib: modify notmuch.h for automatic document generation

2014-01-01 Thread Jani Nikula
Minimal changes to produce a sensible result.
---
 lib/notmuch.h | 443 +++---
 1 file changed, 302 insertions(+), 141 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index d30768d..02604c5 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -18,9 +18,19 @@
  * Author: Carl Worth cwo...@cworth.org
  */
 
+/**
+ * @defgroup notmuch The notmuch API
+ *
+ * Not much of an email library, (just index and search)
+ *
+ * @{
+ */
+
 #ifndef NOTMUCH_H
 #define NOTMUCH_H
 
+#ifndef __DOXYGEN__
+
 #ifdef  __cplusplus
 # define NOTMUCH_BEGIN_DECLS  extern C {
 # define NOTMUCH_END_DECLS}
@@ -49,19 +59,28 @@ NOTMUCH_BEGIN_DECLS
 #define LIBNOTMUCH_MINOR_VERSION   1
 #define LIBNOTMUCH_MICRO_VERSION   0
 
-/*
+#endif /* __DOXYGEN__ */
+
+/**
  * Check the version of the notmuch library being compiled against.
  *
  * Return true if the library being compiled against is of the
  * specified version or above. For example:
  *
+ * @code
  * #if LIBNOTMUCH_CHECK_VERSION(3, 1, 0)
  * (code requiring libnotmuch 3.1.0 or above)
  * #endif
+ * @endcode
+ *
+ * LIBNOTMUCH_CHECK_VERSION has been defined since version 3.1.0; to
+ * check for versions prior to that, use:
  *
- * LIBNOTMUCH_CHECK_VERSION has been defined since version 3.1.0; you
- * can use #if !defined(NOTMUCH_CHECK_VERSION) to check for versions
- * prior to that.
+ * @code
+ * #if !defined(NOTMUCH_CHECK_VERSION)
+ * (code requiring libnotmuch prior to 3.1.0)
+ * #endif
+ * @endcode
  */
 #define LIBNOTMUCH_CHECK_VERSION (major, minor, micro) \
 (LIBNOTMUCH_MAJOR_VERSION  (major) || 
\
@@ -69,72 +88,86 @@ NOTMUCH_BEGIN_DECLS
  (LIBNOTMUCH_MAJOR_VERSION == (major)  LIBNOTMUCH_MINOR_VERSION == 
(minor)  \
   LIBNOTMUCH_MICRO_VERSION = (micro)))
 
+/**
+ * Notmuch boolean type.
+ */
 typedef int notmuch_bool_t;
 
-/* Status codes used for the return values of most functions.
+/**
+ * Status codes used for the return values of most functions.
  *
  * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
- * completed without error. Any other value indicates an error as
- * follows:
- *
- * NOTMUCH_STATUS_SUCCESS: No error occurred.
- *
- * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory
- *
- * XXX: We don't really want to expose this lame XAPIAN_EXCEPTION
- * value. Instead we should map to things like DATABASE_LOCKED or
- * whatever.
- *
- * NOTMUCH_STATUS_READ_ONLY_DATABASE: An attempt was made to write to
- * a database opened in read-only mode.
- *
- * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
- *
- * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to read or
- * write to a file (this could be file not found, permission
- * denied, etc.)
- *
- * NOTMUCH_STATUS_FILE_NOT_EMAIL: A file was presented that doesn't
- * appear to be an email message.
- *
- * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: A file contains a message ID
- * that is identical to a message already in the database.
- *
- * NOTMUCH_STATUS_NULL_POINTER: The user erroneously passed a NULL
- * pointer to a notmuch function.
- *
- * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds
- * NOTMUCH_TAG_MAX)
- *
- * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw
- * function has been called more times than notmuch_message_freeze.
- *
- * NOTMUCH_STATUS_UNBALANCED_ATOMIC: notmuch_database_end_atomic has
- * been called more times than notmuch_database_begin_atomic.
- *
- * And finally:
- *
- * NOTMUCH_STATUS_LAST_STATUS: Not an actual status value. Just a way
- * to find out how many valid status values there are.
+ * completed without error. Any other value indicates an error.
  */
 typedef enum _notmuch_status {
+/**
+ * No error occurred.
+ */
 NOTMUCH_STATUS_SUCCESS = 0,
+/**
+ * Out of memory.
+ */
 NOTMUCH_STATUS_OUT_OF_MEMORY,
+/**
+ * An attempt was made to write to a database opened in read-only
+ * mode.
+ */
 NOTMUCH_STATUS_READ_ONLY_DATABASE,
+/**
+ * A Xapian exception occurred.
+ */
 NOTMUCH_STATUS_XAPIAN_EXCEPTION,
+/**
+ * An error occurred trying to read or write to a file (this could
+ * be file not found, permission denied, etc.)
+ *
+ * @todo We don't really want to expose this lame XAPIAN_EXCEPTION
+ * value. Instead we should map to things like DATABASE_LOCKED or
+ * whatever.
+ */
 NOTMUCH_STATUS_FILE_ERROR,
+/**
+ * A file was presented that doesn't appear to be an email
+ * message.
+ */
 NOTMUCH_STATUS_FILE_NOT_EMAIL,
+/**
+ * A file contains a message ID that is identical to a message
+ * already in the database.
+ */
 NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,
+/**
+ * The user erroneously passed a NULL pointer to a notmuch
+ * function.
+ */
 NOTMUCH_STATUS_NULL_POINTER,
+/**
+ * A 

[PATCH v2 1/2] devel: add doxygen configuration file

2014-01-01 Thread Jani Nikula
This is a pretty basic config to get started, generated using 'doxygen
-s -g' and mildly tweaked.

To generate the library man page man/man3/notmuch.3 from lib/notmuch.h
use:

$ doxygen devel/doxygen.cfg
---
 devel/doxygen.cfg | 304 ++
 1 file changed, 304 insertions(+)
 create mode 100644 devel/doxygen.cfg

diff --git a/devel/doxygen.cfg b/devel/doxygen.cfg
new file mode 100644
index 000..65d5fb5
--- /dev/null
+++ b/devel/doxygen.cfg
@@ -0,0 +1,304 @@
+# Doxyfile 1.8.4
+
+#---
+# Project related configuration options
+#---
+DOXYFILE_ENCODING  = UTF-8
+PROJECT_NAME   = Notmuch 0.17
+PROJECT_NUMBER =
+PROJECT_BRIEF  =
+PROJECT_LOGO   =
+OUTPUT_DIRECTORY   =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE= English
+BRIEF_MEMBER_DESC  = YES
+REPEAT_BRIEF   = YES
+ABBREVIATE_BRIEF   =
+ALWAYS_DETAILED_SEC= NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES= NO
+STRIP_FROM_PATH=
+STRIP_FROM_INC_PATH=
+SHORT_NAMES= NO
+JAVADOC_AUTOBRIEF  = YES
+QT_AUTOBRIEF   = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS   = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE   = 8
+ALIASES=
+TCL_SUBST  =
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+EXTENSION_MAPPING  =
+MARKDOWN_SUPPORT   = YES
+AUTOLINK_SUPPORT   = YES
+BUILTIN_STL_SUPPORT= NO
+CPP_CLI_SUPPORT= NO
+SIP_SUPPORT= NO
+IDL_PROPERTY_SUPPORT   = YES
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING= YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS  = NO
+TYPEDEF_HIDES_STRUCT   = YES
+LOOKUP_CACHE_SIZE  = 0
+#---
+# Build related configuration options
+#---
+EXTRACT_ALL= NO
+EXTRACT_PRIVATE= NO
+EXTRACT_PACKAGE= NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS  = NO
+INTERNAL_DOCS  = NO
+CASE_SENSE_NAMES   = YES
+HIDE_SCOPE_NAMES   = NO
+SHOW_INCLUDE_FILES = NO
+FORCE_LOCAL_INCLUDES   = NO
+INLINE_INFO= YES
+SORT_MEMBER_DOCS   = NO
+SORT_BRIEF_DOCS= NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES   = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING  = NO
+GENERATE_TODOLIST  = NO
+GENERATE_TESTLIST  = NO
+GENERATE_BUGLIST   = NO
+GENERATE_DEPRECATEDLIST= NO
+ENABLED_SECTIONS   =
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES= NO
+SHOW_FILES = NO
+SHOW_NAMESPACES= NO
+FILE_VERSION_FILTER=
+LAYOUT_FILE=
+CITE_BIB_FILES =
+#---
+# configuration options related to warning and progress messages
+#---
+QUIET  = YES
+WARNINGS   = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR  = YES
+WARN_NO_PARAMDOC   = NO
+WARN_FORMAT= $file:$line: $text
+WARN_LOGFILE   =
+#---
+# configuration options related to the input files
+#---
+INPUT  = lib/notmuch.h
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS  =
+RECURSIVE  = NO
+EXCLUDE=
+EXCLUDE_SYMLINKS   = NO
+EXCLUDE_PATTERNS   =
+EXCLUDE_SYMBOLS=
+EXAMPLE_PATH   =
+EXAMPLE_PATTERNS   =
+EXAMPLE_RECURSIVE  = NO
+IMAGE_PATH =
+INPUT_FILTER   =
+FILTER_PATTERNS=
+FILTER_SOURCE_FILES= NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+#---
+# configuration options related to source browsing
+#---
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS= YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION= NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS  = NO
+VERBATIM_HEADERS   = NO
+#---
+# configuration options related to the alphabetical class index
+#---
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX= 5

Re: notmuch-0.16: realpath() compatibility issue; clang visibility problem

2014-01-04 Thread Jani Nikula
For the visibility issue please upgrade Notmuch.

BR,
Jani.

On Jan 4, 2014 2:26 PM, Thomas Klausner t...@giga.or.at wrote:

 Hi!

 I'm currently starting to try out notmuch-0.16 on NetBSD. It went off
 to a rocky start, since it segfaulted in the initial config setup.

 Debugging it I found that notmuch uses a glibc extension to realpath,
 allowing NULL as second argument.

 I've converted it to use a prepared buffer instead; attached is a
 possible patch that makes notmuch complete its setup phase for me, and
 adds inclusion of the header files suggested by the realpath man page
 on NetBSD. Please address this issue in some way in the next release.

 Additionally, when compiling with clang, there are issues with the
 visibility. The symptoms are:

 In file included from lib/database.cc:21:
 In file included from ./lib/database-private.h:33:
 ./lib/notmuch-private.h:479:8: error: visibility does not match previous
declaration
 array subscriptstruct visible _notmuch_string_list {
^
 ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
  # define visible __attribute__((visibility(default)))
 ^
 ./lib/notmuch-private.h:52:13: note: previous attribute is here
 #pragma GCC visibility push(hidden)
 ^

 In file included from lib/parse-time-vrp.cc:23:
 In file included from ./lib/database-private.h:33:
 ./lib/notmuch-private.h:479:8: error: visibility does not match previous
declaration
 struct visible _notmuch_string_list {
^
 ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
 # define visible __attribute__((visibility(default)))
 ^
 ./lib/notmuch-private.h:52:13: note: previous attribute is here
 #pragma GCC visibility push(hidden)
 ^
 1 warning generated.
 In file included from lib/directory.cc:21:
 ./lib/notmuch-private.h:479:8: error: visibility does not match previous
declaration
 struct visible _notmuch_string_list {
^
 ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
 # define visible __attribute__((visibility(default)))
 ^
 ./lib/notmuch-private.h:52:13: note: previous attribute is here
 #pragma GCC visibility push(hidden)
 ^

 and so on. I guess it is because the visibility differs between c and
 c++. I've disabled visibility locally, see second attached patch, but
 of course that's not a solution, just a workaround. Suggestions
 welcome.

 Thanks,
  Thomas

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

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


Re: notmuch-0.16: realpath() compatibility issue; clang visibility problem

2014-01-04 Thread Jani Nikula
I guess we should look at realpath() compatibility, but in fairness passing
NULL for the second parameter is according to POSIX.1-2008, not glibc
extension.

On Jan 4, 2014 2:35 PM, Jani Nikula j...@nikula.org wrote:

 For the visibility issue please upgrade Notmuch.

 BR,
 Jani.

 On Jan 4, 2014 2:26 PM, Thomas Klausner t...@giga.or.at wrote:
 
  Hi!
 
  I'm currently starting to try out notmuch-0.16 on NetBSD. It went off
  to a rocky start, since it segfaulted in the initial config setup.
 
  Debugging it I found that notmuch uses a glibc extension to realpath,
  allowing NULL as second argument.
 
  I've converted it to use a prepared buffer instead; attached is a
  possible patch that makes notmuch complete its setup phase for me, and
  adds inclusion of the header files suggested by the realpath man page
  on NetBSD. Please address this issue in some way in the next release.
 
  Additionally, when compiling with clang, there are issues with the
  visibility. The symptoms are:
 
  In file included from lib/database.cc:21:
  In file included from ./lib/database-private.h:33:
  ./lib/notmuch-private.h:479:8: error: visibility does not match
previous declaration
  array subscriptstruct visible _notmuch_string_list {
 ^
  ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
   # define visible __attribute__((visibility(default)))
  ^
  ./lib/notmuch-private.h:52:13: note: previous attribute is here
  #pragma GCC visibility push(hidden)
  ^
 
  In file included from lib/parse-time-vrp.cc:23:
  In file included from ./lib/database-private.h:33:
  ./lib/notmuch-private.h:479:8: error: visibility does not match
previous declaration
  struct visible _notmuch_string_list {
 ^
  ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
  # define visible __attribute__((visibility(default)))
  ^
  ./lib/notmuch-private.h:52:13: note: previous attribute is here
  #pragma GCC visibility push(hidden)
  ^
  1 warning generated.
  In file included from lib/directory.cc:21:
  ./lib/notmuch-private.h:479:8: error: visibility does not match
previous declaration
  struct visible _notmuch_string_list {
 ^
  ./lib/notmuch-private.h:67:33: note: expanded from macro 'visible'
  # define visible __attribute__((visibility(default)))
  ^
  ./lib/notmuch-private.h:52:13: note: previous attribute is here
  #pragma GCC visibility push(hidden)
  ^
 
  and so on. I guess it is because the visibility differs between c and
  c++. I've disabled visibility locally, see second attached patch, but
  of course that's not a solution, just a workaround. Suggestions
  welcome.
 
  Thanks,
   Thomas
 
  ___
  notmuch mailing list
  notmuch@notmuchmail.org
  http://notmuchmail.org/mailman/listinfo/notmuch
 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: notmuch-0.16: realpath() compatibility issue; clang visibility problem

2014-01-04 Thread Jani Nikula
On Jan 5, 2014 12:38 AM, Thomas Klausner t...@giga.or.at wrote:

 On Sat, Jan 04, 2014 at 09:18:15AM -0400, David Bremner wrote:
  I'm not sure what the right answer is here. MATHPATHLEN (and PATH_MAX)
  are not necessarily defined; in particular this would break
  compilation on GNU Hurd. Perhaps we should ship a compatibility
  implementation of a POSIX.1-2008 compatible [1] realpath. Or maybe
  realpath can be avoided completely here.

 A compatibility implementation for POSIX.1-2008-realpath would be
 great, as would be avoiding the call. Why is it necessary to resolve
 $HOME here?

realpath is used to follow, not overwrite symlinks.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 0/5] lib: make folder: prefix literal

2014-01-09 Thread Jani Nikula
Hi all, this series makes the folder: search prefix literal, or switches
it from a probabilistic prefix to a boolean prefix. With this, you have
to give the path from the maildir root to the folder you want in full,
including the maildir cur/new component, if any. Examples:

folder:cur
folder:foo/bar
folder:

The last one can be used to refer to the maildir root (note that in
shell you'll need quoting to pass the double quotes to xapian,
folder:'').

The old probabilistic folder: prefix is problematic in a number of
ways. It's not possible to refer to the maildir root. It does stemming,
so inboxing would match inbox too. cur for the folder in maildir
root would match all cur folders across the maildir hierarchy. Likely
some others I forgot.

WARNING! The change requires a database format version bump, and a
database upgrade, which is automatically done on 'notmuch new'. The
upgrade is irreversible if you want to try this on your database! A
complete database rebuild is required for reverting the database format
version. Make sure your backups are in order!

The series includes some tests, including an initial upgrade test, along
with a test database in the previous format version.


BR,
Jani.



Jani Nikula (5):
  lib: make folder: prefix literal
  test: fix insert folder: searches
  test: fix test for literal folder: search
  test: add test database in format version 1
  test: add database upgrade test from format version 1

 lib/database.cc|  39 -
 lib/message.cc | 154 +
 lib/notmuch-private.h  |   3 +
 test/insert|  10 +--
 test/notmuch-test  |   1 +
 test/search-by-folder  |  24 -
 test/test-databases/README |   5 ++
 test/test-databases/database-v1.tar.gz | Bin 0 - 252243 bytes
 test/upgrade   |  25 ++
 9 files changed, 174 insertions(+), 87 deletions(-)
 create mode 100644 test/test-databases/README
 create mode 100644 test/test-databases/database-v1.tar.gz
 create mode 100755 test/upgrade

-- 
1.8.5.2

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


[PATCH 1/5] lib: make folder: prefix literal

2014-01-09 Thread Jani Nikula
In xapian terms, convert folder: prefix from probabilistic to boolean
prefix. This change constitutes a database change: bump the database
version and add database upgrade support.
---
 lib/database.cc   |  39 -
 lib/message.cc| 154 +-
 lib/notmuch-private.h |   3 +
 3 files changed, 117 insertions(+), 79 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index f395061..145fd66 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -42,7 +42,7 @@ typedef struct {
 const char *prefix;
 } prefix_t;
 
-#define NOTMUCH_DATABASE_VERSION 1
+#define NOTMUCH_DATABASE_VERSION 2
 
 #define STRINGIFY(s) _SUB_STRINGIFY(s)
 #define _SUB_STRINGIFY(s) #s
@@ -208,7 +208,8 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
 { thread,G },
 { tag,   K },
 { is,K },
-{ id,Q }
+{ id,Q },
+{ folder,P },
 };
 
 static prefix_t PROBABILISTIC_PREFIX[]= {
@@ -216,7 +217,6 @@ static prefix_t PROBABILISTIC_PREFIX[]= {
 { to,XTO },
 { attachment,XATTACHMENT },
 { subject,   XSUBJECT},
-{ folder,XFOLDER}
 };
 
 const char *
@@ -1167,6 +1167,39 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
}
 }
 
+/*
+ * Prior to version 2, the folder: prefix was probabilistic and
+ * stemmed. Change it to the current boolean prefix.
+ */
+if (version  2) {
+   notmuch_query_t *query = notmuch_query_create (notmuch, );
+   notmuch_messages_t *messages;
+   notmuch_message_t *message;
+
+   count = 0;
+   total = notmuch_query_count_messages (query);
+
+   for (messages = notmuch_query_search_messages (query);
+notmuch_messages_valid (messages);
+notmuch_messages_move_to_next (messages)) {
+   if (do_progress_notify) {
+   progress_notify (closure, (double) count / total);
+   do_progress_notify = 0;
+   }
+
+   message = notmuch_messages_get (messages);
+
+   _notmuch_message_upgrade_folder (message);
+   _notmuch_message_sync (message);
+
+   notmuch_message_destroy (message);
+
+   count++;
+   }
+
+   notmuch_query_destroy (query);
+}
+
 db-set_metadata (version, STRINGIFY (NOTMUCH_DATABASE_VERSION));
 db-flush ();
 
diff --git a/lib/message.cc b/lib/message.cc
index 1b46379..500aa26 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -505,89 +505,27 @@ _notmuch_message_add_filename (notmuch_message_t *message,
 _notmuch_message_add_term (message, file-direntry, direntry);
 
 /* New terms allow user to search with folder: specification. */
-_notmuch_message_gen_terms (message, folder, directory);
+_notmuch_message_add_term (message, folder, directory);
 
 talloc_free (local);
 
 return NOTMUCH_STATUS_SUCCESS;
 }
 
-/* Remove a particular 'filename' from 'message'.
- *
- * This change will not be reflected in the database until the next
- * call to _notmuch_message_sync.
- *
- * If this message still has other filenames, returns
- * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID.
- *
- * Note: This function does not remove a document from the database,
- * even if the specified filename is the only filename for this
- * message. For that functionality, see
- * _notmuch_database_remove_message. */
-notmuch_status_t
-_notmuch_message_remove_filename (notmuch_message_t *message,
- const char *filename)
+static void
+_notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
 {
-const char *direntry_prefix = _find_prefix (file-direntry);
-int direntry_prefix_len = strlen (direntry_prefix);
-const char *folder_prefix = _find_prefix (folder);
-int folder_prefix_len = strlen (folder_prefix);
-void *local = talloc_new (message);
-char *zfolder_prefix = talloc_asprintf(local, Z%s, folder_prefix);
-int zfolder_prefix_len = strlen (zfolder_prefix);
-char *direntry;
-notmuch_private_status_t private_status;
-notmuch_status_t status;
-Xapian::TermIterator i, last;
-
-status = _notmuch_database_filename_to_direntry (
-   local, message-notmuch, filename, NOTMUCH_FIND_LOOKUP, direntry);
-if (status || !direntry)
-   return status;
+Xapian::TermIterator i;
+size_t prefix_len = strlen (prefix);
 
-/* Unlink this file from its parent directory. */
-private_status = _notmuch_message_remove_term (message,
-  file-direntry, direntry);
-status = COERCE_STATUS (private_status,
-   Unexpected error from 
_notmuch_message_remove_term);
-if (status)
-   return status;
-
-/* Re-synchronize folder: terms for this message. This requires:
- *  1. 

[PATCH 3/5] test: fix test for literal folder: search

2014-01-09 Thread Jani Nikula
---
 test/search-by-folder | 24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/test/search-by-folder b/test/search-by-folder
index 5cc2ca8..84ca438 100755
--- a/test/search-by-folder
+++ b/test/search-by-folder
@@ -3,6 +3,7 @@ test_description='notmuch search by folder: (with variations)'
 . ./test-lib.sh
 
 add_message '[dir]=bad' '[subject]=To the bone'
+add_message '[dir]=.' '[subject]=Top level'
 add_message '[dir]=bad/news' '[subject]=Bears'
 mkdir -p ${MAIL_DIR}/duplicate/bad/news
 cp $gen_msg_filename ${MAIL_DIR}/duplicate/bad/news
@@ -12,29 +13,46 @@ add_message '[dir]=things/favorite' '[subject]=Raindrops, 
whiskers, kettles'
 add_message '[dir]=things/bad' '[subject]=Bites, stings, sad feelings'
 
 test_begin_subtest Single-world folder: specification (multiple results)
-output=$(notmuch search folder:bad | notmuch_search_sanitize)
+output=$(notmuch search folder:bad folder:bad/news folder:things/bad | 
notmuch_search_sanitize)
 test_expect_equal $output thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
To the bone (inbox unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings 
(inbox unread)
 
+test_begin_subtest Top level folder
+output=$(notmuch search folder:'' | notmuch_search_sanitize)
+test_expect_equal $output thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Top level (inbox unread)
+
 test_begin_subtest Two-word path to narrow results to one
 output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
 test_expect_equal $output thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Bears (inbox unread)
 
+test_begin_subtest Folder search with --output=files
+output=$(notmuch search --output=files folder:bad/news | sed -e 
s,$MAIL_DIR,MAIL_DIR,)
+test_expect_equal $output MAIL_DIR/bad/news/msg-003
+MAIL_DIR/duplicate/bad/news/msg-003
+
 test_begin_subtest After removing duplicate instance of matching path
 rm -r ${MAIL_DIR}/bad/news
 notmuch new
 output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
+test_expect_equal $output 
+
+test_begin_subtest Folder search with --output=files part #2
+output=$(notmuch search --output=files folder:duplicate/bad/news | sed -e 
s,$MAIL_DIR,MAIL_DIR,)
+test_expect_equal $output MAIL_DIR/duplicate/bad/news/msg-003
+
+test_begin_subtest After removing duplicate instance of matching path part #2
+output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize)
 test_expect_equal $output thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Bears (inbox unread)
 
 test_begin_subtest After rename, old path returns nothing
 mv ${MAIL_DIR}/duplicate/bad/news ${MAIL_DIR}/duplicate/bad/olds
 notmuch new
-output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
+output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize)
 test_expect_equal $output 
 
 test_begin_subtest After rename, new path returns result
-output=$(notmuch search folder:bad/olds | notmuch_search_sanitize)
+output=$(notmuch search folder:duplicate/bad/olds | notmuch_search_sanitize)
 test_expect_equal $output thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; 
Bears (inbox unread)
 
 test_done
-- 
1.8.5.2

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


[PATCH 5/5] test: add database upgrade test from format version 1

2014-01-09 Thread Jani Nikula
---
 test/notmuch-test |  1 +
 test/upgrade  | 25 +
 2 files changed, 26 insertions(+)
 create mode 100755 test/upgrade

diff --git a/test/notmuch-test b/test/notmuch-test
index d6fdd3a..68c8ad9 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -69,6 +69,7 @@ TESTS=
   parse-time-string
   search-date
   thread-replies
+  upgrade
 
 TESTS=${NOTMUCH_TESTS:=$TESTS}
 
diff --git a/test/upgrade b/test/upgrade
new file mode 100755
index 000..edee35d
--- /dev/null
+++ b/test/upgrade
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+test_description=database upgrade
+
+. ./test-lib.sh
+
+tar zxf $TEST_DIRECTORY/test-databases/database-v1.tar.gz -C ${MAIL_DIR} 
--strip-components=1
+
+# XXX: Test new notmuch with old database in read-only mode
+
+test_begin_subtest database upgrade from format version 1
+output=$(notmuch new)
+test_expect_equal $output \
+Welcome to a new version of notmuch! Your database will now be upgraded.
+Your notmuch database has now been upgraded to database format version 2.
+No new mail.
+
+# XXX: Add some meaningful tests on the upgraded database, testing the
+# things that have been upgraded. For folder search, this means
+# actually having folders in the corpus.
+
+test_begin_subtest Top level folder
+output=$(notmuch search folder:'' | notmuch_search_sanitize)
+test_expect_equal $output 
+
+test_done
-- 
1.8.5.2

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


[PATCH 2/5] test: fix insert folder: searches

2014-01-09 Thread Jani Nikula
folder: is now boolean prefix.
---
 test/insert | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/test/insert b/test/insert
index e8dc4c0..4bbccd5 100755
--- a/test/insert
+++ b/test/insert
@@ -126,14 +126,14 @@ test_expect_equal $dirname $MAIL_DIR/new
 test_begin_subtest Insert message into folder
 gen_insert_msg
 notmuch insert --folder=Drafts  $gen_msg_filename
-output=$(notmuch search --output=files folder:Drafts)
+output=$(notmuch search --output=files folder:Drafts/new)
 dirname=$(dirname $output)
 test_expect_equal $dirname $MAIL_DIR/Drafts/new
 
 test_begin_subtest Insert message into folder, add/remove tags
 gen_insert_msg
 notmuch insert --folder=Drafts +draft -unread  $gen_msg_filename
-output=$(notmuch search --output=messages folder:Drafts tag:draft NOT 
tag:unread)
+output=$(notmuch search --output=messages folder:Drafts/cur tag:draft NOT 
tag:unread)
 test_expect_equal $output id:$gen_msg_id
 
 gen_insert_msg
@@ -143,21 +143,21 @@ test_expect_code 1 Insert message into non-existent 
folder \
 test_begin_subtest Insert message, create folder
 gen_insert_msg
 notmuch insert --folder=F --create-folder +folder  $gen_msg_filename
-output=$(notmuch search --output=files folder:F tag:folder)
+output=$(notmuch search --output=files folder:F/new tag:folder)
 basename=$(basename $output)
 test_expect_equal_file $gen_msg_filename $MAIL_DIR/F/new/${basename}
 
 test_begin_subtest Insert message, create subfolder
 gen_insert_msg
 notmuch insert --folder=F/G/H/I/J --create-folder +folder  $gen_msg_filename
-output=$(notmuch search --output=files folder:F/G/H/I/J tag:folder)
+output=$(notmuch search --output=files folder:F/G/H/I/J/new tag:folder)
 basename=$(basename $output)
 test_expect_equal_file $gen_msg_filename 
${MAIL_DIR}/F/G/H/I/J/new/${basename}
 
 test_begin_subtest Insert message, create existing subfolder
 gen_insert_msg
 notmuch insert --folder=F/G/H/I/J --create-folder +folder  $gen_msg_filename
-output=$(notmuch count folder:F/G/H/I/J tag:folder)
+output=$(notmuch count folder:F/G/H/I/J/new tag:folder)
 test_expect_equal $output 2
 
 gen_insert_msg
-- 
1.8.5.2

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


[PATCH] cli: initialize quiet variable in compact

2014-01-10 Thread Jani Nikula
Surprisingly there's no compiler warning!
---
 notmuch-compact.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/notmuch-compact.c b/notmuch-compact.c
index 8b820c0..6c59093 100644
--- a/notmuch-compact.c
+++ b/notmuch-compact.c
@@ -32,7 +32,7 @@ notmuch_compact_command (notmuch_config_t *config, int argc, 
char *argv[])
 const char *path = notmuch_config_get_database_path (config);
 const char *backup_path = NULL;
 notmuch_status_t ret;
-notmuch_bool_t quiet;
+notmuch_bool_t quiet = FALSE;
 int opt_index;
 
 notmuch_opt_desc_t options[] = {
-- 
1.8.5.2

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


[PATCH 2/2] cli: close config and do talloc report also on errors

2014-01-10 Thread Jani Nikula
Seems like the sensible thing to do.
---
 notmuch.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/notmuch.c b/notmuch.c
index 2d7f33d..b3fa9f3 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -256,7 +256,7 @@ main (int argc, char *argv[])
 const char *command_name = NULL;
 command_t *command;
 char *config_file_name = NULL;
-notmuch_config_t *config;
+notmuch_config_t *config = NULL;
 notmuch_bool_t print_help=FALSE, print_version=FALSE;
 int opt_index;
 int ret;
@@ -316,7 +316,9 @@ main (int argc, char *argv[])
 
 ret = (command-function)(config, argc - opt_index, argv + opt_index);
 
-notmuch_config_close (config);
+  DONE:
+if (config)
+   notmuch_config_close (config);
 
 talloc_report = getenv (NOTMUCH_TALLOC_REPORT);
 if (talloc_report  strcmp (talloc_report, ) != 0) {
@@ -334,7 +336,6 @@ main (int argc, char *argv[])
}
 }
 
-  DONE:
 talloc_free (local);
 
 return ret;
-- 
1.8.5.2

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


Re: [PATCH] show: add In-reply-to, References fields to structured formats

2014-01-12 Thread Jani Nikula
On Sun, 12 Jan 2014, Peter Wang noval...@gmail.com wrote:
 This is useful when 'show' is used to retrieve a draft message
 which is in reply to another message.

I'd like to know more about *how* this is useful. Indeed the whole big
picture about supporting draft or postponed messages is foggy. I would
like to have some clarity about that first.

Apparently the idea is to index draft messages. How do you save them?
What guarantees are there that they look enough like real messages that
they get indexed? Does this patch mean that the idea is to resume draft
messages using the structured formats instead of opening the raw file?
Why?  What do you plan to do with the saved draft? And so on...

BR,
Jani.

 ---
  devel/schemata  |  9 -
  notmuch-show.c  | 16 
  test/thread-replies |  7 +++
  3 files changed, 27 insertions(+), 5 deletions(-)

 diff --git a/devel/schemata b/devel/schemata
 index 41dc4a6..dd41217 100644
 --- a/devel/schemata
 +++ b/devel/schemata
 @@ -14,7 +14,7 @@ are interleaved. Keys are printed as keywords (symbols 
 preceded by a
  colon), e.g. (:id 123 :time 54321 :from foobar). Null is printed as
  nil, true as t and false as nil.
  
 -This is version 2 of the structured output format.
 +This is version 3 of the structured output format.
  
  Version history
  ---
 @@ -26,6 +26,9 @@ v1
  v2
  - Added the thread_summary.query field.
  
 +v3
 +- Added headers.in-reply-to and headers.references fields.
 +
  Common non-terminals
  
  
 @@ -105,6 +108,10 @@ headers = {
  Cc?:string,
  Bcc?:   string,
  Reply-To?:  string,
 +# Added in schema version 3.
 +In-reply-to?:   string,
 +# Added in schema version 3.
 +References?:string,
  Date:   string
  }
  
 diff --git a/notmuch-show.c b/notmuch-show.c
 index c07f887..774ba44 100644
 --- a/notmuch-show.c
 +++ b/notmuch-show.c
 @@ -222,6 +222,8 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage 
 *message,
  InternetAddressList *recipients;
  const char *recipients_string;
  const char *reply_to_string;
 +const char *in_reply_to_string;
 +const char *references_string;
  
  sp-begin_map (sp);
  
 @@ -258,13 +260,19 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage 
 *message,
   sp-string (sp, reply_to_string);
  }
  
 -if (reply) {
 +in_reply_to_string = g_mime_object_get_header (GMIME_OBJECT (message), 
 In-reply-to);
 +if (in_reply_to_string || reply) {
   sp-map_key (sp, In-reply-to);
 - sp-string (sp, g_mime_object_get_header (GMIME_OBJECT (message), 
 In-reply-to));
 + sp-string (sp, in_reply_to_string);
 +}
  
 +references_string = g_mime_object_get_header (GMIME_OBJECT (message), 
 References);
 +if (references_string || reply) {
   sp-map_key (sp, References);
 - sp-string (sp, g_mime_object_get_header (GMIME_OBJECT (message), 
 References));
 -} else {
 + sp-string (sp, references_string);
 +}
 +
 +if (! reply) {
   sp-map_key (sp, Date);
   sp-string (sp, g_mime_message_get_date_as_string (message));
  }
 diff --git a/test/thread-replies b/test/thread-replies
 index eeb70d0..9d4b379 100755
 --- a/test/thread-replies
 +++ b/test/thread-replies
 @@ -39,6 +39,8 @@ expected='[[[{id: f...@one.com,
   tags: [inbox, unread], headers: {Subject: Re: one,
   From: Notmuch Test Suite test_su...@notmuchmail.org,
   To: Notmuch Test Suite test_su...@notmuchmail.org,
 + In-reply-to: mumble,
 + References: f...@one.com,
   Date: Fri, 05 Jan 2001 15:43:57 +},
   body: [{id: 1, content-type: text/plain,
   content: This is just a test message (#2)\n}]}, []]'
 @@ -68,6 +70,8 @@ expected='[[[{id: f...@two.com,
   headers: {Subject: Re: two,
   From: Notmuch Test Suite test_su...@notmuchmail.org,
   To: Notmuch Test Suite test_su...@notmuchmail.org,
 + In-reply-to: b...@baz.com,
 + References: f...@two.com,
   Date: Fri, 05 Jan 2001 15:43:57 +},
   body: [{id: 1,
   content-type: text/plain, content: This is just a test message 
 (#4)\n}]},
 @@ -95,6 +99,7 @@ expected='[[[{id: f...@three.com, match: true, 
 excluded: false,
   headers: {Subject: Re: three,
   From: Notmuch Test Suite test_su...@notmuchmail.org,
   To: Notmuch Test Suite test_su...@notmuchmail.org,
 + In-reply-to: f...@three.com,
   Date: Fri, 05 Jan 2001 15:43:57 +}, body: [{id: 1,
   content-type: text/plain, content: This is just a test message 
 (#6)\n}]},
   []]'
 @@ -124,6 +129,8 @@ expected='[[[{id: f...@four.com, match: true, 
 excluded: false,
   headers: {Subject: neither,
   From: Notmuch Test Suite test_su...@notmuchmail.org,
   To: Notmuch Test Suite test_su...@notmuchmail.org,
 + In-reply-to: b...@four.com,
 + References: b...@four.com f...@four.com,
   Date: Fri, 05 Jan 2001 15:43:57 +}, body: [{id: 1,
   content-type: text/plain, content: This is just a test message 
 (#9)\n}]},
   [], [[{id: 

Re: [PATCH] notmuch: Add maildir: search option

2014-01-12 Thread Jani Nikula
On Tue, 12 Nov 2013, Peter Zijlstra pet...@infradead.org wrote:
 Subject: notmuch: Add maildir: search option

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

Hi Peter -

Per some discussion on IRC about the usefulness of the current folder:
prefix, I went ahead and sent patches to make folder: a boolean prefix
[1]. It's not the same as your maildir: implementation, but I believe
you could use it to achieve the things you want with that. In
particular, my proposed folder: prefix is the literal path from
maildir root, and does not make any assumptions about maildir - i.e. it
requires the final cur/new too. (That can be useful for some mutt users
who need the cur/new distinction.)

I am not opposed to adding another prefix like maildir: that does make
assumptions on the mail storage and transformations on the path, but I
do think it would be less important with the boolean folder: in place.

BR,
Jani.


[1] id:cover.1389304779.git.j...@nikula.org




 Given a Maildir++ layout like:

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

 This patch generates the following search index:

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

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

   maildir:INBOX and not tag:list

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

 Signed-off-by: Peter Zijlstra pet...@infradead.org
 ---

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

   subject:PATCH/0

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


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

 diff --git a/lib/database.cc b/lib/database.cc
 index a021bf17253c..53aeaa68954d 100644
 --- a/lib/database.cc
 +++ b/lib/database.cc
 @@ -208,15 +208,16 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
  { thread,  G },
  { tag, K },
  { is,  K },
 -{ id,  Q }
 +{ id,  Q },
 +{ maildir, XMAILDIR: },
  };
  
  static prefix_t PROBABILISTIC_PREFIX[]= {
  { from,XFROM },
  { to,  XTO },
  { attachment,  XATTACHMENT },
 -{ subject, XSUBJECT},
 -{ folder,  XFOLDER}
 +{ subject, XSUBJECT },
 +{ folder,  XFOLDER },
  };
  
  const char *
 diff --git a/lib/message.cc b/lib/message.cc
 index 1b4637950f8e..45a727a6208f 100644
 --- a/lib/message.cc
 +++ b/lib/message.cc
 @@ -22,6 +22,7 @@
  #include database-private.h
  
  #include stdint.h
 +#include string.h
  
  #include gmime/gmime.h
  
 @@ -485,6 +486,8 @@ _notmuch_message_add_filename (notmuch_message_t *message,
  notmuch_status_t status;
  void *local = talloc_new (message);
  char *direntry;
 +char *maildir;
 +int i;
  
  if (filename == NULL)
   INTERNAL_ERROR (Message filename cannot be NULL.);
 @@ -507,6 +510,43 @@ _notmuch_message_add_filename (notmuch_message_t 
 *message,
  /* New terms allow user to search with folder: specification. */
  _notmuch_message_gen_terms (message, folder, directory);
  
 +/* Convert the directory into a maildir path */
 +maildir = talloc_strdup(local, directory);
 +
 +/* Strip the maildir cur, new directory entries. */
 +i = strlen(maildir);
 +if (strncmp(maildir + i - 3, cur, 3) == 0 ||
 + strncmp(maildir + i - 3, new, 3) == 0) {
 + maildir[i - 3] = '\0';
 + i -= 3;
 +}
 +
 +/* Strip trailing '/' */
 +while (maildir[i-1] == '/') {
 + maildir[i-1] = '\0';
 + i--;
 +}
 +
 +/* Strip leading '/' */
 +while (maildir[0] == '/')
 + maildir++;
 +
 +/* Strip leading '.' */
 +while (maildir[0] == '.')
 + maildir++;
 +
 +/* Replace all remaining '.' with '/' */
 +for (i = 0; maildir[i]; i++) {
 +

Re: [PATCH] notmuch: Add maildir: search option

2014-01-12 Thread Jani Nikula
On Sun, 12 Jan 2014, Peter Zijlstra pet...@infradead.org wrote:
 Right, sorry for disappearing; I failed to find time to finish the
 patch.

That's what I figured, but didn't want to pester you...

 I did actually modify it do loose the /new,/cur bits and I think I
 addressed all other comments, including the file removal part.

 Where I got 'stuck' was writing test cases.

Yeah, that can be a pain, but pretty much a mandatory one. Me mucking
with the folder: prefix also requires doing the database upgrade.

 Anyway, I'll try and have a look at the recent notmuch.git and see if it
 does what I'd like it to.

It's currently just patches, awaiting review, but the idea of modifying
the folder: prefix was met with approval, at least on IRC.

BR,
Jani.

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


Re: encrypting replies to encrypted mail

2014-01-12 Thread Jani Nikula
On Sun, 12 Jan 2014, Jameson Graef Rollins jroll...@finestructure.net wrote:
 The question is how do we solve this problem.  The tricky bit is that
 notmuch-emacs uses message-mode to compose and send messages, and mml to
 handle signing and encrypting, but uses the binary reply command to
 generate reply bodies.  message-mode therefore does not know if the
 original message was encrypted or not.

The notmuch reply command structured output formats contain the original
message, with all the information needed to determine whether the
message was signed and/or encrypted. Someone(tm) just needs to write the
code to check that in emacs (probably fits in the quoting loop), and
insert the appropriate mml tag (or whatever it's called) to tell message
mode to encrypt.

BR,
Jani.

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


Re: [Patch v3 1/3] info: start info documentation.

2014-01-17 Thread Jani Nikula
On Wed, 15 Jan 2014, David Bremner da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 Initially, just a skeleton of documentation for the emacs
 interface. There are a few dangling references to other info pages;
 these are to be generated from the man pages in a following commit.

 As far as actual documentation, so far this contains only a brief
 intro to notmuch-hello.
 ---
  INSTALL |  12 +-
  Makefile|  10 +-
  configure   |  32 +
  info/Makefile   |   7 ++
  info/Makefile.local |  33 +
  info/notmuch-emacs.texi | 324 
 
  6 files changed, 412 insertions(+), 6 deletions(-)
  create mode 100644 info/Makefile
  create mode 100644 info/Makefile.local
  create mode 100644 info/notmuch-emacs.texi

 diff --git a/INSTALL b/INSTALL
 index fce9352..451bf05 100644
 --- a/INSTALL
 +++ b/INSTALL
 @@ -60,16 +60,24 @@ Talloc which are each described below:
  
   Talloc is available from http://talloc.samba.org/
  
 + texinfo
 + ---
 +
 + To build the info documentation, you need makeinfo and
 + pod2texi. To install the info documentation, you need
 + install-info; these are all part of the texinfo distribution
 + as of version 5.0.
 +
  On a modern, package-based operating system you can install all of the
  dependencies with a simple simple command line. For example:
  
For Debian and similar:
  
 -sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
 +sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
 makeinfo texinfo
  
For Fedora and similar:
  
 - sudo yum install xapian-core-devel gmime-devel libtalloc-devel
 + sudo yum install xapian-core-devel gmime-devel libtalloc-devel texinfo
  
  On other systems, a similar command can be used, but the details of
  the package names may be different.
 diff --git a/Makefile b/Makefile
 index 0428160..250fbaa 100644
 --- a/Makefile
 +++ b/Makefile
 @@ -2,10 +2,12 @@
  # given explicitly on the command line) so mention it first.
  all:
  
 -# List all subdirectories here. Each contains its own Makefile.local.
 -# Use of '=', without '+=', seems to be required for out-of-tree
 -# builds to work.
 -subdirs = compat completion emacs lib man parse-time-string performance-test 
 util test

Please read the comment you're removing again! ;)

 +# List all subdirectories here. Each contains its own Makefile.local
 +subdirs := compat completion emacs lib man parse-time-string
 +subdirs += performance-test util info
 +# it seems to be important to keep test last.
 +subdirs += test
 +
  
  # We make all targets depend on the Makefiles themselves.
  global_deps = Makefile Makefile.config Makefile.local \
 diff --git a/configure b/configure
 index 13b6062..e75c1d4 100755
 --- a/configure
 +++ b/configure
 @@ -376,6 +376,10 @@ if [ -z ${EMACSETCDIR} ]; then
  fi
  fi
  
 +if [ -z ${INFODIR} ]; then
 +INFODIR='$(prefix)/share/info'
 +fi
 +
  printf Checking if emacs is available... 
  if emacs --quick --batch  /dev/null 21; then
  printf Yes.\n
 @@ -385,6 +389,24 @@ else
  have_emacs=0
  fi
  
 +printf Checking for makeinfo... 
 +if makeinfo --version  /dev/null 21; then
 +printf Yes.\n
 +have_makeinfo=1
 +else
 +printf No (so will not info docs)\n

Parse error?

 +have_makeinfo=0
 +fi
 +
 +printf Checking for install-info... 
 +if install-info --version  /dev/null 21; then
 +printf Yes.\n
 +have_installinfo=1
 +else
 +printf No (so will not install info docs)\n
 +have_installinfo=0
 +fi
 +
  libdir_in_ldconfig=0
  
  printf Checking which platform we are on... 
 @@ -740,6 +762,16 @@ emacsetcdir=${EMACSETCDIR}
  # Whether there's an emacs binary available for byte-compiling
  HAVE_EMACS = ${have_emacs}
  
 +# Whether there's a makeinfo binary available to build info docs
 +HAVE_MAKEINFO = ${have_makeinfo}
 +
 +# Whether there's an install-info binary available
 +HAVE_INSTALLINFO = ${have_installinfo}
 +
 +# where to install info files
 +

Extra empty line.

 +INFODIR = ${INFODIR}
 +
  # The directory to which desktop files should be installed
  desktop_dir = \$(prefix)/share/applications
  
 diff --git a/info/Makefile b/info/Makefile
 new file mode 100644
 index 000..de492a7
 --- /dev/null
 +++ b/info/Makefile
 @@ -0,0 +1,7 @@
 +# See Makefile.local for the list of files to be compiled in this
 +# directory.
 +all:
 + $(MAKE) -C .. all
 +
 +.DEFAULT:
 + $(MAKE) -C .. $@
 diff --git a/info/Makefile.local b/info/Makefile.local
 new file mode 100644
 index 000..55e9740
 --- /dev/null
 +++ b/info/Makefile.local
 @@ -0,0 +1,33 @@
 +# -*- makefile -*-
 +
 +dir := info
 +
 +texi_sources :=  $(dir)/notmuch-emacs.texi
 +emacs_info := $(texi_sources:.texi=.info)
 +
 +info := $(emacs_info)
 +
 +ifeq ($(HAVE_MAKEINFO),1)
 +all: $(info)
 +endif
 +
 +ifeq ($(HAVE_INSTALLINFO),1)
 +install: install-info
 +endif
 +
 

Re: [Patch v3 1/3] info: start info documentation.

2014-01-17 Thread Jani Nikula
On Wed, 15 Jan 2014, David Bremner da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 Initially, just a skeleton of documentation for the emacs
 interface. There are a few dangling references to other info pages;
 these are to be generated from the man pages in a following commit.

Is it possible to add a link to the info page from notmuch-hello?

Jani.




 As far as actual documentation, so far this contains only a brief
 intro to notmuch-hello.
 ---
  INSTALL |  12 +-
  Makefile|  10 +-
  configure   |  32 +
  info/Makefile   |   7 ++
  info/Makefile.local |  33 +
  info/notmuch-emacs.texi | 324 
 
  6 files changed, 412 insertions(+), 6 deletions(-)
  create mode 100644 info/Makefile
  create mode 100644 info/Makefile.local
  create mode 100644 info/notmuch-emacs.texi

 diff --git a/INSTALL b/INSTALL
 index fce9352..451bf05 100644
 --- a/INSTALL
 +++ b/INSTALL
 @@ -60,16 +60,24 @@ Talloc which are each described below:
  
   Talloc is available from http://talloc.samba.org/
  
 + texinfo
 + ---
 +
 + To build the info documentation, you need makeinfo and
 + pod2texi. To install the info documentation, you need
 + install-info; these are all part of the texinfo distribution
 + as of version 5.0.
 +
  On a modern, package-based operating system you can install all of the
  dependencies with a simple simple command line. For example:
  
For Debian and similar:
  
 -sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
 +sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
 makeinfo texinfo
  
For Fedora and similar:
  
 - sudo yum install xapian-core-devel gmime-devel libtalloc-devel
 + sudo yum install xapian-core-devel gmime-devel libtalloc-devel texinfo
  
  On other systems, a similar command can be used, but the details of
  the package names may be different.
 diff --git a/Makefile b/Makefile
 index 0428160..250fbaa 100644
 --- a/Makefile
 +++ b/Makefile
 @@ -2,10 +2,12 @@
  # given explicitly on the command line) so mention it first.
  all:
  
 -# List all subdirectories here. Each contains its own Makefile.local.
 -# Use of '=', without '+=', seems to be required for out-of-tree
 -# builds to work.
 -subdirs = compat completion emacs lib man parse-time-string performance-test 
 util test
 +# List all subdirectories here. Each contains its own Makefile.local
 +subdirs := compat completion emacs lib man parse-time-string
 +subdirs += performance-test util info
 +# it seems to be important to keep test last.
 +subdirs += test
 +
  
  # We make all targets depend on the Makefiles themselves.
  global_deps = Makefile Makefile.config Makefile.local \
 diff --git a/configure b/configure
 index 13b6062..e75c1d4 100755
 --- a/configure
 +++ b/configure
 @@ -376,6 +376,10 @@ if [ -z ${EMACSETCDIR} ]; then
  fi
  fi
  
 +if [ -z ${INFODIR} ]; then
 +INFODIR='$(prefix)/share/info'
 +fi
 +
  printf Checking if emacs is available... 
  if emacs --quick --batch  /dev/null 21; then
  printf Yes.\n
 @@ -385,6 +389,24 @@ else
  have_emacs=0
  fi
  
 +printf Checking for makeinfo... 
 +if makeinfo --version  /dev/null 21; then
 +printf Yes.\n
 +have_makeinfo=1
 +else
 +printf No (so will not info docs)\n
 +have_makeinfo=0
 +fi
 +
 +printf Checking for install-info... 
 +if install-info --version  /dev/null 21; then
 +printf Yes.\n
 +have_installinfo=1
 +else
 +printf No (so will not install info docs)\n
 +have_installinfo=0
 +fi
 +
  libdir_in_ldconfig=0
  
  printf Checking which platform we are on... 
 @@ -740,6 +762,16 @@ emacsetcdir=${EMACSETCDIR}
  # Whether there's an emacs binary available for byte-compiling
  HAVE_EMACS = ${have_emacs}
  
 +# Whether there's a makeinfo binary available to build info docs
 +HAVE_MAKEINFO = ${have_makeinfo}
 +
 +# Whether there's an install-info binary available
 +HAVE_INSTALLINFO = ${have_installinfo}
 +
 +# where to install info files
 +
 +INFODIR = ${INFODIR}
 +
  # The directory to which desktop files should be installed
  desktop_dir = \$(prefix)/share/applications
  
 diff --git a/info/Makefile b/info/Makefile
 new file mode 100644
 index 000..de492a7
 --- /dev/null
 +++ b/info/Makefile
 @@ -0,0 +1,7 @@
 +# See Makefile.local for the list of files to be compiled in this
 +# directory.
 +all:
 + $(MAKE) -C .. all
 +
 +.DEFAULT:
 + $(MAKE) -C .. $@
 diff --git a/info/Makefile.local b/info/Makefile.local
 new file mode 100644
 index 000..55e9740
 --- /dev/null
 +++ b/info/Makefile.local
 @@ -0,0 +1,33 @@
 +# -*- makefile -*-
 +
 +dir := info
 +
 +texi_sources :=  $(dir)/notmuch-emacs.texi
 +emacs_info := $(texi_sources:.texi=.info)
 +
 +info := $(emacs_info)
 +
 +ifeq ($(HAVE_MAKEINFO),1)
 +all: $(info)
 +endif
 +
 +ifeq ($(HAVE_INSTALLINFO),1)
 +install: install-info
 +endif
 +
 +%.info: %.texi
 

[PATCH] lib: fix clang compiler warning

2014-01-17 Thread Jani Nikula
With some combination of clang and talloc, not using the return value
of talloc_steal() produces a warning. Ignore it, as talloc_steal() has
no failure modes per documentation.
---
 lib/thread.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/thread.cc b/lib/thread.cc
index 4dcf705..8f53e12 100644
--- a/lib/thread.cc
+++ b/lib/thread.cc
@@ -524,7 +524,7 @@ _notmuch_thread_create (void *ctx,
 _resolve_thread_relationships (thread);
 
 /* Commit to returning thread. */
-talloc_steal (ctx, thread);
+(void) talloc_steal (ctx, thread);
 
   DONE:
 talloc_free (local);
-- 
1.8.5.2

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


[PATCH] cli: abstract common config get/set code

2014-01-17 Thread Jani Nikula
Pretty straightforward abstraction similar to get/set list.

---

v2 of id:1376839205-5115-1-git-send-email-j...@nikula.org adding a few
comments about config value caching per David's request. Dropped the
2nd patch as too tricky.
---
 notmuch-config.c | 86 +++-
 1 file changed, 35 insertions(+), 51 deletions(-)

diff --git a/notmuch-config.c b/notmuch-config.c
index 6845e3c..4aad9eb 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -496,6 +496,32 @@ notmuch_config_is_new (notmuch_config_t *config)
 return config-is_new;
 }
 
+static const char *
+_config_get (notmuch_config_t *config, char **field,
+const char *group, const char *key)
+{
+/* read from config file and cache value, if not cached already */
+if (*field == NULL) {
+   char *value;
+   value = g_key_file_get_string (config-key_file, group, key, NULL);
+   if (value) {
+   *field = talloc_strdup (config, value);
+   free (value);
+   }
+}
+return *field;
+}
+
+static void
+_config_set (notmuch_config_t *config, char **field,
+const char *group, const char *key, const char *value)
+{
+g_key_file_set_string (config-key_file, group, key, value);
+
+/* drop the cached value */
+talloc_free (*field);
+*field = NULL;
+}
 
 static const char **
 _config_get_list (notmuch_config_t *config,
@@ -504,6 +530,7 @@ _config_get_list (notmuch_config_t *config,
 {
 assert(outlist);
 
+/* read from config file and cache value, if not cached already */
 if (*outlist == NULL) {
 
char **inlist = g_key_file_get_string_list (config-key_file,
@@ -535,6 +562,8 @@ _config_set_list (notmuch_config_t *config,
  size_t length, const char ***config_var )
 {
 g_key_file_set_string_list (config-key_file, group, name, list, length);
+
+/* drop the cached value */
 talloc_free (*config_var);
 *config_var = NULL;
 }
@@ -542,85 +571,40 @@ _config_set_list (notmuch_config_t *config,
 const char *
 notmuch_config_get_database_path (notmuch_config_t *config)
 {
-char *path;
-
-if (config-database_path == NULL) {
-   path = g_key_file_get_string (config-key_file,
- database, path, NULL);
-   if (path) {
-   config-database_path = talloc_strdup (config, path);
-   free (path);
-   }
-}
-
-return config-database_path;
+return _config_get (config, config-database_path, database, path);
 }
 
 void
 notmuch_config_set_database_path (notmuch_config_t *config,
  const char *database_path)
 {
-g_key_file_set_string (config-key_file,
-  database, path, database_path);
-
-talloc_free (config-database_path);
-config-database_path = NULL;
+_config_set (config, config-database_path, database, path, 
database_path);
 }
 
 const char *
 notmuch_config_get_user_name (notmuch_config_t *config)
 {
-char *name;
-
-if (config-user_name == NULL) {
-   name = g_key_file_get_string (config-key_file,
- user, name, NULL);
-   if (name) {
-   config-user_name = talloc_strdup (config, name);
-   free (name);
-   }
-}
-
-return config-user_name;
+return _config_get (config, config-user_name, user, name);
 }
 
 void
 notmuch_config_set_user_name (notmuch_config_t *config,
  const char *user_name)
 {
-g_key_file_set_string (config-key_file,
-  user, name, user_name);
-
-talloc_free (config-user_name);
-config-user_name = NULL;
+_config_set (config, config-user_name, user, name, user_name);
 }
 
 const char *
 notmuch_config_get_user_primary_email (notmuch_config_t *config)
 {
-char *email;
-
-if (config-user_primary_email == NULL) {
-   email = g_key_file_get_string (config-key_file,
-  user, primary_email, NULL);
-   if (email) {
-   config-user_primary_email = talloc_strdup (config, email);
-   free (email);
-   }
-}
-
-return config-user_primary_email;
+return _config_get (config, config-user_primary_email, user, 
primary_email);
 }
 
 void
 notmuch_config_set_user_primary_email (notmuch_config_t *config,
   const char *primary_email)
 {
-g_key_file_set_string (config-key_file,
-  user, primary_email, primary_email);
-
-talloc_free (config-user_primary_email);
-config-user_primary_email = NULL;
+_config_set (config, config-user_primary_email, user, primary_email, 
primary_email);
 }
 
 const char **
-- 
1.8.5.2

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


[PATCH v2] lib: add return status to database close and destroy

2014-01-19 Thread Jani Nikula
notmuch_database_close may fail in Xapian -flush() or -close(), so
report the status. Similarly for notmuch_database_destroy which calls
close.

This is required for notmuch insert to report error status if message
indexing failed.

---

v2 of
id:29b808bb6bf051fe21b6a72f12bb4ad1badfbf97.1385903109.git.j...@nikula.org
picked out of the series.
---
 lib/database.cc | 30 --
 lib/notmuch.h   | 15 +--
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index f395061..46a9a8f 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -767,14 +767,17 @@ notmuch_database_open (const char *path,
 return status;
 }
 
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *notmuch)
 {
+notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
 try {
if (notmuch-xapian_db != NULL 
notmuch-mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
(static_cast Xapian::WritableDatabase * 
(notmuch-xapian_db))-flush ();
 } catch (const Xapian::Error error) {
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
if (! notmuch-exception_reported) {
fprintf (stderr, Error: A Xapian exception occurred flushing 
database: %s\n,
 error.get_msg().c_str());
@@ -788,7 +791,9 @@ notmuch_database_close (notmuch_database_t *notmuch)
try {
notmuch-xapian_db-close();
} catch (const Xapian::Error error) {
-   /* do nothing */
+   /* don't clobber previous error status */
+   if (status == NOTMUCH_STATUS_SUCCESS)
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
 }
 
@@ -802,6 +807,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
 notmuch-value_range_processor = NULL;
 delete notmuch-date_range_processor;
 notmuch-date_range_processor = NULL;
+
+return status;
 }
 
 #if HAVE_XAPIAN_COMPACT
@@ -965,8 +972,15 @@ notmuch_database_compact (const char *path,
 }
 
   DONE:
-if (notmuch)
-   notmuch_database_destroy (notmuch);
+if (notmuch) {
+   notmuch_status_t ret2;
+
+   ret2 = notmuch_database_destroy (notmuch);
+
+   /* don't clobber previous error status */
+   if (ret == NOTMUCH_STATUS_SUCCESS  ret2 != NOTMUCH_STATUS_SUCCESS)
+   ret = ret2;
+}
 
 talloc_free (local);
 
@@ -984,11 +998,15 @@ notmuch_database_compact (unused (const char *path),
 }
 #endif
 
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *notmuch)
 {
-notmuch_database_close (notmuch);
+notmuch_status_t status;
+
+status = notmuch_database_close (notmuch);
 talloc_free (notmuch);
+
+return status;
 }
 
 const char *
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 02604c5..7ac7118 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -287,8 +287,16 @@ notmuch_database_open (const char *path,
  *
  * notmuch_database_close can be called multiple times.  Later calls
  * have no effect.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successfully closed the database.
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the
+ * database has been closed but there are no guarantees the
+ * changes to the database, if any, have been flushed to disk.
  */
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *database);
 
 /**
@@ -317,8 +325,11 @@ notmuch_database_compact (const char* path,
 /**
  * Destroy the notmuch database, closing it if necessary and freeing
  * all associated resources.
+ *
+ * Return value as in notmuch_database_close if the database was open;
+ * notmuch_database_destroy itself has no failure modes.
  */
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *database);
 
 /**
-- 
1.8.5.2

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


[PATCH 1/7] cli: extract single message addition in notmuch new to clarify code

2014-01-19 Thread Jani Nikula
The add_files() function has grown huge, chop it up a bit. No
functional changes.
---
 notmuch-new.c | 109 +-
 1 file changed, 55 insertions(+), 54 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 6a8b1b2..1dd8fc9 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -240,6 +240,60 @@ _entry_in_ignore_list (const char *entry, 
add_files_state_t *state)
 return FALSE;
 }
 
+/* Add a single file to the database. */
+static notmuch_status_t
+add_file (notmuch_database_t *notmuch, const char *filename,
+ add_files_state_t *state)
+{
+notmuch_message_t *message = NULL;
+const char **tag;
+notmuch_status_t status;
+
+status = notmuch_database_begin_atomic (notmuch);
+if (status)
+   goto DONE;
+
+status = notmuch_database_add_message (notmuch, filename, message);
+switch (status) {
+/* Success. */
+case NOTMUCH_STATUS_SUCCESS:
+   state-added_messages++;
+   notmuch_message_freeze (message);
+   for (tag = state-new_tags; *tag != NULL; tag++)
+   notmuch_message_add_tag (message, *tag);
+   if (state-synchronize_flags)
+   notmuch_message_maildir_flags_to_tags (message);
+   notmuch_message_thaw (message);
+   break;
+/* Non-fatal issues (go on to next file). */
+case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
+   if (state-synchronize_flags)
+   notmuch_message_maildir_flags_to_tags (message);
+   break;
+case NOTMUCH_STATUS_FILE_NOT_EMAIL:
+   fprintf (stderr, Note: Ignoring non-mail file: %s\n, filename);
+   break;
+/* Fatal issues. Don't process anymore. */
+case NOTMUCH_STATUS_READ_ONLY_DATABASE:
+case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
+case NOTMUCH_STATUS_OUT_OF_MEMORY:
+   fprintf (stderr, Error: %s. Halting processing.\n,
+notmuch_status_to_string (status));
+   goto DONE;
+default:
+   INTERNAL_ERROR (add_message returned unexpected value: %d, status);
+   goto DONE;
+}
+
+status = notmuch_database_end_atomic (notmuch);
+
+  DONE:
+if (message)
+   notmuch_message_destroy (message);
+
+return status;
+}
+
 /* Examine 'path' recursively as follows:
  *
  *   o Ask the filesystem for the mtime of 'path' (fs_mtime)
@@ -291,7 +345,6 @@ add_files (notmuch_database_t *notmuch,
 char *next = NULL;
 time_t fs_mtime, db_mtime;
 notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
-notmuch_message_t *message = NULL;
 struct dirent **fs_entries = NULL;
 int i, num_fs_entries = 0, entry_type;
 notmuch_directory_t *directory;
@@ -300,7 +353,6 @@ add_files (notmuch_database_t *notmuch,
 time_t stat_time;
 struct stat st;
 notmuch_bool_t is_maildir;
-const char **tag;
 
 if (stat (path, st)) {
fprintf (stderr, Error reading directory %s: %s\n,
@@ -527,63 +579,12 @@ add_files (notmuch_database_t *notmuch,
fflush (stdout);
}
 
-   status = notmuch_database_begin_atomic (notmuch);
+   status = add_file (notmuch, next, state);
if (status) {
ret = status;
goto DONE;
}
 
-   status = notmuch_database_add_message (notmuch, next, message);
-   switch (status) {
-   /* success */
-   case NOTMUCH_STATUS_SUCCESS:
-   state-added_messages++;
-   notmuch_message_freeze (message);
-   for (tag=state-new_tags; *tag != NULL; tag++)
-   notmuch_message_add_tag (message, *tag);
-   if (state-synchronize_flags == TRUE)
-   notmuch_message_maildir_flags_to_tags (message);
-   notmuch_message_thaw (message);
-   break;
-   /* Non-fatal issues (go on to next file) */
-   case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-   if (state-synchronize_flags == TRUE)
-   notmuch_message_maildir_flags_to_tags (message);
-   break;
-   case NOTMUCH_STATUS_FILE_NOT_EMAIL:
-   fprintf (stderr, Note: Ignoring non-mail file: %s\n,
-next);
-   break;
-   /* Fatal issues. Don't process anymore. */
-   case NOTMUCH_STATUS_READ_ONLY_DATABASE:
-   case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
-   case NOTMUCH_STATUS_OUT_OF_MEMORY:
-   fprintf (stderr, Error: %s. Halting processing.\n,
-notmuch_status_to_string (status));
-   ret = status;
-   goto DONE;
-   default:
-   case NOTMUCH_STATUS_FILE_ERROR:
-   case NOTMUCH_STATUS_NULL_POINTER:
-   case NOTMUCH_STATUS_TAG_TOO_LONG:
-   case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
-   case NOTMUCH_STATUS_UNBALANCED_ATOMIC:
-   case NOTMUCH_STATUS_LAST_STATUS:
-   INTERNAL_ERROR (add_message returned unexpected value: %d,  
status);
-   goto DONE;
-   }
-
-   status = notmuch_database_end_atomic (notmuch);
-   if (status) {
-   ret = status;
-   goto DONE;
-

[PATCH 2/7] cli: only check the ignore list if needed

2014-01-19 Thread Jani Nikula
Premature optimization is the root of all evil, but this is simple
enough.
---
 notmuch-new.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 1dd8fc9..7f3b3b0 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -728,7 +728,7 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
strcmp (entry-d_name, .notmuch) == 0 ||
_entry_in_ignore_list (entry-d_name, state))
{
-   if (_entry_in_ignore_list (entry-d_name, state)  state-debug)
+   if (state-debug  _entry_in_ignore_list (entry-d_name, state))
printf ((D) count_files: explicitly ignoring %s/%s\n,
path,
entry-d_name);
-- 
1.8.5.2

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


[PATCH 3/7] cli: use dirent_type in count_files too

2014-01-19 Thread Jani Nikula
Avoid an extra stat per file, if possible, also when counting the
files for initial indexing.
---
 notmuch-new.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 7f3b3b0..e6ca841 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -702,9 +702,9 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
 {
 struct dirent *entry = NULL;
 char *next;
-struct stat st;
 struct dirent **fs_entries = NULL;
 int num_fs_entries = scandir (path, fs_entries, 0, dirent_sort_inode);
+int entry_type;
 int i = 0;
 
 if (num_fs_entries == -1) {
@@ -742,15 +742,14 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
continue;
}
 
-   stat (next, st);
-
-   if (S_ISREG (st.st_mode)) {
+   entry_type = dirent_type (path, entry);
+   if (entry_type == S_IFREG) {
*count = *count + 1;
if (*count % 1000 == 0) {
printf (Found %d files so far.\r, *count);
fflush (stdout);
}
-   } else if (S_ISDIR (st.st_mode)) {
+   } else if (entry_type == S_IFDIR) {
count_files (next, count, state);
}
 
-- 
1.8.5.2

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


[PATCH 0/7] cli: notmuch new improvements

2014-01-19 Thread Jani Nikula
Here's an assortment of notmuch new fixes, non-functional cleanups, and
the oft-requested --quiet option.

These should be pretty straightforward to review.

BR,
Jani.


Jani Nikula (7):
  cli: extract single message addition in notmuch new to clarify code
  cli: only check the ignore list if needed
  cli: use dirent_type in count_files too
  cli: for loop is more customary
  cli: abstract notmuch new result printing
  cli: add --quiet option to notmuch new
  man: document notmuch new --quiet option

 man/man1/notmuch-new.1 |   5 +
 notmuch-new.c  | 253 ++---
 2 files changed, 137 insertions(+), 121 deletions(-)

-- 
1.8.5.2

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


[PATCH 4/7] cli: for loop is more customary

2014-01-19 Thread Jani Nikula
With the happy day stop condition within the while, it was
confusing. Switch to the paradigm for loop. No functional changes.
---
 notmuch-new.c | 10 +++---
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index e6ca841..f6d9c3a 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -704,8 +704,7 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
 char *next;
 struct dirent **fs_entries = NULL;
 int num_fs_entries = scandir (path, fs_entries, 0, dirent_sort_inode);
-int entry_type;
-int i = 0;
+int entry_type, i;
 
 if (num_fs_entries == -1) {
fprintf (stderr, Warning: failed to open directory %s: %s\n,
@@ -713,11 +712,8 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
goto DONE;
 }
 
-while (!interrupted) {
-if (i == num_fs_entries)
-   break;
-
-entry = fs_entries[i++];
+for (i = 0; i  num_fs_entries  ! interrupted; i++) {
+entry = fs_entries[i];
 
/* Ignore special directories to avoid infinite recursion.
 * Also ignore the .notmuch directory and files/directories
-- 
1.8.5.2

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


[PATCH 5/7] cli: abstract notmuch new result printing

2014-01-19 Thread Jani Nikula
The notmuch_new_command() function has grown huge, chop it up a
bit. This should also be helpful when adding a --quiet option to
notmuch new. No functional changes.
---
 notmuch-new.c | 80 +--
 1 file changed, 39 insertions(+), 41 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index f6d9c3a..c443181 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -864,13 +864,49 @@ _remove_directory (void *ctx,
 return status;
 }
 
+static void
+print_results (const add_files_state_t *state)
+{
+double elapsed;
+struct timeval tv_now;
+
+gettimeofday (tv_now, NULL);
+elapsed = notmuch_time_elapsed (state-tv_start, tv_now);
+
+if (state-processed_files) {
+   printf (Processed %d %s in , state-processed_files,
+   state-processed_files == 1 ? file : total files);
+   notmuch_time_print_formatted_seconds (elapsed);
+   if (elapsed  1)
+   printf ( (%d files/sec.).\033[K\n,
+   (int) (state-processed_files / elapsed));
+   else
+   printf (.\033[K\n);
+}
+
+if (state-added_messages)
+   printf (Added %d new %s to the database., state-added_messages,
+   state-added_messages == 1 ? message : messages);
+else
+   printf (No new mail.);
+
+if (state-removed_messages)
+   printf ( Removed %d %s., state-removed_messages,
+   state-removed_messages == 1 ? message : messages);
+
+if (state-renamed_messages)
+   printf ( Detected %d file %s., state-renamed_messages,
+   state-renamed_messages == 1 ? rename : renames);
+
+printf (\n);
+}
+
 int
 notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
 {
 notmuch_database_t *notmuch;
 add_files_state_t add_files_state;
-double elapsed;
-struct timeval tv_now, tv_start;
+struct timeval tv_start;
 int ret = 0;
 struct stat st;
 const char *db_path;
@@ -1017,45 +1053,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
 if (timer_is_active)
stop_progress_printing_timer ();
 
-gettimeofday (tv_now, NULL);
-elapsed = notmuch_time_elapsed (add_files_state.tv_start,
-   tv_now);
-
-if (add_files_state.processed_files) {
-   printf (Processed %d %s in , add_files_state.processed_files,
-   add_files_state.processed_files == 1 ?
-   file : total files);
-   notmuch_time_print_formatted_seconds (elapsed);
-   if (elapsed  1) {
-   printf ( (%d files/sec.).\033[K\n,
-   (int) (add_files_state.processed_files / elapsed));
-   } else {
-   printf (.\033[K\n);
-   }
-}
-
-if (add_files_state.added_messages) {
-   printf (Added %d new %s to the database.,
-   add_files_state.added_messages,
-   add_files_state.added_messages == 1 ?
-   message : messages);
-} else {
-   printf (No new mail.);
-}
-
-if (add_files_state.removed_messages) {
-   printf ( Removed %d %s.,
-   add_files_state.removed_messages,
-   add_files_state.removed_messages == 1 ? message : messages);
-}
-
-if (add_files_state.renamed_messages) {
-   printf ( Detected %d file %s.,
-   add_files_state.renamed_messages,
-   add_files_state.renamed_messages == 1 ? rename : renames);
-}
-
-printf (\n);
+print_results (add_files_state);
 
 if (ret)
fprintf (stderr, Note: A fatal error was encountered: %s\n,
-- 
1.8.5.2

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


[PATCH 6/7] cli: add --quiet option to notmuch new

2014-01-19 Thread Jani Nikula
Tie it to --verbose (resulting in verbosity levels of quiet, normal,
and verbose) but leave --debug orthogonal. Do some drive-by cleaning
while at it.
---
 notmuch-new.c | 47 ---
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index c443181..cd74489 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -34,9 +34,15 @@ typedef struct _filename_list {
 _filename_node_t **tail;
 } _filename_list_t;
 
+enum verbosity {
+VERBOSITY_QUIET,
+VERBOSITY_NORMAL,
+VERBOSITY_VERBOSE,
+};
+
 typedef struct {
 int output_is_a_tty;
-notmuch_bool_t verbose;
+enum verbosity verbosity;
 notmuch_bool_t debug;
 const char **new_tags;
 size_t new_tags_length;
@@ -566,13 +572,11 @@ add_files (notmuch_database_t *notmuch,
 
state-processed_files++;
 
-   if (state-verbose) {
+   if (state-verbosity = VERBOSITY_VERBOSE) {
if (state-output_is_a_tty)
printf(\r\033[K);
 
-   printf (%i/%i: %s,
-   state-processed_files,
-   state-total_files,
+   printf (%i/%i: %s, state-processed_files, state-total_files,
next);
 
putchar((state-output_is_a_tty) ? '\r' : '\n');
@@ -741,7 +745,7 @@ count_files (const char *path, int *count, 
add_files_state_t *state)
entry_type = dirent_type (path, entry);
if (entry_type == S_IFREG) {
*count = *count + 1;
-   if (*count % 1000 == 0) {
+   if (*count % 1000 == 0  state-verbosity = VERBOSITY_NORMAL) {
printf (Found %d files so far.\r, *count);
fflush (stdout);
}
@@ -917,13 +921,15 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
 int i;
 notmuch_bool_t timer_is_active = FALSE;
 notmuch_bool_t no_hooks = FALSE;
+notmuch_bool_t quiet = FALSE, verbose = FALSE;
 
-add_files_state.verbose = FALSE;
+add_files_state.verbosity = VERBOSITY_NORMAL;
 add_files_state.debug = FALSE;
 add_files_state.output_is_a_tty = isatty (fileno (stdout));
 
 notmuch_opt_desc_t options[] = {
-   { NOTMUCH_OPT_BOOLEAN,  add_files_state.verbose, verbose, 'v', 0 },
+   { NOTMUCH_OPT_BOOLEAN,  quiet, quiet, 'q', 0 },
+   { NOTMUCH_OPT_BOOLEAN,  verbose, verbose, 'v', 0 },
{ NOTMUCH_OPT_BOOLEAN,  add_files_state.debug, debug, 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN,  no_hooks, no-hooks, 'n', 0 },
{ 0, 0, 0, 0, 0 }
@@ -933,6 +939,12 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
 if (opt_index  0)
return EXIT_FAILURE;
 
+/* quiet trumps verbose */
+if (quiet)
+   add_files_state.verbosity = VERBOSITY_QUIET;
+else if (verbose)
+   add_files_state.verbosity = VERBOSITY_VERBOSE;
+
 add_files_state.new_tags = notmuch_config_get_new_tags (config, 
add_files_state.new_tags_length);
 add_files_state.new_ignore = notmuch_config_get_new_ignore (config, 
add_files_state.new_ignore_length);
 add_files_state.synchronize_flags = 
notmuch_config_get_maildir_synchronize_flags (config);
@@ -954,7 +966,8 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
if (interrupted)
return EXIT_FAILURE;
 
-   printf (Found %d total files (that's not much mail).\n, count);
+   if (add_files_state.verbosity = VERBOSITY_NORMAL)
+   printf (Found %d total files (that's not much mail).\n, count);
if (notmuch_database_create (db_path, notmuch))
return EXIT_FAILURE;
add_files_state.total_files = count;
@@ -964,11 +977,14 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
return EXIT_FAILURE;
 
if (notmuch_database_needs_upgrade (notmuch)) {
-   printf (Welcome to a new version of notmuch! Your database will 
now be upgraded.\n);
+   if (add_files_state.verbosity = VERBOSITY_NORMAL)
+   printf (Welcome to a new version of notmuch! Your database 
will now be upgraded.\n);
gettimeofday (add_files_state.tv_start, NULL);
-   notmuch_database_upgrade (notmuch, upgrade_print_progress,
+   notmuch_database_upgrade (notmuch,
+ add_files_state.verbosity = 
VERBOSITY_NORMAL ? upgrade_print_progress : NULL,
  add_files_state);
-   printf (Your notmuch database has now been upgraded to database 
format version %u.\n,
+   if (add_files_state.verbosity = VERBOSITY_NORMAL)
+   printf (Your notmuch database has now been upgraded to 
database format version %u.\n,
notmuch_database_get_version (notmuch));
}
 
@@ -999,8 +1015,8 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
 add_files_state.removed_directories = _filename_list_create (config);
 

[PATCH 7/7] man: document notmuch new --quiet option

2014-01-19 Thread Jani Nikula
---
 man/man1/notmuch-new.1 | 5 +
 1 file changed, 5 insertions(+)

diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1
index 5725b7d..7e71926 100644
--- a/man/man1/notmuch-new.1
+++ b/man/man1/notmuch-new.1
@@ -60,6 +60,11 @@ include
 
 Prevents hooks from being run.
 .RE
+.RS 4
+.TP 4
+.BR \-\-quiet
+Do not print progress or results.
+.RE
 .RE
 .SH SEE ALSO
 
-- 
1.8.5.2

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


Re: [PATCH 6/7] cli: add --quiet option to notmuch new

2014-01-24 Thread Jani Nikula
On Fri, 24 Jan 2014, Mark Walters markwalters1...@gmail.com wrote:
 I am not sure I like doing the database upgrade with no comment to the
 user at all.

I think --quiet should mean we don't write to stdout at all. So the
question becomes, is the database upgrade worth warning about in stderr?

 In fact I am not sure I like doing the upgrade without being
 specifically told to (e.g. it does not give the user a clear chance to
 backup the database first)

 What would people think about having a --upgrade-database option to
 notmuch new? 

We discussed this at length on IRC some time ago. I think we concluded
we should continue doing it automatically, but I'll post a summary when
I have the time.

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


Re: [PATCH 2/3] lib: make notmuch_threads_valid return FALSE when passed NULL

2014-01-24 Thread Jani Nikula
On Thu, 23 Jan 2014, David Bremner da...@tethera.net wrote:
 Without this patch, the example code in the header docs crashes for certain
 invalid queries (see id:871u00oimv@approx.mit.edu)
 ---
  lib/notmuch.h | 2 ++
  lib/query.cc  | 3 +++
  2 files changed, 5 insertions(+)

 diff --git a/lib/notmuch.h b/lib/notmuch.h
 index 02604c5..68896ae 100644
 --- a/lib/notmuch.h
 +++ b/lib/notmuch.h
 @@ -802,6 +802,8 @@ notmuch_query_destroy (notmuch_query_t *query);
   * valid object. Whereas when this function returns FALSE,
   * notmuch_threads_get will return NULL.
   *
 + * If passed a NULL pointer, this function returns FALSE
 + *
   * See the documentation of notmuch_query_search_threads for example
   * code showing how to iterate over a notmuch_threads_t object.
   */
 diff --git a/lib/query.cc b/lib/query.cc
 index ec60e2e..60ff8bd 100644
 --- a/lib/query.cc
 +++ b/lib/query.cc
 @@ -462,6 +462,9 @@ notmuch_threads_valid (notmuch_threads_t *threads)
  {
  unsigned int doc_id;
  
 +if (! threads)
 + return FALSE;
 +

LGTM, and this is in line with notmuch_messages_valid().

BR,
Jani.

  while (threads-doc_id_pos  threads-doc_ids-len) {
   doc_id = g_array_index (threads-doc_ids, unsigned int,
   threads-doc_id_pos);
 -- 
 1.8.5.2

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


<    4   5   6   7   8   9   10   11   12   13   >