[PATCH 1/4] lib: create field processors from prefix table

2017-02-26 Thread David Bremner
This is a bit more code than hardcoding the two existing field
processors, but it should make it easy to add more.
---
 lib/database-private.h |  3 ++-
 lib/database.cc| 62 +++---
 2 files changed, 46 insertions(+), 19 deletions(-)

diff --git a/lib/database-private.h b/lib/database-private.h
index 06882439..ab3d9691 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -153,7 +153,8 @@ operator&=(_notmuch_features &a, _notmuch_features b)
 typedef enum notmuch_field_flags {
 NOTMUCH_FIELD_NO_FLAGS = 0,
 NOTMUCH_FIELD_EXTERNAL = 1 << 0,
-NOTMUCH_FIELD_PROBABILISTIC = 1 << 1
+NOTMUCH_FIELD_PROBABILISTIC = 1 << 1,
+NOTMUCH_FIELD_PROCESSOR = 1 << 2,
 } notmuch_field_flag_t;
 
 /*
diff --git a/lib/database.cc b/lib/database.cc
index ba440d4d..fa4c3116 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -270,6 +270,12 @@ prefix_t prefix_table[] = {
  * discussion.
  */
 { "folder","XFOLDER:", NOTMUCH_FIELD_EXTERNAL 
},
+#if HAVE_XAPIAN_FIELD_PROCESSOR
+{ "date",  NULL,   NOTMUCH_FIELD_EXTERNAL |
+   NOTMUCH_FIELD_PROCESSOR },
+{ "query", NULL,   NOTMUCH_FIELD_EXTERNAL |
+   NOTMUCH_FIELD_PROCESSOR },
+#endif
 { "from",  "XFROM",NOTMUCH_FIELD_EXTERNAL |
NOTMUCH_FIELD_PROBABILISTIC },
 { "to","XTO",  NOTMUCH_FIELD_EXTERNAL |
@@ -282,6 +288,43 @@ prefix_t prefix_table[] = {
NOTMUCH_FIELD_PROBABILISTIC },
 };
 
+static void
+_setup_query_field_default (const prefix_t *prefix, notmuch_database_t 
*notmuch)
+{
+if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
+   notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
+else
+   notmuch->query_parser->add_boolean_prefix (prefix->name, 
prefix->prefix);
+}
+
+#if HAVE_XAPIAN_FIELD_PROCESSOR
+static void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
+   Xapian::FieldProcessor *fp;
+
+   if (STRNCMP_LITERAL (prefix->name, "date") == 0)
+   fp = (new DateFieldProcessor())->release ();
+   else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
+   fp = (new QueryFieldProcessor (*notmuch->query_parser, 
notmuch))->release ();
+   else
+   INTERNAL_ERROR("unsupported field processor prefix: %s\n", 
prefix->name);
+
+   /* we treat all field-processor fields as boolean in order to get the 
raw input */
+   notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
+} else {
+   _setup_query_field_default (prefix, notmuch);
+}
+}
+#else
+static inline void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+_setup_query_field_default (prefix, notmuch);
+}
+#endif
+
 const char *
 _find_prefix (const char *name)
 {
@@ -1028,18 +1071,6 @@ notmuch_database_open_verbose (const char *path,
notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor 
(NOTMUCH_VALUE_TIMESTAMP);
notmuch->date_range_processor = new ParseTimeValueRangeProcessor 
(NOTMUCH_VALUE_TIMESTAMP);
-#if HAVE_XAPIAN_FIELD_PROCESSOR
-   /* This currently relies on the query parser to pass anything
-* with a .. to the range processor */
-   {
-   Xapian::FieldProcessor * date_fp = new DateFieldProcessor();
-   Xapian::FieldProcessor * query_fp =
-   new QueryFieldProcessor (*notmuch->query_parser, notmuch);
-
-   notmuch->query_parser->add_boolean_prefix("date", date_fp->release 
());
-   notmuch->query_parser->add_boolean_prefix("query", 
query_fp->release ());
-   }
-#endif
notmuch->last_mod_range_processor = new 
Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
 
notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
@@ -1053,12 +1084,7 @@ notmuch_database_open_verbose (const char *path,
for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
const prefix_t *prefix = &prefix_table[i];
if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
-   if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC) {
-   notmuch->query_parser->add_prefix (prefix->name, 
prefix->prefix);
-   } else {
-   notmuch->query_parser->add_boolean_prefix (prefix->name,
-  prefix->prefix);
-   }
+   _setup_query_field (prefix, notmuch);
}
}
 } catch (const Xapian::Error &error) {
-- 
2.11.0

___
notmuch mailin

v6 of regexp searching

2017-02-26 Thread David Bremner
This obsoletes the unmerged patches from

 id:20170217030754.32069-1-da...@tethera.net

The first two I plan to merge for 0.24 (barring corrections or objections)

[PATCH 1/4] lib: create field processors from prefix table
[PATCH 2/4] lib: regexp matching in 'subject' and 'from'

The second two could go in for 0.24, or wait.

[PATCH 3/4] lib: add mid: as a synonym for id:
[PATCH 4/4] lib: Add regexp searching for mid: prefix

The big change is a fix for the problem Jani noticed in

id:87innwhhid@nikula.org

in the case where field processors are not present.

Interdiff follows.

diff --git a/lib/database-private.h b/lib/database-private.h
index 9fd4102c..ab3d9691 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -154,7 +154,7 @@ typedef enum notmuch_field_flags {
 NOTMUCH_FIELD_NO_FLAGS = 0,
 NOTMUCH_FIELD_EXTERNAL = 1 << 0,
 NOTMUCH_FIELD_PROBABILISTIC = 1 << 1,
-NOTMUCH_FIELD_PROCESSOR = 1 << 2
+NOTMUCH_FIELD_PROCESSOR = 1 << 2,
 } notmuch_field_flag_t;
 
 /*
diff --git a/lib/database.cc b/lib/database.cc
index 6e5ea106..09337602 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -293,19 +293,42 @@ prefix_t prefix_table[] = {
NOTMUCH_FIELD_PROCESSOR},
 };
 
+static void
+_setup_query_field_default (const prefix_t *prefix, notmuch_database_t 
*notmuch)
+{
+if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
+   notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
+else
+   notmuch->query_parser->add_boolean_prefix (prefix->name, 
prefix->prefix);
+}
+
 #if HAVE_XAPIAN_FIELD_PROCESSOR
-static Xapian::FieldProcessor *
-_make_field_processor (const char *name, notmuch_field_flag_t options,
-  notmuch_database_t *notmuch) {
-if (STRNCMP_LITERAL (name, "date") == 0)
-   return (new DateFieldProcessor())->release ();
-else if (STRNCMP_LITERAL(name, "query") == 0)
-   return (new QueryFieldProcessor (*notmuch->query_parser, 
notmuch))->release ();
+static void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
+   Xapian::FieldProcessor *fp;
+
+   if (STRNCMP_LITERAL (prefix->name, "date") == 0)
+   fp = (new DateFieldProcessor())->release ();
+   else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
+   fp = (new QueryFieldProcessor (*notmuch->query_parser, 
notmuch))->release ();
else
-   return (new RegexpFieldProcessor (name, options, 
*notmuch->query_parser, notmuch))->release ();
+   fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
+   *notmuch->query_parser, 
notmuch))->release ();
+
+   /* we treat all field-processor fields as boolean in order to get the 
raw input */
+   notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
+} else {
+   _setup_query_field_default (prefix, notmuch);
+}
 }
 #else
-#define _make_field_processor(name, options, db) NULL
+static inline void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+_setup_query_field_default (prefix, notmuch);
+}
 #endif
 
 const char *
@@ -1067,22 +1090,7 @@ notmuch_database_open_verbose (const char *path,
for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
const prefix_t *prefix = &prefix_table[i];
if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
-   /* we treat all field-processor fields as boolean in order
-  to get the raw input */
-   if (HAVE_XAPIAN_FIELD_PROCESSOR &&
-   (prefix->flags & NOTMUCH_FIELD_PROCESSOR)) {
-   Xapian::FieldProcessor *fp = _make_field_processor 
(prefix->name,
-   
prefix->flags,
-   
notmuch);
-
-   notmuch->query_parser->add_boolean_prefix (prefix->name, 
fp);
-   } else if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC) {
-   notmuch->query_parser->add_prefix (prefix->name,
-  prefix->prefix);
-   } else {
-   notmuch->query_parser->add_boolean_prefix (prefix->name,
-  prefix->prefix);
-   }
+   _setup_query_field (prefix, notmuch);
}
}
 } catch (const Xapian::Error &error) {
diff --git a/lib/regexp-fields.h b/lib/regexp-fields.h
index 8a0e72e1..72d12b37 100644
--- a/lib/regexp-fields.h
+++ b/lib/regexp-fields.h
@@ -63,7 +63,7 @@ class RegexpFieldProcessor : public Xapian::FieldProcessor {
  protected:
 Xapian::valueno slot;
 std::string term_prefix;
-int options;
+notmuch_field_flag_t options;
 Xapian::QueryParser &parser;
 notmuch_

[PATCH 4/4] lib: Add regexp searching for mid: prefix

2017-02-26 Thread David Bremner
The bulk of the change is passing in the field options to the regexp
field processor, so that we can properly handle the
fallback (non-regexp case).
---
 lib/database.cc   |  6 --
 lib/regexp-fields.cc  | 28 +---
 lib/regexp-fields.h   |  4 +++-
 test/T650-regexp-query.sh | 16 
 4 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index b7fc53ee..09337602 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -262,7 +262,8 @@ prefix_t prefix_table[] = {
 { "tag",   "K",NOTMUCH_FIELD_EXTERNAL },
 { "is","K",NOTMUCH_FIELD_EXTERNAL },
 { "id","Q",NOTMUCH_FIELD_EXTERNAL },
-{ "mid",   "Q",NOTMUCH_FIELD_EXTERNAL },
+{ "mid",   "Q",NOTMUCH_FIELD_EXTERNAL |
+   NOTMUCH_FIELD_PROCESSOR },
 { "path",  "P",NOTMUCH_FIELD_EXTERNAL },
 { "property",  "XPROPERTY",NOTMUCH_FIELD_EXTERNAL },
 /*
@@ -313,7 +314,8 @@ _setup_query_field (const prefix_t *prefix, 
notmuch_database_t *notmuch)
else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
fp = (new QueryFieldProcessor (*notmuch->query_parser, 
notmuch))->release ();
else
-   fp = (new RegexpFieldProcessor (prefix->name, 
*notmuch->query_parser, notmuch))->release ();
+   fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
+   *notmuch->query_parser, 
notmuch))->release ();
 
/* we treat all field-processor fields as boolean in order to get the 
raw input */
notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
diff --git a/lib/regexp-fields.cc b/lib/regexp-fields.cc
index b2b39504..a32b965e 100644
--- a/lib/regexp-fields.cc
+++ b/lib/regexp-fields.cc
@@ -114,13 +114,21 @@ static inline Xapian::valueno _find_slot (std::string 
prefix)
return NOTMUCH_VALUE_FROM;
 else if (prefix == "subject")
return NOTMUCH_VALUE_SUBJECT;
+else if (prefix == "mid")
+   return NOTMUCH_VALUE_MESSAGE_ID;
 else
throw Xapian::QueryParserError ("unsupported regexp field '" + prefix + 
"'");
 }
 
-RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix, 
Xapian::QueryParser &parser_, notmuch_database_t *notmuch_)
-   : slot (_find_slot (prefix)), term_prefix (_find_prefix (prefix.c_str 
())),
- parser (parser_), notmuch (notmuch_)
+RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix,
+   notmuch_field_flag_t options_,
+   Xapian::QueryParser &parser_,
+   notmuch_database_t *notmuch_)
+   : slot (_find_slot (prefix)),
+ term_prefix (_find_prefix (prefix.c_str ())),
+ options (options_),
+ parser (parser_),
+ notmuch (notmuch_)
 {
 };
 
@@ -135,10 +143,16 @@ RegexpFieldProcessor::operator() (const std::string & str)
throw Xapian::QueryParserError ("unmatch regex delimiter in '" + 
str + "'");
}
 } else {
-   /* TODO replace this with a nicer API level triggering of
-* phrase parsing, when possible */
-   std::string quoted='"' + str + '"';
-   return parser.parse_query (quoted, NOTMUCH_QUERY_PARSER_FLAGS, 
term_prefix);
+   if (options & NOTMUCH_FIELD_PROBABILISTIC) {
+   /* TODO replace this with a nicer API level triggering of
+* phrase parsing, when possible */
+   std::string quoted='"' + str + '"';
+   return parser.parse_query (quoted, NOTMUCH_QUERY_PARSER_FLAGS, 
term_prefix);
+   } else {
+   /* Boolean prefix */
+   std::string term = term_prefix + str;
+   return Xapian::Query (term);
+   }
 }
 }
 #endif
diff --git a/lib/regexp-fields.h b/lib/regexp-fields.h
index bac11999..72d12b37 100644
--- a/lib/regexp-fields.h
+++ b/lib/regexp-fields.h
@@ -63,11 +63,13 @@ class RegexpFieldProcessor : public Xapian::FieldProcessor {
  protected:
 Xapian::valueno slot;
 std::string term_prefix;
+notmuch_field_flag_t options;
 Xapian::QueryParser &parser;
 notmuch_database_t *notmuch;
 
  public:
-RegexpFieldProcessor (std::string prefix, Xapian::QueryParser &parser_, 
notmuch_database_t *notmuch_);
+RegexpFieldProcessor (std::string prefix, notmuch_field_flag_t options,
+ Xapian::QueryParser &parser_, notmuch_database_t 
*notmuch_);
 
 ~RegexpFieldProcessor () { };
 
diff --git a/test/T650-regexp-query.sh b/test/T650-regexp-query.sh
index a8039610..f0868a15 100755
--- a/test/T650-regexp-query.sh
+++ b/test/T650-regexp-query.sh
@@ -79,4 +79,20 @@ Query string was: from:/unbalanced[/
 EOF
 test_expect_equal_file EXPECTED OUTPUT

[PATCH 2/4] lib: regexp matching in 'subject' and 'from'

2017-02-26 Thread David Bremner
the idea is that you can run

% notmuch search subject://
% notmuch search from://

or

% notmuch search subject:"your usual phrase search"
% notmuch search from:"usual phrase search"

This feature is only available with recent Xapian, specifically
support for field processors is needed.

It should work with bindings, since it extends the query parser.

This is easy to extend for other value slots, but currently the only
value slots are date, message_id, from, subject, and last_mod. Date is
already searchable;  message_id is left for a followup commit.

This was originally written by Austin Clements, and ported to Xapian
field processors (from Austin's custom query parser) by yours truly.
---
 doc/man7/notmuch-search-terms.rst |  25 ++-
 lib/Makefile.local|   1 +
 lib/database.cc   |   9 ++-
 lib/regexp-fields.cc  | 144 ++
 lib/regexp-fields.h   |  77 
 test/T650-regexp-query.sh |  82 ++
 6 files changed, 332 insertions(+), 6 deletions(-)
 create mode 100644 lib/regexp-fields.cc
 create mode 100644 lib/regexp-fields.h
 create mode 100755 test/T650-regexp-query.sh

diff --git a/doc/man7/notmuch-search-terms.rst 
b/doc/man7/notmuch-search-terms.rst
index de93d733..47cab48d 100644
--- a/doc/man7/notmuch-search-terms.rst
+++ b/doc/man7/notmuch-search-terms.rst
@@ -34,10 +34,14 @@ indicate user-supplied values):
 
 -  from:
 
+-  from://
+
 -  to:
 
 -  subject:
 
+-  subject://
+
 -  attachment:
 
 -  mimetype:
@@ -71,6 +75,15 @@ subject of an email. Searching for a phrase in the subject 
is supported
 by including quotation marks around the phrase, immediately following
 **subject:**.
 
+If notmuch is built with **Xapian Field Processors** (see below) the
+**from:** and **subject** prefix can be also used to restrict the
+results to those whose from/subject value matches a regular expression
+(see **regex(7)**) delimited with //.
+
+::
+
+   notmuch search 'from:/bob@.*[.]example[.]com/'
+
 The **attachment:** prefix can be used to search for specific filenames
 (or extensions) of attachments to email messages.
 
@@ -220,13 +233,18 @@ Boolean and Probabilistic Prefixes
 --
 
 Xapian (and hence notmuch) prefixes are either **boolean**, supporting
-exact matches like "tag:inbox"  or **probabilistic**, supporting a more 
flexible **term** based searching. The prefixes currently supported by notmuch 
are as follows.
-
+exact matches like "tag:inbox" or **probabilistic**, supporting a more
+flexible **term** based searching. Certain **special** prefixes are
+processed by notmuch in a way not stricly fitting either of Xapian's
+built in styles. The prefixes currently supported by notmuch are as
+follows.
 
 Boolean
**tag:**, **id:**, **thread:**, **folder:**, **path:**, **property:**
 Probabilistic
-   **from:**, **to:**, **subject:**, **attachment:**, **mimetype:**
+  **to:**, **attachment:**, **mimetype:**
+Special
+   **from:**, **query:**, **subject:**
 
 Terms and phrases
 -
@@ -396,6 +414,7 @@ Currently the following features require field processor 
support:
 
 - non-range date queries, e.g. "date:today"
 - named queries e.g. "query:my_special_query"
+- regular expression searches, e.g. "subject:/^\\[SPAM\\]/"
 
 SEE ALSO
 
diff --git a/lib/Makefile.local b/lib/Makefile.local
index b77e5780..cd92fc79 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -52,6 +52,7 @@ libnotmuch_cxx_srcs = \
$(dir)/query.cc \
$(dir)/query-fp.cc  \
$(dir)/config.cc\
+   $(dir)/regexp-fields.cc \
$(dir)/thread.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/database.cc b/lib/database.cc
index fa4c3116..573c9fe0 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -21,6 +21,7 @@
 #include "database-private.h"
 #include "parse-time-vrp.h"
 #include "query-fp.h"
+#include "regexp-fields.h"
 #include "string-util.h"
 
 #include 
@@ -277,7 +278,8 @@ prefix_t prefix_table[] = {
NOTMUCH_FIELD_PROCESSOR },
 #endif
 { "from",  "XFROM",NOTMUCH_FIELD_EXTERNAL |
-   NOTMUCH_FIELD_PROBABILISTIC },
+   NOTMUCH_FIELD_PROBABILISTIC |
+   NOTMUCH_FIELD_PROCESSOR },
 { "to","XTO",  NOTMUCH_FIELD_EXTERNAL |
NOTMUCH_FIELD_PROBABILISTIC },
 { "attachment","XATTACHMENT",  NOTMUCH_FIELD_EXTERNAL |
@@ -285,7 +287,8 @@ prefix_t prefix_table[] = {
 { "mimetype",  "XMIMETYPE",NOTMUCH_FIELD_EXTERNAL |
NOTMUCH_FIELD_PROBABILISTIC },
 { "subject",   "XS

[PATCH 3/4] lib: add mid: as a synonym for id:

2017-02-26 Thread David Bremner
mid: is the url scheme suggested by URL 2392. We also plan to
introduce more flexible searches for mid: than are possible with
id: (in order not to break assumptions about the special behaviour of
id:, e.g. identifying at most one message).
---
 lib/database.cc | 1 +
 test/T080-search.sh | 6 ++
 2 files changed, 7 insertions(+)

diff --git a/lib/database.cc b/lib/database.cc
index 573c9fe0..b7fc53ee 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -262,6 +262,7 @@ prefix_t prefix_table[] = {
 { "tag",   "K",NOTMUCH_FIELD_EXTERNAL },
 { "is","K",NOTMUCH_FIELD_EXTERNAL },
 { "id","Q",NOTMUCH_FIELD_EXTERNAL },
+{ "mid",   "Q",NOTMUCH_FIELD_EXTERNAL },
 { "path",  "P",NOTMUCH_FIELD_EXTERNAL },
 { "property",  "XPROPERTY",NOTMUCH_FIELD_EXTERNAL },
 /*
diff --git a/test/T080-search.sh b/test/T080-search.sh
index 5e8b20ce..6149da93 100755
--- a/test/T080-search.sh
+++ b/test/T080-search.sh
@@ -34,6 +34,11 @@ add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 
2000 12:00:00 -"
 output=$(notmuch search id:${gen_msg_id} | notmuch_search_sanitize)
 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; 
search by id (inbox unread)"
 
+test_begin_subtest "Search by mid:"
+add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 
-"'
+output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; 
search by mid (inbox unread)"
+
 test_begin_subtest "Search by tag:"
 add_message '[subject]="search by tag"' '[date]="Sat, 01 Jan 2000 12:00:00 
-"'
 notmuch tag +searchbytag id:${gen_msg_id}
@@ -127,6 +132,7 @@ thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by 
to (inbox unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox 
unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
+thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by mid (inbox unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox 
searchbytag unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox 
unread)
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox 
unread)
-- 
2.11.0

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


[PATCH 2/6] lib: replace n_query_search_threads with status returning version

2017-02-26 Thread David Bremner
This function was deprecated in notmuch 0.21. We finally remove the
deprecated API, and rename the status returning version to the simpler
name. The status returning is kept as a deprecated alias.
---
 bindings/python/notmuch/query.py | 10 +-
 bindings/ruby/query.c|  2 +-
 lib/notmuch.h| 20 +---
 lib/query.cc | 17 +
 notmuch-search.c |  2 +-
 notmuch-show.c   |  2 +-
 6 files changed, 22 insertions(+), 31 deletions(-)

diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index a0f4f64b..3419f626 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -134,10 +134,10 @@ class Query(object):
 self._assert_query_is_initialized()
 self._exclude_tag(self._query, _str(tagname))
 
-"""notmuch_query_search_threads_st"""
-_search_threads_st = nmlib.notmuch_query_search_threads_st
-_search_threads_st.argtypes = [NotmuchQueryP, POINTER(NotmuchThreadsP)]
-_search_threads_st.restype = c_uint
+"""notmuch_query_search_threads"""
+_search_threads = nmlib.notmuch_query_search_threads
+_search_threads.argtypes = [NotmuchQueryP, POINTER(NotmuchThreadsP)]
+_search_threads.restype = c_uint
 
 def search_threads(self):
 """Execute a query for threads
@@ -155,7 +155,7 @@ class Query(object):
 """
 self._assert_query_is_initialized()
 threads_p = NotmuchThreadsP() # == NULL
-status = Query._search_threads_st(self._query, byref(threads_p))
+status = Query._search_threads(self._query, byref(threads_p))
 if status != 0:
 raise NotmuchError(status)
 
diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c
index ce66926c..4b3f1c4f 100644
--- a/bindings/ruby/query.c
+++ b/bindings/ruby/query.c
@@ -138,7 +138,7 @@ notmuch_rb_query_search_threads (VALUE self)
 
 Data_Get_Notmuch_Query (self, query);
 
-status = notmuch_query_search_threads_st (query, &threads);
+status = notmuch_query_search_threads (query, &threads);
 if (status)
notmuch_rb_status_raise (status);
 
diff --git a/lib/notmuch.h b/lib/notmuch.h
index af4efbc8..601b2e3e 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -855,24 +855,22 @@ notmuch_query_add_tag_exclude (notmuch_query_t *query, 
const char *tag);
  * notmuch_threads_destroy function, but there's no good reason
  * to call it if the query is about to be destroyed).
  *
- * @since libnotmuch 4.2 (notmuch 0.20)
+ * @since libnotmuch 5.0 (notmuch 0.25)
  */
 notmuch_status_t
-notmuch_query_search_threads_st (notmuch_query_t *query,
-notmuch_threads_t **out);
+notmuch_query_search_threads (notmuch_query_t *query,
+ notmuch_threads_t **out);
 
 /**
- * Like notmuch_query_search_threads_st, but without a status return.
- *
- * If a Xapian exception occurs this function will return NULL.
+ * Deprecated alias for notmuch_query_search_threads.
  *
- * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please
- * use notmuch_query_search_threads_st instead.
+ * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please
+ * use notmuch_query_search_threads instead.
  *
  */
-NOTMUCH_DEPRECATED(4,3)
-notmuch_threads_t *
-notmuch_query_search_threads (notmuch_query_t *query);
+NOTMUCH_DEPRECATED(5,0)
+notmuch_status_t
+notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t 
**out);
 
 /**
  * Execute a query for messages, returning a notmuch_messages_t object
diff --git a/lib/query.cc b/lib/query.cc
index 4ccd8104..d138f09b 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -432,22 +432,15 @@ _notmuch_threads_destructor (notmuch_threads_t *threads)
 return 0;
 }
 
-
-notmuch_threads_t *
-notmuch_query_search_threads (notmuch_query_t *query)
+notmuch_status_t
+notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t 
**out)
 {
-notmuch_status_t status;
-notmuch_threads_t *threads;
-status = notmuch_query_search_threads_st (query, &threads);
-if (status)
-   return NULL;
-else
-   return threads;
+return notmuch_query_search_threads(query, out);
 }
 
 notmuch_status_t
-notmuch_query_search_threads_st (notmuch_query_t *query,
-notmuch_threads_t **out)
+notmuch_query_search_threads (notmuch_query_t *query,
+ notmuch_threads_t **out)
 {
 notmuch_threads_t *threads;
 notmuch_messages_t *messages;
diff --git a/notmuch-search.c b/notmuch-search.c
index 8c65d5ad..c6899ffa 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -132,7 +132,7 @@ do_search_threads (search_context_t *ctx)
ctx->offset = 0;
 }
 
-status = notmuch_query_search_threads_st (ctx->query, &threads);
+status = notmuch_query_search_threads (ctx->query, &threads);
 if (print_status_query("notmuch search

[PATCH 4/6] fixup! lib: replace deprecated n_q_search_messages with status returning version

2017-02-26 Thread David Bremner
---
 bindings/python/notmuch/query.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index 9942a2bc..a91bb740 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -177,7 +177,7 @@ class Query(object):
 """
 self._assert_query_is_initialized()
 msgs_p = NotmuchMessagesP() # == NULL
-status = Query._search_messages_st(self._query, byref(msgs_p))
+status = Query._search_messages(self._query, byref(msgs_p))
 if status != 0:
 raise NotmuchError(status)
 
-- 
2.11.0

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


[PATCH 1/6] lib: bump SONAME to libnotmuch5

2017-02-26 Thread David Bremner
We plan a sequence of ABI breaking changes. Put the SONAME change in a
separate commit to make reordering easier.
---
 lib/notmuch.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index 16da8be9..af4efbc8 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -55,8 +55,8 @@ NOTMUCH_BEGIN_DECLS
  * The library version number.  This must agree with the soname
  * version in Makefile.local.
  */
-#define LIBNOTMUCH_MAJOR_VERSION   4
-#define LIBNOTMUCH_MINOR_VERSION   4
+#define LIBNOTMUCH_MAJOR_VERSION   5
+#define LIBNOTMUCH_MINOR_VERSION   0
 #define LIBNOTMUCH_MICRO_VERSION   0
 
 
-- 
2.11.0

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


[PATCH 5/6] lib: replace deprecated n_q_count_messages with status returning version

2017-02-26 Thread David Bremner
This function was deprecated in notmuch 0.21.  We re-use the name for
a status returning version, and deprecate the _st name. One or two
remaining uses of the (removed) non-status returning version fixed at
the same time
---
 bindings/python/notmuch/query.py |  2 +-
 bindings/ruby/query.c|  2 +-
 lib/database.cc  |  2 +-
 lib/message.cc   |  2 +-
 lib/notmuch.h| 17 -
 lib/query.cc | 12 
 notmuch-count.c  |  2 +-
 notmuch-reply.c  |  2 +-
 notmuch-search.c |  2 +-
 notmuch-show.c   |  2 +-
 test/T560-lib-error.sh   |  4 ++--
 11 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index a91bb740..10fb6dcc 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -185,7 +185,7 @@ class Query(object):
 raise NullPointerError
 return Messages(msgs_p, self)
 
-_count_messages = nmlib.notmuch_query_count_messages_st
+_count_messages = nmlib.notmuch_query_count_messages
 _count_messages.argtypes = [NotmuchQueryP, POINTER(c_uint)]
 _count_messages.restype = c_uint
 
diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c
index 2e36df6a..b6edaef3 100644
--- a/bindings/ruby/query.c
+++ b/bindings/ruby/query.c
@@ -180,7 +180,7 @@ notmuch_rb_query_count_messages (VALUE self)
 
 Data_Get_Notmuch_Query (self, query);
 
-status = notmuch_query_count_messages_st (query, &count);
+status = notmuch_query_count_messages (query, &count);
 if (status)
notmuch_rb_status_raise (status);
 
diff --git a/lib/database.cc b/lib/database.cc
index 13b9e647..4fc691ff 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1463,7 +1463,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
query = notmuch_query_create (notmuch, "");
unsigned msg_count;
 
-   status = notmuch_query_count_messages_st (query, &msg_count);
+   status = notmuch_query_count_messages (query, &msg_count);
if (status)
goto DONE;
 
diff --git a/lib/message.cc b/lib/message.cc
index 007f1171..29e54425 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -1123,7 +1123,7 @@ _notmuch_message_delete (notmuch_message_t *message)
 query = notmuch_query_create (notmuch, query_string);
 if (query == NULL)
return NOTMUCH_STATUS_OUT_OF_MEMORY;
-status = notmuch_query_count_messages_st (query, &count);
+status = notmuch_query_count_messages (query, &count);
 if (status) {
notmuch_query_destroy (query);
return status;
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 4b01e3ad..b79618f6 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -1008,22 +1008,21 @@ notmuch_threads_destroy (notmuch_threads_t *threads);
  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The
  *  value of *count is not defined.
  *
- * @since libnotmuch 4.3 (notmuch 0.21)
+ * @since libnotmuch 5 (notmuch 0.25)
  */
 notmuch_status_t
-notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count);
+notmuch_query_count_messages (notmuch_query_t *query, unsigned int *count);
 
 /**
- * like notmuch_query_count_messages_st, but without a status return.
+ * Deprecated alias for notmuch_query_count_messages
  *
- * May return 0 in the case of errors.
  *
- * @deprecated Deprecated since libnotmuch 4.3 (notmuch 0.21). Please
- * use notmuch_query_count_messages_st instead.
+ * @deprecated Deprecated since libnotmuch 5.0 (notmuch 0.25). Please
+ * use notmuch_query_count_messages instead.
  */
-NOTMUCH_DEPRECATED(4,3)
-unsigned int
-notmuch_query_count_messages (notmuch_query_t *query);
+NOTMUCH_DEPRECATED(5,0)
+notmuch_status_t
+notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count);
 
 /**
  * Return the number of threads matching a search.
diff --git a/lib/query.cc b/lib/query.cc
index 60d1db94..25b953c7 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -533,18 +533,14 @@ notmuch_threads_destroy (notmuch_threads_t *threads)
 talloc_free (threads);
 }
 
-unsigned int
-notmuch_query_count_messages (notmuch_query_t *query)
+notmuch_status_t
+notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
 {
-notmuch_status_t status;
-unsigned int count;
-
-status = notmuch_query_count_messages_st (query, &count);
-return status ? 0 : count;
+return notmuch_query_count_messages (query, count_out);
 }
 
 notmuch_status_t
-notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
+notmuch_query_count_messages (notmuch_query_t *query, unsigned *count_out)
 {
 return _notmuch_query_count_documents (query, "mail", count_out);
 }
diff --git a/notmuch-count.c b/notmuch-count.c
index d3457bbe..493be30f 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -92,7 +92,7 @@ pr

[PATCH 3/6] lib: replace deprecated n_q_search_messages with status returning version

2017-02-26 Thread David Bremner
This function was deprecated in notmuch 0.21.  We re-use the name for
a status returning version, and deprecate the _st name.
---
 bindings/python/notmuch/query.py |  6 +++---
 bindings/ruby/query.c|  2 +-
 lib/database.cc  |  2 +-
 lib/notmuch.h| 22 +++---
 lib/query.cc | 20 
 lib/thread.cc|  2 +-
 notmuch-count.c  |  2 +-
 notmuch-dump.c   |  2 +-
 notmuch-reply.c  |  2 +-
 notmuch-search.c |  4 ++--
 notmuch-show.c   |  2 +-
 notmuch-tag.c|  2 +-
 test/T560-lib-error.sh   |  2 +-
 test/T640-database-modified.sh   |  2 +-
 14 files changed, 34 insertions(+), 38 deletions(-)

diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index 3419f626..9942a2bc 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -164,9 +164,9 @@ class Query(object):
 return Threads(threads_p, self)
 
 """notmuch_query_search_messages_st"""
-_search_messages_st = nmlib.notmuch_query_search_messages_st
-_search_messages_st.argtypes = [NotmuchQueryP, POINTER(NotmuchMessagesP)]
-_search_messages_st.restype = c_uint
+_search_messages = nmlib.notmuch_query_search_messages
+_search_messages.argtypes = [NotmuchQueryP, POINTER(NotmuchMessagesP)]
+_search_messages.restype = c_uint
 
 def search_messages(self):
 """Filter messages according to the query and return
diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c
index 4b3f1c4f..2e36df6a 100644
--- a/bindings/ruby/query.c
+++ b/bindings/ruby/query.c
@@ -159,7 +159,7 @@ notmuch_rb_query_search_messages (VALUE self)
 
 Data_Get_Notmuch_Query (self, query);
 
-status = notmuch_query_search_messages_st (query, &messages);
+status = notmuch_query_search_messages (query, &messages);
 if (status)
notmuch_rb_status_raise (status);
 
diff --git a/lib/database.cc b/lib/database.cc
index ba440d4d..13b9e647 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1501,7 +1501,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
 
query = notmuch_query_create (notmuch, "");
 
-   status = notmuch_query_search_messages_st (query, &messages);
+   status = notmuch_query_search_messages (query, &messages);
if (status)
goto DONE;
for (;
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 601b2e3e..4b01e3ad 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -911,23 +911,23 @@ notmuch_query_search_threads_st (notmuch_query_t *query, 
notmuch_threads_t **out
  *
  * If a Xapian exception occurs this function will return NULL.
  *
- * @since libnotmuch 4.2 (notmuch 0.20)
+ * @since libnotmuch 5 (notmuch 0.25)
  */
 notmuch_status_t
-notmuch_query_search_messages_st (notmuch_query_t *query,
- notmuch_messages_t **out);
+notmuch_query_search_messages (notmuch_query_t *query,
+  notmuch_messages_t **out);
 /**
- * Like notmuch_query_search_messages, but without a status return.
- *
- * If a Xapian exception occurs this function will return NULL.
+ * Deprecated alias for notmuch_query_search_messages
  *
- * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please use
- * notmuch_query_search_messages_st instead.
+ * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please use
+ * notmuch_query_search_messages instead.
  *
  */
-NOTMUCH_DEPRECATED(4,3)
-notmuch_messages_t *
-notmuch_query_search_messages (notmuch_query_t *query);
+
+NOTMUCH_DEPRECATED(5,0)
+notmuch_status_t
+notmuch_query_search_messages_st (notmuch_query_t *query,
+ notmuch_messages_t **out);
 
 /**
  * Destroy a notmuch_query_t along with any associated resources.
diff --git a/lib/query.cc b/lib/query.cc
index d138f09b..60d1db94 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -171,20 +171,16 @@ _notmuch_exclude_tags (notmuch_query_t *query, 
Xapian::Query xquery)
 return exclude_query;
 }
 
-notmuch_messages_t *
-notmuch_query_search_messages (notmuch_query_t *query)
+
+notmuch_status_t
+notmuch_query_search_messages_st (notmuch_query_t *query,
+ notmuch_messages_t **out)
 {
-notmuch_status_t status;
-notmuch_messages_t *messages;
-status = notmuch_query_search_messages_st (query, &messages);
-if (status)
-   return NULL;
-else
-   return messages;
+return notmuch_query_search_messages (query, out);
 }
 
 notmuch_status_t
-notmuch_query_search_messages_st (notmuch_query_t *query,
+notmuch_query_search_messages (notmuch_query_t *query,
  notmuch_messages_t **out)
 {
 return _notmuch_query_search_documents (query, "mail", out);
@@ -454,7 +450,7 @@ notmuch_query_search_threads (notmuch_query_t *query,
 
 threads->query = qu

v2 remove notmuch_query_{count,search}_{threads,messages}

2017-02-26 Thread David Bremner
After some discussion on IRC, here's a second version. This both
removes the old versions, and steals the name.

I've intentionally written notmuch 0.25 in the comments, as I'd like
to merge these changes, or something like them at the beginning of the
0.25 cycle. Origininally I thought that some of the library fixes for
for 0.25 needed API changes, but that doesn't seem to be the case.

d

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


[PATCH 6/6] lib: replace deprecated n_q_count_threads with status returning version

2017-02-26 Thread David Bremner
This function was deprecated in notmuch 0.21.  We re-use the name for
a status returning version, and deprecate the _st name.
---
 bindings/python/notmuch/query.py |  2 +-
 bindings/ruby/query.c|  2 +-
 lib/notmuch.h| 16 +++-
 lib/query.cc | 12 
 notmuch-count.c  |  2 +-
 notmuch-search.c |  2 +-
 6 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py
index 10fb6dcc..06c7b11b 100644
--- a/bindings/python/notmuch/query.py
+++ b/bindings/python/notmuch/query.py
@@ -204,7 +204,7 @@ class Query(object):
 raise NotmuchError(status)
 return count.value
 
-_count_threads = nmlib.notmuch_query_count_threads_st
+_count_threads = nmlib.notmuch_query_count_threads
 _count_threads.argtypes = [NotmuchQueryP, POINTER(c_uint)]
 _count_threads.restype = c_uint
 
diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c
index b6edaef3..8b46d700 100644
--- a/bindings/ruby/query.c
+++ b/bindings/ruby/query.c
@@ -201,7 +201,7 @@ notmuch_rb_query_count_threads (VALUE self)
 
 Data_Get_Notmuch_Query (self, query);
 
-status = notmuch_query_count_threads_st (query, &count);
+status = notmuch_query_count_threads (query, &count);
 if (status)
notmuch_rb_status_raise (status);
 
diff --git a/lib/notmuch.h b/lib/notmuch.h
index b79618f6..e692e9bb 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -1044,22 +1044,20 @@ notmuch_query_count_messages_st (notmuch_query_t 
*query, unsigned int *count);
  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The
  *  value of *count is not defined.
  *
- * @since libnotmuch 4.3 (notmuch 0.21)
+ * @since libnotmuch 5 (notmuch 0.25)
  */
 notmuch_status_t
-notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count);
+notmuch_query_count_threads (notmuch_query_t *query, unsigned *count);
 
 /**
- * like notmuch_query_count_threads, but without a status return.
- *
- * May return 0 in case of errors.
+ * Deprecated alias for notmuch_query_count_threads
  *
- * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please
+ * @deprecated Deprecated as of libnotmuch 5.0 (notmuch 0.25). Please
  * use notmuch_query_count_threads_st instead.
  */
-NOTMUCH_DEPRECATED(4,3)
-unsigned int
-notmuch_query_count_threads (notmuch_query_t *query);
+NOTMUCH_DEPRECATED(5,0)
+notmuch_status_t
+notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count);
 
 /**
  * Get the thread ID of 'thread'.
diff --git a/lib/query.cc b/lib/query.cc
index 25b953c7..6c692e8e 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -612,18 +612,14 @@ _notmuch_query_count_documents (notmuch_query_t *query, 
const char *type, unsign
 return NOTMUCH_STATUS_SUCCESS;
 }
 
-unsigned
-notmuch_query_count_threads (notmuch_query_t *query)
+notmuch_status_t
+notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count)
 {
-notmuch_status_t status;
-unsigned int count;
-
-status = notmuch_query_count_threads_st (query, &count);
-return status ? 0 : count;
+return notmuch_query_count_threads (query, count);
 }
 
 notmuch_status_t
-notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count)
+notmuch_query_count_threads (notmuch_query_t *query, unsigned *count)
 {
 notmuch_messages_t *messages;
 GHashTable *hash;
diff --git a/notmuch-count.c b/notmuch-count.c
index 493be30f..cf80ee25 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -98,7 +98,7 @@ print_count (notmuch_database_t *notmuch, const char 
*query_str,
printf ("%u", ucount);
break;
 case OUTPUT_THREADS:
-   status = notmuch_query_count_threads_st (query, &ucount);
+   status = notmuch_query_count_threads (query, &ucount);
if (print_status_query ("notmuch count", query, status))
return -1;
printf ("%u", ucount);
diff --git a/notmuch-search.c b/notmuch-search.c
index 71218fdd..30722e86 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -123,7 +123,7 @@ do_search_threads (search_context_t *ctx)
 if (ctx->offset < 0) {
unsigned count;
notmuch_status_t status;
-   status = notmuch_query_count_threads_st (ctx->query, &count);
+   status = notmuch_query_count_threads (ctx->query, &count);
if (print_status_query ("notmuch search", ctx->query, status))
return 1;
 
-- 
2.11.0

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


[RFC PATCH] doc: add support for adding configure options as Sphinx tags

2017-02-26 Thread Jani Nikula
Add the configure options specified in $(TAGS) that equal 1 as tags on
the Sphinx command line using the -t option. The tags may be used to
conditionally include documentation using the Sphinx "only" directive
[1].

As an example, indicate in the documentation whether the Xapian field
processor is likely to be available (assuming the notmuch binary was
built in the same environment as the documentation).

[1] 
http://www.sphinx-doc.org/en/stable/markup/misc.html#including-content-based-on-tags

---

Just an idea, not sure if it makes sense.
---
 doc/Makefile.local| 7 ++-
 doc/man7/notmuch-search-terms.rst | 8 
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/doc/Makefile.local b/doc/Makefile.local
index c6f05ca879c0..24fc457cab14 100644
--- a/doc/Makefile.local
+++ b/doc/Makefile.local
@@ -7,8 +7,13 @@ SPHINXOPTS:= -q
 SPHINXBUILD   = sphinx-build
 DOCBUILDDIR  := $(dir)/_build
 
+# Configure options to be added as Sphinx tags.
+# Add "-t " for each make variable in TAGS that equals 1.
+TAGS := HAVE_XAPIAN_FIELD_PROCESSOR HAVE_XAPIAN_COMPACT
+TAGOPTS := $(patsubst %=1,-t %,$(filter %=1,$(foreach 
tag,$(TAGS),$(tag)=$(value $(tag)
+
 # Internal variables.
-ALLSPHINXOPTS   := -d $(DOCBUILDDIR)/doctrees $(SPHINXOPTS) $(srcdir)/$(dir)
+ALLSPHINXOPTS   := -d $(DOCBUILDDIR)/doctrees $(SPHINXOPTS) $(TAGOPTS) 
$(srcdir)/$(dir)
 APIMAN := $(DOCBUILDDIR)/man/man3/notmuch.3
 DOXYFILE   := $(srcdir)/$(dir)/doxygen.cfg
 
diff --git a/doc/man7/notmuch-search-terms.rst 
b/doc/man7/notmuch-search-terms.rst
index de93d7332472..0a2f74ce57a6 100644
--- a/doc/man7/notmuch-search-terms.rst
+++ b/doc/man7/notmuch-search-terms.rst
@@ -392,6 +392,14 @@ notmuch was built against a sufficiently recent version of 
Xapian by running
 
   % notmuch config get built_with.field_processor
 
+.. only:: HAVE_XAPIAN_FIELD_PROCESSOR
+
+   The documentation was built on a host with field processor support.
+
+.. only:: not HAVE_XAPIAN_FIELD_PROCESSOR
+
+   The documentation was built on a host without field processor support.
+
 Currently the following features require field processor support:
 
 - non-range date queries, e.g. "date:today"
-- 
2.11.0

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


Re: [PATCH 1/2] cli/config: don't try to open config file for 'notmuch help'

2017-02-26 Thread Tomi Ollila
On Sun, Feb 26 2017, Jani Nikula  wrote:

> The help command does not really need to try to open the config
> file. So don't.
>
> ---

I've forgotten this ... added notmuch::0.24 to this series and will
check carefully and test tomorrow...

Tomi

>
> This will allow better error reporting such as
> id:1483570332-11820-1-git-send-email-tomi.oll...@iki.fi while still
> ensuring 'notmuch help' succeeds in the absence of config files.
> ---
>  notmuch-client.h |  7 ++-
>  notmuch-config.c | 12 
>  notmuch.c| 34 +-
>  3 files changed, 31 insertions(+), 22 deletions(-)
>
> diff --git a/notmuch-client.h b/notmuch-client.h
> index 21b087980a17..1099122426af 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -263,10 +263,15 @@ json_quote_str (const void *ctx, const char *str);
>  
>  /* notmuch-config.c */
>  
> +typedef enum {
> +NOTMUCH_CONFIG_OPEN  = 1 << 0,
> +NOTMUCH_CONFIG_CREATE = 1 << 1,
> +} notmuch_config_mode_t;
> +
>  notmuch_config_t *
>  notmuch_config_open (void *ctx,
>const char *filename,
> -  notmuch_bool_t create_new);
> +  notmuch_config_mode_t config_mode);
>  
>  void
>  notmuch_config_close (notmuch_config_t *config);
> diff --git a/notmuch-config.c b/notmuch-config.c
> index b202bb1e2299..959410cce7b8 100644
> --- a/notmuch-config.c
> +++ b/notmuch-config.c
> @@ -322,7 +322,7 @@ out:
>  notmuch_config_t *
>  notmuch_config_open (void *ctx,
>const char *filename,
> -  notmuch_bool_t create_new)
> +  notmuch_config_mode_t config_mode)
>  {
>  GError *error = NULL;
>  size_t tmp;
> @@ -356,9 +356,13 @@ notmuch_config_open (void *ctx,
>  
>  config->key_file = g_key_file_new ();
>  
> -if (! get_config_from_file (config, create_new)) {
> - talloc_free (config);
> - return NULL;
> +if (config_mode & NOTMUCH_CONFIG_OPEN) {
> + notmuch_bool_t create_new = (config_mode & NOTMUCH_CONFIG_CREATE) != 0;
> +
> + if (! get_config_from_file (config, create_new)) {
> + talloc_free (config);
> + return NULL;
> + }
>  }
>  
>  /* Whenever we know of configuration sections that don't appear in
> diff --git a/notmuch.c b/notmuch.c
> index b9c320329dd5..8e332ce64410 100644
> --- a/notmuch.c
> +++ b/notmuch.c
> @@ -33,7 +33,7 @@ typedef int (*command_function_t) (notmuch_config_t 
> *config, int argc, char *arg
>  typedef struct command {
>  const char *name;
>  command_function_t function;
> -notmuch_bool_t create_config;
> +notmuch_config_mode_t config_mode;
>  const char *summary;
>  } command_t;
>  
> @@ -97,35 +97,35 @@ int notmuch_minimal_options (const char *subcommand_name,
>  }
>  
>  static command_t commands[] = {
> -{ NULL, notmuch_command, TRUE,
> +{ NULL, notmuch_command, NOTMUCH_CONFIG_OPEN | NOTMUCH_CONFIG_CREATE,
>"Notmuch main command." },
> -{ "setup", notmuch_setup_command, TRUE,
> +{ "setup", notmuch_setup_command, NOTMUCH_CONFIG_OPEN | 
> NOTMUCH_CONFIG_CREATE,
>"Interactively set up notmuch for first use." },
> -{ "new", notmuch_new_command, FALSE,
> +{ "new", notmuch_new_command, NOTMUCH_CONFIG_OPEN,
>"Find and import new messages to the notmuch database." },
> -{ "insert", notmuch_insert_command, FALSE,
> +{ "insert", notmuch_insert_command, NOTMUCH_CONFIG_OPEN,
>"Add a new message into the maildir and notmuch database." },
> -{ "search", notmuch_search_command, FALSE,
> +{ "search", notmuch_search_command, NOTMUCH_CONFIG_OPEN,
>"Search for messages matching the given search terms." },
> -{ "address", notmuch_address_command, FALSE,
> +{ "address", notmuch_address_command, NOTMUCH_CONFIG_OPEN,
>"Get addresses from messages matching the given search terms." },
> -{ "show", notmuch_show_command, FALSE,
> +{ "show", notmuch_show_command, NOTMUCH_CONFIG_OPEN,
>"Show all messages matching the search terms." },
> -{ "count", notmuch_count_command, FALSE,
> +{ "count", notmuch_count_command, NOTMUCH_CONFIG_OPEN,
>"Count messages matching the search terms." },
> -{ "reply", notmuch_reply_command, FALSE,
> +{ "reply", notmuch_reply_command, NOTMUCH_CONFIG_OPEN,
>"Construct a reply template for a set of messages." },
> -{ "tag", notmuch_tag_command, FALSE,
> +{ "tag", notmuch_tag_command, NOTMUCH_CONFIG_OPEN,
>"Add/remove tags for all messages matching the search terms." },
> -{ "dump", notmuch_dump_command, FALSE,
> +{ "dump", notmuch_dump_command, NOTMUCH_CONFIG_OPEN,
>"Create a plain-text dump of the tags for each message." },
> -{ "restore", notmuch_restore_command, FALSE,
> +{ "restore", notmuch_restore_command, NOTMUCH_CONFIG_OPEN,
>"Restore the tags from the given dump file (see 'dump')." },
> -{ "compact", notmuch_compact_command, FALSE

Re: [patch v5 5/6] lib: add mid: as a synonym for id:

2017-02-26 Thread Jani Nikula
On Thu, 16 Feb 2017, David Bremner  wrote:
> mid: is the url scheme suggested by URL 2392. We also plan to
> introduce more flexible searches for mid: than are possible with
> id: (in order not to break assumptions about the special behaviour of
> id:, e.g. identifying at most one message).

LGTM.

> ---
>  lib/database.cc | 1 +
>  test/T080-search.sh | 6 ++
>  2 files changed, 7 insertions(+)
>
> diff --git a/lib/database.cc b/lib/database.cc
> index ee971f32..21c8c5f2 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -262,6 +262,7 @@ prefix_t prefix_table[] = {
>  { "tag", "K",NOTMUCH_FIELD_EXTERNAL },
>  { "is",  "K",NOTMUCH_FIELD_EXTERNAL },
>  { "id",  "Q",NOTMUCH_FIELD_EXTERNAL },
> +{ "mid", "Q",NOTMUCH_FIELD_EXTERNAL },
>  { "path","P",NOTMUCH_FIELD_EXTERNAL 
> },
>  { "property","XPROPERTY",NOTMUCH_FIELD_EXTERNAL },
>  /*
> diff --git a/test/T080-search.sh b/test/T080-search.sh
> index 5e8b20ce..6149da93 100755
> --- a/test/T080-search.sh
> +++ b/test/T080-search.sh
> @@ -34,6 +34,11 @@ add_message '[subject]="search by id"' '[date]="Sat, 01 
> Jan 2000 12:00:00 -"
>  output=$(notmuch search id:${gen_msg_id} | notmuch_search_sanitize)
>  test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test 
> Suite; search by id (inbox unread)"
>  
> +test_begin_subtest "Search by mid:"
> +add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 
> -"'
> +output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
> +test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test 
> Suite; search by mid (inbox unread)"
> +
>  test_begin_subtest "Search by tag:"
>  add_message '[subject]="search by tag"' '[date]="Sat, 01 Jan 2000 12:00:00 
> -"'
>  notmuch tag +searchbytag id:${gen_msg_id}
> @@ -127,6 +132,7 @@ thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search 
> by to (inbox unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox 
> unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
> +thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by mid (inbox 
> unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox 
> searchbytag unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox 
> unread)
>  thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) 
> (inbox unread)
> -- 
> 2.11.0
>
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> https://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch


Re: [patch v5 4/6] lib: regexp matching in 'subject' and 'from'

2017-02-26 Thread Jani Nikula
On Thu, 16 Feb 2017, David Bremner  wrote:
> the idea is that you can run
>
> % notmuch search subject://
> % notmuch search from://
>
> or
>
> % notmuch search subject:"your usual phrase search"
> % notmuch search from:"usual phrase search"
>
> This feature is only available with recent Xapian, specifically
> support for field processors is needed.
>
> It should work with bindings, since it extends the query parser.
>
> This is easy to extend for other value slots, but currently the only
> value slots are date, message_id, from, subject, and last_mod. Date is
> already searchable;  message_id is left for a followup commit.
>
> This was originally written by Austin Clements, and ported to Xapian
> field processors (from Austin's custom query parser) by yours truly.
> ---
>  doc/man7/notmuch-search-terms.rst |  25 ++-
>  lib/Makefile.local|   1 +
>  lib/database.cc   |  11 +--
>  lib/regexp-fields.cc  | 144 
> ++
>  lib/regexp-fields.h   |  77 
>  test/T630-regexp-query.sh |  81 +
>  6 files changed, 332 insertions(+), 7 deletions(-)
>  create mode 100644 lib/regexp-fields.cc
>  create mode 100644 lib/regexp-fields.h
>  create mode 100755 test/T630-regexp-query.sh
>
> diff --git a/doc/man7/notmuch-search-terms.rst 
> b/doc/man7/notmuch-search-terms.rst
> index de93d733..47cab48d 100644
> --- a/doc/man7/notmuch-search-terms.rst
> +++ b/doc/man7/notmuch-search-terms.rst
> @@ -34,10 +34,14 @@ indicate user-supplied values):
>  
>  -  from:
>  
> +-  from://
> +
>  -  to:
>  
>  -  subject:
>  
> +-  subject://
> +
>  -  attachment:
>  
>  -  mimetype:
> @@ -71,6 +75,15 @@ subject of an email. Searching for a phrase in the subject 
> is supported
>  by including quotation marks around the phrase, immediately following
>  **subject:**.
>  
> +If notmuch is built with **Xapian Field Processors** (see below) the
> +**from:** and **subject** prefix can be also used to restrict the
> +results to those whose from/subject value matches a regular expression
> +(see **regex(7)**) delimited with //.
> +
> +::
> +
> +   notmuch search 'from:/bob@.*[.]example[.]com/'
> +
>  The **attachment:** prefix can be used to search for specific filenames
>  (or extensions) of attachments to email messages.
>  
> @@ -220,13 +233,18 @@ Boolean and Probabilistic Prefixes
>  --
>  
>  Xapian (and hence notmuch) prefixes are either **boolean**, supporting
> -exact matches like "tag:inbox"  or **probabilistic**, supporting a more 
> flexible **term** based searching. The prefixes currently supported by 
> notmuch are as follows.
> -
> +exact matches like "tag:inbox" or **probabilistic**, supporting a more
> +flexible **term** based searching. Certain **special** prefixes are
> +processed by notmuch in a way not stricly fitting either of Xapian's
> +built in styles. The prefixes currently supported by notmuch are as
> +follows.
>  
>  Boolean
> **tag:**, **id:**, **thread:**, **folder:**, **path:**, **property:**
>  Probabilistic
> -   **from:**, **to:**, **subject:**, **attachment:**, **mimetype:**
> +  **to:**, **attachment:**, **mimetype:**
> +Special
> +   **from:**, **query:**, **subject:**
>  
>  Terms and phrases
>  -
> @@ -396,6 +414,7 @@ Currently the following features require field processor 
> support:
>  
>  - non-range date queries, e.g. "date:today"
>  - named queries e.g. "query:my_special_query"
> +- regular expression searches, e.g. "subject:/^\\[SPAM\\]/"
>  
>  SEE ALSO
>  
> diff --git a/lib/Makefile.local b/lib/Makefile.local
> index b77e5780..cd92fc79 100644
> --- a/lib/Makefile.local
> +++ b/lib/Makefile.local
> @@ -52,6 +52,7 @@ libnotmuch_cxx_srcs =   \
>   $(dir)/query.cc \
>   $(dir)/query-fp.cc  \
>   $(dir)/config.cc\
> + $(dir)/regexp-fields.cc \
>   $(dir)/thread.cc
>  
>  libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) 
> $(libnotmuch_cxx_srcs:.cc=.o)
> diff --git a/lib/database.cc b/lib/database.cc
> index 450ee295..ee971f32 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -21,6 +21,7 @@
>  #include "database-private.h"
>  #include "parse-time-vrp.h"
>  #include "query-fp.h"
> +#include "regexp-fields.h"
>  #include "string-util.h"
>  
>  #include 
> @@ -277,7 +278,8 @@ prefix_t prefix_table[] = {
>   NOTMUCH_FIELD_PROCESSOR },
>  #endif
>  { "from","XFROM",NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC },
> + NOTMUCH_FIELD_PROBABILISTIC |
> + NOTMUCH_FIELD_PROCESSOR },
>  { "to",  "XTO",  NOTMUCH_FIELD_EXTERNAL |
>   NOTMUCH_FIELD_PROBABILISTIC },
> 

Re: [patch v5 3/6] lib: create field processors from prefix table

2017-02-26 Thread Jani Nikula
On Thu, 16 Feb 2017, David Bremner  wrote:
> This is a bit more code than hardcoding the two existing field
> processors, but it should make it easy to add more.
> ---
>  lib/database-private.h |  3 ++-
>  lib/database.cc| 45 +++--
>  2 files changed, 33 insertions(+), 15 deletions(-)
>
> diff --git a/lib/database-private.h b/lib/database-private.h
> index 2fb60f5e..60d1fead 100644
> --- a/lib/database-private.h
> +++ b/lib/database-private.h
> @@ -153,7 +153,8 @@ operator&=(_notmuch_features &a, _notmuch_features b)
>  typedef enum notmuch_field_flags {
>  NOTMUCH_FIELD_NO_FLAGS = 0,
>  NOTMUCH_FIELD_EXTERNAL = 1 << 0,
> -NOTMUCH_FIELD_PROBABILISTIC = 1 << 1
> +NOTMUCH_FIELD_PROBABILISTIC = 1 << 1,
> +NOTMUCH_FIELD_PROCESSOR = 1 << 2

Nitpick, if you add a comma at the end, subsequent changes will have
smaller diff.

>  } notmuch_field_flag_t;
>  
>  /*
> diff --git a/lib/database.cc b/lib/database.cc
> index 8016c4df..450ee295 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -270,6 +270,12 @@ prefix_t prefix_table[] = {
>   * discussion.
>   */
>  { "folder",  "XFOLDER:", NOTMUCH_FIELD_EXTERNAL 
> },
> +#if HAVE_XAPIAN_FIELD_PROCESSOR
> +{ "date",NULL,   NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> +{ "query",   NULL,   NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> +#endif
>  { "from","XFROM",NOTMUCH_FIELD_EXTERNAL |
>   NOTMUCH_FIELD_PROBABILISTIC },
>  { "to",  "XTO",  NOTMUCH_FIELD_EXTERNAL |
> @@ -282,6 +288,20 @@ prefix_t prefix_table[] = {
>   NOTMUCH_FIELD_PROBABILISTIC },
>  };
>  
> +#if HAVE_XAPIAN_FIELD_PROCESSOR
> +static Xapian::FieldProcessor *
> +_make_field_processor (const char *name, notmuch_database_t *notmuch) {
> +if (STRNCMP_LITERAL (name, "date") == 0)
> + return (new DateFieldProcessor())->release ();
> +else if (STRNCMP_LITERAL(name, "query") == 0)
> + return (new QueryFieldProcessor (*notmuch->query_parser, 
> notmuch))->release ();
> +
> +INTERNAL_ERROR ("no field processor for prefix '%s'\n", name);
> +}
> +#else
> +#define _make_field_processor(name, db) NULL

Nitpick, if you make this a proper static inline function that just
returns NULL, you'll get type checking but the end result will be the
same.

> +#endif
> +
>  const char *
>  _find_prefix (const char *name)
>  {
> @@ -1027,18 +1047,6 @@ notmuch_database_open_verbose (const char *path,
>   notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
>   notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor 
> (NOTMUCH_VALUE_TIMESTAMP);
>   notmuch->date_range_processor = new ParseTimeValueRangeProcessor 
> (NOTMUCH_VALUE_TIMESTAMP);
> -#if HAVE_XAPIAN_FIELD_PROCESSOR
> - /* This currently relies on the query parser to pass anything
> -  * with a .. to the range processor */
> - {
> - Xapian::FieldProcessor * date_fp = new DateFieldProcessor();
> - Xapian::FieldProcessor * query_fp =
> - new QueryFieldProcessor (*notmuch->query_parser, notmuch);
> -
> - notmuch->query_parser->add_boolean_prefix("date", date_fp->release 
> ());
> - notmuch->query_parser->add_boolean_prefix("query", 
> query_fp->release ());
> - }
> -#endif
>   notmuch->last_mod_range_processor = new 
> Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
>  
>   notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
> @@ -1052,8 +1060,17 @@ notmuch_database_open_verbose (const char *path,
>   for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
>   const prefix_t *prefix = &prefix_table[i];
>   if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
> - if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC) {
> - notmuch->query_parser->add_prefix (prefix->name, 
> prefix->prefix);
> + /* we treat all field-processor fields as boolean in order
> +to get the raw input */
> + if (HAVE_XAPIAN_FIELD_PROCESSOR &&
> + (prefix->flags & NOTMUCH_FIELD_PROCESSOR)) {
> + Xapian::FieldProcessor *fp = _make_field_processor 
> (prefix->name,
> + 
> notmuch);
> +
> + notmuch->query_parser->add_boolean_prefix (prefix->name, 
> fp);

Are you sure this builds for HAVE_XAPIAN_FIELD_PROCESSOR=0? I think this
assumes the compiler eliminates the dead code before actually compiling
it. Xapian::FieldProcessor is not there for older Xapian, is it?

I strongly prefer having conditionally compilation at the function leve

[PATCH 2/2] notmuch-config: ENOENT vs generic handling when file open fails.

2017-02-26 Thread Jani Nikula
From: Tomi Ollila 

When opening configuration file fails, ENOENT (file not found) is
handled specially -- in setup missing file is ok (often expected),
and otherwise user can be informed to run notmuch setup.

In any other case the the reason is unknown, so there is no other
option but to print generic error message to stderr.
---
 notmuch-config.c | 29 ++---
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/notmuch-config.c b/notmuch-config.c
index 959410cce7b8..e4aaef610173 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -215,24 +215,23 @@ get_config_from_file (notmuch_config_t *config, 
notmuch_bool_t create_new)
 
 FILE *fp = fopen(config->filename, "r");
 if (fp == NULL) {
-   /* If create_new is true, then the caller is prepared for a
-* default configuration file in the case of FILE NOT FOUND.
-*/
-   if (create_new) {
-   config->is_new = TRUE;
-   ret = TRUE;
-   goto out;
-   } else if (errno == ENOENT) {
-   fprintf (stderr, "Configuration file %s not found.\n"
-"Try running 'notmuch setup' to create a configuration.\n",
-config->filename);
-   goto out;
+   if (errno == ENOENT) {
+   /* If create_new is true, then the caller is prepared for a
+* default configuration file in the case of FILE NOT FOUND.
+*/
+   if (create_new) {
+   config->is_new = TRUE;
+   ret = TRUE;
+   } else {
+   fprintf (stderr, "Configuration file %s not found.\n"
+"Try running 'notmuch setup' to create a 
configuration.\n",
+config->filename);
+   }
} else {
-   fprintf (stderr, "Error opening config file '%s': %s\n"
-"Try running 'notmuch setup' to create a configuration.\n",
+   fprintf (stderr, "Error opening config file '%s': %s\n",
 config->filename, strerror(errno));
-   goto out;
}
+   goto out;
 }
 
 config_str = talloc_zero_array (config, char, config_bufsize);
-- 
2.11.0

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


[PATCH 1/2] cli/config: don't try to open config file for 'notmuch help'

2017-02-26 Thread Jani Nikula
The help command does not really need to try to open the config
file. So don't.

---

This will allow better error reporting such as
id:1483570332-11820-1-git-send-email-tomi.oll...@iki.fi while still
ensuring 'notmuch help' succeeds in the absence of config files.
---
 notmuch-client.h |  7 ++-
 notmuch-config.c | 12 
 notmuch.c| 34 +-
 3 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 21b087980a17..1099122426af 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -263,10 +263,15 @@ json_quote_str (const void *ctx, const char *str);
 
 /* notmuch-config.c */
 
+typedef enum {
+NOTMUCH_CONFIG_OPEN= 1 << 0,
+NOTMUCH_CONFIG_CREATE = 1 << 1,
+} notmuch_config_mode_t;
+
 notmuch_config_t *
 notmuch_config_open (void *ctx,
 const char *filename,
-notmuch_bool_t create_new);
+notmuch_config_mode_t config_mode);
 
 void
 notmuch_config_close (notmuch_config_t *config);
diff --git a/notmuch-config.c b/notmuch-config.c
index b202bb1e2299..959410cce7b8 100644
--- a/notmuch-config.c
+++ b/notmuch-config.c
@@ -322,7 +322,7 @@ out:
 notmuch_config_t *
 notmuch_config_open (void *ctx,
 const char *filename,
-notmuch_bool_t create_new)
+notmuch_config_mode_t config_mode)
 {
 GError *error = NULL;
 size_t tmp;
@@ -356,9 +356,13 @@ notmuch_config_open (void *ctx,
 
 config->key_file = g_key_file_new ();
 
-if (! get_config_from_file (config, create_new)) {
-   talloc_free (config);
-   return NULL;
+if (config_mode & NOTMUCH_CONFIG_OPEN) {
+   notmuch_bool_t create_new = (config_mode & NOTMUCH_CONFIG_CREATE) != 0;
+
+   if (! get_config_from_file (config, create_new)) {
+   talloc_free (config);
+   return NULL;
+   }
 }
 
 /* Whenever we know of configuration sections that don't appear in
diff --git a/notmuch.c b/notmuch.c
index b9c320329dd5..8e332ce64410 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -33,7 +33,7 @@ typedef int (*command_function_t) (notmuch_config_t *config, 
int argc, char *arg
 typedef struct command {
 const char *name;
 command_function_t function;
-notmuch_bool_t create_config;
+notmuch_config_mode_t config_mode;
 const char *summary;
 } command_t;
 
@@ -97,35 +97,35 @@ int notmuch_minimal_options (const char *subcommand_name,
 }
 
 static command_t commands[] = {
-{ NULL, notmuch_command, TRUE,
+{ NULL, notmuch_command, NOTMUCH_CONFIG_OPEN | NOTMUCH_CONFIG_CREATE,
   "Notmuch main command." },
-{ "setup", notmuch_setup_command, TRUE,
+{ "setup", notmuch_setup_command, NOTMUCH_CONFIG_OPEN | 
NOTMUCH_CONFIG_CREATE,
   "Interactively set up notmuch for first use." },
-{ "new", notmuch_new_command, FALSE,
+{ "new", notmuch_new_command, NOTMUCH_CONFIG_OPEN,
   "Find and import new messages to the notmuch database." },
-{ "insert", notmuch_insert_command, FALSE,
+{ "insert", notmuch_insert_command, NOTMUCH_CONFIG_OPEN,
   "Add a new message into the maildir and notmuch database." },
-{ "search", notmuch_search_command, FALSE,
+{ "search", notmuch_search_command, NOTMUCH_CONFIG_OPEN,
   "Search for messages matching the given search terms." },
-{ "address", notmuch_address_command, FALSE,
+{ "address", notmuch_address_command, NOTMUCH_CONFIG_OPEN,
   "Get addresses from messages matching the given search terms." },
-{ "show", notmuch_show_command, FALSE,
+{ "show", notmuch_show_command, NOTMUCH_CONFIG_OPEN,
   "Show all messages matching the search terms." },
-{ "count", notmuch_count_command, FALSE,
+{ "count", notmuch_count_command, NOTMUCH_CONFIG_OPEN,
   "Count messages matching the search terms." },
-{ "reply", notmuch_reply_command, FALSE,
+{ "reply", notmuch_reply_command, NOTMUCH_CONFIG_OPEN,
   "Construct a reply template for a set of messages." },
-{ "tag", notmuch_tag_command, FALSE,
+{ "tag", notmuch_tag_command, NOTMUCH_CONFIG_OPEN,
   "Add/remove tags for all messages matching the search terms." },
-{ "dump", notmuch_dump_command, FALSE,
+{ "dump", notmuch_dump_command, NOTMUCH_CONFIG_OPEN,
   "Create a plain-text dump of the tags for each message." },
-{ "restore", notmuch_restore_command, FALSE,
+{ "restore", notmuch_restore_command, NOTMUCH_CONFIG_OPEN,
   "Restore the tags from the given dump file (see 'dump')." },
-{ "compact", notmuch_compact_command, FALSE,
+{ "compact", notmuch_compact_command, NOTMUCH_CONFIG_OPEN,
   "Compact the notmuch database." },
-{ "config", notmuch_config_command, FALSE,
+{ "config", notmuch_config_command, NOTMUCH_CONFIG_OPEN,
   "Get or set settings in the notmuch configuration file." },
-{ "help", notmuch_help_command, TRUE, /* create but don't save config */
+  

Re: [PATCH] test: fix tests for content-disposition

2017-02-26 Thread Jani Nikula
On Sun, 26 Feb 2017, David Bremner  wrote:
> Mark Walters  writes:
>
>> This fixes all tests for the recent addition of content-disposition to
>> the structured format outputs of notmuch-show.
>> ---
>>
>> Since Jani added the content-disposition as I wanted to use it from emacs 
>> (thanks Jani!)
>> I thought I should fix the tests.
>>
>> I don't know if it should be folded in to the main patch or applied
>> separately. Either is fine with me.
>
> Unfortunately this does not apply since 
> 75bb23f74874e3820b0295d0a618045fc5f33417

Rebased version at id:20170226183348.30470-1-j...@nikula.org with Mark's
test updates squashed in (I dislike having commits where tests fail).

BR,
Jani.

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


[PATCH v2 1/2] cli/show: abstract get content disposition

2017-02-26 Thread Jani Nikula
Reduce duplication in follow-up work. As a side effect, handle error
returns from g_mime_content_disposition_get_disposition() without
segfaulting.
---
 notmuch-show.c | 16 +---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index ab4ea1c2bdc1..7630f49dbc59 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -110,6 +110,17 @@ _get_one_line_summary (const void *ctx, notmuch_message_t 
*message)
from, relative_date, tags);
 }
 
+static const char *_get_disposition(GMimeObject *meta)
+{
+GMimeContentDisposition *disposition;
+
+disposition = g_mime_object_get_content_disposition (meta);
+if (!disposition)
+   return NULL;
+
+return g_mime_content_disposition_get_disposition (disposition);
+}
+
 /* Emit a sequence of key/value pairs for the metadata of message.
  * The caller should begin a map before calling this. */
 static void
@@ -463,14 +474,13 @@ format_part_text (const void *ctx, sprinter_t *sp, 
mime_node_t *node,
notmuch_message_get_flag (message, 
NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 1 : 0,
notmuch_message_get_filename (message));
 } else {
-   GMimeContentDisposition *disposition = 
g_mime_object_get_content_disposition (meta);
+   const char *disposition = _get_disposition (meta);
const char *cid = g_mime_object_get_content_id (meta);
const char *filename = leaf ?
g_mime_part_get_filename (GMIME_PART (node->part)) : NULL;
 
if (disposition &&
-   strcasecmp (g_mime_content_disposition_get_disposition 
(disposition),
-   GMIME_DISPOSITION_ATTACHMENT) == 0)
+   strcasecmp (disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)
part_type = "attachment";
else
part_type = "part";
-- 
2.11.0

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


[PATCH v2 2/2] cli/show: add content-disposition to structured output message parts

2017-02-26 Thread Jani Nikula
Help the clients decide how to display parts.

Test updates by Mark Walters .
---
 devel/schemata |  2 ++
 notmuch-show.c |  6 ++
 test/T160-json.sh  |  2 +-
 test/T170-sexp.sh  |  2 +-
 test/T190-multipart.sh | 22 ++
 test/T350-crypto.sh|  1 +
 6 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/devel/schemata b/devel/schemata
index 6dede7a453d7..00ebb7a6e714 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -28,6 +28,7 @@ v2
 
 v3
 - Replaced message.filename string with a list of filenames.
+- Added part.content-disposition field.
 
 Common non-terminals
 
@@ -79,6 +80,7 @@ part = {
 sigstatus?: sigstatus,
 
 content-type:   string,
+content-disposition?:   string,
 content-id?:string,
 # if content-type starts with "multipart/":
 content:[part*],
diff --git a/notmuch-show.c b/notmuch-show.c
index 7630f49dbc59..744b62727c26 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -595,6 +595,7 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, 
mime_node_t *node,
 GMimeObject *meta = node->envelope_part ?
GMIME_OBJECT (node->envelope_part) : node->part;
 GMimeContentType *content_type = g_mime_object_get_content_type (meta);
+const char *disposition = _get_disposition (meta);
 const char *cid = g_mime_object_get_content_id (meta);
 const char *filename = GMIME_IS_PART (node->part) ?
g_mime_part_get_filename (GMIME_PART (node->part)) : NULL;
@@ -624,6 +625,11 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, 
mime_node_t *node,
 sp->map_key (sp, "content-type");
 sp->string (sp, g_mime_content_type_to_string (content_type));
 
+if (disposition) {
+   sp->map_key (sp, "content-disposition");
+   sp->string (sp, disposition);
+}
+
 if (cid) {
sp->map_key (sp, "content-id");
sp->string (sp, cid);
diff --git a/test/T160-json.sh b/test/T160-json.sh
index 85b9b41f314c..5a954e3baf0d 100755
--- a/test/T160-json.sh
+++ b/test/T160-json.sh
@@ -48,7 +48,7 @@ output=$(notmuch show --format=json "id:$id")
 filename=$(notmuch search --output=files "id:$id")
 # Get length of README after base64-encoding, minus additional newline.
 attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
-test_expect_equal_json "$output" "[[[{\"id\": \"$id\", \"match\": true, 
\"excluded\": false, \"filename\": [\"$filename\"], \"timestamp\": 946728000, 
\"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": 
{\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite 
\", \"To\": \"test_su...@notmuchmail.org\", 
\"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": [{\"id\": 1, 
\"content-type\": \"multipart/mixed\", \"content\": [{\"id\": 2, 
\"content-type\": \"text/plain\", \"content\": \"This is a test message with 
inline attachment with a filename\"}, {\"id\": 3, \"content-type\": 
\"application/octet-stream\", \"content-length\": $attachment_length, 
\"content-transfer-encoding\": \"base64\", \"filename\": \"README\"}]}]}, ["
+test_expect_equal_json "$output" "[[[{\"id\": \"$id\", \"match\": true, 
\"excluded\": false, \"filename\": [\"$filename\"], \"timestamp\": 946728000, 
\"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": 
{\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite 
\", \"To\": \"test_su...@notmuchmail.org\", 
\"Date\": \"Sat, 01 Jan 2000 12:00:00 +\"}, \"body\": [{\"id\": 1, 
\"content-type\": \"multipart/mixed\", \"content\": [{\"id\": 2, 
\"content-type\": \"text/plain\", \"content\": \"This is a test message with 
inline attachment with a filename\"}, {\"id\": 3, \"content-type\": 
\"application/octet-stream\", \"content-length\": $attachment_length, 
\"content-transfer-encoding\": \"base64\", \"content-disposition\": \"inline\", 
\"filename\": \"README\"}]}]}, ["
 
 test_begin_subtest "Search message: json, utf-8"
 add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 
Jan 2000 12:00:00 -\"" "[body]=\"jsön-search-méssage\""
diff --git a/test/T170-sexp.sh b/test/T170-sexp.sh
index 07113c0ad9a2..40e5e21d62cc 100755
--- a/test/T170-sexp.sh
+++ b/test/T170-sexp.sh
@@ -39,7 +39,7 @@ output=$(notmuch show --format=sexp "id:$id")
 filename=$(notmuch search --output=files "id:$id")
 # Get length of README after base64-encoding, minus additional newline.
 attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
-test_expect_equal "$output" ":id \"$id\" :match t :excluded nil :filename 
(\"$filename\") :timestamp 946728000 :date_relative \"2000-01-01\" :tags 
(\"inbox\") :headers (:Subject \"sexp-show-inline-attachment-filename\" :From 
\"Notmuch Test Suite \" :To 
\"test_su...@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +\") :body 
((:id 1 :content-type \"multipart/mixed\" :content ((:id 2 :content-type 
\"text/plain\" :content \"This is a test message with inline attachment with

[PATCH 3/3] test: suppress diff for broken test without V=1

2017-02-26 Thread Jani Nikula
Known broken tests are, well, known broken. Do not print the result
diff for them unless V=1 is specified. Now that the test description
is printed also when known broken tests fail, the user can also skip
to running the individual failing tests.
---
 test/Makefile.local |  2 +-
 test/test-lib.sh| 10 --
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/test/Makefile.local b/test/Makefile.local
index f8cf90d07e2d..4680597292cf 100644
--- a/test/Makefile.local
+++ b/test/Makefile.local
@@ -61,7 +61,7 @@ test-binaries: $(TEST_BINARIES)
 
 test:  all test-binaries
 ifeq ($V,)
-   @echo 'Use "$(MAKE) V=1" to print test headings and PASSing results.'
+   @echo 'Use "$(MAKE) V=1" to see the details for passing and known 
broken tests.'
@env NOTMUCH_TEST_QUIET=1 ${test_src_dir}/notmuch-test $(OPTIONS)
 else
 # The user has explicitly enabled quiet execution.
diff --git a/test/test-lib.sh b/test/test-lib.sh
index 2d9efa0ba799..eadfa31f850e 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -873,7 +873,9 @@ test_failure_message_ () {
say_color error "%-6s" "$1"
echo " $2"
shift 2
-   echo "$@" | sed -e 's/^//'
+   if [ "$#" != "0" ]; then
+   echo "$@" | sed -e 's/^//'
+   fi
if test "$verbose" != "t"; then cat test.output; fi
 }
 
@@ -887,7 +889,11 @@ test_known_broken_ok_ () {
 test_known_broken_failure_ () {
test_reset_state_
test_broken=$(($test_broken+1))
-   test_failure_message_ "BROKEN" "$test_subtest_name" "$@"
+   if [ -z "$NOTMUCH_TEST_QUIET" ]; then
+   test_failure_message_ "BROKEN" "$test_subtest_name" "$@"
+   else
+   test_failure_message_ "BROKEN" "$test_subtest_name"
+   fi
return 1
 }
 
-- 
2.11.0

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


[PATCH 1/3] test: shrink T590-thread-breakage test decription to one line

2017-02-26 Thread Jani Nikula
The test description is used for log output, I think the intention is
to keep it as a one-liner. Leave the rest of the long description as a
comment.
---
 test/T590-thread-breakage.sh | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/test/T590-thread-breakage.sh b/test/T590-thread-breakage.sh
index 6e4031af46bb..38abc2113c26 100755
--- a/test/T590-thread-breakage.sh
+++ b/test/T590-thread-breakage.sh
@@ -3,21 +3,21 @@
 # Copyright (c) 2016 Daniel Kahn Gillmor
 #
 
-test_description='thread breakage during reindexing
+test_description='thread breakage during reindexing'
 
-notmuch uses ghost documents to track messages we have seen references
-to but have never seen.  Regardless of the order of delivery, message
-deletion, and reindexing, the list of ghost messages for a given
-stored corpus should not vary, so that threads can be reassmebled
-cleanly.
-
-In practice, we accept a small amount of variation (and therefore
-traffic pattern metadata leakage to be stored in the index) for the
-sake of efficiency.
-
-This test also embeds some subtests to ensure that indexing actually
-works properly and attempted fixes to threading issues do not break
-the expected contents of the index.'
+# notmuch uses ghost documents to track messages we have seen references
+# to but have never seen.  Regardless of the order of delivery, message
+# deletion, and reindexing, the list of ghost messages for a given
+# stored corpus should not vary, so that threads can be reassmebled
+# cleanly.
+#
+# In practice, we accept a small amount of variation (and therefore
+# traffic pattern metadata leakage to be stored in the index) for the
+# sake of efficiency.
+#
+# This test also embeds some subtests to ensure that indexing actually
+# works properly and attempted fixes to threading issues do not break
+# the expected contents of the index.
 
 . ./test-lib.sh || exit 1
 
-- 
2.11.0

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


[PATCH 2/3] test: print test description also for failing known broken tests

2017-02-26 Thread Jani Nikula
With the test description, the user can see the test script name, and
debug with that alone.
---
 test/test-lib.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index d8e159437ca9..2d9efa0ba799 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -858,12 +858,12 @@ test_ok_ () {
 }
 
 test_failure_ () {
+   print_test_description
if test "$test_subtest_known_broken_" = "t"; then
test_known_broken_failure_ "$@"
return
fi
test_failure=$(($test_failure + 1))
-   print_test_description
test_failure_message_ "FAIL" "$test_subtest_name" "$@"
test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
return 1
-- 
2.11.0

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


[PATCH 8/9] test: require test_begin_subtest before test_expect_success

2017-02-26 Thread Jani Nikula
Unify the subtests by requiring test_begin_subtest before
test_expect_success. (Similar change for test_expect_code will
follow.)

This increases clarity in the test scripts by having a separate line
for the start of the subtest with the heading, and makes it possible
to simplify the test infrastructure by making all subtests similar.
---
 test/README| 14 +++---
 test/T000-basic.sh | 33 +
 test/T010-help-test.sh | 27 ++-
 test/T020-compact.sh   |  7 ---
 test/T190-multipart.sh | 20 
 test/T240-dump-restore.sh  | 33 -
 test/T310-emacs.sh |  9 -
 test/T340-maildir-sync.sh  |  6 --
 test/T350-crypto.sh|  9 ++---
 test/T355-smime.sh |  6 --
 test/T380-atomicity.sh |  3 ++-
 test/T400-hooks.sh |  4 ++--
 test/T530-upgrade.sh   |  5 +++--
 test/T560-lib-error.sh |  3 ++-
 test/T570-revision-tracking.sh | 16 
 test/T600-named-queries.sh |  8 
 test/test-lib.sh   | 18 +++---
 test/test-verbose  |  6 --
 18 files changed, 124 insertions(+), 103 deletions(-)

diff --git a/test/README b/test/README
index 104a120ea28b..7acdb4b81f4d 100644
--- a/test/README
+++ b/test/README
@@ -189,17 +189,17 @@ Test harness library
 There are a handful helper functions defined in the test harness
 library for your script to use.
 
- test_expect_success  

[PATCH 7/9] test: drop the implicit prereq check mechanism from test_expect_*

2017-02-26 Thread Jani Nikula
The only place where we use the implicit prereq check is T000-basic.sh
where we check that it works. It's an added complication that we don't
use. Remove it.

The test_have_prereq function can still be used for the same effect in
subtests that use test_begin_subtest. For now, this will make it
impossible to have prereqs in one-line subtests that don't require
test_begin_subtest. This will be fixed in follow-up work.
---
 test/T000-basic.sh |  2 +-
 test/test-lib.sh   | 26 ++
 2 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/test/T000-basic.sh b/test/T000-basic.sh
index 0a8d6cdf40fc..78e183361e7d 100755
--- a/test/T000-basic.sh
+++ b/test/T000-basic.sh
@@ -23,7 +23,7 @@ test_expect_success 'success is reported like this' '
 '
 test_set_prereq HAVEIT
 haveit=no
-test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
+test_expect_success 'test runs if prerequisite is satisfied' '
 test_have_prereq HAVEIT &&
 haveit=yes
 '
diff --git a/test/test-lib.sh b/test/test-lib.sh
index 056483c47c0a..3a69c399f6eb 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -570,9 +570,8 @@ test_expect_equal ()
error "bug in the test script: test_expect_equal without 
test_begin_subtest"
fi
inside_subtest=
-   test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
-   error "bug in the test script: not 2 or 3 parameters to 
test_expect_equal"
+   error "bug in the test script: not 2 parameters to test_expect_equal"
 
output="$1"
expected="$2"
@@ -597,9 +596,8 @@ test_expect_equal_file ()
error "bug in the test script: test_expect_equal_file without 
test_begin_subtest"
fi
inside_subtest=
-   test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
-   error "bug in the test script: not 2 or 3 parameters to 
test_expect_equal"
+   error "bug in the test script: not 2 parameters to 
test_expect_equal_file"
 
file1="$1"
file2="$2"
@@ -640,9 +638,8 @@ test_sort_json () {
 }
 
 test_emacs_expect_t () {
-   test "$#" = 2 && { prereq=$1; shift; } || prereq=
test "$#" = 1 ||
-   error "bug in the test script: not 1 or 2 parameters to 
test_emacs_expect_t"
+   error "bug in the test script: not 1 parameter to test_emacs_expect_t"
if [ -z "$inside_subtest" ]; then
error "bug in the test script: test_emacs_expect_t without 
test_begin_subtest"
fi
@@ -757,12 +754,8 @@ notmuch_config_sanitize ()
 # End of notmuch helper functions
 
 # Use test_set_prereq to tell that a particular prerequisite is available.
-# The prerequisite can later be checked for in two ways:
 #
-# - Explicitly using test_have_prereq.
-#
-# - Implicitly by specifying the prerequisite tag in the calls to
-#   test_expect_{success,failure,code}.
+# The prerequisite can later be checked for by using test_have_prereq.
 #
 # The single parameter is the prerequisite tag (a simple word, in all
 # capital letters by convention).
@@ -891,11 +884,6 @@ test_skip () {
break
esac
done
-   if test -z "$to_skip" && test -n "$prereq" &&
-  ! test_have_prereq "$prereq"
-   then
-   to_skip=t
-   fi
case "$to_skip" in
t)
test_report_skip_ "$@"
@@ -929,9 +917,8 @@ test_subtest_known_broken () {
 }
 
 test_expect_success () {
-   test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
-   error "bug in the test script: not 2 or 3 parameters to 
test-expect-success"
+   error "bug in the test script: not 2 parameters to test_expect_success"
test_subtest_name="$1"
test_reset_state_
if ! test_skip "$@"
@@ -950,9 +937,8 @@ test_expect_success () {
 }
 
 test_expect_code () {
-   test "$#" = 4 && { prereq=$1; shift; } || prereq=
test "$#" = 3 ||
-   error "bug in the test script: not 3 or 4 parameters to 
test-expect-code"
+   error "bug in the test script: not 3 parameters to test_expect_code"
test_subtest_name="$2"
test_reset_state_
if ! test_skip "$@"
-- 
2.11.0

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


[PATCH 6/9] test: ensure test_begin_subtest has been called before test_expect_*

2017-02-26 Thread Jani Nikula
This is the expectation, increase robustness of the test suite by
requiring it.
---
 test/test-lib.sh | 9 +
 1 file changed, 9 insertions(+)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index 0a486f4cde9a..056483c47c0a 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -566,6 +566,9 @@ test_begin_subtest ()
 test_expect_equal ()
 {
exec 1>&6 2>&7  # Restore stdout and stderr
+   if [ -z "$inside_subtest" ]; then
+   error "bug in the test script: test_expect_equal without 
test_begin_subtest"
+   fi
inside_subtest=
test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
@@ -590,6 +593,9 @@ test_expect_equal ()
 test_expect_equal_file ()
 {
exec 1>&6 2>&7  # Restore stdout and stderr
+   if [ -z "$inside_subtest" ]; then
+   error "bug in the test script: test_expect_equal_file without 
test_begin_subtest"
+   fi
inside_subtest=
test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
@@ -637,6 +643,9 @@ test_emacs_expect_t () {
test "$#" = 2 && { prereq=$1; shift; } || prereq=
test "$#" = 1 ||
error "bug in the test script: not 1 or 2 parameters to 
test_emacs_expect_t"
+   if [ -z "$inside_subtest" ]; then
+   error "bug in the test script: test_emacs_expect_t without 
test_begin_subtest"
+   fi
 
# Run the test.
if ! test_skip "$test_subtest_name"
-- 
2.11.0

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


[PATCH 9/9] test: require test_begin_subtest before test_expect_code

2017-02-26 Thread Jani Nikula
Unify the subtests by requiring test_begin_subtest before
test_expect_code. (Similar change for test_expect_success has already
been done.)

This increases clarity in the test scripts by having a separate line
for the start of the subtest with the heading, and makes it possible
to simplify the test infrastructure by making all subtests similar.
---
 test/README|  5 +
 test/T000-basic.sh | 11 ---
 test/T020-compact.sh   |  3 ++-
 test/T050-new.sh   |  4 ++--
 test/T070-insert.sh| 34 --
 test/T150-tagging.sh   | 13 +
 test/T160-json.sh  |  8 
 test/T400-hooks.sh | 14 --
 test/T570-revision-tracking.sh | 16 
 test/T600-named-queries.sh |  4 ++--
 test/test-lib.sh   | 18 +++---
 11 files changed, 75 insertions(+), 55 deletions(-)

diff --git a/test/README b/test/README
index 7acdb4b81f4d..dcd05237a062 100644
--- a/test/README
+++ b/test/README
@@ -200,6 +200,11 @@ library for your script to use.

[PATCH 0/9] test: cleanup and refactoring

2017-02-26 Thread Jani Nikula
The first half is cleanups, throwing out unused stuff.

The second half requires test_begin_subtest before *all* subtests.

BR,
Jani.


Jani Nikula (9):
  test: remove unused regexp convenience variables
  test: remove unused filter functions
  test: remove unused test_external and test_external_without_stderr
  test: remove unused and no-op --long-tests parameter
  test: only accept short and long options, not silly in-betweens
  test: ensure test_begin_subtest has been called before test_expect_*
  test: drop the implicit prereq check mechanism from test_expect_*
  test: require test_begin_subtest before test_expect_success
  test: require test_begin_subtest before test_expect_code

 test/README|  17 ++--
 test/T000-basic.sh |  44 ---
 test/T010-help-test.sh |  27 ---
 test/T020-compact.sh   |  10 ++-
 test/T050-new.sh   |   4 +-
 test/T070-insert.sh|  34 
 test/T150-tagging.sh   |  13 ++-
 test/T160-json.sh  |   8 +-
 test/T190-multipart.sh |  20 ++---
 test/T240-dump-restore.sh  |  33 +---
 test/T310-emacs.sh |   9 +--
 test/T340-maildir-sync.sh  |   6 +-
 test/T350-crypto.sh|   9 ++-
 test/T355-smime.sh |   6 +-
 test/T380-atomicity.sh |   3 +-
 test/T400-hooks.sh |  18 +++--
 test/T530-upgrade.sh   |   5 +-
 test/T560-lib-error.sh |   3 +-
 test/T570-revision-tracking.sh |  32 
 test/T600-named-queries.sh |  12 +--
 test/test-lib.sh   | 176 ++---
 test/test-verbose  |   6 +-
 22 files changed, 217 insertions(+), 278 deletions(-)

-- 
2.11.0

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


[PATCH 3/9] test: remove unused test_external and test_external_without_stderr

2017-02-26 Thread Jani Nikula
They've been unused since their introduction in commit 0083854b1204
("Copy test framework from Git"), only causing maintenance burden.
---
 test/test-lib.sh | 59 
 1 file changed, 59 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index 2ccb62eec122..218a06527f88 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -963,65 +963,6 @@ test_expect_code () {
fi
 }
 
-# test_external runs external test scripts that provide continuous
-# test output about their progress, and succeeds/fails on
-# zero/non-zero exit code.  It outputs the test output on stdout even
-# in non-verbose mode, and announces the external script with "* run
-# : ..." before running it.  When providing relative paths, keep in
-# mind that all scripts run in "trash directory".
-# Usage: test_external description command arguments...
-# Example: test_external 'Perl API' perl ../path/to/test.pl
-test_external () {
-   test "$#" = 4 && { prereq=$1; shift; } || prereq=
-   test "$#" = 3 ||
-   error >&6 "bug in the test script: not 3 or 4 parameters to 
test_external"
-   test_subtest_name="$1"
-   shift
-   test_reset_state_
-   if ! test_skip "$test_subtest_name" "$@"
-   then
-   # Announce the script to reduce confusion about the
-   # test output that follows.
-   say_color "" " run $test_count: $descr ($*)"
-   # Run command; redirect its stderr to &4 as in
-   # test_run_, but keep its stdout on our stdout even in
-   # non-verbose mode.
-   "$@" 2>&4
-   if [ "$?" = 0 ]
-   then
-   test_ok_
-   else
-   test_failure_ "$@"
-   fi
-   fi
-}
-
-# Like test_external, but in addition tests that the command generated
-# no output on stderr.
-test_external_without_stderr () {
-   # The temporary file has no (and must have no) security
-   # implications.
-   tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
-   stderr="$tmp/git-external-stderr.$$.tmp"
-   test_external "$@" 4> "$stderr"
-   [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
-   test_subtest_name="no stderr: $1"
-   shift
-   if [ ! -s "$stderr" ]; then
-   rm "$stderr"
-   test_ok_
-   else
-   if [ "$verbose" = t ]; then
-   output=`echo; echo Stderr is:; cat "$stderr"`
-   else
-   output=
-   fi
-   # rm first in case test_failure exits.
-   rm "$stderr"
-   test_failure_ "$@" "$output"
-   fi
-}
-
 # This is not among top-level (test_expect_success)
 # but is a prefix that can be used in the test script, like:
 #
-- 
2.11.0

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


[PATCH 4/9] test: remove unused and no-op --long-tests parameter

2017-02-26 Thread Jani Nikula
It's been unused since its introduction in commit 0083854b1204 ("Copy
test framework from Git").
---
 test/test-lib.sh | 2 --
 1 file changed, 2 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index 218a06527f88..44c510517f97 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -117,8 +117,6 @@ do
debug=t; shift ;;

-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
immediate=t; shift ;;
-   
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
-   GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
-h|--h|--he|--hel|--help)
help=t; shift ;;
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-- 
2.11.0

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


[PATCH 1/9] test: remove unused regexp convenience variables

2017-02-26 Thread Jani Nikula
They've been unused since their introduction in commit 0083854b1204
("Copy test framework from Git").
---
 test/test-lib.sh | 9 -
 1 file changed, 9 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index d8e159437ca9..b136fb949ec1 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -93,15 +93,6 @@ unset GREP_OPTIONS
 # For emacsclient
 unset ALTERNATE_EDITOR
 
-# Convenience
-#
-# A regexp to match 5 and 40 hexdigits
-_x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
-_x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05"
-
-_x04='[0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
-_x32="$_x04$_x04$_x04$_x04$_x04$_x04$_x04$_x04"
-
 # Each test should start with something like this, after copyright notices:
 #
 # test_description='Description of this test...
-- 
2.11.0

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


[PATCH 2/9] test: remove unused filter functions

2017-02-26 Thread Jani Nikula
They've been unused since their introduction in commit 0083854b1204
("Copy test framework from Git").
---
 test/test-lib.sh | 27 ---
 1 file changed, 27 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index b136fb949ec1..2ccb62eec122 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -274,33 +274,6 @@ TEST_TMPDIR=$(mktemp -d 
"${TMPDIR:-/tmp}/notmuch-test-$$.XX")
 trap 'trap_exit' EXIT
 trap 'trap_signal' HUP INT TERM
 
-test_decode_color () {
-   sed -e 's/.\[1m//g' \
-   -e 's/.\[31m//g' \
-   -e 's/.\[32m//g' \
-   -e 's/.\[33m//g' \
-   -e 's/.\[34m//g' \
-   -e 's/.\[35m//g' \
-   -e 's/.\[36m//g' \
-   -e 's/.\[m//g'
-}
-
-q_to_nul () {
-   perl -pe 'y/Q/\000/'
-}
-
-q_to_cr () {
-   tr Q '\015'
-}
-
-append_cr () {
-   sed -e 's/$/Q/' | tr Q '\015'
-}
-
-remove_cr () {
-   tr '\015' Q | sed -e 's/Q$//'
-}
-
 # Generate a new message in the mail directory, with a unique message
 # ID and subject. The message is not added to the index.
 #
-- 
2.11.0

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


[PATCH 5/9] test: only accept short and long options, not silly in-betweens

2017-02-26 Thread Jani Nikula
It's not notmuch style to accept sloppy parameter names.
---
 test/test-lib.sh | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/test/test-lib.sh b/test/test-lib.sh
index 44c510517f97..0a486f4cde9a 100644
--- a/test/test-lib.sh
+++ b/test/test-lib.sh
@@ -113,15 +113,15 @@ unset ALTERNATE_EDITOR
 while test "$#" -ne 0
 do
case "$1" in
-   -d|--d|--de|--deb|--debu|--debug)
+   -d|--debug)
debug=t; shift ;;
-   
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
+   -i|--immediate)
immediate=t; shift ;;
-   -h|--h|--he|--hel|--help)
+   -h|--help)
help=t; shift ;;
-   -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+   -v|--verbose)
verbose=t; shift ;;
-   -q|--q|--qu|--qui|--quie|--quiet)
+   -q|--quiet)
quiet=t; shift ;;
--with-dashes)
with_dashes=t; shift ;;
@@ -130,7 +130,7 @@ do
--no-python)
# noop now...
shift ;;
-   --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
+   --valgrind)
valgrind=t; verbose=t; shift ;;
--tee)
shift ;; # was handled already
-- 
2.11.0

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


Re: [PATCH] test: fix tests for content-disposition

2017-02-26 Thread David Bremner
Mark Walters  writes:

> This fixes all tests for the recent addition of content-disposition to
> the structured format outputs of notmuch-show.
> ---
>
> Since Jani added the content-disposition as I wanted to use it from emacs 
> (thanks Jani!)
> I thought I should fix the tests.
>
> I don't know if it should be folded in to the main patch or applied
> separately. Either is fine with me.

Unfortunately this does not apply since 75bb23f74874e3820b0295d0a618045fc5f33417
___
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch


Re: v2 _notmuch_message_ensure_metadata exception handling

2017-02-26 Thread David Bremner
Jani Nikula  writes:

> On Sat, 25 Feb 2017, David Bremner  wrote:
>> I tried to address most of Jani's comments on v1 [1]. The bad news is
>> that the test is a bit delicate, it really does need the whole corpus.
>
> Too bad. I hope it's not too dependent on the environment and the phase
> of the Moon, etc.

We'll have to see. FWIW, the only problems I had were false positives,
i.e. passing when it should not.
>
> The series LGTM.

pushed to master
___
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] emacs: use (system-name) instead of system-name

2017-02-26 Thread David Bremner
Jani Nikula  writes:

> Fix the deprecation warning:
>
> In notmuch-maildir-fcc-make-uniq-maildir-id:
> emacs/notmuch-maildir-fcc.el:279:53:Warning: ‘system-name’ is an obsolete
> variable (as of 25.1); use (system-name) instead

pushed to master

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


Re: [PATCH 1/2] cli/show: list all filenames of a message in the formatted output

2017-02-26 Thread David Bremner
Jani Nikula  writes:

> Instead of just having the first filename for the message, list all
> duplicate filenames of the message as a list in the formatted
> outputs. This bumps the format version to 3.
>
> ---
>
> v2: fix tests, and fix bugs found by the added tests :)

series pushed to master
___
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] emacs: use (system-name) instead of system-name

2017-02-26 Thread Tomi Ollila
On Sun, Feb 26 2017, Jani Nikula  wrote:

> Fix the deprecation warning:
>
> In notmuch-maildir-fcc-make-uniq-maildir-id:
> emacs/notmuch-maildir-fcc.el:279:53:Warning: ‘system-name’ is an obsolete
> variable (as of 25.1); use (system-name) instead
>
> I've used (system-name) since at least 2011, so it must have been
> around quite a while.

It sure is. LGTM.

Tomi


> ---
>  emacs/notmuch-maildir-fcc.el | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/emacs/notmuch-maildir-fcc.el b/emacs/notmuch-maildir-fcc.el
> index a754b60c7ea3..777658ccfb4a 100644
> --- a/emacs/notmuch-maildir-fcc.el
> +++ b/emacs/notmuch-maildir-fcc.el
> @@ -276,7 +276,7 @@ If CREATE is non-nil then create the folder if necessary."
>  (defun notmuch-maildir-fcc-make-uniq-maildir-id ()
> (let* ((ftime (float-time))
> (microseconds (mod (* 100 ftime) 100))
> -   (hostname (notmuch-maildir-fcc-host-fixer system-name)))
> +   (hostname (notmuch-maildir-fcc-host-fixer (system-name
>   (setq notmuch-maildir-fcc-count (+ notmuch-maildir-fcc-count 1))
>   (format "%d.%d_%d_%d.%s"
>ftime
> -- 
> 2.11.0
>
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> https://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] emacs: use (system-name) instead of system-name

2017-02-26 Thread Jani Nikula
Fix the deprecation warning:

In notmuch-maildir-fcc-make-uniq-maildir-id:
emacs/notmuch-maildir-fcc.el:279:53:Warning: ‘system-name’ is an obsolete
variable (as of 25.1); use (system-name) instead

I've used (system-name) since at least 2011, so it must have been
around quite a while.
---
 emacs/notmuch-maildir-fcc.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/emacs/notmuch-maildir-fcc.el b/emacs/notmuch-maildir-fcc.el
index a754b60c7ea3..777658ccfb4a 100644
--- a/emacs/notmuch-maildir-fcc.el
+++ b/emacs/notmuch-maildir-fcc.el
@@ -276,7 +276,7 @@ If CREATE is non-nil then create the folder if necessary."
 (defun notmuch-maildir-fcc-make-uniq-maildir-id ()
(let* ((ftime (float-time))
  (microseconds (mod (* 100 ftime) 100))
- (hostname (notmuch-maildir-fcc-host-fixer system-name)))
+ (hostname (notmuch-maildir-fcc-host-fixer (system-name
  (setq notmuch-maildir-fcc-count (+ notmuch-maildir-fcc-count 1))
  (format "%d.%d_%d_%d.%s"
 ftime
-- 
2.11.0

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


Re: v2 _notmuch_message_ensure_metadata exception handling

2017-02-26 Thread Jani Nikula
On Sat, 25 Feb 2017, David Bremner  wrote:
> I tried to address most of Jani's comments on v1 [1]. The bad news is
> that the test is a bit delicate, it really does need the whole corpus.

Too bad. I hope it's not too dependent on the environment and the phase
of the Moon, etc.

> I did decide to follow the suggestion to make the _reopen function
> private for now. It would be nice if we could hide that complexity
> from library users, I guess we'll have to see.

It's easy enough to expose that later if need be.

The series LGTM.

BR,
Jani.

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


Re: [PATCH] lib: remove notmuch_query_{count, search}_{threads, messages}

2017-02-26 Thread Tomi Ollila
On Sat, Feb 25 2017, David Bremner  wrote:

> Jani Nikula  writes:
>
>> On Wed, 22 Feb 2017, David Bremner  wrote:
>>> These 4 functions were originally deprecated in notmuch 0.21, more
>>> than a year ago.
>>
>> This leaves the implementations of the functions as unused code behind.

I thought this was intentional as there were no LIBNOTMUCH_*_VERSION bump.

>
> oh oops.
>
>> How long until we can add them back with the same signature as the _st
>> versions, and deprecate the _st versions instead? ;)
>>
>
> I was thinking at least one release ;).

So, for 0.25 the non _st versions are back, _st versions as wrapper (or
some linking-time aliases?/?) for the non_st and n-year deprecation period
for the _st version (to not piss developers using the API again ;) ?

>
> d

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


Re: [PATCH 1/2] cli/show: list all filenames of a message in the formatted output

2017-02-26 Thread Tomi Ollila
On Sat, Feb 25 2017, Jani Nikula  wrote:

> Instead of just having the first filename for the message, list all
> duplicate filenames of the message as a list in the formatted
> outputs. This bumps the format version to 3.
>
> ---

Looks good to me. Tests pass.

Tomi


>
> v2: fix tests, and fix bugs found by the added tests :)
>
> I presume the UI could do fancy things with this to highlight messages
> with dupes better. I haven't quite figured out yet what that could be,
> but this seems like the right thing to do regardless.
> ---
>  devel/schemata   |  5 -
>  notmuch-client.h |  2 +-
>  notmuch-show.c   | 15 ++-
>  test/T070-insert.sh  |  2 +-
>  test/T160-json.sh| 10 +-
>  test/T170-sexp.sh| 10 +-
>  test/T190-multipart.sh   |  6 +++---
>  test/T220-reply.sh   |  2 +-
>  test/T340-maildir-sync.sh|  2 +-
>  test/T350-crypto.sh  | 14 +++---
>  test/T355-smime.sh   |  2 +-
>  test/T470-missing-headers.sh |  4 ++--
>  test/T510-thread-replies.sh  | 22 +++---
>  test/test-lib.sh |  2 +-
>  14 files changed, 57 insertions(+), 41 deletions(-)
>
> diff --git a/devel/schemata b/devel/schemata
> index 41dc4a60fff3..6dede7a453d7 100644
> --- a/devel/schemata
> +++ b/devel/schemata
> @@ -26,6 +26,9 @@ v1
>  v2
>  - Added the thread_summary.query field.
>  
> +v3
> +- Replaced message.filename string with a list of filenames.
> +
>  Common non-terminals
>  
>  
> @@ -59,7 +62,7 @@ message = {
>  # (format_message_sprinter)
>  id: messageid,
>  match:  bool,
> -filename:string,
> +filename:[string*],
>  timestamp:  unix_time, # date header as unix time
>  date_relative:  string,   # user-friendly timestamp
>  tags:   [string*],
> diff --git a/notmuch-client.h b/notmuch-client.h
> index d026e6004239..21b087980a17 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -145,7 +145,7 @@ chomp_newline (char *str)
>   * this.  New (required) map fields can be added without increasing
>   * this.
>   */
> -#define NOTMUCH_FORMAT_CUR 2
> +#define NOTMUCH_FORMAT_CUR 3
>  /* The minimum supported structured output format version.  Requests
>   * for format versions below this will return an error. */
>  #define NOTMUCH_FORMAT_MIN 1
> diff --git a/notmuch-show.c b/notmuch-show.c
> index 22fa655ad20d..ab4ea1c2bdc1 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -133,7 +133,20 @@ format_message_sprinter (sprinter_t *sp, 
> notmuch_message_t *message)
>  sp->boolean (sp, notmuch_message_get_flag (message, 
> NOTMUCH_MESSAGE_FLAG_EXCLUDED));
>  
>  sp->map_key (sp, "filename");
> -sp->string (sp, notmuch_message_get_filename (message));
> +if (notmuch_format_version >= 3) {
> + notmuch_filenames_t *filenames;
> +
> + sp->begin_list (sp);
> + for (filenames = notmuch_message_get_filenames (message);
> +  notmuch_filenames_valid (filenames);
> +  notmuch_filenames_move_to_next (filenames)) {
> + sp->string (sp, notmuch_filenames_get (filenames));
> + }
> + notmuch_filenames_destroy (filenames);
> + sp->end (sp);
> +} else {
> + sp->string (sp, notmuch_message_get_filename (message));
> +}
>  
>  sp->map_key (sp, "timestamp");
>  date = notmuch_message_get_date (message);
> diff --git a/test/T070-insert.sh b/test/T070-insert.sh
> index 3dd76737c530..9120debabf8c 100755
> --- a/test/T070-insert.sh
> +++ b/test/T070-insert.sh
> @@ -43,7 +43,7 @@ expected='[[[{
>   "id": "'"${gen_msg_id}"'",
>   "match": true,
>   "excluded": false,
> - "filename": "'"${cur_msg_filename}"'",
> + "filename": ["'"${cur_msg_filename}"'"],
>   "timestamp": 946728000,
>   "date_relative": "2000-01-01",
>   "tags": ["inbox","unread"],
> diff --git a/test/T160-json.sh b/test/T160-json.sh
> index b346f37ee471..099632b4a286 100755
> --- a/test/T160-json.sh
> +++ b/test/T160-json.sh
> @@ -5,16 +5,16 @@ test_description="--format=json output"
>  test_begin_subtest "Show message: json"
>  add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 
> 12:00:00 -\"" "[bcc]=\"test_suite+...@notmuchmail.org\"" 
> "[reply-to]=\"test_suite+repl...@notmuchmail.org\"" 
> "[body]=\"json-show-message\""
>  output=$(notmuch show --format=json "json-show-message")
> -test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": 
> true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", 
> \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": 
> [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", 
> \"From\": \"Notmuch Test Suite \", \"To\": 
> \"Notmuch Test Suite \", \"Bcc\": 
> \"test_suite+...@notmuchmail.org\", \"Reply-To\": 
> \"test_suite+repl...@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 
> +\"}, \"body