]> git.cworth.org Git - notmuch/commitdiff
emacs: Add new option notmuch-search-hide-excluded master
authorMohsin Kaleem <mohkale@kisara.moe>
Sun, 10 Mar 2024 18:57:41 +0000 (18:57 +0000)
committerDavid Bremner <david@tethera.net>
Sat, 6 Apr 2024 18:03:45 +0000 (15:03 -0300)
The new notmuch-search-hide-excluded option allows users to configure whether
to show or hide excluded messages (as determined by search.exclude_tags
in the local notmuch config file). It defaults to true for now to maintain
backwards-compatibility with how notmuch-{search,tree} already worked.

New commands notmuch-search-toggle-hide-excluded and
notmuch-tree-toggle-exclude have also been added. They toggle the value
of notmuch-search-hide-excluded for the search in the current search or
tree buffer. It's bound to "i" in the respective keymaps for these
modes.

Lastly I've amended some calls to notmuch-tree and notmuch-unthreaded
which didn't pass through the buffer local value of
notmuch-search-oldest-first (and now notmuch-search-exclude).
Examples of where I've done this include:
  + notmuch-jump-search
  + notmuch-tree-from-search-current-query
  + notmuch-unthreaded-from-search-current-query
  + notmuch-tree-from-search-thread

A new test file for Emacs has been added which covers the usage of the
new `notmuch-search-hide-excluded' option and interactively hiding or
showing mail with excluded tags. These test cover the basic usage of
the `notmuch-search-toggle-hide-excluded' command in notmuch-search,
notmuch-tree and notmuch-unthreaded searches. These tests also cover
the persistence of the current value of the hide-excluded mail option
as a user switches from between these different search commands.

[1]: id:87ilxlxsng.fsf@kisara.moe

Amended-by: db, fix indentation in T461-emacs-search-exclude.sh
177 files changed:
.gitignore
NEWS
bindings/Makefile.local
bindings/python-cffi/tests/conftest.py
bindings/python/notmuch/compat.py
bindings/python/notmuch/version.py
bindings/ruby/database.c
bindings/ruby/defs.h
bindings/ruby/directory.c
bindings/ruby/filenames.c
bindings/ruby/init.c
bindings/ruby/message.c
bindings/ruby/messages.c
bindings/ruby/query.c
bindings/ruby/tags.c
bindings/ruby/thread.c
compat/have_strcasestr.c
completion/notmuch-completion.bash
completion/zsh/_notmuch
configure
contrib/notmuch-mutt/README
contrib/notmuch-mutt/notmuch-mutt
debian/changelog
debian/control
debian/libnotmuch5.install [deleted file]
debian/libnotmuch5.symbols [deleted file]
debian/libnotmuch5t64.install [new file with mode: 0644]
debian/libnotmuch5t64.lintian-overrides [new file with mode: 0644]
debian/libnotmuch5t64.symbols [new file with mode: 0644]
debian/rules
debian/tests/control [new file with mode: 0644]
devel/emacs-keybindings.org
devel/notmuch-web/nmweb.py
devel/notmuch-web/templates/show.html
devel/schemata
doc/Makefile.local
doc/conf.py
doc/elisp.py [new file with mode: 0644]
doc/man1/notmuch-config.rst
doc/man1/notmuch-git.rst
doc/man1/notmuch-search.rst
doc/man1/notmuch-show.rst
doc/man1/notmuch.rst
doc/man7/notmuch-search-terms.rst
doc/man7/notmuch-sexp-queries.rst
doc/notmuch-emacs.rst
emacs/notmuch-address.el
emacs/notmuch-emacs-mua
emacs/notmuch-hello.el
emacs/notmuch-jump.el
emacs/notmuch-lib.el
emacs/notmuch-mua.el
emacs/notmuch-parser.el
emacs/notmuch-print.el
emacs/notmuch-show.el
emacs/notmuch-tag.el
emacs/notmuch-tree.el
emacs/notmuch-wash.el
emacs/notmuch.el
lib/Makefile.local
lib/config.cc
lib/database-private.h
lib/database.cc
lib/index.cc
lib/lastmod-fp.cc [new file with mode: 0644]
lib/lastmod-fp.h [new file with mode: 0644]
lib/message-property.cc
lib/message.cc
lib/notmuch-private.h
lib/notmuch.h
lib/open.cc
lib/parse-sexp.cc
lib/query.cc
lib/regexp-fields.cc
lib/string-map.c
notmuch-client.h
notmuch-config.c
notmuch-git.py
notmuch-new.c
notmuch-show.c
notmuch.c
performance-test/README
performance-test/T02-tag.sh
performance-test/download/notmuch-email-corpus-0.5.tar.xz.asc [new file with mode: 0644]
performance-test/version.sh
test/README
test/T000-basic.sh
test/T010-help-test.sh
test/T030-config.sh
test/T040-setup.sh
test/T050-new.sh
test/T055-path-config.sh
test/T060-count.sh
test/T070-insert.sh
test/T080-search.sh
test/T081-sexpr-search.sh
test/T095-address.sh
test/T131-show-limiting.sh [new file with mode: 0755]
test/T150-tagging.sh
test/T160-json.sh
test/T220-reply.sh
test/T240-dump-restore.sh
test/T310-emacs.sh
test/T350-crypto.sh
test/T355-smime.sh
test/T356-protected-headers.sh
test/T360-symbol-hiding.sh
test/T390-python.sh
test/T391-python-cffi.sh
test/T392-python-cffi-notmuch.sh
test/T395-ruby.sh
test/T410-argument-parsing.sh
test/T450-emacs-show.sh
test/T460-emacs-tree.sh
test/T461-emacs-search-exclude.sh [new file with mode: 0755]
test/T480-hex-escaping.sh
test/T490-parse-time-string.sh
test/T520-show.sh
test/T550-db-features.sh
test/T560-lib-error.sh
test/T566-lib-message.sh
test/T570-revision-tracking.sh
test/T590-libconfig.sh
test/T592-thread-breakage.sh
test/T610-message-property.sh
test/T700-reindex.sh
test/T710-message-id.sh
test/T760-as-text.sh [new file with mode: 0755]
test/T800-asan.sh
test/T810-tsan.sh [new file with mode: 0755]
test/T810-tsan.suppressions [new file with mode: 0644]
test/T850-git.sh
test/corpora/crypto/basic-encrypted.eml
test/corpora/crypto/encrypted-rfc822-attachment
test/corpora/crypto/encrypted-signed.eml
test/corpora/indexing/PATCH-1-2-system_data_types.7-srcfix.txt:2,S [new file with mode: 0644]
test/corpora/indexing/fake-pdf:2,S [new file with mode: 0644]
test/corpora/indexing/mbox-attachment.eml [deleted file]
test/corpora/insert/mbox-attachment.eml [new file with mode: 0644]
test/corpora/mangling/mixed-up.eml
test/corpora/protected-headers/double-wrapped-with-phony-protected-header.eml
test/corpora/protected-headers/encrypted-message-with-forwarded-attachment.eml
test/corpora/protected-headers/encrypted-signed-not-masked.eml
test/corpora/protected-headers/encrypted-signed.eml
test/corpora/protected-headers/misplaced-protected-header.eml
test/corpora/protected-headers/nested-rfc822-message.eml
test/corpora/protected-headers/no-protected-header-attribute.eml
test/corpora/protected-headers/phony-protected-header-bad-encryption.eml
test/corpora/protected-headers/protected-header.eml
test/corpora/protected-headers/protected-with-legacy-display.eml
test/corpora/protected-headers/signed-protected-header.eml
test/corpora/protected-headers/simple-signed-mail.eml
test/corpora/protected-headers/subjectless-protected-header.eml
test/corpora/protected-headers/wrapped-protected-header.eml
test/emacs-exclude.expected-output/notmuch-search-tag-inbox-with-excluded [new file with mode: 0644]
test/emacs-exclude.expected-output/notmuch-search-tag-inbox-without-excluded [new file with mode: 0644]
test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-with-excluded [new file with mode: 0644]
test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-without-excluded [new file with mode: 0644]
test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-with-excluded [new file with mode: 0644]
test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-without-excluded [new file with mode: 0644]
test/emacs-tree.expected-output/inbox-outline [new file with mode: 0644]
test/emacs-tree.expected-output/notmuch-tree-tag-inbox-oldest-first [new file with mode: 0644]
test/export-dirs.sh
test/gnupg-secret-key.NOTE [deleted file]
test/gnupg-secret-key.asc [deleted file]
test/notmuch-test
test/openpgp4-secret-key.asc [new file with mode: 0644]
test/openpgp4-secret-key.asc.NOTE [new file with mode: 0644]
test/setup.expected-output/config-with-comments
test/test-lib-common.sh
test/test-lib-emacs.sh
test/test-lib.el
test/test-lib.sh
util/xapian-extra.h [new file with mode: 0644]
version.txt
vim/README
vim/notmuch.txt

index f94d1480c1f91d5ff64e8a0f746f4f79de19b839..eda6d9cff7473613aca1e36d54fb4dd5e8872a2c 100644 (file)
@@ -21,3 +21,4 @@
 /bindings/python-cffi/_notmuch_config.py
 TAGS
 tags
 /bindings/python-cffi/_notmuch_config.py
 TAGS
 tags
+__pycache__
diff --git a/NEWS b/NEWS
index 1e0b6a6cf915a67e6882824fa6b58481d5a26788..cf8107f26362431549dc410cb8379de5c10221f1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,120 @@
-Notmuch 0.37 (UNRELEASED)
+Notmuch 0.38.3 (2024-03-09)
+===========================
+
+CLI
+---
+
+Fix a bug in configuration code that caused the notmuch command to
+erroneously report "Error: could not locate database" under some
+circumstances.
+
+Notmuch 0.38.2 (2023-12-01)
+===========================
+
+Library
+-------
+
+Make sorting of string maps lexicographic on (key,value) pairs. This
+avoids some test failures due to variation in message property output
+order.
+
+Emacs
+-----
+
+Avoid extra separators after the last address in `notmuch-emacs-mua`.
+
+
+Notmuch 0.38.1 (2023-10-26)
+===========================
+
+CLI
+---
+
+Report parse errors in config files.
+
+Emacs
+-----
+
+Fix image toggling for Emacs >= 29.1.
+
+notmuch-mutt
+------------
+
+Fix syntax error in script.
+
+Notmuch 0.38 (2023-09-12)
+=========================
+
+General
+-------
+
+Support relative lastmod queries (see notmuch-sexp-queries(7) and
+notmuch-search-terms(7) for details).
+
+Support indexing of designated attachments as text (see
+notmuch-config(1) for details).
+
+CLI
+---
+
+Add options --offset and --limit to notmuch-show(1).
+
+Emacs
+-----
+
+New commands notmuch-search-edit-search and notmuch-tree-edit-search.
+
+Introduce notmuch-tree-outline-mode.
+
+Some compatibility fixes for Emacs 29. At least one issue (hiding
+images) remains in 0.38.
+
+Support completion when piping to external command.
+
+Fix regression in updating tag display introduced by 0.37.
+
+Library
+-------
+
+Fix bug creating database when database.path is not set.
+
+Incremental performance improvements for message deletion.
+
+Catch Xapian exceptions when deleting messages.
+
+Sync removed message properties to the database.
+
+Replace use of thread-unsafe Query::MatchAll in the infix query
+parser.
+
+Notmuch-Mutt
+------------
+
+Be more careful when clearing the results directory.
+
+Ruby
+----
+
+Use `database_open_with_config`, and provide compatible path search
+semantics.
+
+Bugfix for query.get_sort
+
+Test Suite
+----------
+
+Support testing installed version of notmuch.
+
+Adapt to some breaking changes in glib handling of init files.
+
+Replace OpenPGP key used in test suite.
+
+Performance Tests
+-----------------
+
+Update signatures for performance test corpus.
+
+Notmuch 0.37 (2022-08-21)
 =========================
 
 Library
 =========================
 
 Library
@@ -42,6 +158,10 @@ with large messages and threads" in the notmuch-emacs documentation).
 Allow the user to select (with '%') a different duplicate message file
 to display.
 
 Allow the user to select (with '%') a different duplicate message file
 to display.
 
+Use `message-dont-reply-to-names` in `notmuch-message-mode`.
+
+Support custom header-line format for notmuch-show mode.
+
 Notmuch 0.36 (2022-04-25)
 =========================
 
 Notmuch 0.36 (2022-04-25)
 =========================
 
@@ -50,7 +170,7 @@ Library
 
 Add the `sexp` prefix to the infix (traditional) query parser. This
 allows specific subqueries to be parsed by the sexp parser (with
 
 Add the `sexp` prefix to the infix (traditional) query parser. This
 allows specific subqueries to be parsed by the sexp parser (with
-appropropriate quoting). See `notmuch-search-terms(7)` for details.
+appropriate quoting). See `notmuch-search-terms(7)` for details.
 
 Add another heuristic to regexp fields to prevent phrase parsing of
 bracketed sub-expressions.
 
 Add another heuristic to regexp fields to prevent phrase parsing of
 bracketed sub-expressions.
@@ -72,7 +192,7 @@ the database.
 Documentation
 -------------
 
 Documentation
 -------------
 
-Reorganize documention for `notmuch-config`. Add a few links from
+Reorganize documentation for `notmuch-config`. Add a few links from
 other man pages.
 
 Emacs
 other man pages.
 
 Emacs
@@ -119,7 +239,7 @@ Fix some small memory leaks in `notmuch_database_open_with_config`.
 CLI
 ---
 
 CLI
 ---
 
-Improve handling of leading/trailing punctation and space for
+Improve handling of leading/trailing punctuation and space for
 configuration lists.
 
 Only ignore `.notmuch` at the top level in `notmuch new`.
 configuration lists.
 
 Only ignore `.notmuch` at the top level in `notmuch new`.
@@ -138,7 +258,7 @@ lazily.
 Don't add space to completion candidates, improves compatibility with
 third party completion frameworks.
 
 Don't add space to completion candidates, improves compatibility with
 third party completion frameworks.
 
-Make citation formating more robust against whitespace.
+Make citation formatting more robust against whitespace.
 
 Use `--excludes=false` when generating the 'All tags' section.
 
 
 Use `--excludes=false` when generating the 'All tags' section.
 
@@ -539,7 +659,7 @@ Notmuch 0.31.2 (2020-11-08)
 Build
 -----
 
 Build
 -----
 
-Catch one more occurence of "version" in the build system, which
+Catch one more occurrence of "version" in the build system, which
 caused the file to be regenerated in the release tarball.
 
 Notmuch 0.31.1 (2020-11-08)
 caused the file to be regenerated in the release tarball.
 
 Notmuch 0.31.1 (2020-11-08)
index 7b10af088abbb98716ae45c4cba35cf7a50ffeb2..9875123ab106cc6a94f5d62ba4e29ea60f24e742 100644 (file)
@@ -34,3 +34,7 @@ CLEAN += $(patsubst %,$(dir)/ruby/%, \
 CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
 
 CLEAN += bindings/python-cffi/build $(dir)/python-cffi.stamp
 CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
 
 CLEAN += bindings/python-cffi/build $(dir)/python-cffi.stamp
+CLEAN += bindings/python-cffi/__pycache__
+
+DISTCLEAN += bindings/python-cffi/_notmuch_config.py \
+       bindings/python-cffi/notmuch2.egg-info
index 6835fd30f723509cd6235540d35deadfc838cfa7..fe90c7879d8ad7ef0babb85386d7c87c2706a47c 100644 (file)
@@ -43,7 +43,7 @@ def notmuch(maildir):
         env = os.environ.copy()
         env['NOTMUCH_CONFIG'] = str(cfg_fname)
         proc = subprocess.run(cmd,
         env = os.environ.copy()
         env['NOTMUCH_CONFIG'] = str(cfg_fname)
         proc = subprocess.run(cmd,
-                              timeout=5,
+                              timeout=120,
                               env=env)
         proc.check_returncode()
     return run
                               env=env)
         proc.check_returncode()
     return run
index c931329e96972237d5f380ba2270a9dcc2d28d56..4a94e05c805d1a9fc28d035fbde09f3b404ff202 100644 (file)
@@ -47,7 +47,10 @@ if sys.version_info[0] == 2:
 
         return value
 else:
 
         return value
 else:
-    from configparser import SafeConfigParser
+    from configparser import ConfigParser as SafeConfigParser
+
+    if not hasattr(SafeConfigParser, 'readfp'):   # py >= 3.12
+        SafeConfigParser.readfp = SafeConfigParser.read_file
 
     class Python3StringMixIn(object):
         def __str__(self):
 
     class Python3StringMixIn(object):
         def __str__(self):
index 591446261914ff51e021bce490219a4e830d2bd8..fd4152eef9ca772fff115b70860f8fb506c21ab0 100644 (file)
@@ -1,3 +1,3 @@
 # this file should be kept in sync with ../../../version
 # this file should be kept in sync with ../../../version
-__VERSION__ = '0.36'
+__VERSION__ = '0.38.3'
 SOVERSION = '5'
 SOVERSION = '5'
index 9c3dbd96f0b292f856c2ccca2448b8483503a568..ed224ef713bf1f1ed2319678038be5182563d38b 100644 (file)
@@ -58,40 +58,56 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
     notmuch_database_t *database;
     notmuch_status_t ret;
 
     notmuch_database_t *database;
     notmuch_status_t ret;
 
+    path = NULL;
+    create = 0;
+    mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
+
     /* Check arguments */
     /* Check arguments */
-    rb_scan_args (argc, argv, "11", &pathv, &hashv);
+    rb_scan_args (argc, argv, "02", &pathv, &hashv);
 
 
-    SafeStringValue (pathv);
-    path = RSTRING_PTR (pathv);
+    if (!NIL_P (pathv)) {
+       SafeStringValue (pathv);
+       path = RSTRING_PTR (pathv);
+    }
 
     if (!NIL_P (hashv)) {
 
     if (!NIL_P (hashv)) {
-       Check_Type (hashv, T_HASH);
-       create = RTEST (rb_hash_aref (hashv, ID2SYM (ID_db_create)));
-       modev = rb_hash_aref (hashv, ID2SYM (ID_db_mode));
-       if (NIL_P (modev))
-           mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
-       else if (!FIXNUM_P (modev))
-           rb_raise (rb_eTypeError, ":mode isn't a Fixnum");
-       else {
-           mode = FIX2INT (modev);
-           switch (mode) {
-           case NOTMUCH_DATABASE_MODE_READ_ONLY:
-           case NOTMUCH_DATABASE_MODE_READ_WRITE:
-               break;
-           default:
-               rb_raise ( rb_eTypeError, "Invalid mode");
+       VALUE rmode, rcreate;
+       VALUE kwargs[2];
+       static ID keyword_ids[2];
+
+       if (!keyword_ids[0]) {
+           keyword_ids[0] = rb_intern_const ("mode");
+           keyword_ids[1] = rb_intern_const ("create");
+       }
+
+       rb_get_kwargs (hashv, keyword_ids, 0, 2, kwargs);
+
+       rmode = kwargs[0];
+       rcreate = kwargs[1];
+
+       if (rmode != Qundef) {
+           if (!FIXNUM_P (rmode))
+               rb_raise (rb_eTypeError, ":mode isn't a Fixnum");
+           else {
+               mode = FIX2INT (rmode);
+               switch (mode) {
+               case NOTMUCH_DATABASE_MODE_READ_ONLY:
+               case NOTMUCH_DATABASE_MODE_READ_WRITE:
+                   break;
+               default:
+                   rb_raise ( rb_eTypeError, "Invalid mode");
+               }
            }
        }
            }
        }
-    } else {
-       create = 0;
-       mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
+       if (rcreate != Qundef)
+           create = RTEST (rcreate);
     }
 
     rb_check_typeddata (self, &notmuch_rb_database_type);
     if (create)
        ret = notmuch_database_create (path, &database);
     else
     }
 
     rb_check_typeddata (self, &notmuch_rb_database_type);
     if (create)
        ret = notmuch_database_create (path, &database);
     else
-       ret = notmuch_database_open (path, mode, &database);
+       ret = notmuch_database_open_with_config (path, mode, NULL, NULL, &database, NULL);
     notmuch_rb_status_raise (ret);
 
     DATA_PTR (self) = notmuch_rb_object_create (database, "notmuch_rb_database");
     notmuch_rb_status_raise (ret);
 
     DATA_PTR (self) = notmuch_rb_object_create (database, "notmuch_rb_database");
@@ -408,7 +424,7 @@ notmuch_rb_database_get_all_tags (VALUE self)
 
        rb_raise (notmuch_rb_eBaseError, "%s", msg);
     }
 
        rb_raise (notmuch_rb_eBaseError, "%s", msg);
     }
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
+    return notmuch_rb_tags_get (tags);
 }
 
 /*
 }
 
 /*
index e2541e8f8de30f6c828be3edbde0699d57760dcc..a2cb38c8a74425ed193144c2607b752210f603f5 100644 (file)
@@ -33,7 +33,6 @@ extern VALUE notmuch_rb_cThreads;
 extern VALUE notmuch_rb_cThread;
 extern VALUE notmuch_rb_cMessages;
 extern VALUE notmuch_rb_cMessage;
 extern VALUE notmuch_rb_cThread;
 extern VALUE notmuch_rb_cMessages;
 extern VALUE notmuch_rb_cMessage;
-extern VALUE notmuch_rb_cTags;
 
 extern VALUE notmuch_rb_eBaseError;
 extern VALUE notmuch_rb_eDatabaseError;
 
 extern VALUE notmuch_rb_eBaseError;
 extern VALUE notmuch_rb_eDatabaseError;
@@ -48,8 +47,6 @@ extern VALUE notmuch_rb_eUnbalancedFreezeThawError;
 extern VALUE notmuch_rb_eUnbalancedAtomicError;
 
 extern ID ID_call;
 extern VALUE notmuch_rb_eUnbalancedAtomicError;
 
 extern ID ID_call;
-extern ID ID_db_create;
-extern ID ID_db_mode;
 
 /* RSTRING_PTR() is new in ruby-1.9 */
 #if !defined(RSTRING_PTR)
 
 /* RSTRING_PTR() is new in ruby-1.9 */
 #if !defined(RSTRING_PTR)
@@ -59,7 +56,6 @@ extern ID ID_db_mode;
 extern const rb_data_type_t notmuch_rb_object_type;
 extern const rb_data_type_t notmuch_rb_database_type;
 extern const rb_data_type_t notmuch_rb_directory_type;
 extern const rb_data_type_t notmuch_rb_object_type;
 extern const rb_data_type_t notmuch_rb_database_type;
 extern const rb_data_type_t notmuch_rb_directory_type;
-extern const rb_data_type_t notmuch_rb_filenames_type;
 extern const rb_data_type_t notmuch_rb_query_type;
 extern const rb_data_type_t notmuch_rb_threads_type;
 extern const rb_data_type_t notmuch_rb_thread_type;
 extern const rb_data_type_t notmuch_rb_query_type;
 extern const rb_data_type_t notmuch_rb_threads_type;
 extern const rb_data_type_t notmuch_rb_thread_type;
@@ -92,9 +88,6 @@ extern const rb_data_type_t notmuch_rb_tags_type;
 #define Data_Get_Notmuch_Directory(obj, ptr) \
     Data_Get_Notmuch_Object ((obj), &notmuch_rb_directory_type, (ptr))
 
 #define Data_Get_Notmuch_Directory(obj, ptr) \
     Data_Get_Notmuch_Object ((obj), &notmuch_rb_directory_type, (ptr))
 
-#define Data_Get_Notmuch_FileNames(obj, ptr) \
-    Data_Get_Notmuch_Object ((obj), &notmuch_rb_filenames_type, (ptr))
-
 #define Data_Get_Notmuch_Query(obj, ptr) \
     Data_Get_Notmuch_Object ((obj), &notmuch_rb_query_type, (ptr))
 
 #define Data_Get_Notmuch_Query(obj, ptr) \
     Data_Get_Notmuch_Object ((obj), &notmuch_rb_query_type, (ptr))
 
@@ -226,10 +219,7 @@ notmuch_rb_directory_get_child_directories (VALUE self);
 
 /* filenames.c */
 VALUE
 
 /* filenames.c */
 VALUE
-notmuch_rb_filenames_destroy (VALUE self);
-
-VALUE
-notmuch_rb_filenames_each (VALUE self);
+notmuch_rb_filenames_get (notmuch_filenames_t *fnames);
 
 /* query.c */
 VALUE
 
 /* query.c */
 VALUE
@@ -370,10 +360,7 @@ notmuch_rb_message_thaw (VALUE self);
 
 /* tags.c */
 VALUE
 
 /* tags.c */
 VALUE
-notmuch_rb_tags_destroy (VALUE self);
-
-VALUE
-notmuch_rb_tags_each (VALUE self);
+notmuch_rb_tags_get (notmuch_tags_t *tags);
 
 /* init.c */
 void
 
 /* init.c */
 void
index 910f0a99f238239f2c5717b2a85b2cbca190bcf5..f267d82f16976ee7fec41779c11d332ab7ac35ad 100644 (file)
@@ -87,7 +87,7 @@ notmuch_rb_directory_get_child_files (VALUE self)
 
     fnames = notmuch_directory_get_child_files (dir);
 
 
     fnames = notmuch_directory_get_child_files (dir);
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
+    return notmuch_rb_filenames_get (fnames);
 }
 
 /*
 }
 
 /*
@@ -106,5 +106,5 @@ notmuch_rb_directory_get_child_directories (VALUE self)
 
     fnames = notmuch_directory_get_child_directories (dir);
 
 
     fnames = notmuch_directory_get_child_directories (dir);
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
+    return notmuch_rb_filenames_get (fnames);
 }
 }
index 0dec19520b59b0b421df5c7a4cb03826e69d235d..60c3fb8b3b412e121d5cea76b46b11af15b25191 100644 (file)
@@ -1,53 +1,11 @@
-/* The Ruby interface to the notmuch mail library
- *
- * Copyright © 2010 Ali Polatel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see https://www.gnu.org/licenses/ .
- *
- * Author: Ali Polatel <alip@exherbo.org>
- */
-
 #include "defs.h"
 
 #include "defs.h"
 
-/*
- * call-seq: FILENAMES.destroy! => nil
- *
- * Destroys the filenames, freeing all resources allocated for it.
- */
-VALUE
-notmuch_rb_filenames_destroy (VALUE self)
-{
-    notmuch_rb_object_destroy (self, &notmuch_rb_filenames_type);
-
-    return Qnil;
-}
-
-/*
- * call-seq: FILENAMES.each {|item| block } => FILENAMES
- *
- * Calls +block+ once for each element in +self+, passing that element as a
- * parameter.
- */
 VALUE
 VALUE
-notmuch_rb_filenames_each (VALUE self)
+notmuch_rb_filenames_get (notmuch_filenames_t *fnames)
 {
 {
-    notmuch_filenames_t *fnames;
-
-    Data_Get_Notmuch_FileNames (self, fnames);
+    VALUE rb_array = rb_ary_new ();
 
     for (; notmuch_filenames_valid (fnames); notmuch_filenames_move_to_next (fnames))
 
     for (; notmuch_filenames_valid (fnames); notmuch_filenames_move_to_next (fnames))
-       rb_yield (rb_str_new2 (notmuch_filenames_get (fnames)));
-
-    return self;
+       rb_ary_push (rb_array, rb_str_new2 (notmuch_filenames_get (fnames)));
+    return rb_array;
 }
 }
index cd9f04cd734687da69d2a3b30a511c4f9a3f2c50..2d1994af22740c6640d91367b8d81b40283fe717 100644 (file)
 
 VALUE notmuch_rb_cDatabase;
 VALUE notmuch_rb_cDirectory;
 
 VALUE notmuch_rb_cDatabase;
 VALUE notmuch_rb_cDirectory;
-VALUE notmuch_rb_cFileNames;
 VALUE notmuch_rb_cQuery;
 VALUE notmuch_rb_cThreads;
 VALUE notmuch_rb_cThread;
 VALUE notmuch_rb_cMessages;
 VALUE notmuch_rb_cMessage;
 VALUE notmuch_rb_cQuery;
 VALUE notmuch_rb_cThreads;
 VALUE notmuch_rb_cThread;
 VALUE notmuch_rb_cMessages;
 VALUE notmuch_rb_cMessage;
-VALUE notmuch_rb_cTags;
 
 VALUE notmuch_rb_eBaseError;
 VALUE notmuch_rb_eDatabaseError;
 
 VALUE notmuch_rb_eBaseError;
 VALUE notmuch_rb_eDatabaseError;
@@ -43,8 +41,6 @@ VALUE notmuch_rb_eUnbalancedFreezeThawError;
 VALUE notmuch_rb_eUnbalancedAtomicError;
 
 ID ID_call;
 VALUE notmuch_rb_eUnbalancedAtomicError;
 
 ID ID_call;
-ID ID_db_create;
-ID ID_db_mode;
 
 const rb_data_type_t notmuch_rb_object_type = {
     .wrap_struct_name = "notmuch_object",
 
 const rb_data_type_t notmuch_rb_object_type = {
     .wrap_struct_name = "notmuch_object",
@@ -65,13 +61,11 @@ const rb_data_type_t notmuch_rb_object_type = {
 
 define_type (database);
 define_type (directory);
 
 define_type (database);
 define_type (directory);
-define_type (filenames);
 define_type (query);
 define_type (threads);
 define_type (thread);
 define_type (messages);
 define_type (message);
 define_type (query);
 define_type (threads);
 define_type (thread);
 define_type (messages);
 define_type (message);
-define_type (tags);
 
 /*
  * Document-module: Notmuch
 
 /*
  * Document-module: Notmuch
@@ -86,13 +80,11 @@ define_type (tags);
  * the user:
  *
  * - Notmuch::Database
  * the user:
  *
  * - Notmuch::Database
- * - Notmuch::FileNames
  * - Notmuch::Query
  * - Notmuch::Threads
  * - Notmuch::Messages
  * - Notmuch::Thread
  * - Notmuch::Message
  * - Notmuch::Query
  * - Notmuch::Threads
  * - Notmuch::Messages
  * - Notmuch::Thread
  * - Notmuch::Message
- * - Notmuch::Tags
  */
 
 void
  */
 
 void
@@ -101,8 +93,6 @@ Init_notmuch (void)
     VALUE mod;
 
     ID_call = rb_intern ("call");
     VALUE mod;
 
     ID_call = rb_intern ("call");
-    ID_db_create = rb_intern ("create");
-    ID_db_mode = rb_intern ("mode");
 
     mod = rb_define_module ("Notmuch");
 
 
     mod = rb_define_module ("Notmuch");
 
@@ -297,17 +287,6 @@ Init_notmuch (void)
     rb_define_method (notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); /* in directory.c */
     rb_define_method (notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); /* in directory.c */
 
     rb_define_method (notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); /* in directory.c */
     rb_define_method (notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); /* in directory.c */
 
-    /*
-     * Document-class: Notmuch::FileNames
-     *
-     * Notmuch file names
-     */
-    notmuch_rb_cFileNames = rb_define_class_under (mod, "FileNames", rb_cObject);
-    rb_undef_method (notmuch_rb_cFileNames, "initialize");
-    rb_define_method (notmuch_rb_cFileNames, "destroy!", notmuch_rb_filenames_destroy, 0); /* in filenames.c */
-    rb_define_method (notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); /* in filenames.c */
-    rb_include_module (notmuch_rb_cFileNames, rb_mEnumerable);
-
     /*
      * Document-class: Notmuch::Query
      *
     /*
      * Document-class: Notmuch::Query
      *
@@ -395,15 +374,4 @@ Init_notmuch (void)
     rb_define_method (notmuch_rb_cMessage, "tags_to_maildir_flags", notmuch_rb_message_tags_to_maildir_flags, 0); /* in message.c */
     rb_define_method (notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); /* in message.c */
     rb_define_method (notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); /* in message.c */
     rb_define_method (notmuch_rb_cMessage, "tags_to_maildir_flags", notmuch_rb_message_tags_to_maildir_flags, 0); /* in message.c */
     rb_define_method (notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); /* in message.c */
     rb_define_method (notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); /* in message.c */
-
-    /*
-     * Document-class: Notmuch::Tags
-     *
-     * Notmuch tags
-     */
-    notmuch_rb_cTags = rb_define_class_under (mod, "Tags", rb_cObject);
-    rb_undef_method (notmuch_rb_cTags, "initialize");
-    rb_define_method (notmuch_rb_cTags, "destroy!", notmuch_rb_tags_destroy, 0); /* in tags.c */
-    rb_define_method (notmuch_rb_cTags, "each", notmuch_rb_tags_each, 0); /* in tags.c */
-    rb_include_module (notmuch_rb_cTags, rb_mEnumerable);
 }
 }
index f45c95cc5051d8475920c5a59bf07706e829e0be..13c182f6549481b0866fb1789e25e8d874ac8b69 100644 (file)
@@ -120,7 +120,7 @@ notmuch_rb_message_get_filenames (VALUE self)
 
     fnames = notmuch_message_get_filenames (message);
 
 
     fnames = notmuch_message_get_filenames (message);
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
+    return notmuch_rb_filenames_get (fnames);
 }
 
 /*
 }
 
 /*
@@ -221,7 +221,7 @@ notmuch_rb_message_get_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
+    return notmuch_rb_tags_get (tags);
 }
 
 /*
 }
 
 /*
index ca5b10d04b09702629eddbeb1eb217bef84a4274..6369d0523008b6dadda38bc58cde3c8c908badf5 100644 (file)
@@ -71,5 +71,5 @@ notmuch_rb_messages_collect_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
+    return notmuch_rb_tags_get (tags);
 }
 }
index 8a2b4d3d48350e6b37ea9de73d86927ddb80e301..077def02f63021336de66d2c8c8e68edf1b4e6c4 100644 (file)
@@ -45,7 +45,7 @@ notmuch_rb_query_get_sort (VALUE self)
 
     Data_Get_Notmuch_Query (self, query);
 
 
     Data_Get_Notmuch_Query (self, query);
 
-    return FIX2INT (notmuch_query_get_sort (query));
+    return INT2FIX (notmuch_query_get_sort (query));
 }
 
 /*
 }
 
 /*
index 2af85e36598220f1cb93e806a8080ed2c3a3b862..b64874d1d4f441aabe8851338633871e8018886d 100644 (file)
@@ -1,56 +1,13 @@
-/* The Ruby interface to the notmuch mail library
- *
- * Copyright © 2010, 2011 Ali Polatel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see https://www.gnu.org/licenses/ .
- *
- * Author: Ali Polatel <alip@exherbo.org>
- */
-
 #include "defs.h"
 
 #include "defs.h"
 
-/*
- * call-seq: TAGS.destroy! => nil
- *
- * Destroys the tags, freeing all resources allocated for it.
- */
-VALUE
-notmuch_rb_tags_destroy (VALUE self)
-{
-    notmuch_rb_object_destroy (self, &notmuch_rb_tags_type);
-
-    return Qnil;
-}
-
-/*
- * call-seq: TAGS.each {|item| block } => TAGS
- *
- * Calls +block+ once for each element in +self+, passing that element as a
- * parameter.
- */
 VALUE
 VALUE
-notmuch_rb_tags_each (VALUE self)
+notmuch_rb_tags_get (notmuch_tags_t *tags)
 {
 {
-    const char *tag;
-    notmuch_tags_t *tags;
-
-    Data_Get_Notmuch_Tags (self, tags);
+    VALUE rb_array = rb_ary_new ();
 
     for (; notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) {
 
     for (; notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) {
-       tag = notmuch_tags_get (tags);
-       rb_yield (rb_str_new2 (tag));
+       const char *tag = notmuch_tags_get (tags);
+       rb_ary_push (rb_array, rb_str_new2 (tag));
     }
     }
-
-    return self;
+    return rb_array;
 }
 }
index 7cb2a3dcc6ebeacdd5c4c37b726a53056c436a5c..b20ed89376f802626d5cb4b0d847b020c18de196 100644 (file)
@@ -204,5 +204,5 @@ notmuch_rb_thread_get_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
+    return notmuch_rb_tags_get (tags);
 }
 }
index 3cd1838d950bd30c6239053a09d2a8f401f8b537..8e004572dbf04865f538ba8d051b1745ae2fd495 100644 (file)
@@ -1,5 +1,6 @@
 #define _GNU_SOURCE
 #define _GNU_SOURCE
-#include <strings.h>
+#include <strings.h> /* strcasecmp() in POSIX */
+#include <string.h> /* strcasecmp() in *BSD */
 
 int
 main ()
 
 int
 main ()
index 0022b54bff5df41765aecdd640484a6dd53b5e5f..3748846edf8392ef80403bf352e0dd9318a80854 100644 (file)
@@ -530,7 +530,7 @@ _notmuch_show()
     ! $split &&
     case "${cur}" in
        -*)
     ! $split &&
     case "${cur}" in
        -*)
-           local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html ${_notmuch_shared_options}"
+           local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html --limit= --offset= ${_notmuch_shared_options}"
            compopt -o nospace
            COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
            ;;
            compopt -o nospace
            COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
            ;;
index e207d90b72020f0a94fa46c72702a34a6a1ddc35..0bdd7f772a7ae9be4f85a2b31bb1dc65d91a6864 100644 (file)
@@ -245,6 +245,8 @@ _notmuch_show() {
     '--exclude=[respect excluded tags setting]:exclude tags:(true false)' \
     '--body=[output body]:output body content:(true false)' \
     '--include-html[include text/html parts in the output]' \
     '--exclude=[respect excluded tags setting]:exclude tags:(true false)' \
     '--body=[output body]:output body content:(true false)' \
     '--include-html[include text/html parts in the output]' \
+    '--limit=[limit the number of displayed results]:limit: ' \
+    '--offset=[skip displaying the first N results]:offset: ' \
     '*::search term:_notmuch_search_term'
 }
 
     '*::search term:_notmuch_search_term'
 }
 
index 5247e05a9754a9fa545cb576ea38e8711539d301..7afd08c7dac7822b74cf3315b5ba6adacbdb1de7 100755 (executable)
--- a/configure
+++ b/configure
@@ -422,6 +422,18 @@ else
 fi
 unset test_cmdline
 
 fi
 unset test_cmdline
 
+printf "C compiler supports thread sanitizer... "
+test_cmdline="${CC} ${CFLAGS} ${CPPFLAGS} -fsanitize=thread minimal.c ${LDFLAGS} -o minimal"
+if ${test_cmdline} >/dev/null 2>&1 && ./minimal
+then
+    printf "Yes.\n"
+    have_tsan=1
+else
+    printf "Nope, skipping those tests.\n"
+    have_tsan=0
+fi
+unset test_cmdline
+
 printf "Reading libnotmuch version from source... "
 cat > _libversion.c <<EOF
 #include <stdio.h>
 printf "Reading libnotmuch version from source... "
 cat > _libversion.c <<EOF
 #include <stdio.h>
@@ -525,9 +537,9 @@ EOF
        printf 'No.\nCould not make tempdir for testing session-key support.\n'
        errors=$((errors + 1))
     elif ${CC} ${CFLAGS} ${gmime_cflags} _check_session_keys.c ${gmime_ldflags} -o _check_session_keys \
        printf 'No.\nCould not make tempdir for testing session-key support.\n'
        errors=$((errors + 1))
     elif ${CC} ${CFLAGS} ${gmime_cflags} _check_session_keys.c ${gmime_ldflags} -o _check_session_keys \
-          && GNUPGHOME=${TEMP_GPG} gpg --batch --quiet --import < "$srcdir"/test/gnupg-secret-key.asc \
+          && GNUPGHOME=${TEMP_GPG} gpg --batch --quiet --import < "$srcdir"/test/openpgp4-secret-key.asc \
           && SESSION_KEY=$(GNUPGHOME=${TEMP_GPG} ./_check_session_keys) \
           && SESSION_KEY=$(GNUPGHOME=${TEMP_GPG} ./_check_session_keys) \
-          && [ $SESSION_KEY = 9:0BACD64099D1468AB07C796F0C0AC4851948A658A15B34E803865E9FC635F2F5 ]
+          && [ $SESSION_KEY = 9:496A0B6D15A5E7BA762FB8E5FE6DEE421D4D9BBFCEAD1CDD0CCF636D07ADE621 ]
     then
        printf "OK.\n"
     else
     then
        printf "OK.\n"
     else
@@ -541,8 +553,8 @@ version of GPGME.
 Please try to rebuild your version of GMime against a more recent
 version of GPGME (at least GPGME 1.8.0).
 EOF
 Please try to rebuild your version of GMime against a more recent
 version of GPGME (at least GPGME 1.8.0).
 EOF
-       if command -v gpgme-config >/dev/null; then
-           printf 'Your current GPGME development version is: %s\n' "$(gpgme-config --version)"
+       if GPGME_VERS="$(pkg-config --modversion gpgme || gpgme-config --version)"; then
+           printf 'Your current GPGME development version is: %s\n' "$GPGME_VERS"
        else
            printf 'You do not have the GPGME development libraries installed.\n'
        fi
        else
            printf 'You do not have the GPGME development libraries installed.\n'
        fi
@@ -670,7 +682,7 @@ int main () {
     body = GMIME_MULTIPART_ENCRYPTED(g_mime_message_get_mime_part (g_mime_parser_construct_message (parser, NULL)));
     if (body == NULL) return !!        fprintf (stderr, "did not find a multipart/encrypted message\n");
 
     body = GMIME_MULTIPART_ENCRYPTED(g_mime_message_get_mime_part (g_mime_parser_construct_message (parser, NULL)));
     if (body == NULL) return !!        fprintf (stderr, "did not find a multipart/encrypted message\n");
 
-    output = g_mime_multipart_encrypted_decrypt (body, GMIME_DECRYPT_NONE, "9:13607E4217515A70EC8DF9DBC16C5327B94577561D98AD1246FA8756659C7899", &result, &error);
+    output = g_mime_multipart_encrypted_decrypt (body, GMIME_DECRYPT_NONE, "9:9E1CDF53BBF794EA34F894B5B68E1E56FB015EA69F81D2A5EAB7F96C7B65783E", &result, &error);
     if (error || output == NULL) return !! fprintf (stderr, "decrypt failed\n");
 
     sig_list = g_mime_decrypt_result_get_signatures (result);
     if (error || output == NULL) return !! fprintf (stderr, "decrypt failed\n");
 
     sig_list = g_mime_decrypt_result_get_signatures (result);
@@ -691,7 +703,7 @@ EOF
        printf 'No.\nCould not make tempdir for testing signature verification when decrypting with session keys.\n'
        errors=$((errors + 1))
     elif ${CC} ${CFLAGS} ${gmime_cflags} _verify_sig_with_session_key.c ${gmime_ldflags} -o _verify_sig_with_session_key \
        printf 'No.\nCould not make tempdir for testing signature verification when decrypting with session keys.\n'
        errors=$((errors + 1))
     elif ${CC} ${CFLAGS} ${gmime_cflags} _verify_sig_with_session_key.c ${gmime_ldflags} -o _verify_sig_with_session_key \
-           && GNUPGHOME=${TEMP_GPG} gpg --batch --quiet --import < "$srcdir"/test/gnupg-secret-key.asc \
+           && GNUPGHOME=${TEMP_GPG} gpg --batch --quiet --import < "$srcdir"/test/openpgp4-secret-key.asc \
            && rm -f ${TEMP_GPG}/private-keys-v1.d/*.key
     then
        if GNUPGHOME=${TEMP_GPG} ./_verify_sig_with_session_key; then
            && rm -f ${TEMP_GPG}/private-keys-v1.d/*.key
     then
        if GNUPGHOME=${TEMP_GPG} ./_verify_sig_with_session_key; then
@@ -1590,8 +1602,9 @@ NOTMUCH_GMIME_VERIFY_WITH_SESSION_KEY=${gmime_verify_with_session_key}
 NOTMUCH_ZLIB_CFLAGS="${zlib_cflags}"
 NOTMUCH_ZLIB_LDFLAGS="${zlib_ldflags}"
 
 NOTMUCH_ZLIB_CFLAGS="${zlib_cflags}"
 NOTMUCH_ZLIB_LDFLAGS="${zlib_ldflags}"
 
-# Does the C compiler support the address sanitizer
+# Does the C compiler support the sanitizers
 NOTMUCH_HAVE_ASAN=${have_asan}
 NOTMUCH_HAVE_ASAN=${have_asan}
+NOTMUCH_HAVE_TSAN=${have_tsan}
 
 # do we have man pages?
 NOTMUCH_HAVE_MAN=$((have_sphinx))
 
 # do we have man pages?
 NOTMUCH_HAVE_MAN=$((have_sphinx))
index 26996c4ab2ccd1136b56e71e0c9d8c86c21a295a..c7520228782b2cacaf48e3b661c593013741e1ba 100644 (file)
@@ -39,8 +39,6 @@ To *run* notmuch-mutt you will need Perl with the following libraries:
   (Debian package: libmail-box-perl)
 - Mail::Header <https://metacpan.org/pod/Mail::Header>
   (Debian package: libmailtools-perl)
   (Debian package: libmail-box-perl)
 - Mail::Header <https://metacpan.org/pod/Mail::Header>
   (Debian package: libmailtools-perl)
-- String::ShellQuote <https://metacpan.org/pod/String::ShellQuote>
-  (Debian package: libstring-shellquote-perl)
 - Term::ReadLine::Gnu <https://metacpan.org/pod/Term::ReadLine::Gnu>
   (Debian package: libterm-readline-gnu-perl)
 
 - Term::ReadLine::Gnu <https://metacpan.org/pod/Term::ReadLine::Gnu>
   (Debian package: libterm-readline-gnu-perl)
 
index d1e2c084b4208f093f97a47e81169da28a65d9ad..b81252c809a8e3ed2fae56fd8e2bb14a6e56ed09 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # notmuch-mutt - notmuch (of a) helper for Mutt
 #
 #
 # notmuch-mutt - notmuch (of a) helper for Mutt
 #
-# Copyright: © 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
+# Copyright: Â© 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
 # License: GNU General Public License (GPL), version 3 or above
 #
 # See the bottom of this file for more documentation.
 # License: GNU General Public License (GPL), version 3 or above
 #
 # See the bottom of this file for more documentation.
@@ -13,11 +13,11 @@ use warnings;
 
 use File::Path;
 use File::Basename;
 
 use File::Path;
 use File::Basename;
+use File::Find;
 use Getopt::Long qw(:config no_getopt_compat);
 use Mail::Header;
 use Mail::Box::Maildir;
 use Pod::Usage;
 use Getopt::Long qw(:config no_getopt_compat);
 use Mail::Header;
 use Mail::Box::Maildir;
 use Pod::Usage;
-use String::ShellQuote;
 use Term::ReadLine;
 use Digest::SHA;
 
 use Term::ReadLine;
 use Digest::SHA;
 
@@ -26,9 +26,53 @@ my $xdg_cache_dir = "$ENV{HOME}/.cache";
 $xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
 my $cache_dir = "$xdg_cache_dir/notmuch/mutt";
 
 $xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
 my $cache_dir = "$xdg_cache_dir/notmuch/mutt";
 
+sub die_dir($$) {
+    my ($maildir, $error) = @_;
+    die "notmuch-mutt: search cache maildir $maildir $error\n".
+        "Please ensure that the notmuch-mutt search cache Maildir\n".
+        "contains no subfolders or real mail data, only symlinks to mail\n";
+}
+
+sub die_subdir($$$) {
+    my ($maildir, $subdir, $error) = @_;
+    die_dir($maildir, "subdir $subdir $error");
+}
 
 
-# create an empty maildir (if missing) or empty an existing maildir"
-sub empty_maildir($) {
+# check that the search cache maildir is that and not a real maildir
+# otherwise there could be data loss when the search cache is emptied
+sub check_search_cache_maildir($) {
+    my ($maildir) = (@_);
+
+    return unless -e $maildir;
+
+    -d $maildir or die_dir($maildir, 'is not a directory');
+
+    opendir(my $mdh, $maildir) or die_dir($maildir, "cannot be opened: $!");
+    my @contents = grep { !/^\.\.?$/ } readdir $mdh;
+    closedir $mdh;
+
+    my @required = ('cur', 'new', 'tmp');
+    foreach my $d (@required) {
+        -l "$maildir/$d" and die_dir($maildir, "contains symlink $d");
+        -e "$maildir/$d" or die_subdir($maildir, $d, 'is missing');
+        -d "$maildir/$d" or die_subdir($maildir, $d, 'is not a directory');
+        find(sub {
+            $_ eq '.' and return;
+            $_ eq '..' and return;
+            -l $_ or die_subdir($maildir, $d, "contains non-symlink $_");
+        }, "$maildir/$d");
+    }
+
+    my %required = map { $_ => 1 } @required;
+    foreach my $d (@contents) {
+        -l "$maildir/$d" and die_dir( $maildir, "contains symlink $d");
+        -d "$maildir/$d" or die_dir( $maildir, "contains non-directory $d");
+        exists($required{$d}) or die_dir( $maildir, "contains directory $d");
+    }
+}
+
+# create an empty search cache maildir (if missing) or empty existing one
+sub empty_search_cache_maildir($) {
     my ($maildir) = (@_);
     rmtree($maildir) if (-d $maildir);
     my $folder = new Mail::Box::Maildir(folder => $maildir,
     my ($maildir) = (@_);
     rmtree($maildir) if (-d $maildir);
     my $folder = new Mail::Box::Maildir(folder => $maildir,
@@ -46,7 +90,8 @@ sub search($$$) {
     push @args, "--duplicate=1" if $remove_dups;
     push @args, $query;
 
     push @args, "--duplicate=1" if $remove_dups;
     push @args, $query;
 
-    empty_maildir($maildir);
+    check_search_cache_maildir($maildir);
+    empty_search_cache_maildir($maildir);
     open my $pipe, '-|', @args or die "Running @args failed: $!\n";
     while (<$pipe>) {
        chomp;
     open my $pipe, '-|', @args or die "Running @args failed: $!\n";
     while (<$pipe>) {
        chomp;
@@ -121,21 +166,23 @@ sub thread_action($$@) {
 
     my $mid = get_message_id();
     if (! defined $mid) {
 
     my $mid = get_message_id();
     if (! defined $mid) {
-       empty_maildir($results_dir);
        die "notmuch-mutt: cannot find Message-Id, abort.\n";
     }
        die "notmuch-mutt: cannot find Message-Id, abort.\n";
     }
-    my $search_cmd = 'notmuch search --output=threads ' . shell_quote("id:$mid");
-    my $tid = `$search_cmd`;   # get thread id
-    chomp($tid);
 
 
-    search($results_dir, $remove_dups, $tid);
+    $mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
+    $mid =~ s/"/""""/g; # escape all double quote characters twice
+
+    search($results_dir, $remove_dups, qq{thread:"{id:""$mid""}"});
 }
 
 sub tag_action(@) {
     my $mid = get_message_id();
     defined $mid or die "notmuch-mutt: cannot find Message-Id, abort.\n";
 
 }
 
 sub tag_action(@) {
     my $mid = get_message_id();
     defined $mid or die "notmuch-mutt: cannot find Message-Id, abort.\n";
 
-    system("notmuch", "tag", @_, "--", "id:$mid");
+    $mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
+    $mid =~ s/"/""/g; # escape all double quote characters
+
+    system("notmuch", "tag", @_, "--", qq{id:"$mid"});
 }
 
 sub die_usage() {
 }
 
 sub die_usage() {
index 1c6f3586bf9c44d5d5489d9bc74a27da749f4352..1177f085e9b067446e718b04455c19932b14072d 100644 (file)
@@ -1,3 +1,106 @@
+notmuch (0.38.3-1) unstable; urgency=medium
+
+  * New upstream bugfix release
+  * Bug fix: "Recommends transitional package gnupg-agent instead of
+    gpg-agent", thanks to Andreas Metzler (Closes: #1064114).
+
+ -- David Bremner <bremner@debian.org>  Sat, 09 Mar 2024 23:13:07 -0400
+
+notmuch (0.38.2-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Rename libraries for 64-bit time_t transition.  Closes: #1063205
+
+ -- Benjamin Drung <bdrung@debian.org>  Wed, 28 Feb 2024 23:56:48 +0000
+
+notmuch (0.38.2-1) unstable; urgency=medium
+
+  * New upstream bugfix release
+
+ -- David Bremner <bremner@debian.org>  Fri, 01 Dec 2023 07:51:09 -0400
+
+notmuch (0.38.1-1) unstable; urgency=medium
+
+  * New upstream bugfix release
+
+ -- David Bremner <bremner@debian.org>  Thu, 26 Oct 2023 19:58:42 -0300
+
+notmuch (0.38.1~rc1-1) experimental; urgency=medium
+
+  * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org>  Thu, 12 Oct 2023 19:53:10 -0300
+
+notmuch (0.38.1~pre0-1) experimental; urgency=medium
+
+  * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org>  Sun, 01 Oct 2023 08:14:17 -0300
+
+notmuch (0.38-2) unstable; urgency=medium
+
+  * Restrict autopkgtests to amd64 and aarch64. There are failures in
+    remaining architectures, but the same tests pass at build time, so any
+    bugs are probably related to either the autopkgtest environment, or
+    the (new) upstream test runner for installed notmuch.
+
+ -- David Bremner <bremner@debian.org>  Wed, 13 Sep 2023 19:55:00 -0300
+
+notmuch (0.38-1) unstable; urgency=medium
+
+  * New upstream release
+  * Bug fix: "FTBFS: 6 tests failed.", thanks to Aurelien Jarno (Closes:
+    #1051111).
+  * Run most of upstream test suite as autopkgtests
+
+ -- David Bremner <bremner@debian.org>  Tue, 12 Sep 2023 08:33:24 -0300
+
+notmuch (0.38~rc2-1) experimental; urgency=medium
+
+  * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org>  Sun, 03 Sep 2023 09:10:24 -0300
+
+notmuch (0.38~rc1-1) experimental; urgency=medium
+
+  * New upstream release candidate
+  * Hopefully reduce/eliminate intermittent failures of T460 by
+    controlling Emacs native compilation.
+  * Disable T810-tsan on ppc64el
+
+ -- David Bremner <bremner@debian.org>  Sat, 26 Aug 2023 08:31:21 -0300
+
+notmuch (0.38~rc0-1) experimental; urgency=medium
+
+  * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org>  Thu, 24 Aug 2023 10:56:06 -0300
+
+notmuch (0.37-1) unstable; urgency=medium
+
+  * New upstream release.
+  * Build-depend on emacs-el to work around #1017698
+
+ -- David Bremner <bremner@debian.org>  Wed, 24 Aug 2022 09:12:19 -0700
+
+notmuch (0.37~rc0-3) experimental; urgency=medium
+
+  * Another no-change re-upload with binaries.
+
+ -- David Bremner <bremner@debian.org>  Sun, 14 Aug 2022 11:49:21 -0300
+
+notmuch (0.37~rc0-2) experimental; urgency=medium
+
+  * Binary upload for NEW (notmuch-git is a new binary package)
+
+ -- David Bremner <bremner@debian.org>  Sun, 14 Aug 2022 10:55:24 -0300
+
+notmuch (0.37~rc0-1) experimental; urgency=medium
+
+  * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org>  Sun, 14 Aug 2022 07:28:22 -0300
+
 notmuch (0.36-1) unstable; urgency=medium
 
   * New upstream release
 notmuch (0.36-1) unstable; urgency=medium
 
   * New upstream release
index 0ffe958c86b9916940d4326e7dc38797a567341c..4fded909a03ca5d4910c2cc8f1fee4f03795ebbe 100644 (file)
@@ -9,7 +9,7 @@ Build-Conflicts:
  gdb [ia64 mips mips64el hppa],
  gdb-minimal,
  ruby1.8,
  gdb [ia64 mips mips64el hppa],
  gdb-minimal,
  ruby1.8,
-Build-Depends:
+Build-Depends: dpkg-dev (>= 1.22.5),
  bash-completion (>=1.9.0~),
  debhelper-compat (= 13),
  dh-elpa (>= 1.3),
  bash-completion (>=1.9.0~),
  debhelper-compat (= 13),
  dh-elpa (>= 1.3),
@@ -19,6 +19,7 @@ Build-Depends:
  dpkg-dev (>= 1.17.14),
  dtach (>= 0.8) <!nocheck>,
  emacs-nox | emacs-gtk | emacs-lucid | emacs25-nox | emacs25 (>=25~) | emacs25-lucid (>=25~) | emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~),
  dpkg-dev (>= 1.17.14),
  dtach (>= 0.8) <!nocheck>,
  emacs-nox | emacs-gtk | emacs-lucid | emacs25-nox | emacs25 (>=25~) | emacs25-lucid (>=25~) | emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~),
+ emacs-el,
  gdb [!ia64 !mips !mips64el !kfreebsd-any !alpha !hppa] <!nocheck>,
  git <!nocheck>,
  gnupg <!nocheck>,
  gdb [!ia64 !mips !mips64el !kfreebsd-any !alpha !hppa] <!nocheck>,
  git <!nocheck>,
  gnupg <!nocheck>,
@@ -49,12 +50,12 @@ Rules-Requires-Root: no
 Package: notmuch
 Architecture: any
 Depends:
 Package: notmuch
 Architecture: any
 Depends:
- libnotmuch5 (= ${binary:Version}),
+ libnotmuch5t64 (= ${binary:Version}),
  ${misc:Depends},
  ${shlibs:Depends},
 Recommends:
  elpa-notmuch | notmuch-vim | notmuch-mutt | alot,
  ${misc:Depends},
  ${shlibs:Depends},
 Recommends:
  elpa-notmuch | notmuch-vim | notmuch-mutt | alot,
- gnupg-agent,
+ gpg-agent,
  gpgsm,
 Suggests:
  mailscripts,
  gpgsm,
 Suggests:
  mailscripts,
@@ -98,7 +99,10 @@ Description: thread-based email index, search and tagging
  .
  This package contains the HTML documentation
 
  .
  This package contains the HTML documentation
 
-Package: libnotmuch5
+Package: libnotmuch5t64
+Provides: ${t64:Provides}
+Replaces: libnotmuch5
+Breaks: libnotmuch5 (<< ${source:Version})
 Section: libs
 Architecture: any
 Depends:
 Section: libs
 Architecture: any
 Depends:
@@ -119,7 +123,7 @@ Package: libnotmuch-dev
 Section: libdevel
 Architecture: any
 Depends:
 Section: libdevel
 Architecture: any
 Depends:
- libnotmuch5 (= ${binary:Version}),
+ libnotmuch5t64 (= ${binary:Version}),
  ${misc:Depends},
 Description: thread-based email index, search and tagging (development)
  Notmuch is a system for indexing, searching, reading, and tagging
  ${misc:Depends},
 Description: thread-based email index, search and tagging (development)
  Notmuch is a system for indexing, searching, reading, and tagging
@@ -134,7 +138,7 @@ Package: python3-notmuch
 Architecture: all
 Section: python
 Depends:
 Architecture: all
 Section: python
 Depends:
- libnotmuch5 (>= ${source:Version}),
+ libnotmuch5t64 (>= ${source:Version}),
  ${misc:Depends},
  ${python3:Depends},
 Description: Python 3 legacy interface to the notmuch mail search and index library
  ${misc:Depends},
  ${python3:Depends},
 Description: Python 3 legacy interface to the notmuch mail search and index library
@@ -152,7 +156,7 @@ Package: python3-notmuch2
 Architecture: any
 Section: python
 Depends:
 Architecture: any
 Section: python
 Depends:
- libnotmuch5 (>= ${source:Version}),
+ libnotmuch5t64 (>= ${source:Version}),
  ${misc:Depends},
  ${python3:Depends},
  ${shlibs:Depends},
  ${misc:Depends},
  ${python3:Depends},
  ${shlibs:Depends},
@@ -226,7 +230,6 @@ Architecture: all
 Depends:
  libmail-box-perl,
  libmailtools-perl,
 Depends:
  libmail-box-perl,
  libmailtools-perl,
- libstring-shellquote-perl,
  libterm-readline-gnu-perl,
  notmuch (>= 0.4),
  ${misc:Depends},
  libterm-readline-gnu-perl,
  notmuch (>= 0.4),
  ${misc:Depends},
diff --git a/debian/libnotmuch5.install b/debian/libnotmuch5.install
deleted file mode 100644 (file)
index a513b47..0000000
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/*/libnotmuch.so.*
diff --git a/debian/libnotmuch5.symbols b/debian/libnotmuch5.symbols
deleted file mode 100644 (file)
index e6d2b7c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-libnotmuch.so.5 libnotmuch5 #MINVER#
-* Build-Depends-Package: libnotmuch-dev
- notmuch_built_with@Base 0.23~rc0
- notmuch_config_get@Base 0.32~rc0
- notmuch_config_get_bool@Base 0.32~rc0
- notmuch_config_get_pairs@Base 0.32~rc0
- notmuch_config_get_values@Base 0.32~rc0
- notmuch_config_get_values_string@Base 0.32~rc0
- notmuch_config_list_destroy@Base 0.23~rc0
- notmuch_config_list_key@Base 0.23~rc0
- notmuch_config_list_move_to_next@Base 0.23~rc0
- notmuch_config_list_valid@Base 0.23~rc0
- notmuch_config_list_value@Base 0.23~rc0
- notmuch_config_pairs_destroy@Base 0.32~rc0
- notmuch_config_pairs_key@Base 0.32~rc0
- notmuch_config_pairs_move_to_next@Base 0.32~rc0
- notmuch_config_pairs_valid@Base 0.32~rc0
- notmuch_config_pairs_value@Base 0.32~rc0
- notmuch_config_path@Base 0.32~rc0
- notmuch_config_set@Base 0.32~rc0
- notmuch_config_values_destroy@Base 0.32~rc0
- notmuch_config_values_get@Base 0.32~rc0
- notmuch_config_values_move_to_next@Base 0.32~rc0
- notmuch_config_values_start@Base 0.32~rc0
- notmuch_config_values_valid@Base 0.32~rc0
- notmuch_database_add_message@Base 0.3
- notmuch_database_begin_atomic@Base 0.9~rc1
- notmuch_database_close@Base 0.13~rc1
- notmuch_database_compact@Base 0.17~rc1
- notmuch_database_compact_db@Base 0.32~rc0
- notmuch_database_create@Base 0.3
- notmuch_database_create_verbose@Base 0.20~rc1
- notmuch_database_create_with_config@Base 0.32~rc0
- notmuch_database_destroy@Base 0.13~rc1
- notmuch_database_end_atomic@Base 0.9~rc1
- notmuch_database_find_message@Base 0.9~rc2
- notmuch_database_find_message_by_filename@Base 0.9~rc2
- notmuch_database_get_all_tags@Base 0.3
- notmuch_database_get_config@Base 0.23~rc0
- notmuch_database_get_config_list@Base 0.23~rc0
- notmuch_database_get_default_indexopts@Base 0.26~rc0
- notmuch_database_get_directory@Base 0.3
- notmuch_database_get_path@Base 0.3
- notmuch_database_get_revision@Base 0.21~rc1
- notmuch_database_get_version@Base 0.3
- notmuch_database_index_file@Base 0.26~rc0
- notmuch_database_load_config@Base 0.32~rc0
- notmuch_database_needs_upgrade@Base 0.3
- notmuch_database_open@Base 0.3
- notmuch_database_open_verbose@Base 0.20~rc1
- notmuch_database_open_with_config@Base 0.32~rc0
- notmuch_database_remove_message@Base 0.3
- notmuch_database_reopen@Base 0.32~rc0
- notmuch_database_set_config@Base 0.23~rc0
- notmuch_database_status_string@Base 0.20~rc1
- notmuch_database_upgrade@Base 0.3
- notmuch_directory_delete@Base 0.21~rc1
- notmuch_directory_destroy@Base 0.3
- notmuch_directory_get_child_directories@Base 0.3
- notmuch_directory_get_child_files@Base 0.3
- notmuch_directory_get_mtime@Base 0.3
- notmuch_directory_set_mtime@Base 0.3
- notmuch_filenames_destroy@Base 0.3
- notmuch_filenames_get@Base 0.3
- notmuch_filenames_move_to_next@Base 0.3
- notmuch_filenames_valid@Base 0.3
- notmuch_indexopts_destroy@Base 0.26~rc0
- notmuch_indexopts_get_decrypt_policy@Base 0.26~rc0
- notmuch_indexopts_set_decrypt_policy@Base 0.26~rc0
- notmuch_message_add_property@Base 0.23~rc0
- notmuch_message_add_tag@Base 0.3
- notmuch_message_count_files@Base 0.26~rc0
- notmuch_message_count_properties@Base 0.27~rc0
- notmuch_message_destroy@Base 0.3
- notmuch_message_freeze@Base 0.3
- notmuch_message_get_database@Base 0.27~rc0
- notmuch_message_get_date@Base 0.3
- notmuch_message_get_filename@Base 0.3
- notmuch_message_get_filenames@Base 0.5
- notmuch_message_get_flag@Base 0.3
- notmuch_message_get_flag_st@Base 0.31~rc0
- notmuch_message_get_header@Base 0.3
- notmuch_message_get_message_id@Base 0.3
- notmuch_message_get_properties@Base 0.23~rc0
- notmuch_message_get_property@Base 0.23~rc0
- notmuch_message_get_replies@Base 0.3
- notmuch_message_get_tags@Base 0.3
- notmuch_message_get_thread_id@Base 0.3
- notmuch_message_has_maildir_flag@Base 0.26~rc0
- notmuch_message_has_maildir_flag_st@Base 0.31~rc0
- notmuch_message_maildir_flags_to_tags@Base 0.5
- notmuch_message_properties_destroy@Base 0.23~rc0
- notmuch_message_properties_key@Base 0.23~rc0
- notmuch_message_properties_move_to_next@Base 0.23~rc0
- notmuch_message_properties_valid@Base 0.23~rc0
- notmuch_message_properties_value@Base 0.23~rc0
- notmuch_message_reindex@Base 0.26~rc0
- notmuch_message_remove_all_properties@Base 0.23~rc0
- notmuch_message_remove_all_properties_with_prefix@Base 0.26~rc0
- notmuch_message_remove_all_tags@Base 0.3
- notmuch_message_remove_property@Base 0.23~rc0
- notmuch_message_remove_tag@Base 0.3
- notmuch_message_set_flag@Base 0.3
- notmuch_message_tags_to_maildir_flags@Base 0.5
- notmuch_message_thaw@Base 0.3
- notmuch_messages_collect_tags@Base 0.3
- notmuch_messages_destroy@Base 0.3
- notmuch_messages_get@Base 0.3
- notmuch_messages_move_to_next@Base 0.3
- notmuch_messages_valid@Base 0.3
- notmuch_query_add_tag_exclude@Base 0.12~rc1
- notmuch_query_count_messages@Base 0.3
- notmuch_query_count_messages_st@Base 0.21~rc1
- notmuch_query_count_threads@Base 0.10~rc1
- notmuch_query_count_threads_st@Base 0.21~rc1
- notmuch_query_create@Base 0.3
- notmuch_query_create_with_syntax@Base 0.34~rc0
- notmuch_query_destroy@Base 0.3
- notmuch_query_get_database@Base 0.21~rc1
- notmuch_query_get_query_string@Base 0.4
- notmuch_query_get_sort@Base 0.4
- notmuch_query_search_messages@Base 0.3
- notmuch_query_search_messages_st@Base 0.20~rc1
- notmuch_query_search_threads@Base 0.3
- notmuch_query_search_threads_st@Base 0.20~rc1
- notmuch_query_set_omit_excluded@Base 0.13~rc1
- notmuch_query_set_sort@Base 0.3
- notmuch_status_to_string@Base 0.3
- notmuch_tags_destroy@Base 0.3
- notmuch_tags_get@Base 0.3
- notmuch_tags_move_to_next@Base 0.3
- notmuch_tags_valid@Base 0.3
- notmuch_thread_destroy@Base 0.3
- notmuch_thread_get_authors@Base 0.3
- notmuch_thread_get_matched_messages@Base 0.3
- notmuch_thread_get_messages@Base 0.16
- notmuch_thread_get_newest_date@Base 0.3
- notmuch_thread_get_oldest_date@Base 0.3
- notmuch_thread_get_subject@Base 0.3
- notmuch_thread_get_tags@Base 0.3
- notmuch_thread_get_thread_id@Base 0.3
- notmuch_thread_get_toplevel_messages@Base 0.3
- notmuch_thread_get_total_files@Base 0.26~rc0
- notmuch_thread_get_total_messages@Base 0.3
- notmuch_threads_destroy@Base 0.3
- notmuch_threads_get@Base 0.3
- notmuch_threads_move_to_next@Base 0.3
- notmuch_threads_valid@Base 0.3
- (c++)"typeinfo for Xapian::LogicError@Base" 0.6.1
- (c++)"typeinfo for Xapian::RuntimeError@Base" 0.6.1
- (c++)"typeinfo for Xapian::DocNotFoundError@Base" 0.6.1
- (c++)"typeinfo for Xapian::InvalidArgumentError@Base" 0.6.1
- (c++)"typeinfo for Xapian::Error@Base" 0.6.1
- (c++)"typeinfo for Xapian::DatabaseError@Base" 0.24~rc0
- (c++)"typeinfo for Xapian::DatabaseModifiedError@Base" 0.24~rc0
- (c++)"typeinfo for Xapian::DatabaseOpeningError@Base" 0.32~rc0
- (c++|optional=present with Xapian 1.4)"typeinfo for Xapian::QueryParserError@Base" 0.23~rc0
- (c++)"typeinfo name for Xapian::LogicError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::RuntimeError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::DocNotFoundError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::InvalidArgumentError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::Error@Base" 0.6.1
- (c++)"typeinfo name for Xapian::DatabaseError@Base" 0.24~rc0
- (c++)"typeinfo name for Xapian::DatabaseModifiedError@Base" 0.24~rc0
- (c++)"typeinfo name for Xapian::DatabaseOpeningError@Base" 0.32~rc0
- (c++|optional=present with Xapian 1.4)"typeinfo name for Xapian::QueryParserError@Base" 0.23~rc0
diff --git a/debian/libnotmuch5t64.install b/debian/libnotmuch5t64.install
new file mode 100644 (file)
index 0000000..a513b47
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/*/libnotmuch.so.*
diff --git a/debian/libnotmuch5t64.lintian-overrides b/debian/libnotmuch5t64.lintian-overrides
new file mode 100644 (file)
index 0000000..affb63b
--- /dev/null
@@ -0,0 +1 @@
+libnotmuch5t64: package-name-doesnt-match-sonames libnotmuch5
diff --git a/debian/libnotmuch5t64.symbols b/debian/libnotmuch5t64.symbols
new file mode 100644 (file)
index 0000000..5715dec
--- /dev/null
@@ -0,0 +1,166 @@
+libnotmuch.so.5 libnotmuch5t64 #MINVER#
+* Build-Depends-Package: libnotmuch-dev
+ notmuch_built_with@Base 0.23~rc0
+ notmuch_config_get@Base 0.32~rc0
+ notmuch_config_get_bool@Base 0.32~rc0
+ notmuch_config_get_pairs@Base 0.32~rc0
+ notmuch_config_get_values@Base 0.32~rc0
+ notmuch_config_get_values_string@Base 0.32~rc0
+ notmuch_config_list_destroy@Base 0.23~rc0
+ notmuch_config_list_key@Base 0.23~rc0
+ notmuch_config_list_move_to_next@Base 0.23~rc0
+ notmuch_config_list_valid@Base 0.23~rc0
+ notmuch_config_list_value@Base 0.23~rc0
+ notmuch_config_pairs_destroy@Base 0.32~rc0
+ notmuch_config_pairs_key@Base 0.32~rc0
+ notmuch_config_pairs_move_to_next@Base 0.32~rc0
+ notmuch_config_pairs_valid@Base 0.32~rc0
+ notmuch_config_pairs_value@Base 0.32~rc0
+ notmuch_config_path@Base 0.32~rc0
+ notmuch_config_set@Base 0.32~rc0
+ notmuch_config_values_destroy@Base 0.32~rc0
+ notmuch_config_values_get@Base 0.32~rc0
+ notmuch_config_values_move_to_next@Base 0.32~rc0
+ notmuch_config_values_start@Base 0.32~rc0
+ notmuch_config_values_valid@Base 0.32~rc0
+ notmuch_database_add_message@Base 0.3
+ notmuch_database_begin_atomic@Base 0.9~rc1
+ notmuch_database_close@Base 0.13~rc1
+ notmuch_database_compact@Base 0.17~rc1
+ notmuch_database_compact_db@Base 0.32~rc0
+ notmuch_database_create@Base 0.3
+ notmuch_database_create_verbose@Base 0.20~rc1
+ notmuch_database_create_with_config@Base 0.32~rc0
+ notmuch_database_destroy@Base 0.13~rc1
+ notmuch_database_end_atomic@Base 0.9~rc1
+ notmuch_database_find_message@Base 0.9~rc2
+ notmuch_database_find_message_by_filename@Base 0.9~rc2
+ notmuch_database_get_all_tags@Base 0.3
+ notmuch_database_get_config@Base 0.23~rc0
+ notmuch_database_get_config_list@Base 0.23~rc0
+ notmuch_database_get_default_indexopts@Base 0.26~rc0
+ notmuch_database_get_directory@Base 0.3
+ notmuch_database_get_path@Base 0.3
+ notmuch_database_get_revision@Base 0.21~rc1
+ notmuch_database_get_version@Base 0.3
+ notmuch_database_index_file@Base 0.26~rc0
+ notmuch_database_load_config@Base 0.32~rc0
+ notmuch_database_needs_upgrade@Base 0.3
+ notmuch_database_open@Base 0.3
+ notmuch_database_open_verbose@Base 0.20~rc1
+ notmuch_database_open_with_config@Base 0.32~rc0
+ notmuch_database_remove_message@Base 0.3
+ notmuch_database_reopen@Base 0.32~rc0
+ notmuch_database_set_config@Base 0.23~rc0
+ notmuch_database_status_string@Base 0.20~rc1
+ notmuch_database_upgrade@Base 0.3
+ notmuch_directory_delete@Base 0.21~rc1
+ notmuch_directory_destroy@Base 0.3
+ notmuch_directory_get_child_directories@Base 0.3
+ notmuch_directory_get_child_files@Base 0.3
+ notmuch_directory_get_mtime@Base 0.3
+ notmuch_directory_set_mtime@Base 0.3
+ notmuch_filenames_destroy@Base 0.3
+ notmuch_filenames_get@Base 0.3
+ notmuch_filenames_move_to_next@Base 0.3
+ notmuch_filenames_valid@Base 0.3
+ notmuch_indexopts_destroy@Base 0.26~rc0
+ notmuch_indexopts_get_decrypt_policy@Base 0.26~rc0
+ notmuch_indexopts_set_decrypt_policy@Base 0.26~rc0
+ notmuch_message_add_property@Base 0.23~rc0
+ notmuch_message_add_tag@Base 0.3
+ notmuch_message_count_files@Base 0.26~rc0
+ notmuch_message_count_properties@Base 0.27~rc0
+ notmuch_message_destroy@Base 0.3
+ notmuch_message_freeze@Base 0.3
+ notmuch_message_get_database@Base 0.27~rc0
+ notmuch_message_get_date@Base 0.3
+ notmuch_message_get_filename@Base 0.3
+ notmuch_message_get_filenames@Base 0.5
+ notmuch_message_get_flag@Base 0.3
+ notmuch_message_get_flag_st@Base 0.31~rc0
+ notmuch_message_get_header@Base 0.3
+ notmuch_message_get_message_id@Base 0.3
+ notmuch_message_get_properties@Base 0.23~rc0
+ notmuch_message_get_property@Base 0.23~rc0
+ notmuch_message_get_replies@Base 0.3
+ notmuch_message_get_tags@Base 0.3
+ notmuch_message_get_thread_id@Base 0.3
+ notmuch_message_has_maildir_flag@Base 0.26~rc0
+ notmuch_message_has_maildir_flag_st@Base 0.31~rc0
+ notmuch_message_maildir_flags_to_tags@Base 0.5
+ notmuch_message_properties_destroy@Base 0.23~rc0
+ notmuch_message_properties_key@Base 0.23~rc0
+ notmuch_message_properties_move_to_next@Base 0.23~rc0
+ notmuch_message_properties_valid@Base 0.23~rc0
+ notmuch_message_properties_value@Base 0.23~rc0
+ notmuch_message_reindex@Base 0.26~rc0
+ notmuch_message_remove_all_properties@Base 0.23~rc0
+ notmuch_message_remove_all_properties_with_prefix@Base 0.26~rc0
+ notmuch_message_remove_all_tags@Base 0.3
+ notmuch_message_remove_property@Base 0.23~rc0
+ notmuch_message_remove_tag@Base 0.3
+ notmuch_message_set_flag@Base 0.3
+ notmuch_message_tags_to_maildir_flags@Base 0.5
+ notmuch_message_thaw@Base 0.3
+ notmuch_messages_collect_tags@Base 0.3
+ notmuch_messages_destroy@Base 0.3
+ notmuch_messages_get@Base 0.3
+ notmuch_messages_move_to_next@Base 0.3
+ notmuch_messages_valid@Base 0.3
+ notmuch_query_add_tag_exclude@Base 0.12~rc1
+ notmuch_query_count_messages@Base 0.3
+ notmuch_query_count_messages_st@Base 0.21~rc1
+ notmuch_query_count_threads@Base 0.10~rc1
+ notmuch_query_count_threads_st@Base 0.21~rc1
+ notmuch_query_create@Base 0.3
+ notmuch_query_create_with_syntax@Base 0.34~rc0
+ notmuch_query_destroy@Base 0.3
+ notmuch_query_get_database@Base 0.21~rc1
+ notmuch_query_get_query_string@Base 0.4
+ notmuch_query_get_sort@Base 0.4
+ notmuch_query_search_messages@Base 0.3
+ notmuch_query_search_messages_st@Base 0.20~rc1
+ notmuch_query_search_threads@Base 0.3
+ notmuch_query_search_threads_st@Base 0.20~rc1
+ notmuch_query_set_omit_excluded@Base 0.13~rc1
+ notmuch_query_set_sort@Base 0.3
+ notmuch_status_to_string@Base 0.3
+ notmuch_tags_destroy@Base 0.3
+ notmuch_tags_get@Base 0.3
+ notmuch_tags_move_to_next@Base 0.3
+ notmuch_tags_valid@Base 0.3
+ notmuch_thread_destroy@Base 0.3
+ notmuch_thread_get_authors@Base 0.3
+ notmuch_thread_get_matched_messages@Base 0.3
+ notmuch_thread_get_messages@Base 0.16
+ notmuch_thread_get_newest_date@Base 0.3
+ notmuch_thread_get_oldest_date@Base 0.3
+ notmuch_thread_get_subject@Base 0.3
+ notmuch_thread_get_tags@Base 0.3
+ notmuch_thread_get_thread_id@Base 0.3
+ notmuch_thread_get_toplevel_messages@Base 0.3
+ notmuch_thread_get_total_files@Base 0.26~rc0
+ notmuch_thread_get_total_messages@Base 0.3
+ notmuch_threads_destroy@Base 0.3
+ notmuch_threads_get@Base 0.3
+ notmuch_threads_move_to_next@Base 0.3
+ notmuch_threads_valid@Base 0.3
+ (c++)"typeinfo for Xapian::LogicError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::RuntimeError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::DocNotFoundError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::InvalidArgumentError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::Error@Base" 0.6.1
+ (c++)"typeinfo for Xapian::DatabaseError@Base" 0.24~rc0
+ (c++)"typeinfo for Xapian::DatabaseModifiedError@Base" 0.24~rc0
+ (c++)"typeinfo for Xapian::DatabaseOpeningError@Base" 0.32~rc0
+ (c++|optional=present with Xapian 1.4)"typeinfo for Xapian::QueryParserError@Base" 0.23~rc0
+ (c++)"typeinfo name for Xapian::LogicError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::RuntimeError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::DocNotFoundError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::InvalidArgumentError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::Error@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::DatabaseError@Base" 0.24~rc0
+ (c++)"typeinfo name for Xapian::DatabaseModifiedError@Base" 0.24~rc0
+ (c++)"typeinfo name for Xapian::DatabaseOpeningError@Base" 0.32~rc0
+ (c++|optional=present with Xapian 1.4)"typeinfo name for Xapian::QueryParserError@Base" 0.23~rc0
index f9196b82612001ee89a4a1d5753c29901c9ba9d2..a77ffa152daefd3ca8a611121cc3509a9e5c341d 100755 (executable)
@@ -1,4 +1,9 @@
 #!/usr/bin/make -f
 #!/usr/bin/make -f
+include /usr/share/dpkg/architecture.mk
+
+ifeq ($(DEB_HOST_ARCH),ppc64el)
+       export NOTMUCH_SKIP_TESTS = T810-tsan
+endif
 
 export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 
 
 export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 
@@ -7,7 +12,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 
 override_dh_auto_configure:
        BASHCMD=/bin/bash ./configure --prefix=/usr \
 
 override_dh_auto_configure:
        BASHCMD=/bin/bash ./configure --prefix=/usr \
-               --libdir=/usr/lib/$$(dpkg-architecture -q DEB_TARGET_MULTIARCH) \
+               --libdir=/usr/lib/${DEB_TARGET_MULTIARCH} \
                --includedir=/usr/include \
                --mandir=/usr/share/man \
                --infodir=/usr/share/info \
                --includedir=/usr/include \
                --mandir=/usr/share/man \
                --infodir=/usr/share/info \
@@ -24,7 +29,6 @@ override_dh_auto_build:
 override_dh_auto_clean:
        dh_auto_clean
        PYBUILD_NAME=notmuch dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python
 override_dh_auto_clean:
        dh_auto_clean
        PYBUILD_NAME=notmuch dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python
-       PYBUILD_NAME=notmuch2 dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python-cffi
        dh_auto_clean --sourcedirectory bindings/ruby
        $(MAKE) -C contrib/notmuch-mutt clean
 
        dh_auto_clean --sourcedirectory bindings/ruby
        $(MAKE) -C contrib/notmuch-mutt clean
 
diff --git a/debian/tests/control b/debian/tests/control
new file mode 100644 (file)
index 0000000..80be1de
--- /dev/null
@@ -0,0 +1,18 @@
+Test-command: env NOTMUCH_TEST_INSTALLED=1 TERM=dumb
+    NOTMUCH_HAVE_MAN=1 NOTMUCH_HAVE_SFSEXP=1 NOTMUCH_HAVE_XAPIAN_DB_RETRY_LOCK=1
+    NOTMUCH_HAVE_PYTHON3_CFFI=1 NOTMUCH_HAVE_PYTHON3_PYTEST=1
+    NOTMUCH_HAVE_ASAN=1 NOTMUCH_HAVE_TSAN=1
+    ./test/notmuch-test
+Restrictions: allow-stderr
+Architecture: amd64, arm64
+Depends: @,
+ build-essential,
+ dtach,
+ emacs-nox,
+ gdb,
+ git,
+ gnupg,
+ gpgsm,
+ libtalloc-dev,
+ man,
+ xapian-tools
index ad7f72ef0bb3ce039a9bd3fd22988c93b80565c6..218677c2960dc6477c350de7066dd8844e3c815c 100644 (file)
@@ -9,7 +9,7 @@
 | f            |                                        | notmuch-show-forward-message                          | notmuch-show-forward-message            |
 | g            |                                        |                                                       |                                         |
 | h            |                                        | notmuch-show-toggle-visibility-headers                |                                         |
 | f            |                                        | notmuch-show-forward-message                          | notmuch-show-forward-message            |
 | g            |                                        |                                                       |                                         |
 | h            |                                        | notmuch-show-toggle-visibility-headers                |                                         |
-| i            |                                        |                                                       |                                         |
+| i            | notmuch-search-toggle-hide-excluded    |                                                       | notmuch-tree-toggle-hide-excluded       |
 | j            | notmuch-jump-search                    | notmuch-jump-search                                   | notmuch-jump-search                     |
 | k            | notmuch-tag-jump                       | notmuch-tag-jump                                      | notmuch-tag-jump                        |
 | l            | notmuch-search-filter                  | notmuch-show-filter-thread                            | notmuch-tree-filter                     |
 | j            | notmuch-jump-search                    | notmuch-jump-search                                   | notmuch-jump-search                     |
 | k            | notmuch-tag-jump                       | notmuch-tag-jump                                      | notmuch-tag-jump                        |
 | l            | notmuch-search-filter                  | notmuch-show-filter-thread                            | notmuch-tree-filter                     |
index 928e486320f6880c9b41c42b108b67e5874b0135..e0e87b49b2ca2c0de3fc29a36e58fd498841c960 100755 (executable)
@@ -125,13 +125,13 @@ def mailto_addrs(msg,header_name):
     return ''
 
   frm = email.utils.getaddresses([hdr])
     return ''
 
   frm = email.utils.getaddresses([hdr])
-  return ','.join(['<a href="mailto:%s">%s</a> ' % ((l, p) if p else (l, l)) for (p, l) in frm])
+  return ', '.join(['<a href="mailto:%s">%s</a>' % ((l, p) if p else (l, l)) for (p, l) in frm])
 env.globals['mailto_addrs'] = mailto_addrs
 
 def link_msg(msg):
   lnk = quote_plus(msg.messageid.encode('utf8'))
   try:
 env.globals['mailto_addrs'] = mailto_addrs
 
 def link_msg(msg):
   lnk = quote_plus(msg.messageid.encode('utf8'))
   try:
-    subj = msg.header('Subject')
+    subj = html.escape(msg.header('Subject'))
   except LookupError:
     subj = ""
   out = '<a href="%s/show/%s">%s</a>' % (prefix, lnk, subj)
   except LookupError:
     subj = ""
   out = '<a href="%s/show/%s">%s</a>' % (prefix, lnk, subj)
@@ -207,7 +207,7 @@ env.globals['thread_nav'] = thread_nav
 
 def format_message(nm_msg, mid):
   fn = list(nm_msg.filenames())[0]
 
 def format_message(nm_msg, mid):
   fn = list(nm_msg.filenames())[0]
-  msg = MaildirMessage(open(fn))
+  msg = MaildirMessage(open(fn, 'rb'))
   return format_message_walk(msg, mid)
 
 def decodeAnyway(txt, charset='ascii'):
   return format_message_walk(msg, mid)
 
 def decodeAnyway(txt, charset='ascii'):
index 98d36accb95b6c6325e39e8eb8ef7fd6e8513ec4..690f5464ef053a1baf24edec1235b56e0bbe344c 100644 (file)
@@ -3,10 +3,10 @@
 {% set headers = ['Subject', 'Date'] %}
 {% set addr_headers = ['To', 'Cc', 'From'] %}
 {% for header in headers: %}
 {% set headers = ['Subject', 'Date'] %}
 {% set addr_headers = ['To', 'Cc', 'From'] %}
 {% for header in headers: %}
-<p><b>{{header}}:</b>{{m.header(header)|e}}</p>
+<p><b>{{header}}:</b> {{m.header(header)|e}}</p>
 {% endfor %}
 {% for header in addr_headers: %}
 {% endfor %}
 {% for header in addr_headers: %}
-<p><b>{{header}}:</b>{{mailto_addrs(m,header)|safe}}</p>
+<p><b>{{header}}:</b> {{mailto_addrs(m,header)|safe}}</p>
 {% endfor %}
 <hr>
 {% for part in format_message(m,mid): %}{{ part|safe }}{% endfor %}
 {% endfor %}
 <hr>
 {% for part in format_message(m,mid): %}{{ part|safe }}{% endfor %}
index 66bcdbed8d0146967b10260bfb6a599cc3bb63b0..4e05cdacdf0419718f94065a7c58169ca9138afc 100644 (file)
@@ -76,6 +76,7 @@ message = {
     # (format_message_sprinter)
     id:             messageid,
     match:          bool,
     # (format_message_sprinter)
     id:             messageid,
     match:          bool,
+    excluded:       bool,
     filename:      [string*],
     timestamp:      unix_time, # date header as unix time
     date_relative:  string,   # user-friendly timestamp
     filename:      [string*],
     timestamp:      unix_time, # date header as unix time
     date_relative:  string,   # user-friendly timestamp
index 51c729cf7fe5d61ef5719e25c797ecff62d40af5..aafa77a0fe229e7dc2f8435e6e7791c5dc8619ae 100644 (file)
@@ -159,3 +159,5 @@ $(dir)/config.dox: version.stamp
 CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
 CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.stamp
 CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
 CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
 CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.stamp
 CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
+
+CLEAN := $(CLEAN) $(dir)/__pycache__
index 11896b500cddde7cb4a0dcfb7f785658c711c287..ee1b336af2ad61d36336c5891b821cf201915560 100644 (file)
@@ -3,8 +3,10 @@
 
 import sys
 import os
 
 import sys
 import os
+from pathlib import Path
+sys.path.append(str(Path(__file__).parent))
 
 
-extensions = [ 'sphinx.ext.autodoc' ]
+extensions = [ 'sphinx.ext.autodoc', 'elisp' ]
 
 # The suffix of source filenames.
 source_suffix = '.rst'
 
 # The suffix of source filenames.
 source_suffix = '.rst'
@@ -14,7 +16,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'notmuch'
 
 # General information about the project.
 project = u'notmuch'
-copyright = u'2009-2022, Carl Worth and many others'
+copyright = u'2009-2024, Carl Worth and many others'
 
 location = os.path.dirname(__file__)
 
 
 location = os.path.dirname(__file__)
 
@@ -222,12 +224,3 @@ def setup(app):
                         indextemplate='pair: configuration item; %s',
                         ref_nodeclass=docutils.nodes.generated,
                         objname='config item' )
                         indextemplate='pair: configuration item; %s',
                         ref_nodeclass=docutils.nodes.generated,
                         objname='config item' )
-    app.add_object_type('emacsvar','emacsvar',
-                        indextemplate='pair: Emacs variable; %s',
-                        ref_nodeclass=docutils.nodes.generated,
-                        objname='Emacs variable')
-    app.add_object_type('emacscmd','emacscmd',
-                        indextemplate='pair: Emacs command; %s',
-                        ref_nodeclass=docutils.nodes.generated,
-                        objname='Emacs command')
-
diff --git a/doc/elisp.py b/doc/elisp.py
new file mode 100644 (file)
index 0000000..1b0392e
--- /dev/null
@@ -0,0 +1,445 @@
+# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors
+
+# This file is not part of GNU Emacs.
+
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+
+# You should have received a copy of the GNU General Public License along with
+# this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+from collections import namedtuple
+from sphinx import addnodes
+from sphinx.util import ws_re
+from sphinx.roles import XRefRole
+from sphinx.domains import Domain, ObjType
+from sphinx.util.nodes import make_refnode
+from sphinx.directives import ObjectDescription
+
+
+def make_target(cell, name):
+    """Create a target name from ``cell`` and ``name``.
+
+    ``cell`` is the name of a symbol cell, and ``name`` is a symbol name, both
+    as strings.
+
+    The target names are used as cross-reference targets for Sphinx.
+
+    """
+    return '{cell}-{name}'.format(cell=cell, name=name)
+
+
+def to_mode_name(symbol_name):
+    """Convert ``symbol_name`` to a mode name.
+
+    Split at ``-`` and titlecase each part.
+
+    """
+    return ' '.join(p.title() for p in symbol_name.split('-'))
+
+
+class Cell(namedtuple('Cell', 'objtype docname')):
+    """A cell in a symbol.
+
+    A cell holds the object type and the document name of the description for
+    the cell.
+
+    Cell objects are used within symbol entries in the domain data.
+
+    """
+
+    pass
+
+
+class KeySequence(namedtuple('KeySequence', 'keys')):
+    """A key sequence."""
+
+    PREFIX_KEYS = {'C-u'}
+    PREFIX_KEYS.update('M-{}'.format(n) for n in range(10))
+
+    @classmethod
+    def fromstring(cls, s):
+        return cls(s.split())
+
+    @property
+    def command_name(self):
+        """The command name in this key sequence.
+
+        Return ``None`` for key sequences that are no command invocations with
+        ``M-x``.
+
+        """
+        try:
+            return self.keys[self.keys.index('M-x') + 1]
+        except ValueError:
+            return None
+
+    @property
+    def has_prefix(self):
+        """Whether this key sequence has a prefix."""
+        return self.keys[0] in self.PREFIX_KEYS
+
+    def __str__(self):
+        return ' '.join(self.keys)
+
+
+class EmacsLispSymbol(ObjectDescription):
+    """An abstract base class for directives documenting symbols.
+
+    Provide target and index generation and registration of documented symbols
+    within the domain data.
+
+    Deriving classes must have a ``cell`` attribute which refers to the cell
+    the documentation goes in, and a ``label`` attribute which provides a
+    human-readable name for what is documented, used in the index entry.
+
+    """
+
+    cell_for_objtype = {
+        'defcustom': 'variable',
+        'defconst': 'variable',
+        'defvar': 'variable',
+        'defface': 'face'
+    }
+
+    category_for_objtype = {
+        'defcustom': 'Emacs variable (customizable)',
+        'defconst': 'Emacs constant',
+        'defvar': 'Emacs variable',
+        'defface': 'Emacs face'
+    }
+
+    @property
+    def cell(self):
+        """The cell in which to store symbol metadata."""
+        return self.cell_for_objtype[self.objtype]
+
+    @property
+    def label(self):
+        """The label for the documented object type."""
+        return self.objtype
+
+    @property
+    def category(self):
+        """Index category"""
+        return self.category_for_objtype[self.objtype]
+
+    def handle_signature(self, signature, signode):
+        """Create nodes in ``signode`` for the ``signature``.
+
+        ``signode`` is a docutils node to which to add the nodes, and
+        ``signature`` is the symbol name.
+
+        Add the object type label before the symbol name and return
+        ``signature``.
+
+        """
+        label = self.label + ' '
+        signode += addnodes.desc_annotation(label, label)
+        signode += addnodes.desc_name(signature, signature)
+        return signature
+
+    def _add_index(self, name, target):
+        index_text = '{name}; {label}'.format(
+            name=name, label=self.category)
+        self.indexnode['entries'].append(
+            ('pair', index_text, target, '', None))
+
+    def _add_target(self, name, sig, signode):
+        target = make_target(self.cell, name)
+        if target not in self.state.document.ids:
+            signode['names'].append(name)
+            signode['ids'].append(target)
+            signode['first'] = (not self.names)
+            self.state.document.note_explicit_target(signode)
+
+            obarray = self.env.domaindata['el']['obarray']
+            symbol = obarray.setdefault(name, {})
+            if self.cell in symbol:
+                self.state_machine.reporter.warning(
+                    'duplicate description of %s %s, ' % (self.objtype, name)
+                    + 'other instance in '
+                    + self.env.doc2path(symbol[self.cell].docname),
+                    line=self.lineno)
+            symbol[self.cell] = Cell(self.objtype, self.env.docname)
+
+        return target
+
+    def add_target_and_index(self, name, sig, signode):
+        target = self._add_target(name, sig, signode)
+        self._add_index(name, target)
+
+
+class EmacsLispMinorMode(EmacsLispSymbol):
+    cell = 'function'
+    label = 'Minor Mode'
+
+    def handle_signature(self, signature, signode):
+        """Create nodes in ``signode`` for the ``signature``.
+
+        ``signode`` is a docutils node to which to add the nodes, and
+        ``signature`` is the symbol name.
+
+        Add the object type label before the symbol name and return
+        ``signature``.
+
+        """
+        label = self.label + ' '
+        signode += addnodes.desc_annotation(label, label)
+        signode += addnodes.desc_name(signature, to_mode_name(signature))
+        return signature
+
+    def _add_index(self, name, target):
+        return super()._add_index(to_mode_name(name), target)
+
+
+class EmacsLispFunction(EmacsLispSymbol):
+    """A directive to document Emacs Lisp functions."""
+
+    cell_for_objtype = {
+        'defun': 'function',
+        'defmacro': 'function'
+    }
+
+    def handle_signature(self, signature, signode):
+        function_name, *args = ws_re.split(signature)
+        label = self.label + ' '
+        signode += addnodes.desc_annotation(label, label)
+        signode += addnodes.desc_name(function_name, function_name)
+        for arg in args:
+            is_keyword = arg.startswith('&')
+            node = (addnodes.desc_annotation
+                    if is_keyword
+                    else addnodes.desc_addname)
+            signode += node(' ' + arg, ' ' + arg)
+
+        return function_name
+
+
+class EmacsLispKey(ObjectDescription):
+    """A directive to document interactive commands via their bindings."""
+
+    label = 'Emacs command'
+
+    def handle_signature(self, signature, signode):
+        """Create nodes to ``signode`` for ``signature``.
+
+        ``signode`` is a docutils node to which to add the nodes, and
+        ``signature`` is the symbol name.
+        """
+        key_sequence = KeySequence.fromstring(signature)
+        signode += addnodes.desc_name(signature, str(key_sequence))
+        return str(key_sequence)
+
+    def _add_command_target_and_index(self, name, sig, signode):
+        target_name = make_target('function', name)
+        if target_name not in self.state.document.ids:
+            signode['names'].append(name)
+            signode['ids'].append(target_name)
+            self.state.document.note_explicit_target(signode)
+
+            obarray = self.env.domaindata['el']['obarray']
+            symbol = obarray.setdefault(name, {})
+            if 'function' in symbol:
+                self.state_machine.reporter.warning(
+                    'duplicate description of %s %s, ' % (self.objtype, name)
+                    + 'other instance in '
+                    + self.env.doc2path(symbol['function'].docname),
+                    line=self.lineno)
+            symbol['function'] = Cell(self.objtype, self.env.docname)
+
+        index_text = '{name}; {label}'.format(name=name, label=self.label)
+        self.indexnode['entries'].append(
+            ('pair', index_text, target_name, '', None))
+
+    def _add_binding_target_and_index(self, binding, sig, signode):
+        reftarget = make_target('key', binding)
+
+        if reftarget not in self.state.document.ids:
+            signode['names'].append(reftarget)
+            signode['ids'].append(reftarget)
+            signode['first'] = (not self.names)
+            self.state.document.note_explicit_target(signode)
+
+            keymap = self.env.domaindata['el']['keymap']
+            if binding in keymap:
+                self.state_machine.reporter.warning(
+                    'duplicate description of binding %s, ' % binding
+                    + 'other instance in '
+                    + self.env.doc2path(keymap[binding]),
+                    line=self.lineno)
+            keymap[binding] = self.env.docname
+
+        index_text = '{name}; Emacs key binding'.format(name=binding)
+        self.indexnode['entries'].append(
+            ('pair', index_text, reftarget, '', None))
+
+    def add_target_and_index(self, name, sig, signode):
+        # If unprefixed M-x command index as function and not as key binding
+        sequence = KeySequence.fromstring(name)
+        if sequence.command_name and not sequence.has_prefix:
+            self._add_command_target_and_index(sequence.command_name,
+                                               sig, signode)
+        else:
+            self._add_binding_target_and_index(name, sig, signode)
+
+
+class XRefModeRole(XRefRole):
+    """A role to cross-reference a minor mode.
+
+    Like a normal cross-reference role but appends ``-mode`` to the reference
+    target and title-cases the symbol name like Emacs does when referring to
+    modes.
+
+    """
+
+    fix_parens = False
+    lowercase = False
+
+    def process_link(self, env, refnode, has_explicit_title, title, target):
+        refnode['reftype'] = 'minor-mode'
+        target = target + '-mode'
+        return (title if has_explicit_title else to_mode_name(target), target)
+
+
+class EmacsLispDomain(Domain):
+    """A domain to document Emacs Lisp code."""
+
+    name = 'el'
+    label = ''
+
+    object_types = {
+        # TODO: Set search prio for object types
+        # Types for user-facing options and commands
+        'minor-mode': ObjType('minor-mode', 'function', 'mode',
+                              cell='function'),
+        'define-key': ObjType('key binding', cell='interactive'),
+        'defcustom': ObjType('defcustom', 'defcustom', cell='variable'),
+        'defface': ObjType('defface', 'defface', cell='face'),
+        # Object types for code
+        'defun': ObjType('defun', 'defun', cell='function'),
+        'defmacro': ObjType('defmacro', 'defmacro', cell='function'),
+        'defvar': ObjType('defvar', 'defvar', cell='variable'),
+        'defconst': ObjType('defconst', 'defconst', cell='variable')
+    }
+    directives = {
+        'minor-mode': EmacsLispMinorMode,
+        'define-key': EmacsLispKey,
+        'defcustom': EmacsLispSymbol,
+        'defvar': EmacsLispSymbol,
+        'defconst': EmacsLispSymbol,
+        'defface': EmacsLispSymbol,
+        'defun': EmacsLispFunction,
+        'defmacro': EmacsLispFunction
+    }
+    roles = {
+        'mode': XRefModeRole(),
+        'defvar': XRefRole(),
+        'defconst': XRefRole(),
+        'defcustom': XRefRole(),
+        'defface': XRefRole(),
+        'defun': XRefRole(),
+        'defmacro': XRefRole()
+    }
+
+    data_version = 1
+    initial_data = {
+        # Our domain data attempts to somewhat mirror the semantics of Emacs
+        # Lisp, so we have an obarray which holds symbols which in turn have
+        # function, variable, face, etc. cells, and a keymap which holds the
+        # documentation for key bindings.
+        'obarray': {},
+        'keymap': {}
+    }
+
+    def clear_doc(self, docname):
+        """Clear all cells documented ``docname``."""
+        for symbol in self.data['obarray'].values():
+            for cell in list(symbol.keys()):
+                if docname == symbol[cell].docname:
+                    del symbol[cell]
+        for binding in list(self.data['keymap']):
+            if self.data['keymap'][binding] == docname:
+                del self.data['keymap'][binding]
+
+    def resolve_xref(self, env, fromdocname, builder,
+                     objtype, target, node, contnode):
+        """Resolve a cross reference to ``target``."""
+        if objtype == 'key':
+            todocname = self.data['keymap'].get(target)
+            if not todocname:
+                return None
+            reftarget = make_target('key', target)
+        else:
+            cell = self.object_types[objtype].attrs['cell']
+            symbol = self.data['obarray'].get(target, {})
+            if cell not in symbol:
+                return None
+            reftarget = make_target(cell, target)
+            todocname = symbol[cell].docname
+
+        return make_refnode(builder, fromdocname, todocname,
+                            reftarget, contnode, target)
+
+    def resolve_any_xref(self, env, fromdocname, builder,
+                         target, node, contnode):
+        """Return all possible cross references for ``target``."""
+        nodes = ((objtype, self.resolve_xref(env, fromdocname, builder,
+                                             objtype, target, node, contnode))
+                 for objtype in ['key', 'defun', 'defvar', 'defface'])
+        return [('el:{}'.format(objtype), node) for (objtype, node) in nodes
+                if node is not None]
+
+    def merge_warn_duplicate(self, objname, our_docname, their_docname):
+        self.env.warn(
+            their_docname,
+            "Duplicate declaration: '{}' also defined in '{}'.\n".format(
+                objname, their_docname))
+
+    def merge_keymapdata(self, docnames, our_keymap, their_keymap):
+        for key, docname in their_keymap.items():
+            if docname in docnames:
+                if key in our_keymap:
+                    our_docname = our_keymap[key]
+                    self.merge_warn_duplicate(key, our_docname, docname)
+                else:
+                    our_keymap[key] = docname
+
+    def merge_obarraydata(self, docnames, our_obarray, their_obarray):
+        for objname, their_cells in their_obarray.items():
+            our_cells = our_obarray.setdefault(objname, dict())
+            for cellname, their_cell in their_cells.items():
+                if their_cell.docname in docnames:
+                    our_cell = our_cells.get(cellname)
+                    if our_cell:
+                        self.merge_warn_duplicate(objname, our_cell.docname,
+                                                  their_cell.docname)
+                    else:
+                        our_cells[cellname] = their_cell
+
+    def merge_domaindata(self, docnames, otherdata):
+        self.merge_keymapdata(docnames, self.data['keymap'],
+                              otherdata['keymap'])
+        self.merge_obarraydata(docnames, self.data['obarray'],
+                               otherdata['obarray'])
+
+    def get_objects(self):
+        """Get all documented symbols for use in the search index."""
+        for name, symbol in self.data['obarray'].items():
+            for cellname, cell in symbol.items():
+                yield (name, name, cell.objtype, cell.docname,
+                       make_target(cellname, name),
+                       self.object_types[cell.objtype].attrs['searchprio'])
+
+
+def setup(app):
+    app.add_domain(EmacsLispDomain)
+    return {'version': '0.1', 'parallel_read_safe': True}
index 388315f67ec609c396ee0168c7e9741b9990bbec..bd34afa40ee6975a7f1aa316bd4e22e3f1605070 100644 (file)
@@ -122,6 +122,16 @@ paths are presumed relative to `$HOME` for items in section
 
     Default tag prefix (filter) for :any:`notmuch-git`.
 
 
     Default tag prefix (filter) for :any:`notmuch-git`.
 
+.. nmconfig:: index.as_text
+
+   List of regular expressions (without delimiters) for MIME types to
+   be indexed as text. Currently this applies only to attachments.  By
+   default the regex matches anywhere in the content type; if the
+   user wants an anchored match, they should include anchors in their
+   regexes.
+
+   History: This configuration value was introduced in notmuch 0.38.
+
 .. nmconfig:: index.decrypt
 
     Policy for decrypting encrypted messages during indexing.  Must be
 .. nmconfig:: index.decrypt
 
     Policy for decrypting encrypted messages during indexing.  Must be
index ac1908b6103f17be1aa2e995f4dffbf163ab0f87..33a46f84058750ef19b910772089bbe07f7956ed 100644 (file)
@@ -325,11 +325,11 @@ If it is unset, 'default' is assumed.
 
 .. envvar:: NOTMUCH_GIT_DIR
 
 
 .. envvar:: NOTMUCH_GIT_DIR
 
-   Default location of git repository. Overriden by :option:`--git-dir`.
+   Default location of git repository. Overridden by :option:`--git-dir`.
 
 .. envvar:: NOTMUCH_GIT_PREFIX
 
 
 .. envvar:: NOTMUCH_GIT_PREFIX
 
-   Default tag prefix (filter). Overriden by :option:`--tag-prefix`.
+   Default tag prefix (filter). Overridden by :option:`--tag-prefix`.
 
 SEE ALSO
 ========
 
 SEE ALSO
 ========
index ad305efdb6a07a2ff2635c618da21fcce2c9ad9d..b87737ea3bd0ae4b2ba0ec10a0a7014cc971ff2b 100644 (file)
@@ -43,7 +43,7 @@ Supported options for **search** include
 
 .. option:: --output=(summary|threads|messages|files|tags)
 
 
 .. option:: --output=(summary|threads|messages|files|tags)
 
-   summary
+   summary (default)
      Output a summary of each thread with any message matching the
      search terms. The summary includes the thread ID, date, the
      number of messages in the thread (both the number matched and
      Output a summary of each thread with any message matching the
      search terms. The summary includes the thread ID, date, the
      number of messages in the thread (both the number matched and
index 2c0a0de6ad1679ccc2d2596acd3c8936a968e49c..c13d94de024400fa2ca9642424ab6ec03284ad56 100644 (file)
@@ -130,6 +130,15 @@ Supported options for **show** include
    By default, results will be displayed in reverse chronological
    order, (that is, the newest results will be displayed first).
 
    By default, results will be displayed in reverse chronological
    order, (that is, the newest results will be displayed first).
 
+.. option:: --offset=[-]N
+
+   Skip displaying the first N results. With the leading '-', start
+   at the Nth result from the end.
+
+.. option:: --limit=N
+
+   Limit the number of displayed results to N.
+
 .. option:: --verify
 
    Compute and report the validity of any MIME cryptographic
 .. option:: --verify
 
    Compute and report the validity of any MIME cryptographic
index 1fec4ee556efc3a33ceb07a9b38fd5c077ff2806..c488f12a9e7a58193486b5dd5fdf76fe31f62057 100644 (file)
@@ -155,6 +155,23 @@ equivalent:
    notmuch --config:alt-config config get user.name
    notmuch --config alt-config config get user.name
 
    notmuch --config:alt-config config get user.name
    notmuch --config alt-config config get user.name
 
+.. _duplicate-files:
+
+DUPLICATE MESSAGE FILES
+=======================
+
+Notmuch considers the :mailheader:`Message-ID` to be the primary
+identifier of message. Per :rfc:`5322` the :mailheader:`Message-ID` is
+supposed to be globally unique, but this fails in two distinct
+ways. When you receive copies of a message via a mechanism like
+:mailheader:`Cc` or via a mailing list, the copies are typically
+interchangeable. In the case of some broken mail sending software, the
+same :mailheader:`Message-ID` is used for completely unrelated
+messages. The options :option:`search --duplicate` and :option:`show
+--duplicate` options provide the user with control over which message
+file is displayed. Front ends will need to provide their own
+interface, see e.g. the Emacs front-end :any:`emacs-show-duplicates`.
+
 ENVIRONMENT
 ===========
 
 ENVIRONMENT
 ===========
 
index 4f616b7e45d0f619fafb6864a5ddf29f3826be22..acc1c967f7c8470b50237796a693ec59735195b2 100644 (file)
@@ -153,10 +153,11 @@ date:<since>..<until> or date:<date>
 lastmod:<initial-revision>..<final-revision>
     The **lastmod:** prefix can be used to restrict the result by the
     database revision number of when messages were last modified (tags
 lastmod:<initial-revision>..<final-revision>
     The **lastmod:** prefix can be used to restrict the result by the
     database revision number of when messages were last modified (tags
-    were added/removed or filenames changed). This is usually used in
-    conjunction with the ``--uuid`` argument to
-    :any:`notmuch-search(1)` to find messages that have changed since
-    an earlier query.
+    were added/removed or filenames changed). Negative revisions are
+    interpreted relative to the most recent database revision (see
+    :option:`count --lastmod`). This is usually used in conjunction
+    with the ``--uuid`` argument to :any:`notmuch-search(1)` to find
+    messages that have changed since an earlier query.
 
 query:<name>
     The **query:** prefix allows queries to refer to previously saved
 
 query:<name>
     The **query:** prefix allows queries to refer to previously saved
index d28f40bb3f3901dbecf8d8ceb37d81a538d020d2..858ff6850fd3dc6fb6c978e0fdac30f1adafbe30 100644 (file)
@@ -125,6 +125,9 @@ bounds. Either upper or lower bound may be specified as ``""`` or
 ``*`` to specify the lowest possible lower bound or highest possible
 upper bound.
 
 ``*`` to specify the lowest possible lower bound or highest possible
 upper bound.
 
+``lastmod`` ranges support negative arguments, interpreted relative to
+the most recent database revision (see :option:`count --lastmod`).
+
 .. _field-table:
 
 .. table:: Fields with supported modifiers
 .. _field-table:
 
 .. table:: Fields with supported modifiers
@@ -271,7 +274,7 @@ EXAMPLES
 
     Matches any word starting with "prelim", inside a message subject.
 
 
     Matches any word starting with "prelim", inside a message subject.
 
-``(subject (starts-wih quick) "brown fox")``
+``(subject (starts-with quick) "brown fox")``
 
     Match messages whose subject contains "quick brown fox", but also
     "brown fox quicksand".
 
     Match messages whose subject contains "quick brown fox", but also
     "brown fox quicksand".
@@ -333,7 +336,7 @@ user defined fields is permitted within a macro.
 NOTES
 =====
 
 NOTES
 =====
 
-.. [#macro-details] Technically macros impliment lazy evaluation and
+.. [#macro-details] Technically macros implement lazy evaluation and
                     lexical scope. There is one top level scope
                     containing all macro definitions, but all
                     parameter definitions are local to a given macro.
                     lexical scope. There is one top level scope
                     containing all macro definitions, but all
                     parameter definitions are local to a given macro.
@@ -344,10 +347,10 @@ NOTES
 
 .. [#aka-bool] a.k.a. boolean prefixes
 
 
 .. [#aka-bool] a.k.a. boolean prefixes
 
-.. [#not-phrase] Due to the implemention of phrase fields in Xapian,
+.. [#not-phrase] Due to the implementation of phrase fields in Xapian,
                  regex queries could only match individual words.
 
                  regex queries could only match individual words.
 
-.. [#not-body] Due the the way ``body`` is implemented in notmuch,
+.. [#not-body] Due to the way ``body`` is implemented in notmuch,
                this modifier is not supported in the ``body`` field.
 
 .. [#not-path] Due to the way recursive ``path`` queries are implemented
                this modifier is not supported in the ``body`` field.
 
 .. [#not-path] Due to the way recursive ``path`` queries are implemented
index e69bd23da5cf69b343ff69ad4506fc408ab5e0a2..91af6d146f0d9682d125bd38a879d9941245d634 100644 (file)
@@ -14,7 +14,7 @@ manual to refer to the Emacs interface to Notmuch. When this distinction
 is important, we’ll refer to the Emacs interface as
 *notmuch-emacs*.
 
 is important, we’ll refer to the Emacs interface as
 *notmuch-emacs*.
 
-Notmuch-emacs is highly customizable via the the Emacs customization
+Notmuch-emacs is highly customizable via the Emacs customization
 framework (or just by setting the appropriate variables). We try to
 point out relevant variables in this manual, but in order to avoid
 duplication of information, you can usually find the most detailed
 framework (or just by setting the appropriate variables). We try to
 point out relevant variables in this manual, but in order to avoid
 duplication of information, you can usually find the most detailed
@@ -50,19 +50,19 @@ a mouse or by positioning the cursor and pressing ``<return>``
 You can change the overall appearance of the notmuch-hello screen by
 customizing the variables
 
 You can change the overall appearance of the notmuch-hello screen by
 customizing the variables
 
-.. emacsvar:: notmuch-hello-sections
+.. el:defcustom:: notmuch-hello-sections
 
        |docstring::notmuch-hello-sections|
 
 
        |docstring::notmuch-hello-sections|
 
-.. emacsvar:: notmuch-hello-thousands-separator
+.. el:defcustom:: notmuch-hello-thousands-separator
 
        |docstring::notmuch-hello-thousands-separator|
 
 
        |docstring::notmuch-hello-thousands-separator|
 
-.. emacsvar:: notmuch-show-logo
+.. el:defcustom:: notmuch-show-logo
 
        |docstring::notmuch-show-logo|
 
 
        |docstring::notmuch-show-logo|
 
-.. emacsvar:: notmuch-column-control
+.. el:defcustom:: notmuch-column-control
 
     Controls the number of columns for saved searches/tags in notmuch view.
 
 
     Controls the number of columns for saved searches/tags in notmuch view.
 
@@ -94,39 +94,49 @@ customizing the variables
     - if you don't want to worry about all of this nonsense, leave
       this set to `t`.
 
     - if you don't want to worry about all of this nonsense, leave
       this set to `t`.
 
-.. emacsvar:: notmuch-show-empty-saved-searches
+.. el:defcustom:: notmuch-show-empty-saved-searches
 
    |docstring::notmuch-show-empty-saved-searches|
 
 notmuch-hello key bindings
 --------------------------
 
 
    |docstring::notmuch-show-empty-saved-searches|
 
 notmuch-hello key bindings
 --------------------------
 
-``<tab>``
+.. el:define-key:: <tab>
+
     Move to the next widget (button or text entry field)
 
     Move to the next widget (button or text entry field)
 
-``<backtab>``
+.. el:define-key:: <backtab>
+
     Move to the previous widget.
 
     Move to the previous widget.
 
-``<return>``
+.. el:define-key:: <return>
+
     Activate the current widget.
 
     Activate the current widget.
 
-``g`` ``=``
+.. el:define-key:: g
+                   =
+
     Refresh the buffer; mainly update the counts of messages for various
     saved searches.
 
     Refresh the buffer; mainly update the counts of messages for various
     saved searches.
 
-``G``
+.. el:define-key:: G
+
     Import mail, See :ref:`importing`
 
     Import mail, See :ref:`importing`
 
-``m``
+.. el:define-key:: m
+
     Compose a message
 
     Compose a message
 
-``s``
+.. el:define-key:: s
+
     Search the notmuch database using :ref:`notmuch-search`
 
     Search the notmuch database using :ref:`notmuch-search`
 
-``v``
+.. el:define-key:: v
+
     Print notmuch version
 
     Print notmuch version
 
-``q``
+.. el:define-key:: q
+
     Quit
 
 .. _saved-searches:
     Quit
 
 .. _saved-searches:
@@ -144,12 +154,12 @@ The saved searches default to various common searches such as
 ``tag:inbox`` to access the inbox and ``tag:unread`` to access all
 unread mail, but there are several options for customization:
 
 ``tag:inbox`` to access the inbox and ``tag:unread`` to access all
 unread mail, but there are several options for customization:
 
-.. emacsvar:: notmuch-saved-searches
+.. el:defcustom:: notmuch-saved-searches
 
     The list of saved searches, including names, queries, and
     additional per-query options.
 
 
     The list of saved searches, including names, queries, and
     additional per-query options.
 
-.. emacsvar:: notmuch-saved-search-sort-function
+.. el:defcustom:: notmuch-saved-search-sort-function
 
     This variable controls how saved searches should be sorted. A value
     of ``nil`` displays the saved searches in the order they are stored
 
     This variable controls how saved searches should be sorted. A value
     of ``nil`` displays the saved searches in the order they are stored
@@ -163,7 +173,7 @@ The search box lets the user enter a Notmuch query. See section
 syntax. A history of recent searches is also displayed by default. The
 latter is controlled by the variable `notmuch-hello-recent-searches-max`.
 
 syntax. A history of recent searches is also displayed by default. The
 latter is controlled by the variable `notmuch-hello-recent-searches-max`.
 
-.. emacsvar:: notmuch-hello-recent-searches-max
+.. el:defcustom:: notmuch-hello-recent-searches-max
 
               |docstring::notmuch-hello-recent-searches-max|
 
 
               |docstring::notmuch-hello-recent-searches-max|
 
@@ -174,12 +184,12 @@ One special kind of saved search provided by default is for each
 individual tag defined in the database. This can be controlled via the
 following variables.
 
 individual tag defined in the database. This can be controlled via the
 following variables.
 
-.. emacsvar:: notmuch-hello-tag-list-make-query
+.. el:defcustom:: notmuch-hello-tag-list-make-query
 
     Control how to construct a search (“virtual folder”) from a given
     tag.
 
 
     Control how to construct a search (“virtual folder”) from a given
     tag.
 
-.. emacsvar:: notmuch-hello-hide-tags
+.. el:defcustom:: notmuch-hello-hide-tags
 
     Which tags not to display at all.
 
 
     Which tags not to display at all.
 
@@ -200,25 +210,40 @@ The main purpose of the ``notmuch-search-mode`` buffer is to act as a
 menu of results that the user can explore further by pressing
 ``<return>`` on the appropriate line.
 
 menu of results that the user can explore further by pressing
 ``<return>`` on the appropriate line.
 
-``n,C-n,<down>``
+.. el:define-key:: n
+   C-n
+   <down>
+
     Move to next line
 
     Move to next line
 
-``p,C-p,<up>``
+.. el:define-key::
+   p
+   C-p
+   <up>
+
     Move to previous line
 
     Move to previous line
 
-``<return>``
+.. el:define-key:: <return>
+
     Open thread on current line in :ref:`notmuch-show` mode
 
     Open thread on current line in :ref:`notmuch-show` mode
 
-``g`` ``=``
+.. el:define-key:: g
+   =
+
     Refresh the buffer
 
     Refresh the buffer
 
-``?``
+.. el:define-key:: i
+
+    Toggle whether to show messages with excluded tags in search results.
+
+.. el:define-key:: ?
+
     Display full set of key bindings
 
 The presentation of results can be controlled by the following
 variables.
 
     Display full set of key bindings
 
 The presentation of results can be controlled by the following
 variables.
 
-.. emacsvar:: notmuch-search-result-format
+.. el:defcustom:: notmuch-search-result-format
 
    |docstring::notmuch-search-result-format|
 
 
    |docstring::notmuch-search-result-format|
 
@@ -253,21 +278,21 @@ variables.
                                            ("subject" . "%s ")
                                            ("tags" . "(%s)")))
 
                                            ("subject" . "%s ")
                                            ("tags" . "(%s)")))
 
-   See also :emacsvar:`notmuch-tree-result-format` and
-   :emacsvar:`notmuch-unthreaded-result-format`.
+   See also :el:defcustom:`notmuch-tree-result-format` and
+   :el:defcustom:`notmuch-unthreaded-result-format`.
 
 
-.. emacsvar:: notmuch-search-oldest-first
+.. el:defcustom:: notmuch-search-oldest-first
 
     Display the oldest threads at the top of the buffer
 
 It is also possible to customize how the name of buffers containing
 search results is formatted using the following variables:
 
 
     Display the oldest threads at the top of the buffer
 
 It is also possible to customize how the name of buffers containing
 search results is formatted using the following variables:
 
-.. emacsvar:: notmuch-search-buffer-name-format
+.. el:defcustom:: notmuch-search-buffer-name-format
 
        |docstring::notmuch-search-buffer-name-format|
 
 
        |docstring::notmuch-search-buffer-name-format|
 
-.. emacsvar:: notmuch-saved-search-buffer-name-format
+.. el:defcustom:: notmuch-saved-search-buffer-name-format
 
        |docstring::notmuch-saved-search-buffer-name-format|
 
 
        |docstring::notmuch-saved-search-buffer-name-format|
 
@@ -285,50 +310,60 @@ signatures, already-read messages), are hidden. You can make
 these parts visible by clicking with the mouse button or by
 pressing RET after positioning the cursor on a hidden part.
 
 these parts visible by clicking with the mouse button or by
 pressing RET after positioning the cursor on a hidden part.
 
-``<space>``
+.. el:define-key:: <space>
+
     Scroll the current message (if necessary),
     advance to the next message, or advance to the next thread (if
     already on the last message of a thread).
 
     Scroll the current message (if necessary),
     advance to the next message, or advance to the next thread (if
     already on the last message of a thread).
 
-``c``
+.. el:define-key:: c
+
     :ref:`show-copy`
 
     :ref:`show-copy`
 
-``N``
+.. el:define-key:: N
+
     Move to next message
 
     Move to next message
 
-``P``
+.. el:define-key:: P
+
     Move to previous message (or start of current message)
 
     Move to previous message (or start of current message)
 
-``n``
+.. el:define-key:: n
+
     Move to next matching message
 
     Move to next matching message
 
-``p``
+.. el:define-key:: p
+
     Move to previous matching message
 
     Move to previous matching message
 
-``+,-``
+.. el:define-key:: +
+                   -
+
     Add or remove arbitrary tags from the current message.
 
     Add or remove arbitrary tags from the current message.
 
-``!``
+.. el:define-key:: !
+
     |docstring::notmuch-show-toggle-elide-non-matching|
 
     |docstring::notmuch-show-toggle-elide-non-matching|
 
-``?``
+.. el:define-key:: ?
+
     Display full set of key bindings
 
 Display of messages can be controlled by the following variables; see also :ref:`show-large`.
 
     Display full set of key bindings
 
 Display of messages can be controlled by the following variables; see also :ref:`show-large`.
 
-.. emacsvar:: notmuch-message-headers
+.. el:defcustom:: notmuch-message-headers
 
        |docstring::notmuch-message-headers|
 
 
        |docstring::notmuch-message-headers|
 
-.. emacsvar:: notmuch-message-headers-visible
+.. el:defcustom:: notmuch-message-headers-visible
 
        |docstring::notmuch-message-headers-visible|
 
 
        |docstring::notmuch-message-headers-visible|
 
-.. emacsvar:: notmuch-show-header-line
+.. el:defcustom:: notmuch-show-header-line
 
        |docstring::notmuch-show-header-line|
 
 
        |docstring::notmuch-show-header-line|
 
-.. emacsvar:: notmuch-multipart/alternative-discouraged
+.. el:defcustom:: notmuch-multipart/alternative-discouraged
 
    Which mime types to hide by default for multipart messages.
 
 
    Which mime types to hide by default for multipart messages.
 
@@ -356,7 +391,7 @@ Dealing with large messages and threads
 
 If you are finding :ref:`notmuch-show` is annoyingly slow displaying
 large messages, you can customize
 
 If you are finding :ref:`notmuch-show` is annoyingly slow displaying
 large messages, you can customize
-:emacsvar:`notmuch-show-max-text-part-size`.  If you want to speed up the
+:el:defcustom:`notmuch-show-max-text-part-size`.  If you want to speed up the
 display of large threads (with or without large messages), there are
 several options.  First, you can display the same query in one of the
 other modes. :ref:`notmuch-unthreaded` is the most robust for
 display of large threads (with or without large messages), there are
 several options.  First, you can display the same query in one of the
 other modes. :ref:`notmuch-unthreaded` is the most robust for
@@ -364,21 +399,21 @@ extremely large queries, but :ref:`notmuch-tree` is also be faster
 than :ref:`notmuch-show` in general, since it only renders a single
 message a time. If you prefer to stay with the rendered thread
 ("conversation") view of :ref:`notmuch-show`, you can customize the
 than :ref:`notmuch-show` in general, since it only renders a single
 message a time. If you prefer to stay with the rendered thread
 ("conversation") view of :ref:`notmuch-show`, you can customize the
-variables :emacsvar:`notmuch-show-depth-limit`,
-:emacsvar:`notmuch-show-height-limit` and
-:emacsvar:`notmuch-show-max-text-part-size` to limit the amount of
+variables :el:defcustom:`notmuch-show-depth-limit`,
+:el:defcustom:`notmuch-show-height-limit` and
+:el:defcustom:`notmuch-show-max-text-part-size` to limit the amount of
 rendering done initially. Note that these limits are implicitly
 *OR*-ed together, and combinations might have surprising effects.
 
 rendering done initially. Note that these limits are implicitly
 *OR*-ed together, and combinations might have surprising effects.
 
-.. emacsvar:: notmuch-show-depth-limit
+.. el:defcustom:: notmuch-show-depth-limit
 
        |docstring::notmuch-show-depth-limit|
 
 
        |docstring::notmuch-show-depth-limit|
 
-.. emacsvar:: notmuch-show-height-limit
+.. el:defcustom:: notmuch-show-height-limit
 
        |docstring::notmuch-show-height-limit|
 
 
        |docstring::notmuch-show-height-limit|
 
-.. emacsvar:: notmuch-show-max-text-part-size
+.. el:defcustom:: notmuch-show-max-text-part-size
 
        |docstring::notmuch-show-max-text-part-size|
 
 
        |docstring::notmuch-show-max-text-part-size|
 
@@ -392,44 +427,92 @@ but notmuch also provides some shortcuts. These keys are available in
 :ref:`notmuch-show`, and :ref:`notmuch-tree`. A subset are available
 in :ref:`notmuch-search`.
 
 :ref:`notmuch-show`, and :ref:`notmuch-tree`. A subset are available
 in :ref:`notmuch-search`.
 
-``c F``        ``notmuch-show-stash-filename``
+.. el:define-key:: c F
+   M-x notmuch-show-stash-filename
+
    |docstring::notmuch-show-stash-filename|
 
    |docstring::notmuch-show-stash-filename|
 
-``c G`` ``notmuch-show-stash-git-send-email``
+.. el:define-key:: c G
+   M-x notmuch-show-stash-git-send-email
+
    |docstring::notmuch-show-stash-git-send-email|
 
    |docstring::notmuch-show-stash-git-send-email|
 
-``c I`` ``notmuch-show-stash-message-id-stripped``
+.. el:define-key:: c I
+   M-x notmuch-show-stash-message-id-stripped
+
    |docstring::notmuch-show-stash-message-id-stripped|
 
    |docstring::notmuch-show-stash-message-id-stripped|
 
-``c L`` ``notmuch-show-stash-mlarchive-link-and-go``
+.. el:define-key:: c L
+   M-x notmuch-show-stash-mlarchive-link-and-go
+
    |docstring::notmuch-show-stash-mlarchive-link-and-go|
 
    |docstring::notmuch-show-stash-mlarchive-link-and-go|
 
-``c T`` ``notmuch-show-stash-tags``
+.. el:define-key:: c T
+   M-x notmuch-show-stash-tags
+
    |docstring::notmuch-show-stash-tags|
 
    |docstring::notmuch-show-stash-tags|
 
-``c c`` ``notmuch-show-stash-cc``
+.. el:define-key:: c c
+   M-x notmuch-show-stash-cc
+
    |docstring::notmuch-show-stash-cc|
 
    |docstring::notmuch-show-stash-cc|
 
-``c d`` ``notmuch-show-stash-date``
+.. el:define-key:: c d
+   M-x notmuch-show-stash-date
+
    |docstring::notmuch-show-stash-date|
 
    |docstring::notmuch-show-stash-date|
 
-``c f`` ``notmuch-show-stash-from``
+.. el:define-key:: c f
+   M-x notmuch-show-stash-from
+
    |docstring::notmuch-show-stash-from|
 
    |docstring::notmuch-show-stash-from|
 
-``c i`` ``notmuch-show-stash-message-id``
+.. el:define-key:: c i
+   M-x notmuch-show-stash-message-id
+
    |docstring::notmuch-show-stash-message-id|
 
    |docstring::notmuch-show-stash-message-id|
 
-``c l`` ``notmuch-show-stash-mlarchive-link``
+.. el:define-key:: c l
+   M-x notmuch-show-stash-mlarchive-link
+
    |docstring::notmuch-show-stash-mlarchive-link|
 
    |docstring::notmuch-show-stash-mlarchive-link|
 
-``c s`` ``notmuch-show-stash-subject``
+.. el:define-key:: c s
+   M-x notmuch-show-stash-subject
+
    |docstring::notmuch-show-stash-subject|
 
    |docstring::notmuch-show-stash-subject|
 
-``c t`` ``notmuch-show-stash-to``
+.. el:define-key:: c t
+   M-x notmuch-show-stash-to
+
    |docstring::notmuch-show-stash-to|
 
    |docstring::notmuch-show-stash-to|
 
-``c ?``
-    Show all available copying commands
+.. el:define-key:: c ?
+   M-x notmuch-subkeymap-help
+
+   Show all available copying commands
+
+.. _emacs-show-duplicates:
+
+Dealing with duplicates
+-----------------------
+
+If there are multiple files with the same :mailheader:`Message-ID`
+(see :any:`duplicate-files`), then :any:`notmuch-show` displays the
+number of duplicates and identifies the current duplicate. In the
+following example duplicate 3 of 5 is displayed.
+
+.. code-block::
+   :emphasize-lines: 1
+
+    M. Mustermann <max@example.com> (Sat, 30 Jul 2022 10:33:10 -0300) (inbox signed)      3/5
+    Subject: Re: Multiple files per message in emacs
+    To: notmuch@notmuchmail.org
+
+.. el:define-key:: %
+   M-x notmuch-show-choose-duplicate
+
+   |docstring::notmuch-show-choose-duplicate|
 
 .. _notmuch-tree:
 
 
 .. _notmuch-tree:
 
@@ -441,44 +524,62 @@ email archives. Each line in the buffer represents a single
 message giving the relative date, the author, subject, and any
 tags.
 
 message giving the relative date, the author, subject, and any
 tags.
 
-``c``
+.. el:define-key:: c
+
     :ref:`show-copy`
 
     :ref:`show-copy`
 
-``<return>``
+.. el:define-key:: <return>
+
    Displays that message.
 
    Displays that message.
 
-``N``
+.. el:define-key:: N
+
     Move to next message
 
     Move to next message
 
-``P``
+.. el:define-key:: P
+
     Move to previous message
 
     Move to previous message
 
-``n``
+.. el:define-key:: n
+
     Move to next matching message
 
     Move to next matching message
 
-``p``
+.. el:define-key:: p
+
     Move to previous matching message
 
     Move to previous matching message
 
-``o`` ``notmuch-tree-toggle-order``
+.. el:define-key:: o
+   M-x notmuch-tree-toggle-order
+
    |docstring::notmuch-tree-toggle-order|
 
    |docstring::notmuch-tree-toggle-order|
 
-``l`` ``notmuch-tree-filter``
+.. el:define-key:: l
+   M-x notmuch-tree-filter
+
    Filter or LIMIT the current search results based on an additional query string
 
    Filter or LIMIT the current search results based on an additional query string
 
-``t`` ``notmuch-tree-filter-by-tag``
+.. el:define-key:: t
+   M-x notmuch-tree-filter-by-tag
+
    Filter the current search results based on an additional tag
 
    Filter the current search results based on an additional tag
 
+.. el:define-key:: i
+
+    Toggle whether to show messages with excluded tags in search results.
+
+.. el:define-key:: g
+   =
 
 
-``g`` ``=``
     Refresh the buffer
 
     Refresh the buffer
 
-``?``
+.. el:define-key:: ?
+
     Display full set of key bindings
 
 As is the case with :ref:`notmuch-search`, the presentation of results
 can be controlled by the variable ``notmuch-search-oldest-first``.
 
     Display full set of key bindings
 
 As is the case with :ref:`notmuch-search`, the presentation of results
 can be controlled by the variable ``notmuch-search-oldest-first``.
 
-.. emacsvar:: notmuch-tree-result-format
+.. el:defcustom:: notmuch-tree-result-format
 
    |docstring::notmuch-tree-result-format|
 
 
    |docstring::notmuch-tree-result-format|
 
@@ -509,9 +610,48 @@ can be controlled by the variable ``notmuch-search-oldest-first``.
                . " %-54s ")
               ("tags" . "(%s)")))
 
                . " %-54s ")
               ("tags" . "(%s)")))
 
-   See also :emacsvar:`notmuch-search-result-format` and
-   :emacsvar:`notmuch-unthreaded-result-format`.
+   See also :el:defcustom:`notmuch-search-result-format` and
+   :el:defcustom:`notmuch-unthreaded-result-format`.
 
 
+.. _notmuch-tree-outline:
+
+notmuch-tree-outline
+--------------------
+
+When this mode is set, each thread and subthread in the results
+list is treated as a foldable section, with its first message as
+its header.
+
+The mode just makes available in the tree buffer all the
+keybindings in info:emacs#Outline_Mode, and binds the following
+additional keys:
+
+.. el:define-key:: <tab>
+
+   Cycle visibility state of the current message's tree.
+
+.. el:define-key:: <M-tab>
+
+   Cycle visibility state of all trees in the buffer.
+
+The behaviour of this minor mode is affected by the following
+customizable variables:
+
+.. el:defcustom:: notmuch-tree-outline-enabled
+
+   |docstring::notmuch-tree-outline-enabled|
+
+.. el:defcustom:: notmuch-tree-outline-visibility
+
+   |docstring::notmuch-tree-outline-visibility|
+
+.. el:defcustom:: notmuch-tree-outline-auto-close
+
+   |docstring::notmuch-tree-outline-auto-close|
+
+.. el:defcustom:: notmuch-tree-outline-open-on-next
+
+   |docstring::notmuch-tree-outline-open-on-next|
 
 .. _notmuch-unthreaded:
 
 
 .. _notmuch-unthreaded:
 
@@ -524,12 +664,12 @@ is presented.
 
 Keybindings are the same as :any:`notmuch-tree`.
 
 
 Keybindings are the same as :any:`notmuch-tree`.
 
-.. emacsvar:: notmuch-unthreaded-result-format
+.. el:defcustom:: notmuch-unthreaded-result-format
 
    |docstring::notmuch-unthreaded-result-format|
 
 
    |docstring::notmuch-unthreaded-result-format|
 
-   See also :emacsvar:`notmuch-search-result-format` and
-   :emacsvar:`notmuch-tree-result-format`.
+   See also :el:defcustom:`notmuch-search-result-format` and
+   :el:defcustom:`notmuch-tree-result-format`.
 
 Global key bindings
 ===================
 
 Global key bindings
 ===================
@@ -537,13 +677,19 @@ Global key bindings
 Several features are accessible from most places in notmuch through the
 following key bindings:
 
 Several features are accessible from most places in notmuch through the
 following key bindings:
 
-``j``
+.. el:define-key:: j
+
     Jump to saved searches using :ref:`notmuch-jump`.
 
     Jump to saved searches using :ref:`notmuch-jump`.
 
-``k``
+.. el:define-key:: k
+
     Tagging operations using :ref:`notmuch-tag-jump`
 
     Tagging operations using :ref:`notmuch-tag-jump`
 
-``C-_`` ``C-/`` ``C-x u``: Undo previous tagging operation using :ref:`notmuch-tag-undo`
+.. el:define-key:: C-_
+   C-/
+   C-x u
+
+   Undo previous tagging operation using :any:`notmuch-tag-undo`
 
 .. _notmuch-jump:
 
 
 .. _notmuch-jump:
 
@@ -570,29 +716,31 @@ prefix (:kbd:`C-u k`), notmuch displays a menu of the reverses of the
 operations specified in ``notmuch-tagging-keys``; i.e. each
 ``+tag`` is replaced by ``-tag`` and vice versa.
 
 operations specified in ``notmuch-tagging-keys``; i.e. each
 ``+tag`` is replaced by ``-tag`` and vice versa.
 
-.. emacsvar:: notmuch-tagging-keys
+.. el:defcustom:: notmuch-tagging-keys
 
   |docstring::notmuch-tagging-keys|
 
 
   |docstring::notmuch-tagging-keys|
 
-.. _notmuch-tag-undo:
 
 notmuch-tag-undo
 ----------------
 
 
 notmuch-tag-undo
 ----------------
 
-Each notmuch buffer supporting tagging operations (i.e buffers in
+Each notmuch buffer supporting tagging operations (i.e. buffers in
 :any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
 :any:`notmuch-unthreaded` mode) keeps a local stack of tagging
 :any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
 :any:`notmuch-unthreaded` mode) keeps a local stack of tagging
-operations. These can be undone via :emacscmd:`notmuch-tag-undo`. By default
+operations. These can be undone via :any:`notmuch-tag-undo`. By default
 this is bound to the usual Emacs keys for undo.
 
 this is bound to the usual Emacs keys for undo.
 
-.. emacscmd:: notmuch-tag-undo
+.. el:define-key::  C-_
+   C-/
+   C-x u
+   M-x notmuch-tag-undo
 
    |docstring::notmuch-tag-undo|
 
 Buffer navigation
 =================
 
 
    |docstring::notmuch-tag-undo|
 
 Buffer navigation
 =================
 
-.. emacscmd:: notmuch-cycle-notmuch-buffers
+.. el:define-key:: M-x notmuch-cycle-notmuch-buffers
 
    |docstring::notmuch-cycle-notmuch-buffers|
 
 
    |docstring::notmuch-cycle-notmuch-buffers|
 
@@ -604,25 +752,25 @@ Configuration
 Importing Mail
 --------------
 
 Importing Mail
 --------------
 
-.. emacscmd:: notmuch-poll
+.. el:define-key:: M-x notmuch-poll
 
    |docstring::notmuch-poll|
 
 
    |docstring::notmuch-poll|
 
-.. emacsvar:: notmuch-poll-script
+.. el:defcustom:: notmuch-poll-script
 
    |docstring::notmuch-poll-script|
 
 Sending Mail
 ------------
 
 
    |docstring::notmuch-poll-script|
 
 Sending Mail
 ------------
 
-.. emacsvar:: mail-user-agent
+.. el:defcustom:: mail-user-agent
 
        Emacs consults the variable :code:`mail-user-agent` to choose a mail
        sending package for commands like :code:`report-emacs-bug` and
        :code:`compose-mail`.  To use ``notmuch`` for this, customize this
        variable to the symbol :code:`notmuch-user-agent`.
 
 
        Emacs consults the variable :code:`mail-user-agent` to choose a mail
        sending package for commands like :code:`report-emacs-bug` and
        :code:`compose-mail`.  To use ``notmuch`` for this, customize this
        variable to the symbol :code:`notmuch-user-agent`.
 
-.. emacsvar:: message-dont-reply-to-names
+.. el:defcustom:: message-dont-reply-to-names
 
        When composing mail replies, Emacs's message mode uses the
        variable :code:`message-dont-reply-to-names` to exclude
 
        When composing mail replies, Emacs's message mode uses the
        variable :code:`message-dont-reply-to-names` to exclude
index 1a4cdda22b95ffee9434b589f0912700b8c22b02..f756254cb8513ec062ca692299fbb39e4f683fe1 100644 (file)
@@ -153,8 +153,7 @@ matching `notmuch-address-completion-headers-regexp'."
 ;;; Setup
 
 (defun notmuch-address-selection-function (prompt collection initial-input)
 ;;; Setup
 
 (defun notmuch-address-selection-function (prompt collection initial-input)
-  "Call (`completing-read'
-      PROMPT COLLECTION nil nil INITIAL-INPUT 'notmuch-address-history)"
+  "Default address selection function: delegate to completing read."
   (completing-read
    prompt collection nil nil initial-input 'notmuch-address-history))
 
   (completing-read
    prompt collection nil nil initial-input 'notmuch-address-history))
 
index a521497784ec27e91cf9c7ee905641b3d4459012..254e6407cecefbbd8656321d9283cf63d360afca 100755 (executable)
@@ -41,6 +41,9 @@ CREATE_FRAME=
 ELISP=
 MAILTO=
 HELLO=
 ELISP=
 MAILTO=
 HELLO=
+TO_SEP=
+CC_SEP=
+BCC_SEP=
 
 # Short options compatible with mutt(1).
 while getopts :s:c:b:i:h opt; do
 
 # Short options compatible with mutt(1).
 while getopts :s:c:b:i:h opt; do
@@ -86,13 +89,16 @@ while getopts :s:c:b:i:h opt; do
            ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")"
            ;;
        --to)
            ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")"
            ;;
        --to)
-           ELISP="${ELISP} (message-goto-to) (insert \"${OPTARG}, \")"
+           ELISP="${ELISP} (message-goto-to) (insert \"${TO_SEP}${OPTARG}\")"
+           TO_SEP=", "
            ;;
        --cc|c)
            ;;
        --cc|c)
-           ELISP="${ELISP} (message-goto-cc) (insert \"${OPTARG}, \")"
+           ELISP="${ELISP} (message-goto-cc) (insert \"${CC_SEP}${OPTARG}\")"
+           CC_SEP=", "
            ;;
        --bcc|b)
            ;;
        --bcc|b)
-           ELISP="${ELISP} (message-goto-bcc) (insert \"${OPTARG}, \")"
+           ELISP="${ELISP} (message-goto-bcc) (insert \"${BCC_SEP}${OPTARG}\")"
+           BCC_SEP=", "
            ;;
        --body|i)
            ELISP="${ELISP} (message-goto-body) (insert-file \"${OPTARG}\")"
            ;;
        --body|i)
            ELISP="${ELISP} (message-goto-body) (insert-file \"${OPTARG}\")"
index 4662e704f5c253ca99d1eb47456571d41faf3392..b6d1e2aefa67d40c03268e8294716846942c2dc0 100644 (file)
 (declare-function notmuch-poll "notmuch-lib" ())
 (declare-function notmuch-tree "notmuch-tree"
                  (&optional query query-context target buffer-name
 (declare-function notmuch-poll "notmuch-lib" ())
 (declare-function notmuch-tree "notmuch-tree"
                  (&optional query query-context target buffer-name
-                            open-target unthreaded parent-buffer oldest-first))
+                            open-target unthreaded parent-buffer
+                            oldest-first hide-excluded))
 (declare-function notmuch-unthreaded "notmuch-tree"
                  (&optional query query-context target buffer-name
 (declare-function notmuch-unthreaded "notmuch-tree"
                  (&optional query query-context target buffer-name
-                            open-target))
+                            open-target oldest-first hide-excluded))
 
 
 ;;; Options
 
 
 ;;; Options
@@ -143,9 +144,13 @@ a plist. Supported properties are
   :sort-order      Specify the sort order to be used for the search.
                    Possible values are `oldest-first', `newest-first'
                    or nil. Nil means use the default sort order.
   :sort-order      Specify the sort order to be used for the search.
                    Possible values are `oldest-first', `newest-first'
                    or nil. Nil means use the default sort order.
+  :excluded        Whether to show mail with excluded tags in the
+                   search. Possible values are `hide', `show',
+                   or nil. Nil means use the default value of
+                   `notmuch-search-hide-excluded'.
   :search-type     Specify whether to run the search in search-mode,
                    tree mode or unthreaded mode. Set to `tree' to
   :search-type     Specify whether to run the search in search-mode,
                    tree mode or unthreaded mode. Set to `tree' to
-                   specify tree mode, 'unthreaded to specify
+                   specify tree mode, \\='unthreaded to specify
                    unthreaded mode, and set to nil (or anything
                    except tree and unthreaded) to specify search
                    mode.
                    unthreaded mode, and set to nil (or anything
                    except tree and unthreaded) to specify search
                    mode.
@@ -484,19 +489,19 @@ diagonal."
             append (notmuch-hello-reflect-generate-row ncols nrows row list))))
 
 (defun notmuch-hello-widget-search (widget &rest _ignore)
             append (notmuch-hello-reflect-generate-row ncols nrows row list))))
 
 (defun notmuch-hello-widget-search (widget &rest _ignore)
-  (cl-case (widget-get widget :notmuch-search-type)
-   (tree
-    (let ((n (notmuch-search-format-buffer-name (widget-value widget) "tree" t)))
-      (notmuch-tree (widget-get widget :notmuch-search-terms)
-                   nil nil n nil nil nil
-                   (widget-get widget :notmuch-search-oldest-first))))
-   (unthreaded
-    (let ((n (notmuch-search-format-buffer-name (widget-value widget)
-                                               "unthreaded" t)))
-      (notmuch-unthreaded (widget-get widget :notmuch-search-terms) nil nil n)))
-   (t
-    (notmuch-search (widget-get widget :notmuch-search-terms)
-                   (widget-get widget :notmuch-search-oldest-first)))))
+  (let ((search-terms (widget-get widget :notmuch-search-terms))
+       (oldest-first (widget-get widget :notmuch-search-oldest-first))
+       (exclude (widget-get widget :notmuch-search-hide-excluded)))
+    (cl-case (widget-get widget :notmuch-search-type)
+      (tree
+       (let ((n (notmuch-search-format-buffer-name (widget-value widget) "tree" t)))
+        (notmuch-tree search-terms nil nil n nil nil nil oldest-first exclude)))
+      (unthreaded
+       (let ((n (notmuch-search-format-buffer-name (widget-value widget)
+                                                  "unthreaded" t)))
+        (notmuch-unthreaded search-terms nil nil n nil oldest-first exclude)))
+      (t
+       (notmuch-search search-terms oldest-first exclude)))))
 
 (defun notmuch-saved-search-count (search)
   (car (notmuch--process-lines notmuch-command "count" search)))
 
 (defun notmuch-saved-search-count (search)
   (car (notmuch--process-lines notmuch-command "count" search)))
@@ -643,6 +648,10 @@ with `notmuch-hello-query-counts'."
                                     (newest-first nil)
                                     (oldest-first t)
                                     (otherwise notmuch-search-oldest-first)))
                                     (newest-first nil)
                                     (oldest-first t)
                                     (otherwise notmuch-search-oldest-first)))
+                    (exclude (cl-case (plist-get elem :excluded)
+                               (hide t)
+                               (show nil)
+                               (otherwise notmuch-search-hide-excluded)))
                     (search-type (plist-get elem :search-type))
                     (msg-count (plist-get elem :count)))
                (widget-insert (format "%8s "
                     (search-type (plist-get elem :search-type))
                     (msg-count (plist-get elem :count)))
                (widget-insert (format "%8s "
@@ -652,6 +661,7 @@ with `notmuch-hello-query-counts'."
                               :notmuch-search-terms query
                               :notmuch-search-oldest-first oldest-first
                               :notmuch-search-type search-type
                               :notmuch-search-terms query
                               :notmuch-search-oldest-first oldest-first
                               :notmuch-search-type search-type
+                              :notmuch-search-hide-excluded exclude
                               name)
                (setq column-indent
                      (1+ (max 0 (- column-width (length name)))))))
                               name)
                (setq column-indent
                      (1+ (max 0 (- column-width (length name)))))))
@@ -717,7 +727,8 @@ with `notmuch-hello-query-counts'."
   "Keymap for \"notmuch hello\" buffers.")
 
 (define-derived-mode notmuch-hello-mode fundamental-mode "notmuch-hello"
   "Keymap for \"notmuch hello\" buffers.")
 
 (define-derived-mode notmuch-hello-mode fundamental-mode "notmuch-hello"
-  "Major mode for convenient notmuch navigation. This is your entry portal into notmuch.
+  "Major mode for convenient notmuch navigation. This is your entry
+portal into notmuch.
 
 Saved searches are \"bookmarks\" for arbitrary queries. Hit RET
 or click on a saved search to view matching threads. Edit saved
 
 Saved searches are \"bookmarks\" for arbitrary queries. Hit RET
 or click on a saved search to view matching threads. Edit saved
@@ -853,7 +864,8 @@ Complete list of currently available key bindings:
        (widget-create 'notmuch-search-item :value search :size width)))))
 
 (defun notmuch-hello-insert-searches (title query-list &rest options)
        (widget-create 'notmuch-search-item :value search :size width)))))
 
 (defun notmuch-hello-insert-searches (title query-list &rest options)
-  "Insert a section with TITLE showing a list of buttons made from QUERY-LIST.
+  "Insert a section with TITLE showing a list of buttons made from
+QUERY-LIST.
 
 QUERY-LIST should ideally be a plist but for backwards
 compatibility other forms are also accepted (see
 
 QUERY-LIST should ideally be a plist but for backwards
 compatibility other forms are also accepted (see
@@ -867,13 +879,16 @@ Supports the following entries in OPTIONS as a plist:
 :show-empty-searches - show buttons with no matching messages
 :hide-if-empty - hide if no buttons would be shown
    (only makes sense without :show-empty-searches)
 :show-empty-searches - show buttons with no matching messages
 :hide-if-empty - hide if no buttons would be shown
    (only makes sense without :show-empty-searches)
-:filter - This can be a function that takes the search query as its argument and
-   returns a filter to be used in conjunction with the query for that search or nil
-   to hide the element. This can also be a string that is used as a combined with
-   each query using \"and\".
-:filter-count - Separate filter to generate the count displayed each search. Accepts
-   the same values as :filter. If :filter and :filter-count are specified, this
-   will be used instead of :filter, not in conjunction with it."
+:filter - This can be a function that takes the search query as
+   its argument and returns a filter to be used in conjunction
+   with the query for that search or nil to hide the
+   element. This can also be a string that is used as a combined
+   with each query using \"and\".
+:filter-count - Separate filter to generate the count displayed
+   each search. Accepts the same values as :filter. If :filter
+   and :filter-count are specified, this will be used instead of
+   :filter, not in conjunction with it."
+
   (widget-insert title ": ")
   (when (and notmuch-hello-first-run (plist-get options :initially-hidden))
     (add-to-list 'notmuch-hello-hidden-sections title))
   (widget-insert title ": ")
   (when (and notmuch-hello-first-run (plist-get options :initially-hidden))
     (add-to-list 'notmuch-hello-hidden-sections title))
index 6a2769282ec666190b1a7cdeea8364782389977f..3161ed9526d52d5b8de9a9d08eb3bef626eb38ec 100644 (file)
@@ -50,15 +50,21 @@ fast way to jump to a saved search from anywhere in Notmuch."
                 (cl-case (plist-get saved-search :sort-order)
                   (newest-first nil)
                   (oldest-first t)
                 (cl-case (plist-get saved-search :sort-order)
                   (newest-first nil)
                   (oldest-first t)
-                  (otherwise (default-value 'notmuch-search-oldest-first)))))
+                  (otherwise (default-value 'notmuch-search-oldest-first))))
+               (exclude (cl-case (plist-get saved-search :excluded)
+                          (hide t)
+                          (show nil)
+                          (otherwise notmuch-search-hide-excluded))))
            (push (list key name
                        (cond
                         ((eq (plist-get saved-search :search-type) 'tree)
            (push (list key name
                        (cond
                         ((eq (plist-get saved-search :search-type) 'tree)
-                         (lambda () (notmuch-tree query)))
+                         (lambda () (notmuch-tree query nil nil nil nil nil nil
+                                             oldest-first exclude)))
                         ((eq (plist-get saved-search :search-type) 'unthreaded)
                         ((eq (plist-get saved-search :search-type) 'unthreaded)
-                         (lambda () (notmuch-unthreaded query)))
+                         (lambda () (notmuch-unthreaded query nil nil nil nil
+                                                   oldest-first exclude)))
                         (t
                         (t
-                         (lambda () (notmuch-search query oldest-first)))))
+                         (lambda () (notmuch-search query oldest-first exclude)))))
                  action-map)))))
     (setq action-map (nreverse action-map))
     (if action-map
                  action-map)))))
     (setq action-map (nreverse action-map))
     (if action-map
index 84ba8c5e56de2aa151682bea74e30a4f3808b2e3..bf9c4a534a24f5d5c088857ce420600604259326 100644 (file)
@@ -105,6 +105,16 @@ search."
   :group 'notmuch-search)
 (make-variable-buffer-local 'notmuch-search-oldest-first)
 
   :group 'notmuch-search)
 (make-variable-buffer-local 'notmuch-search-oldest-first)
 
+(defcustom notmuch-search-hide-excluded t
+  "Hide mail tagged with a excluded tag.
+
+Excluded tags are defined in the users configuration file under
+the search section. When this variable is true, any mail with
+such a tag will not be shown in the search output."
+  :type 'boolean
+  :group 'notmuch-search)
+(make-variable-buffer-local 'notmuch-search-hide-excluded)
+
 (defcustom notmuch-poll-script nil
   "[Deprecated] Command to run to incorporate new mail into the notmuch database.
 
 (defcustom notmuch-poll-script nil
   "[Deprecated] Command to run to incorporate new mail into the notmuch database.
 
@@ -414,9 +424,9 @@ This is similar to `describe-function' for the current major
 mode, but bindings tables are shown with documentation strings
 rather than command names.  By default, this uses the first line
 of each command's documentation string.  A command can override
 mode, but bindings tables are shown with documentation strings
 rather than command names.  By default, this uses the first line
 of each command's documentation string.  A command can override
-this by setting the 'notmuch-doc property of its command symbol.
+this by setting the \\='notmuch-doc property of its command symbol.
 A command that supports a prefix argument can explicitly document
 A command that supports a prefix argument can explicitly document
-its prefixed behavior by setting the 'notmuch-prefix-doc property
+its prefixed behavior by setting the \\='notmuch-prefix-doc property
 of its command symbol."
   (interactive)
   (let ((doc (substitute-command-keys
 of its command symbol."
   (interactive)
   (let ((doc (substitute-command-keys
@@ -703,6 +713,7 @@ current buffer, if possible."
          (when (mm-inlinable-p handle)
            (set-buffer display-buffer)
            (mm-display-part handle)
          (when (mm-inlinable-p handle)
            (set-buffer display-buffer)
            (mm-display-part handle)
+           (plist-put part :undisplayer (mm-handle-undisplayer handle))
            t))))))
 
 ;;; Generic Utilities
            t))))))
 
 ;;; Generic Utilities
@@ -725,7 +736,7 @@ single element face list."
     (list face)))
 
 (defun notmuch-apply-face (object face &optional below start end)
     (list face)))
 
 (defun notmuch-apply-face (object face &optional below start end)
-  "Combine FACE into the 'face text property of OBJECT between START and END.
+  "Combine FACE into the \\='face text property of OBJECT between START and END.
 
 This function combines FACE with any existing faces between START
 and END in OBJECT.  Attributes specified by FACE take precedence
 
 This function combines FACE with any existing faces between START
 and END in OBJECT.  Attributes specified by FACE take precedence
index ac878a619d07e7c4947f1c359b9d6825580516b6..bf62b65691810f491cb9f98d04e0acc760a4a3ad 100644 (file)
@@ -401,9 +401,10 @@ instead of `message-mode' and SWITCH-FUNCTION is mandatory."
               (addr (and good-tokens (mapconcat #'identity good-tokens ", "))))
          (message-replace-header header addr))))))
 
               (addr (and good-tokens (mapconcat #'identity good-tokens ", "))))
          (message-replace-header header addr))))))
 
+;;;#autoload
 (defun notmuch-mua-mail (&optional to subject other-headers _continue
                                   switch-function yank-action send-actions
 (defun notmuch-mua-mail (&optional to subject other-headers _continue
                                   switch-function yank-action send-actions
-                                  return-action &rest ignored)
+                                  return-action &rest _ignored)
   "Invoke the notmuch mail composition window.
 
 The position of point when the function returns differs depending
   "Invoke the notmuch mail composition window.
 
 The position of point when the function returns differs depending
@@ -416,11 +417,6 @@ moved to the \"To:\" header."
     (let ((user-agent (funcall notmuch-mua-user-agent-function)))
       (unless (string-empty-p user-agent)
        (push (cons 'User-Agent user-agent) other-headers))))
     (let ((user-agent (funcall notmuch-mua-user-agent-function)))
       (unless (string-empty-p user-agent)
        (push (cons 'User-Agent user-agent) other-headers))))
-  (unless (assq 'From other-headers)
-    (push (cons 'From (message-make-from
-                      (notmuch-user-name)
-                      (notmuch-user-primary-email)))
-         other-headers))
   (notmuch-mua-pop-to-buffer (message-buffer-name "mail" to)
                             (or switch-function
                                 (notmuch-mua-get-switch-function)))
   (notmuch-mua-pop-to-buffer (message-buffer-name "mail" to)
                             (or switch-function
                                 (notmuch-mua-get-switch-function)))
@@ -439,6 +435,11 @@ moved to the \"To:\" header."
        ;; Cause `message-setup-1' to do things relevant for mail,
        ;; such as observe `message-default-mail-headers'.
        (message-this-is-mail t))
        ;; Cause `message-setup-1' to do things relevant for mail,
        ;; such as observe `message-default-mail-headers'.
        (message-this-is-mail t))
+    (unless (assq 'From headers)
+      (push (cons 'From (message-make-from
+                        (notmuch-user-name)
+                        (notmuch-user-primary-email)))
+           headers))
     (message-setup-1 headers yank-action send-actions return-action))
   (notmuch-fcc-header-setup)
   (notmuch-mua--remove-dont-reply-to-names)
     (message-setup-1 headers yank-action send-actions return-action))
   (notmuch-fcc-header-setup)
   (notmuch-mua--remove-dont-reply-to-names)
@@ -622,20 +623,24 @@ unencrypted.  Really send? "))))
          (message-send-and-exit arg)
        (message-send arg)))))
 
          (message-send-and-exit arg)
        (message-send arg)))))
 
+;;;#autoload
 (defun notmuch-mua-send-and-exit (&optional arg)
   (interactive "P")
   (notmuch-mua-send-common arg t))
 
 (defun notmuch-mua-send-and-exit (&optional arg)
   (interactive "P")
   (notmuch-mua-send-common arg t))
 
+;;;#autoload
 (defun notmuch-mua-send (&optional arg)
   (interactive "P")
   (notmuch-mua-send-common arg))
 
 (defun notmuch-mua-send (&optional arg)
   (interactive "P")
   (notmuch-mua-send-common arg))
 
+;;;#autoload
 (defun notmuch-mua-kill-buffer ()
   (interactive)
   (message-kill-buffer))
 
 ;;; _
 
 (defun notmuch-mua-kill-buffer ()
   (interactive)
   (message-kill-buffer))
 
 ;;; _
 
+;;;#autoload
 (define-mail-user-agent 'notmuch-user-agent
   'notmuch-mua-mail
   'notmuch-mua-send-and-exit
 (define-mail-user-agent 'notmuch-user-agent
   'notmuch-mua-mail
   'notmuch-mua-send-and-exit
index f04b07c2e51b28e34f03469b88205d279c45a587..710c60e15ec12c7b3f5d6ca02d869d5be45f03d6 100644 (file)
@@ -35,7 +35,7 @@ complete S-expression from the input.  However, it extends this
 with an additional function that requires the next value in the
 input to be a list and descends into it, allowing its elements to
 be read one at a time or further descended into.  Both functions
 with an additional function that requires the next value in the
 input to be a list and descends into it, allowing its elements to
 be read one at a time or further descended into.  Both functions
-can return 'retry to indicate that not enough input is available.
+can return \\='retry to indicate that not enough input is available.
 
 The parser always consumes input from point in the current
 buffer.  Hence, the caller is allowed to delete any data before
 
 The parser always consumes input from point in the current
 buffer.  Hence, the caller is allowed to delete any data before
@@ -52,10 +52,10 @@ point and may resynchronize after an error by moving point."
 (defun notmuch-sexp-read (sp)
   "Consume and return the value at point in the current buffer.
 
 (defun notmuch-sexp-read (sp)
   "Consume and return the value at point in the current buffer.
 
-Returns 'retry if there is insufficient input to parse a complete
+Returns \\='retry if there is insufficient input to parse a complete
 value (though it may still move point over whitespace).  If the
 parser is currently inside a list and the next token ends the
 value (though it may still move point over whitespace).  If the
 parser is currently inside a list and the next token ends the
-list, this moves point just past the terminator and returns 'end.
+list, this moves point just past the terminator and returns \\='end.
 Otherwise, this moves point to just past the end of the value and
 returns the value."
   (skip-chars-forward " \n\r\t")
 Otherwise, this moves point to just past the end of the value and
 returns the value."
   (skip-chars-forward " \n\r\t")
@@ -125,7 +125,7 @@ returns the value."
 (defun notmuch-sexp-begin-list (sp)
   "Parse the beginning of a list value and enter the list.
 
 (defun notmuch-sexp-begin-list (sp)
   "Parse the beginning of a list value and enter the list.
 
-Returns 'retry if there is insufficient input to parse the
+Returns \\='retry if there is insufficient input to parse the
 beginning of the list.  If this is able to parse the beginning of
 a list, it moves point past the token that opens the list and
 returns t.  Later calls to `notmuch-sexp-read' will return the
 beginning of the list.  If this is able to parse the beginning of
 a list, it moves point past the token that opens the list and
 returns t.  Later calls to `notmuch-sexp-read' will return the
index 85fa1f218cfae1111cdb3e053c49cd4e05540b38..8d9f1b0830319c5d2bb2262029334d89b5174a10 100644 (file)
 ;;; Utility functions
 
 (defun notmuch-print-run-evince (file)
 ;;; Utility functions
 
 (defun notmuch-print-run-evince (file)
-  "View FILE using 'evince'."
+  "View FILE using `evince'."
   (start-process "evince" nil "evince" file))
 
 (defun notmuch-print-run-muttprint (&optional output)
   (start-process "evince" nil "evince" file))
 
 (defun notmuch-print-run-muttprint (&optional output)
-  "Pass the contents of the current buffer to 'muttprint'.
+  "Pass the contents of the current buffer to `muttprint'.
 
 Optional OUTPUT allows passing a list of flags to muttprint."
   (apply #'notmuch--call-process-region (point-min) (point-max)
 
 Optional OUTPUT allows passing a list of flags to muttprint."
   (apply #'notmuch--call-process-region (point-min) (point-max)
index e9a9ac2cc08c6e00dd7a0e18fa8a1f61430c071a..4c0ad74d5043cefcefaa86ab65313660dade6884 100644 (file)
@@ -452,14 +452,19 @@ operation on the contents of the current buffer."
 (defun notmuch-show-update-tags (tags)
   "Update the displayed tags of the current message."
   (save-excursion
 (defun notmuch-show-update-tags (tags)
   "Update the displayed tags of the current message."
   (save-excursion
-    (goto-char (notmuch-show-message-top))
-    (when (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
-      (let ((inhibit-read-only t))
-       (replace-match (concat "("
-                              (notmuch-tag-format-tags
-                               tags
-                               (notmuch-show-get-prop :orig-tags))
-                              ")"))))))
+    (let ((inhibit-read-only t)
+         (start (notmuch-show-message-top))
+         (depth (notmuch-show-get-prop :depth))
+         (orig-tags (notmuch-show-get-prop :orig-tags))
+         (props (notmuch-show-get-message-properties))
+         (extent (notmuch-show-message-extent)))
+      (goto-char start)
+      (notmuch-show-insert-headerline props depth tags orig-tags)
+      (put-text-property start (1+ start)
+                        :notmuch-message-properties props)
+      (put-text-property (car extent) (cdr extent) :notmuch-message-extent extent)
+      ;; delete original headerline, but do not save to kill ring
+      (delete-region (point) (1+ (line-end-position))))))
 
 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
 
 (defun notmuch-clean-address (address)
   "Try to clean a single email ADDRESS for display. Return a cons
@@ -530,11 +535,17 @@ Return unchanged ADDRESS if parsing fails."
          (plist-put msg :height height)
          height))))
 
          (plist-put msg :height height)
          height))))
 
-(defun notmuch-show-insert-headerline (headers date tags depth duplicate file-count)
+(defun notmuch-show-insert-headerline (msg-plist depth tags &optional orig-tags)
   "Insert a notmuch style headerline based on HEADERS for a
 message at DEPTH in the current thread."
   "Insert a notmuch style headerline based on HEADERS for a
 message at DEPTH in the current thread."
-  (let ((start (point))
-       (from (notmuch-sanitize
+  (let* ((start (point))
+        (headers (plist-get msg-plist :headers))
+        (duplicate (or (plist-get msg-plist :duplicate) 0))
+        (file-count (length (plist-get msg-plist :filename)))
+        (date (or (and notmuch-show-relative-dates
+                       (plist-get msg-plist :date_relative))
+                  (plist-get headers :Date)))
+        (from (notmuch-sanitize
               (notmuch-show-clean-address (plist-get headers :From)))))
     (when (string-match "\\cR" from)
       ;; If the From header has a right-to-left character add
               (notmuch-show-clean-address (plist-get headers :From)))))
     (when (string-match "\\cR" from)
       ;; If the From header has a right-to-left character add
@@ -549,7 +560,7 @@ message at DEPTH in the current thread."
            " ("
            date
            ") ("
            " ("
            date
            ") ("
-           (notmuch-tag-format-tags tags tags)
+           (notmuch-tag-format-tags tags (or orig-tags tags))
            ")")
     (insert
      (if (> file-count 1)
            ")")
     (insert
      (if (> file-count 1)
@@ -633,8 +644,24 @@ message at DEPTH in the current thread."
                (when show
                  (button-put button :notmuch-lazy-part nil)
                  (notmuch-show-lazy-part lazy-part button))
                (when show
                  (button-put button :notmuch-lazy-part nil)
                  (notmuch-show-lazy-part lazy-part button))
-             ;; else there must be an overlay.
-             (overlay-put overlay 'invisible (not show))
+             (let* ((part (plist-get properties :notmuch-part))
+                    (undisplayer (plist-get part :undisplayer))
+                    (mime-type (plist-get part :computed-type))
+                    (redisplay-data (button-get button
+                                                :notmuch-redisplay-data))
+                    (imagep (string-match "^image/" mime-type)))
+               (cond
+                ((and imagep (not show) undisplayer)
+                 ;; call undisplayer thunk created by gnus.
+                 (funcall undisplayer)
+                 ;; there is an extra newline left
+                 (delete-region
+                  (+ 1 (button-end button))
+                  (+ 2 (button-end button))))
+                ((and imagep show redisplay-data)
+                 (notmuch-show-lazy-part redisplay-data button))
+                (t
+                 (overlay-put overlay 'invisible (not show)))))
              t)))))))
 
 ;;; Part content ID handling
              t)))))))
 
 ;;; Part content ID handling
@@ -1008,10 +1035,13 @@ will return nil if the CID is unknown or cannot be retrieved."
           (part-end (copy-marker (point) t))
           ;; We have to save the depth as we can't find the depth
           ;; when narrowed.
           (part-end (copy-marker (point) t))
           ;; We have to save the depth as we can't find the depth
           ;; when narrowed.
-          (depth (notmuch-show-get-depth)))
+          (depth (notmuch-show-get-depth))
+          (mime-type (plist-get (cadr part-args) :computed-type)))
       (save-restriction
        (narrow-to-region part-beg part-end)
        (delete-region part-beg part-end)
       (save-restriction
        (narrow-to-region part-beg part-end)
        (delete-region part-beg part-end)
+       (when (and mime-type (string-match "^image/" mime-type))
+         (button-put button :notmuch-redisplay-data part-args))
        (apply #'notmuch-show-insert-bodypart-internal part-args)
        (indent-rigidly part-beg
                        part-end
        (apply #'notmuch-show-insert-bodypart-internal part-args)
        (indent-rigidly part-beg
                        part-end
@@ -1095,14 +1125,18 @@ is t, hide the part initially and show the button."
                             (and deep button)
                             (and high button)
                             (and long button))))
                             (and deep button)
                             (and high button)
                             (and long button))))
-        (content-beg (point)))
+        (content-beg (point))
+        (part-data (list msg part mime-type nth depth button)))
     ;; Store the computed mime-type for later use (e.g. by attachment handlers).
     (plist-put part :computed-type mime-type)
     ;; Store the computed mime-type for later use (e.g. by attachment handlers).
     (plist-put part :computed-type mime-type)
-    (if show-part
-       (notmuch-show-insert-bodypart-internal msg part mime-type nth depth button)
+    (cond
+     (show-part
+      (apply #'notmuch-show-insert-bodypart-internal part-data)
+      (when (and button (string-match "^image/" mime-type))
+       (button-put button :notmuch-redisplay-data part-data)))
+     (t
       (when button
       (when button
-       (button-put button :notmuch-lazy-part
-                   (list msg part mime-type nth depth button))))
+       (button-put button :notmuch-lazy-part part-data))))
     ;; Some of the body part handlers leave point somewhere up in the
     ;; part, so we make sure that we're down at the end.
     (goto-char (point-max))
     ;; Some of the body part handlers leave point somewhere up in the
     ;; part, so we make sure that we're down at the end.
     (goto-char (point-max))
@@ -1135,6 +1169,16 @@ is t, hide the part initially and show the button."
 (make-variable-buffer-local 'notmuch-show-previous-subject)
 
 (defun notmuch-show-choose-duplicate (duplicate)
 (make-variable-buffer-local 'notmuch-show-previous-subject)
 
 (defun notmuch-show-choose-duplicate (duplicate)
+  "Display message file with index DUPLICATE in place of the current one.
+
+Message file indices are based on the order the files are
+discovered by `notmuch new' (and hence are somewhat arbitrary),
+and correspond to those passed to the \"\\-\\-duplicate\" arguments
+to the CLI.
+
+When called interactively, the function will prompt for the index
+of the file to display.  An error will be signaled if the index
+is out of range."
   (interactive "Nduplicate: ")
   (let ((count (length (notmuch-show-get-prop :filename))))
     (when (or (> duplicate count)
   (interactive "Nduplicate: ")
   (let ((count (length (notmuch-show-get-prop :filename))))
     (when (or (> duplicate count)
@@ -1161,8 +1205,6 @@ is t, hide the part initially and show the button."
 (defun notmuch-show-insert-msg (msg depth)
   "Insert the message MSG at depth DEPTH in the current thread."
   (let* ((headers (plist-get msg :headers))
 (defun notmuch-show-insert-msg (msg depth)
   "Insert the message MSG at depth DEPTH in the current thread."
   (let* ((headers (plist-get msg :headers))
-        (duplicate (or (plist-get msg :duplicate) 0))
-        (files (length (plist-get msg :filename)))
         ;; Indentation causes the buffer offset of the start/end
         ;; points to move, so we must use markers.
         message-start message-end
         ;; Indentation causes the buffer offset of the start/end
         ;; points to move, so we must use markers.
         message-start message-end
@@ -1170,11 +1212,7 @@ is t, hide the part initially and show the button."
         headers-start headers-end
         (bare-subject (notmuch-show-strip-re (plist-get headers :Subject))))
     (setq message-start (point-marker))
         headers-start headers-end
         (bare-subject (notmuch-show-strip-re (plist-get headers :Subject))))
     (setq message-start (point-marker))
-    (notmuch-show-insert-headerline headers
-                                   (or (and notmuch-show-relative-dates
-                                            (plist-get msg :date_relative))
-                                       (plist-get headers :Date))
-                                   (plist-get msg :tags) depth duplicate files)
+    (notmuch-show-insert-headerline msg depth (plist-get msg :tags))
     (setq content-start (point-marker))
     ;; Set `headers-start' to point after the 'Subject:' header to be
     ;; compatible with the existing implementation. This just sets it
     (setq content-start (point-marker))
     ;; Set `headers-start' to point after the 'Subject:' header to be
     ;; compatible with the existing implementation. This just sets it
@@ -1528,6 +1566,7 @@ non-nil) then the state of the buffer (open/closed messages) is
 reset based on the original query."
   (interactive "P")
   (let ((inhibit-read-only t)
 reset based on the original query."
   (interactive "P")
   (let ((inhibit-read-only t)
+       (mm-inline-override-types (notmuch--inline-override-types))
        (state (unless reset-state
                 (notmuch-show-capture-state))))
     ;; `erase-buffer' does not seem to remove overlays, which can lead
        (state (unless reset-state
                 (notmuch-show-capture-state))))
     ;; `erase-buffer' does not seem to remove overlays, which can lead
@@ -2143,12 +2182,16 @@ to show, nil otherwise."
   "View the original source of the current message."
   (interactive)
   (let* ((id (notmuch-show-get-message-id))
   "View the original source of the current message."
   (interactive)
   (let* ((id (notmuch-show-get-message-id))
-        (buf (get-buffer-create (concat "*notmuch-raw-" id "*")))
+        (duplicate (notmuch-show-get-duplicate))
+        (args (if (> duplicate 1)
+                  (list (format "--duplicate=%d" duplicate) id)
+                (list id)))
+        (buf (get-buffer-create (format "*notmuch-raw-%s-%d*" id duplicate)))
         (inhibit-read-only t))
     (pop-to-buffer-same-window buf)
     (erase-buffer)
     (let ((coding-system-for-read 'no-conversion))
         (inhibit-read-only t))
     (pop-to-buffer-same-window buf)
     (erase-buffer)
     (let ((coding-system-for-read 'no-conversion))
-      (notmuch--call-process notmuch-command nil t nil "show" "--format=raw" id))
+      (apply #'notmuch--call-process notmuch-command nil t nil "show" "--format=raw" args))
     (goto-char (point-min))
     (set-buffer-modified-p nil)
     (setq buffer-read-only t)
     (goto-char (point-min))
     (set-buffer-modified-p nil)
     (setq buffer-read-only t)
@@ -2177,7 +2220,7 @@ message."
   (interactive (let ((query-string (if current-prefix-arg
                                       "Pipe all open messages to command: "
                                     "Pipe message to command: ")))
   (interactive (let ((query-string (if current-prefix-arg
                                       "Pipe all open messages to command: "
                                     "Pipe message to command: ")))
-                (list current-prefix-arg (read-string query-string))))
+                (list current-prefix-arg (read-shell-command query-string))))
   (let (shell-command)
     (if entire-thread
        (setq shell-command
   (let (shell-command)
     (if entire-thread
        (setq shell-command
@@ -2464,10 +2507,12 @@ kill-ring."
 (defun notmuch-show-stash-mlarchive-link (&optional mla)
   "Copy an ML Archive URI for the current message to the kill-ring.
 
 (defun notmuch-show-stash-mlarchive-link (&optional mla)
   "Copy an ML Archive URI for the current message to the kill-ring.
 
-This presumes that the message is available at the selected Mailing List Archive.
+This presumes that the message is available at the selected
+Mailing List Archive.
 
 
-If optional argument MLA is non-nil, use the provided key instead of prompting
-the user (see `notmuch-show-stash-mlarchive-link-alist')."
+If optional argument MLA is non-nil, use the provided key instead
+of prompting the user (see
+`notmuch-show-stash-mlarchive-link-alist')."
   (interactive)
   (let ((url (cdr (assoc
                   (or mla
   (interactive)
   (let ((url (cdr (assoc
                   (or mla
@@ -2484,12 +2529,15 @@ the user (see `notmuch-show-stash-mlarchive-link-alist')."
        (concat url (notmuch-show-get-message-id t))))))
 
 (defun notmuch-show-stash-mlarchive-link-and-go (&optional mla)
        (concat url (notmuch-show-get-message-id t))))))
 
 (defun notmuch-show-stash-mlarchive-link-and-go (&optional mla)
-  "Copy an ML Archive URI for the current message to the kill-ring and visit it.
+  "Copy an ML Archive URI for the current message to the
+ kill-ring and visit it.
 
 
-This presumes that the message is available at the selected Mailing List Archive.
+This presumes that the message is available at the selected
+Mailing List Archive.
 
 
-If optional argument MLA is non-nil, use the provided key instead of prompting
-the user (see `notmuch-show-stash-mlarchive-link-alist')."
+If optional argument MLA is non-nil, use the provided key instead
+of prompting the user (see
+`notmuch-show-stash-mlarchive-link-alist')."
   (interactive)
   (notmuch-show-stash-mlarchive-link mla)
   (browse-url (current-kill 0 t)))
   (interactive)
   (notmuch-show-stash-mlarchive-link mla)
   (browse-url (current-kill 0 t)))
index 959778819617f9cd23498818b2344103fb008c12..811018288f373b1df099fa7b791b27a47e313709 100644 (file)
@@ -159,7 +159,7 @@ place of the tag.
 For example, to replace a tag with another string, simply use
 that string as a formatting expression.  To change the foreground
 of a tag to red, use the expression
 For example, to replace a tag with another string, simply use
 that string as a formatting expression.  To change the foreground
 of a tag to red, use the expression
-  (propertize tag 'face '(:foreground \"red\"))
+  (propertize tag \\='face \\='(:foreground \"red\"))
 
 See also `notmuch-tag-format-image', which can help replace tags
 with images."
 
 See also `notmuch-tag-format-image', which can help replace tags
 with images."
@@ -191,7 +191,7 @@ By default this shows deleted tags with strike-through in red,
 unless strike-through is not available (e.g., emacs is running in
 a terminal) in which case it uses inverse video. To hide deleted
 tags completely set this to
 unless strike-through is not available (e.g., emacs is running in
 a terminal) in which case it uses inverse video. To hide deleted
 tags completely set this to
-  '((\".*\" nil))
+  \\='((\".*\" nil))
 
 See `notmuch-tag-formats' for full documentation."
   :group 'notmuch-show
 
 See `notmuch-tag-formats' for full documentation."
   :group 'notmuch-show
@@ -366,9 +366,9 @@ changed (the normal case) are shown using formats from
 (defcustom notmuch-before-tag-hook nil
   "Hooks that are run before tags of a message are modified.
 
 (defcustom notmuch-before-tag-hook nil
   "Hooks that are run before tags of a message are modified.
 
-'tag-changes' will contain the tags that are about to be added or removed as
+`tag-changes' will contain the tags that are about to be added or removed as
 a list of strings of the form \"+TAG\" or \"-TAG\".
 a list of strings of the form \"+TAG\" or \"-TAG\".
-'query' will be a string containing the search query that determines
+`query' will be a string containing the search query that determines
 the messages that are about to be tagged."
   :type 'hook
   :options '(notmuch-hl-line-mode)
 the messages that are about to be tagged."
   :type 'hook
   :options '(notmuch-hl-line-mode)
@@ -377,9 +377,9 @@ the messages that are about to be tagged."
 (defcustom notmuch-after-tag-hook nil
   "Hooks that are run after tags of a message are modified.
 
 (defcustom notmuch-after-tag-hook nil
   "Hooks that are run after tags of a message are modified.
 
-'tag-changes' will contain the tags that were added or removed as
+`tag-changes' will contain the tags that were added or removed as
 a list of strings of the form \"+TAG\" or \"-TAG\".
 a list of strings of the form \"+TAG\" or \"-TAG\".
-'query' will be a string containing the search query that determines
+`query' will be a string containing the search query that determines
 the messages that were tagged."
   :type 'hook
   :options '(notmuch-hl-line-mode)
 the messages that were tagged."
   :type 'hook
   :options '(notmuch-hl-line-mode)
index f63ac9a518ea43b6b0b62687f05b1f4a77f8cdf7..faec89c48a9a456a294d1202f240a17dde136ffa 100644 (file)
@@ -45,9 +45,6 @@
 (declare-function notmuch-search-previous-thread "notmuch" ())
 (declare-function notmuch-tree-from-search-thread "notmuch" ())
 
 (declare-function notmuch-search-previous-thread "notmuch" ())
 (declare-function notmuch-tree-from-search-thread "notmuch" ())
 
-;; the following variable is defined in notmuch.el
-(defvar notmuch-search-query-string)
-
 ;; this variable distinguishes the unthreaded display from the normal tree display
 (defvar-local notmuch-tree-unthreaded nil
   "A buffer local copy of argument unthreaded to the function notmuch-tree.")
 ;; this variable distinguishes the unthreaded display from the normal tree display
 (defvar-local notmuch-tree-unthreaded nil
   "A buffer local copy of argument unthreaded to the function notmuch-tree.")
@@ -203,7 +200,8 @@ Note that the author string should not contain whitespace
 
 (defface notmuch-tree-match-tree-face
   nil
 
 (defface notmuch-tree-match-tree-face
   nil
-  "Face used in tree mode for the thread tree block graphics in messages matching the query."
+  "Face used in tree mode for the thread tree block graphics in
+messages matching the query."
   :group 'notmuch-tree
   :group 'notmuch-faces)
 
   :group 'notmuch-tree
   :group 'notmuch-faces)
 
@@ -242,7 +240,8 @@ Note that the author string should not contain whitespace
 
 (defface notmuch-tree-no-match-tree-face
   nil
 
 (defface notmuch-tree-no-match-tree-face
   nil
-  "Face used in tree mode for the thread tree block graphics in messages matching the query."
+  "Face used in tree mode for the thread tree block graphics in
+messages matching the query."
   :group 'notmuch-tree
   :group 'notmuch-faces)
 
   :group 'notmuch-tree
   :group 'notmuch-faces)
 
@@ -375,6 +374,7 @@ then NAME behaves like CMD."
     (define-key map [remap notmuch-jump-search]   'notmuch-tree-jump-search)
 
     (define-key map "o" 'notmuch-tree-toggle-order)
     (define-key map [remap notmuch-jump-search]   'notmuch-tree-jump-search)
 
     (define-key map "o" 'notmuch-tree-toggle-order)
+    (define-key map "i" 'notmuch-tree-toggle-hide-excluded)
     (define-key map "S" 'notmuch-search-from-tree-current-query)
     (define-key map "U" 'notmuch-unthreaded-from-tree-current-query)
     (define-key map "Z" 'notmuch-tree-from-unthreaded-current-query)
     (define-key map "S" 'notmuch-search-from-tree-current-query)
     (define-key map "U" 'notmuch-unthreaded-from-tree-current-query)
     (define-key map "Z" 'notmuch-tree-from-unthreaded-current-query)
@@ -399,6 +399,7 @@ then NAME behaves like CMD."
     (define-key map "V" 'notmuch-tree-view-raw-message)
     (define-key map "l" 'notmuch-tree-filter)
     (define-key map "t" 'notmuch-tree-filter-by-tag)
     (define-key map "V" 'notmuch-tree-view-raw-message)
     (define-key map "l" 'notmuch-tree-filter)
     (define-key map "t" 'notmuch-tree-filter-by-tag)
+    (define-key map "E" 'notmuch-tree-edit-search)
 
     ;; The main tree view bindings
     (define-key map (kbd "RET") 'notmuch-tree-show-message)
 
     ;; The main tree view bindings
     (define-key map (kbd "RET") 'notmuch-tree-show-message)
@@ -590,7 +591,9 @@ NOT change the database."
   "Call notmuch search with the current query."
   (interactive)
   (notmuch-tree-close-message-window)
   "Call notmuch search with the current query."
   (interactive)
   (notmuch-tree-close-message-window)
-  (notmuch-search (notmuch-tree-get-query)))
+  (notmuch-search (notmuch-tree-get-query)
+                 notmuch-search-oldest-first
+                 notmuch-search-hide-excluded))
 
 (defun notmuch-tree-message-window-kill-hook ()
   "Close the message pane when exiting the show buffer."
 
 (defun notmuch-tree-message-window-kill-hook ()
   "Close the message pane when exiting the show buffer."
@@ -803,7 +806,8 @@ nil otherwise."
                         target
                         nil
                         unthreaded
                         target
                         nil
                         unthreaded
-                        notmuch-search-oldest-first)))
+                        notmuch-search-oldest-first
+                        notmuch-search-hide-excluded)))
 
 (defun notmuch-tree-thread-top ()
   (when (notmuch-tree-get-message-properties)
 
 (defun notmuch-tree-thread-top ()
   (when (notmuch-tree-get-message-properties)
@@ -1016,7 +1020,10 @@ unchanged ADDRESS if parsing fails."
 A message tree is another name for a single sub-thread: i.e., a
 message together with all its descendents."
   (let ((msg (car tree))
 A message tree is another name for a single sub-thread: i.e., a
 message together with all its descendents."
   (let ((msg (car tree))
-       (replies (cadr tree)))
+       (replies (cadr tree))
+       ;; outline level, computed from the message's depth and
+       ;; whether or not it's the first message in the tree.
+       (level (1+ (if (and (eq 0 depth) (not first)) 1 depth))))
     (cond
      ((and (< 0 depth) (not last))
       (push (alist-get 'vertical-tee  notmuch-tree-thread-symbols) tree-status))
     (cond
      ((and (< 0 depth) (not last))
       (push (alist-get 'vertical-tee  notmuch-tree-thread-symbols) tree-status))
@@ -1036,6 +1043,7 @@ message together with all its descendents."
     (setq msg (plist-put msg :first (and first (eq 0 depth))))
     (setq msg (plist-put msg :tree-status tree-status))
     (setq msg (plist-put msg :orig-tags (plist-get msg :tags)))
     (setq msg (plist-put msg :first (and first (eq 0 depth))))
     (setq msg (plist-put msg :tree-status tree-status))
     (setq msg (plist-put msg :orig-tags (plist-get msg :tags)))
+    (setq msg (plist-put msg :level level))
     (notmuch-tree-goto-and-insert-msg msg)
     (pop tree-status)
     (pop tree-status)
     (notmuch-tree-goto-and-insert-msg msg)
     (pop tree-status)
     (pop tree-status)
@@ -1045,7 +1053,8 @@ message together with all its descendents."
     (notmuch-tree-insert-thread replies (1+ depth) tree-status)))
 
 (defun notmuch-tree-insert-thread (thread depth tree-status)
     (notmuch-tree-insert-thread replies (1+ depth) tree-status)))
 
 (defun notmuch-tree-insert-thread (thread depth tree-status)
-  "Insert the collection of sibling sub-threads THREAD at depth DEPTH in the current forest."
+  "Insert the collection of sibling sub-threads THREAD at depth
+DEPTH in the current forest."
   (let ((n (length thread)))
     (cl-loop for tree in thread
             for count from 1 to n
   (let ((n (length thread)))
     (cl-loop for tree in thread
             for count from 1 to n
@@ -1082,7 +1091,14 @@ Complete list of currently available key bindings:
   (setq notmuch-buffer-refresh-function #'notmuch-tree-refresh-view)
   (hl-line-mode 1)
   (setq buffer-read-only t)
   (setq notmuch-buffer-refresh-function #'notmuch-tree-refresh-view)
   (hl-line-mode 1)
   (setq buffer-read-only t)
-  (setq truncate-lines t))
+  (setq truncate-lines t)
+  (when notmuch-tree-outline-enabled (notmuch-tree-outline-mode 1)))
+
+(defvar notmuch-tree-process-exit-functions nil
+  "Functions called when the process inserting a tree of results finishes.
+
+Functions in this list are called with one argument, the process
+object, and with the tree results buffer as the current buffer.")
 
 (defun notmuch-tree-process-sentinel (proc _msg)
   "Add a message to let user know when \"notmuch tree\" exits."
 
 (defun notmuch-tree-process-sentinel (proc _msg)
   "Add a message to let user know when \"notmuch tree\" exits."
@@ -1102,7 +1118,8 @@ Complete list of currently available key bindings:
                (insert "End of search results.")
                (unless (= exit-status 0)
                  (insert (format " (process returned %d)" exit-status)))
                (insert "End of search results.")
                (unless (= exit-status 0)
                  (insert (format " (process returned %d)" exit-status)))
-               (insert "\n")))))))))
+               (insert "\n"))))
+         (run-hook-with-args 'notmuch-tree-process-exit-functions proc))))))
 
 (defun notmuch-tree-process-filter (proc string)
   "Process and filter the output of \"notmuch show\" for tree view."
 
 (defun notmuch-tree-process-filter (proc string)
   "Process and filter the output of \"notmuch show\" for tree view."
@@ -1120,7 +1137,8 @@ Complete list of currently available key bindings:
                                         results-buf)))))
 
 (defun notmuch-tree-worker (basic-query &optional query-context target
                                         results-buf)))))
 
 (defun notmuch-tree-worker (basic-query &optional query-context target
-                                       open-target unthreaded oldest-first)
+                                       open-target unthreaded oldest-first
+                                       exclude)
   "Insert the tree view of the search in the current buffer.
 
 This is is a helper function for notmuch-tree. The arguments are
   "Insert the tree view of the search in the current buffer.
 
 This is is a helper function for notmuch-tree. The arguments are
@@ -1129,6 +1147,7 @@ the same as for the function notmuch-tree."
   (notmuch-tree-mode)
   (add-hook 'post-command-hook #'notmuch-tree-command-hook t t)
   (setq notmuch-search-oldest-first oldest-first)
   (notmuch-tree-mode)
   (add-hook 'post-command-hook #'notmuch-tree-command-hook t t)
   (setq notmuch-search-oldest-first oldest-first)
+  (setq notmuch-search-hide-excluded exclude)
   (setq notmuch-tree-unthreaded unthreaded)
   (setq notmuch-tree-basic-query basic-query)
   (setq notmuch-tree-query-context (if (or (string= query-context "")
   (setq notmuch-tree-unthreaded unthreaded)
   (setq notmuch-tree-basic-query basic-query)
   (setq notmuch-tree-query-context (if (or (string= query-context "")
@@ -1148,14 +1167,15 @@ the same as for the function notmuch-tree."
                              (and query-context
                                   (concat " and (" query-context ")"))))
         (sort-arg (if oldest-first "--sort=oldest-first" "--sort=newest-first"))
                              (and query-context
                                   (concat " and (" query-context ")"))))
         (sort-arg (if oldest-first "--sort=oldest-first" "--sort=newest-first"))
-        (message-arg (if unthreaded "--unthreaded" "--entire-thread")))
+        (message-arg (if unthreaded "--unthreaded" "--entire-thread"))
+        (exclude-arg (if exclude "--exclude=true" "--exclude=false")))
     (when (equal (car (notmuch--process-lines notmuch-command "count" search-args)) "0")
       (setq search-args basic-query))
     (notmuch-tag-clear-cache)
     (let ((proc (notmuch-start-notmuch
                 "notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
                 "show" "--body=false" "--format=sexp" "--format-version=5"
     (when (equal (car (notmuch--process-lines notmuch-command "count" search-args)) "0")
       (setq search-args basic-query))
     (notmuch-tag-clear-cache)
     (let ((proc (notmuch-start-notmuch
                 "notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
                 "show" "--body=false" "--format=sexp" "--format-version=5"
-                sort-arg message-arg search-args))
+                sort-arg message-arg exclude-arg search-args))
          ;; Use a scratch buffer to accumulate partial output.
          ;; This buffer will be killed by the sentinel, which
          ;; should be called no matter how the process dies.
          ;; Use a scratch buffer to accumulate partial output.
          ;; This buffer will be killed by the sentinel, which
          ;; should be called no matter how the process dies.
@@ -1182,8 +1202,19 @@ default sort order is defined by `notmuch-search-oldest-first'."
   (setq notmuch-search-oldest-first (not notmuch-search-oldest-first))
   (notmuch-tree-refresh-view))
 
   (setq notmuch-search-oldest-first (not notmuch-search-oldest-first))
   (notmuch-tree-refresh-view))
 
+(defun notmuch-tree-toggle-hide-excluded ()
+  "Toggle whether to hide excluded messages.
+
+This command toggles whether to hide excluded messages for the current
+search. The default value for this is defined by `notmuch-search-hide-excluded'."
+  (interactive)
+  (setq notmuch-search-hide-excluded (not notmuch-search-hide-excluded))
+  (notmuch-tree-refresh-view))
+
+;;;###autoload
 (defun notmuch-tree (&optional query query-context target buffer-name
 (defun notmuch-tree (&optional query query-context target buffer-name
-                              open-target unthreaded parent-buffer oldest-first)
+                              open-target unthreaded parent-buffer
+                              oldest-first hide-excluded)
   "Display threads matching QUERY in tree view.
 
 The arguments are:
   "Display threads matching QUERY in tree view.
 
 The arguments are:
@@ -1198,7 +1229,15 @@ The arguments are:
       it is nil \"*notmuch-tree\" followed by QUERY is used.
   OPEN-TARGET: If TRUE open the target message in the message pane.
   UNTHREADED: If TRUE only show matching messages in an unthreaded view."
       it is nil \"*notmuch-tree\" followed by QUERY is used.
   OPEN-TARGET: If TRUE open the target message in the message pane.
   UNTHREADED: If TRUE only show matching messages in an unthreaded view."
-  (interactive)
+  (interactive
+   (list
+    ;; Prompt for a query
+    nil
+    ;; Fill other args with nil.
+    nil nil nil nil nil nil
+    ;; Populate these from the default value of these options.
+    (default-value 'notmuch-search-oldest-first)
+    (default-value 'notmuch-search-hide-excluded)))
   (unless query
     (setq query (notmuch-read-query (concat "Notmuch "
                                            (if unthreaded "unthreaded " "tree ")
   (unless query
     (setq query (notmuch-read-query (concat "Notmuch "
                                            (if unthreaded "unthreaded " "tree ")
@@ -1212,17 +1251,27 @@ The arguments are:
     (pop-to-buffer-same-window buffer))
   ;; Don't track undo information for this buffer
   (setq buffer-undo-list t)
     (pop-to-buffer-same-window buffer))
   ;; Don't track undo information for this buffer
   (setq buffer-undo-list t)
-  (notmuch-tree-worker query query-context target open-target unthreaded oldest-first)
+  (notmuch-tree-worker query query-context target open-target
+                      unthreaded oldest-first hide-excluded)
   (setq notmuch-tree-parent-buffer parent-buffer)
   (setq truncate-lines t))
 
 (defun notmuch-unthreaded (&optional query query-context target buffer-name
   (setq notmuch-tree-parent-buffer parent-buffer)
   (setq truncate-lines t))
 
 (defun notmuch-unthreaded (&optional query query-context target buffer-name
-                                    open-target)
+                                    open-target oldest-first hide-excluded)
   "Display threads matching QUERY in unthreaded view.
 
 See function NOTMUCH-TREE for documentation of the arguments"
   "Display threads matching QUERY in unthreaded view.
 
 See function NOTMUCH-TREE for documentation of the arguments"
-  (interactive)
-  (notmuch-tree query query-context target buffer-name open-target t))
+  (interactive
+   (list
+    ;; Prompt for a query
+    nil
+    ;; Fill other args with nil.
+    nil nil nil nil
+    ;; Populate these from the default value of these options.
+    (default-value 'notmuch-search-oldest-first)
+    (default-value 'notmuch-search-hide-excluded)))
+  (notmuch-tree query query-context target buffer-name open-target
+               t nil oldest-first hide-excluded))
 
 (defun notmuch-tree-filter (query)
   "Filter or LIMIT the current search results based on an additional query string.
 
 (defun notmuch-tree-filter (query)
   "Filter or LIMIT the current search results based on an additional query string.
@@ -1250,6 +1299,22 @@ search results and that are also tagged with the given TAG."
   (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
     (notmuch-tree-close-message-window)
     (notmuch-tree (concat notmuch-tree-basic-query " and tag:" tag)
   (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
     (notmuch-tree-close-message-window)
     (notmuch-tree (concat notmuch-tree-basic-query " and tag:" tag)
+                 notmuch-tree-query-context
+                 nil
+                 nil
+                 nil
+                 notmuch-tree-unthreaded
+                 nil
+                 notmuch-search-oldest-first
+                 notmuch-search-hide-excluded)))
+
+(defun notmuch-tree-edit-search (query)
+  "Edit the current search"
+  (interactive (list (read-from-minibuffer "Edit search: "
+                                          notmuch-tree-basic-query)))
+  (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
+    (notmuch-tree-close-message-window)
+    (notmuch-tree query
                  notmuch-tree-query-context
                  nil
                  nil
                  notmuch-tree-query-context
                  nil
                  nil
@@ -1258,6 +1323,180 @@ search results and that are also tagged with the given TAG."
                  nil
                  notmuch-search-oldest-first)))
 
                  nil
                  notmuch-search-oldest-first)))
 
+;;; Tree outline mode
+;;;; Custom variables
+(defcustom notmuch-tree-outline-enabled nil
+  "Whether to automatically activate `notmuch-tree-outline-mode' in tree views."
+  :type 'boolean)
+
+(defcustom notmuch-tree-outline-visibility 'hide-others
+  "Default state of the forest outline for `notmuch-tree-outline-mode'.
+
+This variable controls the state of a forest initially and after
+a movement command.  If set to nil, all trees are displayed while
+the symbol hide-all indicates that all trees in the forest should
+be folded and hide-other that only the first one should be
+unfolded."
+  :type '(choice (const :tag "Show all" nil)
+                (const :tag "Hide others" hide-others)
+                (const :tag "Hide all" hide-all)))
+
+(defcustom notmuch-tree-outline-auto-close nil
+  "Close message and tree windows when moving past the last message."
+  :type 'boolean)
+
+(defcustom notmuch-tree-outline-open-on-next nil
+  "Open new messages under point if they are closed when moving to next one.
+
+When this flag is set, using the command
+`notmuch-tree-outline-next' with point on a header for a new
+message that is not shown will open its `notmuch-show' buffer
+instead of moving point to next matching message."
+  :type 'boolean)
+
+;;;; Helper functions
+(defsubst notmuch-tree-outline--pop-at-end (pop-at-end)
+  (if notmuch-tree-outline-auto-close (not pop-at-end) pop-at-end))
+
+(defun notmuch-tree-outline--set-visibility ()
+  (when (and notmuch-tree-outline-mode (> (point-max) (point-min)))
+    (cl-case notmuch-tree-outline-visibility
+      (hide-others (notmuch-tree-outline-hide-others))
+      (hide-all (outline-hide-body)))))
+
+(defun notmuch-tree-outline--on-exit (proc)
+  (when (eq (process-status proc) 'exit)
+    (notmuch-tree-outline--set-visibility)))
+
+(add-hook 'notmuch-tree-process-exit-functions #'notmuch-tree-outline--on-exit)
+
+(defsubst notmuch-tree-outline--level (&optional props)
+  (or (plist-get (or props (notmuch-tree-get-message-properties)) :level) 0))
+
+(defsubst notmuch-tree-outline--message-open-p ()
+  (and (buffer-live-p notmuch-tree-message-buffer)
+       (get-buffer-window notmuch-tree-message-buffer)
+       (let ((id (notmuch-tree-get-message-id)))
+        (and id
+             (with-current-buffer notmuch-tree-message-buffer
+               (string= (notmuch-show-get-message-id) id))))))
+
+(defsubst notmuch-tree-outline--at-original-match-p ()
+  (and (notmuch-tree-get-prop :match)
+       (equal (notmuch-tree-get-prop :orig-tags)
+              (notmuch-tree-get-prop :tags))))
+
+(defun notmuch-tree-outline--next (prev thread pop-at-end &optional open-new)
+  (cond (thread
+        (notmuch-tree-thread-top)
+        (if prev
+            (outline-backward-same-level 1)
+          (outline-forward-same-level 1))
+        (when (> (notmuch-tree-outline--level) 0) (outline-show-branches))
+        (notmuch-tree-outline--next nil nil pop-at-end t))
+       ((and (or open-new notmuch-tree-outline-open-on-next)
+             (notmuch-tree-outline--at-original-match-p)
+             (not (notmuch-tree-outline--message-open-p)))
+        (notmuch-tree-outline-hide-others t))
+       (t (outline-next-visible-heading (if prev -1 1))
+          (unless (notmuch-tree-get-prop :match)
+            (notmuch-tree-matching-message prev pop-at-end))
+          (notmuch-tree-outline-hide-others t))))
+
+;;;; User commands
+(defun notmuch-tree-outline-hide-others (&optional and-show)
+  "Fold all threads except the one around point.
+If AND-SHOW is t, make the current message visible if it's not."
+  (interactive)
+  (save-excursion
+    (while (and (not (bobp)) (> (notmuch-tree-outline--level) 1))
+      (outline-previous-heading))
+    (outline-hide-sublevels 1))
+  (when (> (notmuch-tree-outline--level) 0)
+    (outline-show-subtree)
+    (when and-show (notmuch-tree-show-message nil))))
+
+(defun notmuch-tree-outline-next (&optional pop-at-end)
+  "Next matching message in a forest, taking care of thread visibility.
+A prefix argument reverses the meaning of `notmuch-tree-outline-auto-close'."
+  (interactive "P")
+  (let ((pop (notmuch-tree-outline--pop-at-end pop-at-end)))
+    (if (null notmuch-tree-outline-visibility)
+       (notmuch-tree-matching-message nil pop)
+      (notmuch-tree-outline--next nil nil pop))))
+
+(defun notmuch-tree-outline-previous (&optional pop-at-end)
+  "Previous matching message in forest, taking care of thread visibility.
+With prefix, quit the tree view if there is no previous message."
+  (interactive "P")
+  (if (null notmuch-tree-outline-visibility)
+      (notmuch-tree-prev-matching-message pop-at-end)
+    (notmuch-tree-outline--next t nil pop-at-end)))
+
+(defun notmuch-tree-outline-next-thread ()
+  "Next matching thread in forest, taking care of thread visibility."
+  (interactive)
+  (if (null notmuch-tree-outline-visibility)
+      (notmuch-tree-next-thread)
+    (notmuch-tree-outline--next nil t nil)))
+
+(defun notmuch-tree-outline-previous-thread ()
+  "Previous matching thread in forest, taking care of thread visibility."
+  (interactive)
+  (if (null notmuch-tree-outline-visibility)
+      (notmuch-tree-prev-thread)
+    (notmuch-tree-outline--next t t nil)))
+
+;;;; Mode definition
+(defvar notmuch-tree-outline-mode-lighter nil
+  "The lighter mark for notmuch-tree-outline mode.
+Usually empty since outline-minor-mode's lighter will be active.")
+
+(define-minor-mode notmuch-tree-outline-mode
+  "Minor mode allowing message trees to be folded as outlines.
+
+When this mode is set, each thread and subthread in the results
+list is treated as a foldable section, with its first message as
+its header.
+
+The mode just makes available in the tree buffer all the
+keybindings in `outline-minor-mode', and binds the following
+additional keys:
+
+\\{notmuch-tree-outline-mode-map}
+
+The customizable variable `notmuch-tree-outline-visibility'
+controls how navigation in the buffer is affected by this mode:
+
+  - If it is set to nil, `notmuch-tree-outline-previous',
+    `notmuch-tree-outline-next', and their thread counterparts
+    behave just as the corresponding notmuch-tree navigation keys
+    when this mode is not enabled.
+
+  - If, on the other hand, `notmuch-tree-outline-visibility' is
+    set to a non-nil value, these commands hiding the outlines of
+    the trees you are not reading as you move to new messages.
+
+To enable notmuch-tree-outline-mode by default in all
+notmuch-tree buffers, just set
+`notmuch-tree-outline-mode-enabled' to t."
+  :lighter notmuch-tree-outline-mode-lighter
+  :keymap `((,(kbd "TAB") . outline-cycle)
+           (,(kbd "M-TAB") . outline-cycle-buffer)
+           ("n" . notmuch-tree-outline-next)
+           ("p" . notmuch-tree-outline-previous)
+           (,(kbd "M-n") . notmuch-tree-outline-next-thread)
+           (,(kbd "M-p") . notmuch-tree-outline-previous-thread))
+  (outline-minor-mode notmuch-tree-outline-mode)
+  (unless (derived-mode-p 'notmuch-tree-mode)
+    (user-error "notmuch-tree-outline-mode is only meaningful for notmuch trees!"))
+  (if notmuch-tree-outline-mode
+      (progn (setq-local outline-regexp "^[^\n]+")
+            (setq-local outline-level #'notmuch-tree-outline--level)
+            (notmuch-tree-outline--set-visibility))
+    (setq-local outline-regexp (default-value 'outline-regexp))
+    (setq-local        outline-level (default-value 'outline-level))))
+
 ;;; _
 
 (provide 'notmuch-tree)
 ;;; _
 
 (provide 'notmuch-tree)
index 653ecc2ae7d5d4e07ff8a87c9ed95315fb3c30bb..fd8a9d1e2296db96e6cf6642bbe0ba35819942ae 100644 (file)
@@ -381,7 +381,7 @@ original filename the sender had."
          (notmuch-wash-subject-to-filename subject 52)))
 
 (defun notmuch-wash-convert-inline-patch-to-part (msg depth)
          (notmuch-wash-subject-to-filename subject 52)))
 
 (defun notmuch-wash-convert-inline-patch-to-part (msg depth)
-  "Convert an inline patch into a fake 'text/x-diff' attachment.
+  "Convert an inline patch into a fake `text/x-diff' attachment.
 
 Given that this function guesses whether a buffer includes a
 patch and then guesses the extent of the patch, there is scope
 
 Given that this function guesses whether a buffer includes a
 patch and then guesses the extent of the patch, there is scope
index 5cb7acd298ae64899d8f7fcf4513627fdcf556cb..2a73ffa571c41a04b0836a50a991102249fad658 100644 (file)
@@ -187,9 +187,11 @@ there will be called at other points of notmuch execution."
     (define-key map "r" 'notmuch-search-reply-to-thread-sender)
     (define-key map "R" 'notmuch-search-reply-to-thread)
     (define-key map "o" 'notmuch-search-toggle-order)
     (define-key map "r" 'notmuch-search-reply-to-thread-sender)
     (define-key map "R" 'notmuch-search-reply-to-thread)
     (define-key map "o" 'notmuch-search-toggle-order)
+    (define-key map "i" 'notmuch-search-toggle-hide-excluded)
     (define-key map "c" 'notmuch-search-stash-map)
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "l" 'notmuch-search-filter)
     (define-key map "c" 'notmuch-search-stash-map)
     (define-key map "t" 'notmuch-search-filter-by-tag)
     (define-key map "l" 'notmuch-search-filter)
+    (define-key map "E" 'notmuch-search-edit-search)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
     (define-key map "k" 'notmuch-tag-jump)
     (define-key map "*" 'notmuch-search-tag-all)
     (define-key map [mouse-1] 'notmuch-search-show-thread)
     (define-key map "k" 'notmuch-tag-jump)
     (define-key map "*" 'notmuch-search-tag-all)
@@ -549,12 +551,18 @@ Return non-nil on success."
 (defun notmuch-tree-from-search-current-query ()
   "Tree view of current query."
   (interactive)
 (defun notmuch-tree-from-search-current-query ()
   "Tree view of current query."
   (interactive)
-  (notmuch-tree notmuch-search-query-string))
+  (notmuch-tree notmuch-search-query-string
+               nil nil nil nil nil nil
+               notmuch-search-oldest-first
+               notmuch-search-hide-excluded))
 
 (defun notmuch-unthreaded-from-search-current-query ()
   "Unthreaded view of current query."
   (interactive)
 
 (defun notmuch-unthreaded-from-search-current-query ()
   "Unthreaded view of current query."
   (interactive)
-  (notmuch-unthreaded notmuch-search-query-string))
+  (notmuch-unthreaded notmuch-search-query-string
+                     nil nil nil nil
+                     notmuch-search-oldest-first
+                     notmuch-search-hide-excluded))
 
 (defun notmuch-tree-from-search-thread ()
   "Show the selected thread with notmuch-tree."
 
 (defun notmuch-tree-from-search-thread ()
   "Show the selected thread with notmuch-tree."
@@ -563,7 +571,9 @@ Return non-nil on success."
                notmuch-search-query-string
                nil
                (notmuch-prettify-subject (notmuch-search-find-subject))
                notmuch-search-query-string
                nil
                (notmuch-prettify-subject (notmuch-search-find-subject))
-               t nil (current-buffer)))
+               t nil (current-buffer)
+               notmuch-search-oldest-first
+               notmuch-search-hide-excluded))
 
 (defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
   "Begin composing a reply-all to the entire current thread in a new buffer."
 
 (defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
   "Begin composing a reply-all to the entire current thread in a new buffer."
@@ -840,6 +850,7 @@ non-authors is found, assume that all of the authors match."
              overlay)
          (insert invisible-string)
          (setq overlay (make-overlay start (point)))
              overlay)
          (insert invisible-string)
          (setq overlay (make-overlay start (point)))
+         (overlay-put overlay 'evaporate t)
          (overlay-put overlay 'invisible 'ellipsis)
          (overlay-put overlay 'isearch-open-invisible #'delete-overlay)))
       (insert padding))))
          (overlay-put overlay 'invisible 'ellipsis)
          (overlay-put overlay 'isearch-open-invisible #'delete-overlay)))
       (insert padding))))
@@ -1033,14 +1044,16 @@ PROMPT is the string to prompt with."
 
 (put 'notmuch-search 'notmuch-doc "Search for messages.")
 ;;;###autoload
 
 (put 'notmuch-search 'notmuch-doc "Search for messages.")
 ;;;###autoload
-(defun notmuch-search (&optional query oldest-first target-thread target-line
-                                no-display)
+(defun notmuch-search (&optional query oldest-first hide-excluded target-thread
+                                target-line no-display)
   "Display threads matching QUERY in a notmuch-search buffer.
 
 If QUERY is nil, it is read interactively from the minibuffer.
 Other optional parameters are used as follows:
 
   OLDEST-FIRST: A Boolean controlling the sort order of returned threads
   "Display threads matching QUERY in a notmuch-search buffer.
 
 If QUERY is nil, it is read interactively from the minibuffer.
 Other optional parameters are used as follows:
 
   OLDEST-FIRST: A Boolean controlling the sort order of returned threads
+  HIDE-EXCLUDED: A boolean controlling whether to omit threads with excluded
+                 tags.
   TARGET-THREAD: A thread ID (without the thread: prefix) that will be made
                  current if it appears in the search results.
   TARGET-LINE: The line number to move to if the target thread does not
   TARGET-THREAD: A thread ID (without the thread: prefix) that will be made
                  current if it appears in the search results.
   TARGET-LINE: The line number to move to if the target thread does not
@@ -1055,9 +1068,10 @@ the configured default sort order."
    (list
     ;; Prompt for a query
     nil
    (list
     ;; Prompt for a query
     nil
-    ;; Use the default search order (if we're doing a search from a
-    ;; search buffer, ignore any buffer-local overrides)
-    (default-value 'notmuch-search-oldest-first)))
+    ;; Use the default search order and exclude value (if we're doing a
+    ;; search from a search buffer, ignore any buffer-local overrides)
+    (default-value 'notmuch-search-oldest-first)
+    (default-value 'notmuch-search-hide-excluded)))
 
   (let* ((query (or query (notmuch-read-query "Notmuch search: ")))
         (buffer (get-buffer-create (notmuch-search-buffer-title query))))
 
   (let* ((query (or query (notmuch-read-query "Notmuch search: ")))
         (buffer (get-buffer-create (notmuch-search-buffer-title query))))
@@ -1071,6 +1085,7 @@ the configured default sort order."
     (setq notmuch-search-oldest-first oldest-first)
     (setq notmuch-search-target-thread target-thread)
     (setq notmuch-search-target-line target-line)
     (setq notmuch-search-oldest-first oldest-first)
     (setq notmuch-search-target-thread target-thread)
     (setq notmuch-search-target-line target-line)
+    (setq notmuch-search-hide-excluded hide-excluded)
     (notmuch-tag-clear-cache)
     (when (get-buffer-process buffer)
       (error "notmuch search process already running for query `%s'" query))
     (notmuch-tag-clear-cache)
     (when (get-buffer-process buffer)
       (error "notmuch search process already running for query `%s'" query))
@@ -1084,6 +1099,9 @@ the configured default sort order."
                     (if oldest-first
                         "--sort=oldest-first"
                       "--sort=newest-first")
                     (if oldest-first
                         "--sort=oldest-first"
                       "--sort=newest-first")
+                    (if hide-excluded
+                        "--exclude=true"
+                      "--exclude=false")
                     query)))
          ;; Use a scratch buffer to accumulate partial output.
          ;; This buffer will be killed by the sentinel, which
                     query)))
          ;; Use a scratch buffer to accumulate partial output.
          ;; This buffer will be killed by the sentinel, which
@@ -1104,11 +1122,21 @@ same relative position within the new buffer."
   (interactive)
   (notmuch-search notmuch-search-query-string
                  notmuch-search-oldest-first
   (interactive)
   (notmuch-search notmuch-search-query-string
                  notmuch-search-oldest-first
+                 notmuch-search-hide-excluded
                  (notmuch-search-find-thread-id 'bare)
                  (line-number-at-pos)
                  t)
   (goto-char (point-min)))
 
                  (notmuch-search-find-thread-id 'bare)
                  (line-number-at-pos)
                  t)
   (goto-char (point-min)))
 
+(defun notmuch-search-toggle-hide-excluded ()
+  "Toggle whether to hide excluded messages.
+
+This command toggles whether to hide excluded messages for the current
+search. The default value for this is defined by `notmuch-search-hide-excluded'."
+  (interactive)
+  (setq notmuch-search-hide-excluded (not notmuch-search-hide-excluded))
+  (notmuch-search-refresh-view))
+
 (defun notmuch-search-toggle-order ()
   "Toggle the current search order.
 
 (defun notmuch-search-toggle-order ()
   "Toggle the current search order.
 
@@ -1137,7 +1165,8 @@ current search results AND the additional query string provided."
     (notmuch-search (if (string= grouped-original-query "*")
                        grouped-query
                      (concat grouped-original-query " and " grouped-query))
     (notmuch-search (if (string= grouped-original-query "*")
                        grouped-query
                      (concat grouped-original-query " and " grouped-query))
-                   notmuch-search-oldest-first)))
+                   notmuch-search-oldest-first
+                   notmuch-search-hide-excluded)))
 
 (defun notmuch-search-filter-by-tag (tag)
   "Filter the current search results based on a single TAG.
 
 (defun notmuch-search-filter-by-tag (tag)
   "Filter the current search results based on a single TAG.
@@ -1148,13 +1177,22 @@ search results and that are also tagged with the given TAG."
    (list (notmuch-select-tag-with-completion "Filter by tag: "
                                             notmuch-search-query-string)))
   (notmuch-search (concat notmuch-search-query-string " and tag:" tag)
    (list (notmuch-select-tag-with-completion "Filter by tag: "
                                             notmuch-search-query-string)))
   (notmuch-search (concat notmuch-search-query-string " and tag:" tag)
-                 notmuch-search-oldest-first))
+                 notmuch-search-oldest-first
+                 notmuch-search-hide-excluded))
 
 (defun notmuch-search-by-tag (tag)
   "Display threads matching TAG in a notmuch-search buffer."
   (interactive
    (list (notmuch-select-tag-with-completion "Notmuch search tag: ")))
 
 (defun notmuch-search-by-tag (tag)
   "Display threads matching TAG in a notmuch-search buffer."
   (interactive
    (list (notmuch-select-tag-with-completion "Notmuch search tag: ")))
-  (notmuch-search (concat "tag:" tag)))
+  (notmuch-search (concat "tag:" tag)
+                 (default-value 'notmuch-search-oldest-first)
+                 (default-value 'notmuch-search-hide-excluded)))
+
+(defun notmuch-search-edit-search (query)
+  "Edit the current search"
+  (interactive (list (read-from-minibuffer "Edit search: "
+                                          notmuch-search-query-string)))
+  (notmuch-search query notmuch-search-oldest-first))
 
 ;;;###autoload
 (defun notmuch ()
 
 ;;;###autoload
 (defun notmuch ()
index 6d67a2a49291c0dc618062b78b0410ff9b87e532..4e7663056b57ba3e2599368f1e12b2b381d20f08 100644 (file)
@@ -65,7 +65,8 @@ libnotmuch_cxx_srcs =         \
        $(dir)/open.cc          \
        $(dir)/init.cc          \
        $(dir)/parse-sexp.cc    \
        $(dir)/open.cc          \
        $(dir)/init.cc          \
        $(dir)/parse-sexp.cc    \
-       $(dir)/sexp-fp.cc
+       $(dir)/sexp-fp.cc       \
+       $(dir)/lastmod-fp.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
 
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
 
index 503a0c8b585323dd59fad974b55ca47b7399fad6..6cd15fab26bc16610e1c56e1b5e0019b41279259 100644 (file)
@@ -416,7 +416,8 @@ _expand_path (void *ctx, const char *key, const char *val)
 
 notmuch_status_t
 _notmuch_config_load_from_file (notmuch_database_t *notmuch,
 
 notmuch_status_t
 _notmuch_config_load_from_file (notmuch_database_t *notmuch,
-                               GKeyFile *file)
+                               GKeyFile *file,
+                               char **status_string)
 {
     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
     gchar **groups = NULL, **keys, *val;
 {
     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
     gchar **groups = NULL, **keys, *val;
@@ -435,6 +436,7 @@ _notmuch_config_load_from_file (notmuch_database_t *notmuch,
        for (gchar **keys_p = keys; *keys_p; keys_p++) {
            char *absolute_key = talloc_asprintf (notmuch, "%s.%s", *grp,  *keys_p);
            char *normalized_val;
        for (gchar **keys_p = keys; *keys_p; keys_p++) {
            char *absolute_key = talloc_asprintf (notmuch, "%s.%s", *grp,  *keys_p);
            char *normalized_val;
+           GError *gerr = NULL;
 
            /* If we opened from a given path, do not overwrite it */
            if (strcmp (absolute_key, "database.path") == 0 &&
 
            /* If we opened from a given path, do not overwrite it */
            if (strcmp (absolute_key, "database.path") == 0 &&
@@ -442,7 +444,14 @@ _notmuch_config_load_from_file (notmuch_database_t *notmuch,
                notmuch->xapian_db)
                continue;
 
                notmuch->xapian_db)
                continue;
 
-           val = g_key_file_get_string (file, *grp, *keys_p, NULL);
+           val = g_key_file_get_string (file, *grp, *keys_p, &gerr);
+           if (gerr) {
+               if (status_string)
+                   IGNORE_RESULT (asprintf (status_string,
+                                            "GLib: %s\n",
+                                            gerr->message));
+               g_error_free (gerr);
+           }
            if (! val) {
                status = NOTMUCH_STATUS_FILE_ERROR;
                goto DONE;
            if (! val) {
                status = NOTMUCH_STATUS_FILE_ERROR;
                goto DONE;
@@ -599,6 +608,8 @@ _notmuch_config_key_to_string (notmuch_config_key_t key)
        return "database.autocommit";
     case NOTMUCH_CONFIG_EXTRA_HEADERS:
        return "show.extra_headers";
        return "database.autocommit";
     case NOTMUCH_CONFIG_EXTRA_HEADERS:
        return "show.extra_headers";
+    case NOTMUCH_CONFIG_INDEX_AS_TEXT:
+       return "index.as_text";
     default:
        return NULL;
     }
     default:
        return NULL;
     }
@@ -642,6 +653,7 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key)
        else
            email = _get_email_from_passwd_file (notmuch);
        return email;
        else
            email = _get_email_from_passwd_file (notmuch);
        return email;
+    case NOTMUCH_CONFIG_INDEX_AS_TEXT:
     case NOTMUCH_CONFIG_NEW_IGNORE:
        return "";
     case NOTMUCH_CONFIG_AUTOCOMMIT:
     case NOTMUCH_CONFIG_NEW_IGNORE:
        return "";
     case NOTMUCH_CONFIG_AUTOCOMMIT:
index 419b9fe6bd521c0f7ba3e5934fd06a11e3f864a6..61232f1ae3ffcc51bb0dd6b96c91e1b9296e33d3 100644 (file)
@@ -291,6 +291,10 @@ struct _notmuch_database {
 
     /* Track what parameters were specified when opening */
     notmuch_open_param_t params;
 
     /* Track what parameters were specified when opening */
     notmuch_open_param_t params;
+
+    /* list of regular expressions to check for text indexing */
+    regex_t *index_as_text;
+    size_t index_as_text_length;
 };
 
 /* Prior to database version 3, features were implied by the database
 };
 
 /* Prior to database version 3, features were implied by the database
@@ -381,5 +385,11 @@ _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *q
 notmuch_status_t
 _notmuch_date_strings_to_query (Xapian::valueno slot, const std::string &from, const std::string &to,
                                Xapian::Query &output, std::string &msg);
 notmuch_status_t
 _notmuch_date_strings_to_query (Xapian::valueno slot, const std::string &from, const std::string &to,
                                Xapian::Query &output, std::string &msg);
+
+/* lastmod-fp.h */
+notmuch_status_t
+_notmuch_lastmod_strings_to_query (notmuch_database_t *notmuch,
+                                  const std::string &from, const std::string &to,
+                                  Xapian::Query &output, std::string &msg);
 #endif
 #endif
 #endif
 #endif
index c05d70d34842f1fd1f264cc61a45fbb6348b95ca..737a3f3060677b4e7fd5a55fbe5268082f0867f2 100644 (file)
@@ -1454,9 +1454,11 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
                                                        &message);
 
     if (status == NOTMUCH_STATUS_SUCCESS && message) {
                                                        &message);
 
     if (status == NOTMUCH_STATUS_SUCCESS && message) {
-       status = _notmuch_message_remove_filename (message, filename);
+       if (notmuch_message_count_files (message) > 1) {
+           status = _notmuch_message_remove_filename (message, filename);
+       }
        if (status == NOTMUCH_STATUS_SUCCESS)
        if (status == NOTMUCH_STATUS_SUCCESS)
-           _notmuch_message_delete (message);
+           status = _notmuch_message_delete (message);
        else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
            _notmuch_message_sync (message);
 
        else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
            _notmuch_message_sync (message);
 
@@ -1573,3 +1575,15 @@ notmuch_database_status_string (const notmuch_database_t *notmuch)
 {
     return notmuch->status_string;
 }
 {
     return notmuch->status_string;
 }
+
+bool
+_notmuch_database_indexable_as_text (notmuch_database_t *notmuch, const char *mime_string)
+{
+    for (size_t i = 0; i < notmuch->index_as_text_length; i++) {
+       if (regexec (&notmuch->index_as_text[i], mime_string, 0, NULL, 0) == 0) {
+           return true;
+       }
+    }
+
+    return false;
+}
index 728bfb22ab69c4eef52795cf86d7971c7d42e2fe..629dcb222be8545cfde471ce5184f96c88115881 100644 (file)
@@ -380,6 +380,23 @@ _index_pkcs7_part (notmuch_message_t *message,
                   GMimeObject *part,
                   _notmuch_message_crypto_t *msg_crypto);
 
                   GMimeObject *part,
                   _notmuch_message_crypto_t *msg_crypto);
 
+static bool
+_indexable_as_text (notmuch_message_t *message, GMimeObject *part)
+{
+    GMimeContentType *content_type = g_mime_object_get_content_type (part);
+    notmuch_database_t *notmuch = notmuch_message_get_database (message);
+
+    if (content_type) {
+       char *mime_string = g_mime_content_type_get_mime_type (content_type);
+       if (mime_string) {
+           bool ret = _notmuch_database_indexable_as_text (notmuch, mime_string);
+           g_free (mime_string);
+           return ret;
+       }
+    }
+    return false;
+}
+
 /* Callback to generate terms for each mime part of a message. */
 static void
 _index_mime_part (notmuch_message_t *message,
 /* Callback to generate terms for each mime part of a message. */
 static void
 _index_mime_part (notmuch_message_t *message,
@@ -497,9 +514,11 @@ _index_mime_part (notmuch_message_t *message,
        _notmuch_message_add_term (message, "tag", "attachment");
        _notmuch_message_gen_terms (message, "attachment", filename);
 
        _notmuch_message_add_term (message, "tag", "attachment");
        _notmuch_message_gen_terms (message, "attachment", filename);
 
-       /* XXX: Would be nice to call out to something here to parse
-        * the attachment into text and then index that. */
-       goto DONE;
+       if (! _indexable_as_text (message, part)) {
+           /* XXX: Would be nice to call out to something here to parse
+            * the attachment into text and then index that. */
+           goto DONE;
+       }
     }
 
     byte_array = g_byte_array_new ();
     }
 
     byte_array = g_byte_array_new ();
diff --git a/lib/lastmod-fp.cc b/lib/lastmod-fp.cc
new file mode 100644 (file)
index 0000000..f85efd2
--- /dev/null
@@ -0,0 +1,83 @@
+/* lastmod-fp.cc - lastmod range query glue
+ *
+ * This file is part of notmuch.
+ *
+ * Copyright © 2022 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#include "database-private.h"
+#include "lastmod-fp.h"
+
+notmuch_status_t
+_notmuch_lastmod_strings_to_query (notmuch_database_t *notmuch,
+                                  const std::string &from, const std::string &to,
+                                  Xapian::Query &output, std::string &msg)
+{
+    long from_idx = 0L, to_idx = LONG_MAX;
+    long current;
+    std::string str;
+
+    /* revision should not change, but for the avoidance of doubt,
+     * grab for both ends of range, if needed*/
+    current = notmuch_database_get_revision (notmuch, NULL);
+
+    try {
+       if (from.empty ())
+           from_idx = 0L;
+       else
+           from_idx = std::stol (from);
+    } catch (std::logic_error &e) {
+       msg = "bad 'from' revision: '" + from + "'";
+       return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+    }
+
+    if (from_idx < 0)
+       from_idx += current;
+
+    try {
+       if (EMPTY_STRING (to))
+           to_idx = LONG_MAX;
+       else
+           to_idx = std::stol (to);
+    } catch (std::logic_error &e) {
+       msg = "bad 'to' revision: '" + to + "'";
+       return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+    }
+
+    if (to_idx < 0)
+       to_idx += current;
+
+    output = Xapian::Query (Xapian::Query::OP_VALUE_RANGE, NOTMUCH_VALUE_LAST_MOD,
+                           Xapian::sortable_serialise (from_idx),
+                           Xapian::sortable_serialise (to_idx));
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
+Xapian::Query
+LastModRangeProcessor::operator() (const std::string &begin, const std::string &end)
+{
+
+    Xapian::Query output;
+    std::string msg;
+
+    if (_notmuch_lastmod_strings_to_query (notmuch, begin, end, output, msg))
+       throw Xapian::QueryParserError (msg);
+
+    return output;
+}
+
diff --git a/lib/lastmod-fp.h b/lib/lastmod-fp.h
new file mode 100644 (file)
index 0000000..8168fe7
--- /dev/null
@@ -0,0 +1,41 @@
+/* lastmod-fp.h - database revision query glue
+ *
+ * This file is part of notmuch.
+ *
+ * Copyright © 2022 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#ifndef NOTMUCH_LASTMOD_FP_H
+#define NOTMUCH_LASTMOD_FP_H
+
+#include <xapian.h>
+
+class LastModRangeProcessor : public Xapian::RangeProcessor {
+protected:
+    notmuch_database_t *notmuch;
+
+public:
+    LastModRangeProcessor (notmuch_database_t *notmuch_, const std::string prefix_)
+       :  Xapian::RangeProcessor (NOTMUCH_VALUE_LAST_MOD, prefix_, 0), notmuch (notmuch_)
+    {
+    }
+
+    Xapian::Query operator() (const std::string &begin, const std::string &end);
+};
+
+#endif /* NOTMUCH_LASTMOD_FP_H */
index d5afa30c8e2a3e4d74d50a02efa15659febafbaf..7f5203403723d3514e8d85f738d43b546adcabe7 100644 (file)
 #include "database-private.h"
 #include "message-private.h"
 
 #include "database-private.h"
 #include "message-private.h"
 
+#define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error)
+
+static void
+_log_xapian_exception (const char *where, notmuch_message_t *message,  const Xapian::Error error)
+{
+    notmuch_database_t *notmuch = notmuch_message_get_database (message);
+
+    _notmuch_database_log (notmuch,
+                          "A Xapian exception occurred at %s: %s\n",
+                          where,
+                          error.get_msg ().c_str ());
+    notmuch->exception_reported = true;
+}
+
 notmuch_status_t
 notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
 {
 notmuch_status_t
 notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
 {
@@ -83,10 +97,15 @@ _notmuch_message_modify_property (notmuch_message_t *message, const char *key, c
 
     term = talloc_asprintf (message, "%s=%s", key, value);
 
 
     term = talloc_asprintf (message, "%s=%s", key, value);
 
-    if (delete_it)
-       private_status = _notmuch_message_remove_term (message, "property", term);
-    else
-       private_status = _notmuch_message_add_term (message, "property", term);
+    try {
+       if (delete_it)
+           private_status = _notmuch_message_remove_term (message, "property", term);
+       else
+           private_status = _notmuch_message_add_term (message, "property", term);
+    } catch (Xapian::Error &error) {
+       LOG_XAPIAN_EXCEPTION (message, error);
+       return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+    }
 
     if (private_status)
        return COERCE_STATUS (private_status,
 
     if (private_status)
        return COERCE_STATUS (private_status,
@@ -123,15 +142,22 @@ _notmuch_message_remove_all_properties (notmuch_message_t *message, const char *
     if (status)
        return status;
 
     if (status)
        return status;
 
-    _notmuch_message_invalidate_metadata (message, "property");
     if (key)
        term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
                                       prefix ? "" : "=");
     else
        term_prefix = _find_prefix ("property");
 
     if (key)
        term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
                                       prefix ? "" : "=");
     else
        term_prefix = _find_prefix ("property");
 
-    /* XXX better error reporting ? */
-    _notmuch_message_remove_terms (message, term_prefix);
+    try {
+       /* XXX better error reporting ? */
+       _notmuch_message_remove_terms (message, term_prefix);
+    } catch (Xapian::Error &error) {
+       LOG_XAPIAN_EXCEPTION (message, error);
+       return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+    }
+
+    if (! _notmuch_message_frozen (message))
+       _notmuch_message_sync (message);
 
     return NOTMUCH_STATUS_SUCCESS;
 }
 
     return NOTMUCH_STATUS_SUCCESS;
 }
index 1c87f8c0c2eb16ecb6b0f372f22e01072ff4fcae..46638f800997d4c5250b3592e4be8ee79abc2a21 100644 (file)
@@ -719,6 +719,8 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
            /* Ignore failure to remove non-existent term. */
        }
     }
            /* Ignore failure to remove non-existent term. */
        }
     }
+
+    _notmuch_message_invalidate_metadata (message, "property");
 }
 
 
 }
 
 
@@ -941,6 +943,7 @@ _notmuch_message_add_filename (notmuch_message_t *message,
 {
     const char *relative, *directory;
     notmuch_status_t status;
 {
     const char *relative, *directory;
     notmuch_status_t status;
+    notmuch_private_status_t private_status;
     void *local = talloc_new (message);
     char *direntry;
 
     void *local = talloc_new (message);
     char *direntry;
 
@@ -964,10 +967,17 @@ _notmuch_message_add_filename (notmuch_message_t *message,
 
     /* New file-direntry allows navigating to this message with
      * notmuch_directory_get_child_files() . */
 
     /* New file-direntry allows navigating to this message with
      * notmuch_directory_get_child_files() . */
-    status = COERCE_STATUS (_notmuch_message_add_term (message, "file-direntry", direntry),
-                           "adding file-direntry term");
-    if (status)
-       return status;
+    private_status = _notmuch_message_add_term (message, "file-direntry", direntry);
+    switch (private_status) {
+    case NOTMUCH_PRIVATE_STATUS_SUCCESS:
+       break;
+    case NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG:
+       _notmuch_database_log (message->notmuch, "filename too long for file-direntry term: %s\n",
+                              filename);
+       return NOTMUCH_STATUS_PATH_ERROR;
+    default:
+       return COERCE_STATUS (private_status, "adding file-direntry term");
+    }
 
     status = _notmuch_message_add_folder_terms (message, directory);
     if (status)
 
     status = _notmuch_message_add_folder_terms (message, directory);
     if (status)
@@ -1383,21 +1393,22 @@ _notmuch_message_delete (notmuch_message_t *message)
     if (status)
        return status;
 
     if (status)
        return status;
 
-    message->notmuch->writable_xapian_db->delete_document (message->doc_id);
-
-    /* if this was a ghost to begin with, we are done */
-    private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
-    if (private_status)
-       return COERCE_STATUS (private_status,
-                             "Error trying to determine whether message was a ghost");
-    if (is_ghost)
-       return NOTMUCH_STATUS_SUCCESS;
-
-    /* look for a non-ghost message in the same thread */
     try {
        Xapian::PostingIterator thread_doc, thread_doc_end;
        Xapian::PostingIterator mail_doc, mail_doc_end;
 
     try {
        Xapian::PostingIterator thread_doc, thread_doc_end;
        Xapian::PostingIterator mail_doc, mail_doc_end;
 
+       /* look for a non-ghost message in the same thread */
+       /* if this was a ghost to begin with, we are done */
+       private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
+       if (private_status)
+           return COERCE_STATUS (private_status,
+                                 "Error trying to determine whether message was a ghost");
+
+       message->notmuch->writable_xapian_db->delete_document (message->doc_id);
+
+       if (is_ghost)
+           return NOTMUCH_STATUS_SUCCESS;
+
        _notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
                                        &thread_doc_end);
        _notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
        _notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
                                        &thread_doc_end);
        _notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
index 1d3d2b0c9db220d36723728c044f6b0b8e71cfef..367e23e610d0220df108eed1cc078694b10bfea9 100644 (file)
@@ -259,6 +259,10 @@ _notmuch_database_filename_to_direntry (void *ctx,
                                        notmuch_find_flags_t flags,
                                        char **direntry);
 
                                        notmuch_find_flags_t flags,
                                        char **direntry);
 
+bool
+_notmuch_database_indexable_as_text (notmuch_database_t *notmuch,
+                                    const char *mime_string);
+
 /* directory.cc */
 
 notmuch_directory_t *
 /* directory.cc */
 
 notmuch_directory_t *
@@ -722,7 +726,7 @@ notmuch_status_t
 _notmuch_config_load_from_database (notmuch_database_t *db);
 
 notmuch_status_t
 _notmuch_config_load_from_database (notmuch_database_t *db);
 
 notmuch_status_t
-_notmuch_config_load_from_file (notmuch_database_t *db, GKeyFile *file);
+_notmuch_config_load_from_file (notmuch_database_t *db, GKeyFile *file, char **status_string);
 
 notmuch_status_t
 _notmuch_config_load_defaults (notmuch_database_t *db);
 
 notmuch_status_t
 _notmuch_config_load_defaults (notmuch_database_t *db);
index 0b0540b13437f6161adbba741352ae9df0a2cdfd..4e2b0fa48d3daf46dc75f51ded735a95424e9477 100644 (file)
@@ -293,6 +293,8 @@ typedef struct _notmuch_indexopts notmuch_indexopts_t;
  *
  * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
  *
  *
  * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
  *
+ * NOTMUCH_STATUS_PATH_ERROR: filename is too long
+ *
  * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the
  *     database file (such as permission denied, or file not found,
  *     etc.), or the database already exists.
  * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the
  *     database file (such as permission denied, or file not found,
  *     etc.), or the database already exists.
@@ -720,7 +722,8 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
  *
  * The UUID is a NUL-terminated opaque string that uniquely identifies
  * this database.  Two revision numbers are only comparable if they
  *
  * The UUID is a NUL-terminated opaque string that uniquely identifies
  * this database.  Two revision numbers are only comparable if they
- * have the same database UUID.
+ * have the same database UUID. The string 'uuid' is owned by notmuch
+ * and should not be freed or modified by the user.
  */
 unsigned long
 notmuch_database_get_revision (notmuch_database_t *notmuch,
  */
 unsigned long
 notmuch_database_get_revision (notmuch_database_t *notmuch,
@@ -1170,7 +1173,10 @@ notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out
  *
  *     query = notmuch_query_create (database, query_string);
  *
  *
  *     query = notmuch_query_create (database, query_string);
  *
- *     for (messages = notmuch_query_search_messages (query);
+ *     if (notmuch_query_search_messages (query, &messages) != NOTMUCH_STATUS_SUCCESS)
+ *         return EXIT_FAILURE;
+ *
+ *     for (;
  *          notmuch_messages_valid (messages);
  *          notmuch_messages_move_to_next (messages))
  *     {
  *          notmuch_messages_valid (messages);
  *          notmuch_messages_move_to_next (messages))
  *     {
@@ -2558,6 +2564,7 @@ typedef enum {
     NOTMUCH_CONFIG_USER_NAME,
     NOTMUCH_CONFIG_AUTOCOMMIT,
     NOTMUCH_CONFIG_EXTRA_HEADERS,
     NOTMUCH_CONFIG_USER_NAME,
     NOTMUCH_CONFIG_AUTOCOMMIT,
     NOTMUCH_CONFIG_EXTRA_HEADERS,
+    NOTMUCH_CONFIG_INDEX_AS_TEXT,
     NOTMUCH_CONFIG_LAST
 } notmuch_config_key_t;
 
     NOTMUCH_CONFIG_LAST
 } notmuch_config_key_t;
 
index 30cfcf9e6a985728cc4c21024aed70eb72c1cf38..463e38bf0d8f733fe933da033ab993d828255fb7 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "database-private.h"
 #include "parse-time-vrp.h"
 
 #include "database-private.h"
 #include "parse-time-vrp.h"
+#include "lastmod-fp.h"
 #include "path-util.h"
 
 #if HAVE_XAPIAN_DB_RETRY_LOCK
 #include "path-util.h"
 
 #if HAVE_XAPIAN_DB_RETRY_LOCK
@@ -192,6 +193,8 @@ _choose_database_path (notmuch_database_t *notmuch,
                       const char **database_path,
                       char **message)
 {
                       const char **database_path,
                       char **message)
 {
+    notmuch_status_t status;
+
     if (! *database_path) {
        *database_path = getenv ("NOTMUCH_DATABASE");
     }
     if (! *database_path) {
        *database_path = getenv ("NOTMUCH_DATABASE");
     }
@@ -207,8 +210,6 @@ _choose_database_path (notmuch_database_t *notmuch,
        }
     }
     if (! *database_path) {
        }
     }
     if (! *database_path) {
-       notmuch_status_t status;
-
        *database_path = _xdg_dir (notmuch, "XDG_DATA_HOME", ".local/share", profile);
        status = _db_dir_exists (*database_path, message);
        if (status) {
        *database_path = _xdg_dir (notmuch, "XDG_DATA_HOME", ".local/share", profile);
        status = _db_dir_exists (*database_path, message);
        if (status) {
@@ -223,8 +224,6 @@ _choose_database_path (notmuch_database_t *notmuch,
     }
 
     if (! *database_path) {
     }
 
     if (! *database_path) {
-       notmuch_status_t status;
-
        *database_path = talloc_asprintf (notmuch, "%s/mail", getenv ("HOME"));
        status = _db_dir_exists (*database_path, message);
        if (status) {
        *database_path = talloc_asprintf (notmuch, "%s/mail", getenv ("HOME"));
        status = _db_dir_exists (*database_path, message);
        if (status) {
@@ -241,6 +240,71 @@ _choose_database_path (notmuch_database_t *notmuch,
        *message = strdup ("Error: Database path must be absolute.\n");
        return NOTMUCH_STATUS_PATH_ERROR;
     }
        *message = strdup ("Error: Database path must be absolute.\n");
        return NOTMUCH_STATUS_PATH_ERROR;
     }
+
+    status = _db_dir_exists (*database_path, message);
+    if (status) {
+       IGNORE_RESULT (asprintf (message,
+                                "Error: database path '%s' does not exist or is not a directory.\n",
+                                *database_path));
+       return NOTMUCH_STATUS_NO_DATABASE;
+    }
+
+    if (*message) {
+       free (*message);
+       *message = NULL;
+    }
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_mkdir (const char *path, char **message)
+{
+    if (g_mkdir_with_parents (path, 0755)) {
+       IGNORE_RESULT (asprintf (message, "Error: Cannot create directory %s: %s.\n",
+                                path, strerror (errno)));
+       return NOTMUCH_STATUS_FILE_ERROR;
+    }
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_create_database_path (notmuch_database_t *notmuch,
+                      const char *profile,
+                      GKeyFile *key_file,
+                      const char **database_path,
+                      char **message)
+{
+    notmuch_status_t status;
+
+    if (! *database_path) {
+       *database_path = getenv ("NOTMUCH_DATABASE");
+    }
+
+    if (! *database_path && key_file) {
+       char *path = g_key_file_get_string (key_file, "database", "path", NULL);
+       if (path) {
+           if (path[0] == '/')
+               *database_path = talloc_strdup (notmuch, path);
+           else
+               *database_path = talloc_asprintf (notmuch, "%s/%s", getenv ("HOME"), path);
+           g_free (path);
+       }
+    }
+
+    if (! *database_path) {
+       *database_path = _xdg_dir (notmuch, "XDG_DATA_HOME", ".local/share", profile);
+       notmuch->params |= NOTMUCH_PARAM_SPLIT;
+    }
+
+    if (*database_path[0] != '/') {
+       *message = strdup ("Error: Database path must be absolute.\n");
+       return NOTMUCH_STATUS_PATH_ERROR;
+    }
+
+    if ((status = _mkdir (*database_path, message)))
+       return status;
+
     return NOTMUCH_STATUS_SUCCESS;
 }
 
     return NOTMUCH_STATUS_SUCCESS;
 }
 
@@ -261,6 +325,8 @@ _alloc_notmuch (const char *database_path, const char *config_path, const char *
     notmuch->transaction_count = 0;
     notmuch->transaction_threshold = 0;
     notmuch->view = 1;
     notmuch->transaction_count = 0;
     notmuch->transaction_threshold = 0;
     notmuch->view = 1;
+    notmuch->index_as_text = NULL;
+    notmuch->index_as_text_length = 0;
 
     notmuch->params = NOTMUCH_PARAM_NONE;
     if (database_path)
 
     notmuch->params = NOTMUCH_PARAM_NONE;
     if (database_path)
@@ -368,6 +434,53 @@ _load_database_state (notmuch_database_t *notmuch)
        notmuch, notmuch->xapian_db->get_uuid ().c_str ());
 }
 
        notmuch, notmuch->xapian_db->get_uuid ().c_str ());
 }
 
+/* XXX This should really be done lazily, but the error reporting path in the indexing code
+ * would need to be redone to report any errors.
+ */
+notmuch_status_t
+_ensure_index_as_text (notmuch_database_t *notmuch, char **message)
+{
+    int nregex = 0;
+    regex_t *regexv = NULL;
+
+    if (notmuch->index_as_text)
+       return NOTMUCH_STATUS_SUCCESS;
+
+    for (notmuch_config_values_t *list = notmuch_config_get_values (notmuch,
+                                                                   NOTMUCH_CONFIG_INDEX_AS_TEXT);
+        notmuch_config_values_valid (list);
+        notmuch_config_values_move_to_next (list)) {
+       regex_t *new_regex;
+       int rerr;
+       const char *str = notmuch_config_values_get (list);
+       size_t len = strlen (str);
+
+       /* str must be non-empty, because n_c_get_values skips empty
+        * strings */
+       assert (len > 0);
+
+       regexv = talloc_realloc (notmuch, regexv, regex_t, nregex + 1);
+       new_regex = &regexv[nregex];
+
+       rerr = regcomp (new_regex, str, REG_EXTENDED | REG_NOSUB);
+       if (rerr) {
+           size_t error_size = regerror (rerr, new_regex, NULL, 0);
+           char *error = (char *) talloc_size (str, error_size);
+
+           regerror (rerr, new_regex, error, error_size);
+           IGNORE_RESULT (asprintf (message, "Error in index.as_text: %s: %s\n", error, str));
+
+           return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
+       }
+       nregex++;
+    }
+
+    notmuch->index_as_text = regexv;
+    notmuch->index_as_text_length = nregex;
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
 static notmuch_status_t
 _finish_open (notmuch_database_t *notmuch,
              const char *profile,
 static notmuch_status_t
 _finish_open (notmuch_database_t *notmuch,
              const char *profile,
@@ -431,8 +544,7 @@ _finish_open (notmuch_database_t *notmuch,
        notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
        notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP,
                                                                     "date:");
        notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
        notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP,
                                                                     "date:");
-       notmuch->last_mod_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_LAST_MOD,
-                                                                             "lastmod:");
+       notmuch->last_mod_range_processor = new LastModRangeProcessor (notmuch, "lastmod:");
        notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
        notmuch->query_parser->set_database (*notmuch->xapian_db);
        notmuch->stemmer = new Xapian::Stem ("english");
        notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
        notmuch->query_parser->set_database (*notmuch->xapian_db);
        notmuch->stemmer = new Xapian::Stem ("english");
@@ -448,7 +560,7 @@ _finish_open (notmuch_database_t *notmuch,
            goto DONE;
 
        if (key_file)
            goto DONE;
 
        if (key_file)
-           status = _notmuch_config_load_from_file (notmuch, key_file);
+           status = _notmuch_config_load_from_file (notmuch, key_file, &message);
        if (status)
            goto DONE;
 
        if (status)
            goto DONE;
 
@@ -473,6 +585,10 @@ _finish_open (notmuch_database_t *notmuch,
        if (status)
            goto DONE;
 
        if (status)
            goto DONE;
 
+       status = _ensure_index_as_text (notmuch, &message);
+       if (status)
+           goto DONE;
+
        autocommit_str = notmuch_config_get (notmuch, NOTMUCH_CONFIG_AUTOCOMMIT);
        if (unlikely (! autocommit_str)) {
            INTERNAL_ERROR ("missing configuration for autocommit");
        autocommit_str = notmuch_config_get (notmuch, NOTMUCH_CONFIG_AUTOCOMMIT);
        if (unlikely (! autocommit_str)) {
            INTERNAL_ERROR ("missing configuration for autocommit");
@@ -607,7 +723,6 @@ notmuch_database_create_with_config (const char *database_path,
     const char *notmuch_path = NULL;
     char *message = NULL;
     GKeyFile *key_file = NULL;
     const char *notmuch_path = NULL;
     char *message = NULL;
     GKeyFile *key_file = NULL;
-    int err;
 
     _notmuch_init ();
 
 
     _notmuch_init ();
 
@@ -623,13 +738,19 @@ notmuch_database_create_with_config (const char *database_path,
        goto DONE;
     }
 
        goto DONE;
     }
 
-    if ((status = _choose_database_path (notmuch, profile, key_file,
-                                        &database_path, &message)))
-       goto DONE;
-
-    status = _db_dir_exists (database_path, &message);
-    if (status)
+    status = _choose_database_path (notmuch, profile, key_file,
+                                   &database_path, &message);
+    switch (status) {
+    case NOTMUCH_STATUS_SUCCESS:
+       break;
+    case NOTMUCH_STATUS_NO_DATABASE:
+       if ((status = _create_database_path (notmuch, profile, key_file,
+                                            &database_path, &message)))
+           goto DONE;
+       break;
+    default:
        goto DONE;
        goto DONE;
+    }
 
     _set_database_path (notmuch, database_path);
 
 
     _set_database_path (notmuch, database_path);
 
@@ -653,15 +774,9 @@ notmuch_database_create_with_config (const char *database_path,
            goto DONE;
        }
 
            goto DONE;
        }
 
-       err = mkdir (notmuch_path, 0755);
-       if (err) {
-           if (errno != EEXIST) {
-               IGNORE_RESULT (asprintf (&message, "Error: Cannot create directory %s: %s.\n",
-                                        notmuch_path, strerror (errno)));
-               status = NOTMUCH_STATUS_FILE_ERROR;
-               goto DONE;
-           }
-       }
+       status = _mkdir (notmuch_path, &message);
+       if (status)
+           goto DONE;
     }
 
     if (! (notmuch->xapian_path = talloc_asprintf (notmuch, "%s/%s", notmuch_path, "xapian"))) {
     }
 
     if (! (notmuch->xapian_path = talloc_asprintf (notmuch, "%s/%s", notmuch_path, "xapian"))) {
@@ -851,7 +966,7 @@ notmuch_database_load_config (const char *database_path,
     }
 
     if (key_file) {
     }
 
     if (key_file) {
-       status = _notmuch_config_load_from_file (notmuch, key_file);
+       status = _notmuch_config_load_from_file (notmuch, key_file, &message);
        if (status)
            goto DONE;
     }
        if (status)
            goto DONE;
     }
index 0f14d8b7307173981ca43f2fbac9d86f91a1b5e1..9cadbc1359d3fcb2d3813bab7eae5d0a91d6f096 100644 (file)
@@ -563,32 +563,13 @@ _sexp_parse_range (notmuch_database_t *notmuch,  const _sexp_prefix_t *prefix,
     }
 
     if (strcmp (prefix->name, "lastmod") == 0) {
     }
 
     if (strcmp (prefix->name, "lastmod") == 0) {
-       long from_idx, to_idx;
-
-       try {
-           if (EMPTY_STRING (from))
-               from_idx = 0L;
-           else
-               from_idx = std::stol (from);
-       } catch (std::logic_error &e) {
-           _notmuch_database_log (notmuch, "bad 'from' revision: '%s'\n", from);
-           return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
-       }
-
-       try {
-           if (EMPTY_STRING (to))
-               to_idx = LONG_MAX;
-           else
-               to_idx = std::stol (to);
-       } catch (std::logic_error &e) {
-           _notmuch_database_log (notmuch, "bad 'to' revision: '%s'\n", to);
-           return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
+       notmuch_status_t status;
+       status = _notmuch_lastmod_strings_to_query (notmuch, from, to, output, msg);
+       if (status) {
+           if (! msg.empty ())
+               _notmuch_database_log (notmuch, "%s\n", msg.c_str ());
        }
        }
-
-       output = Xapian::Query (Xapian::Query::OP_VALUE_RANGE, NOTMUCH_VALUE_LAST_MOD,
-                               Xapian::sortable_serialise (from_idx),
-                               Xapian::sortable_serialise (to_idx));
-       return NOTMUCH_STATUS_SUCCESS;
+       return status;
     }
 
     _notmuch_database_log (notmuch, "unimplimented range prefix: '%s'\n", prefix->name);
     }
 
     _notmuch_database_log (notmuch, "unimplimented range prefix: '%s'\n", prefix->name);
index 707f6222b16bd001c17097439e49804a6babc4ef..1c60c122c8e9eedd22b2e5481e8e189719551994 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "notmuch-private.h"
 #include "database-private.h"
 
 #include "notmuch-private.h"
 #include "database-private.h"
+#include "xapian-extra.h"
 
 #include <glib.h> /* GHashTable, GPtrArray */
 
 
 #include <glib.h> /* GHashTable, GPtrArray */
 
@@ -186,7 +187,7 @@ _notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch,
 {
     try {
        if (query_string == "" || query_string == "*") {
 {
     try {
        if (query_string == "" || query_string == "*") {
-           output = Xapian::Query::MatchAll;
+           output = xapian_query_match_all ();
        } else {
            output =
                notmuch->query_parser->
        } else {
            output =
                notmuch->query_parser->
index 539915d892f9529d3d011dfa7611bb37aba718d2..3a775261fc3a1c2f31b82f345766e231fbf45f81 100644 (file)
@@ -25,6 +25,7 @@
 #include "regexp-fields.h"
 #include "notmuch-private.h"
 #include "database-private.h"
 #include "regexp-fields.h"
 #include "notmuch-private.h"
 #include "database-private.h"
+#include "xapian-extra.h"
 
 notmuch_status_t
 compile_regex (regex_t &regexp, const char *str, std::string &msg)
 
 notmuch_status_t
 compile_regex (regex_t &regexp, const char *str, std::string &msg)
@@ -200,7 +201,7 @@ RegexpFieldProcessor::operator() (const std::string & str)
     if (str.empty ()) {
        if (options & NOTMUCH_FIELD_PROBABILISTIC) {
            return Xapian::Query (Xapian::Query::OP_AND_NOT,
     if (str.empty ()) {
        if (options & NOTMUCH_FIELD_PROBABILISTIC) {
            return Xapian::Query (Xapian::Query::OP_AND_NOT,
-                                 Xapian::Query::MatchAll,
+                                 xapian_query_match_all (),
                                  Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
        } else {
            return Xapian::Query (term_prefix);
                                  Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
        } else {
            return Xapian::Query (term_prefix);
index e3a81b4fe1457a030154fb3cb05cfc59cd3bb059..99bc2ea2450fe7a188f527106d5f45fb711f8f10 100644 (file)
@@ -86,10 +86,14 @@ _notmuch_string_map_append (notmuch_string_map_t *map,
 static int
 cmppair (const void *pa, const void *pb)
 {
 static int
 cmppair (const void *pa, const void *pb)
 {
+    int cmp = 0;
     notmuch_string_pair_t *a = (notmuch_string_pair_t *) pa;
     notmuch_string_pair_t *b = (notmuch_string_pair_t *) pb;
 
     notmuch_string_pair_t *a = (notmuch_string_pair_t *) pa;
     notmuch_string_pair_t *b = (notmuch_string_pair_t *) pb;
 
-    return strcmp (a->key, b->key);
+    cmp = strcmp (a->key, b->key);
+    if (cmp == 0)
+       cmp = strcmp (a->value, b->value);
+    return cmp;
 }
 
 static void
 }
 
 static void
index 21b49908ae246c1bffd0b7cc242b79b663cbb800..1a87240d3c21de8e51736ede9b408cdd36e23652 100644 (file)
@@ -77,6 +77,8 @@ typedef struct notmuch_show_params {
     bool output_body;
     int duplicate;
     int part;
     bool output_body;
     int duplicate;
     int part;
+    int offset;
+    int limit;
     _notmuch_crypto_t crypto;
     bool include_html;
     GMimeStream *out_stream;
     _notmuch_crypto_t crypto;
     bool include_html;
     GMimeStream *out_stream;
index e9456d794456c080e81abbd6a00efcb6b123c3c4..8123e4381003bd89509edc8d7970737893b1992b 100644 (file)
@@ -278,18 +278,24 @@ notmuch_conffile_open (notmuch_database_t *notmuch,
        return NULL;
     }
 
        return NULL;
     }
 
-    if (config->is_new)
-       g_key_file_set_comment (config->key_file, NULL, NULL,
-                               toplevel_config_comment, NULL);
-
     for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
        const char *name = group_comment_table[i].group_name;
        if (! g_key_file_has_group (config->key_file,  name)) {
            /* Force group to exist before adding comment */
            g_key_file_set_value (config->key_file, name, "dummy_key", "dummy_val");
            g_key_file_remove_key (config->key_file, name, "dummy_key", NULL);
     for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
        const char *name = group_comment_table[i].group_name;
        if (! g_key_file_has_group (config->key_file,  name)) {
            /* Force group to exist before adding comment */
            g_key_file_set_value (config->key_file, name, "dummy_key", "dummy_val");
            g_key_file_remove_key (config->key_file, name, "dummy_key", NULL);
-           g_key_file_set_comment (config->key_file, name, NULL,
-                                   group_comment_table[i].comment, NULL);
+           if (config->is_new && (i == 0) ) {
+               const char *comment;
+
+               comment = talloc_asprintf (config, "%s\n%s",
+                                          toplevel_config_comment,
+                                          group_comment_table[i].comment);
+               g_key_file_set_comment (config->key_file, name, NULL, comment,
+                                       NULL);
+           } else {
+               g_key_file_set_comment (config->key_file, name, NULL,
+                                       group_comment_table[i].comment, NULL);
+           }
        }
     }
     return config;
        }
     }
     return config;
index ceb86fbc14dfa97db10dfec87732452a648edc0b..97073c804a724e4819598089a410c336e9ea48d5 100644 (file)
@@ -31,7 +31,6 @@ import locale as _locale
 import logging as _logging
 import os as _os
 import re as _re
 import logging as _logging
 import os as _os
 import re as _re
-import shutil as _shutil
 import subprocess as _subprocess
 import sys as _sys
 import tempfile as _tempfile
 import subprocess as _subprocess
 import sys as _sys
 import tempfile as _tempfile
@@ -248,13 +247,13 @@ def count_messages(prefix=None):
         stdout=_subprocess.PIPE, wait=True)
     if status != 0:
         _LOG.error("failed to run notmuch config")
         stdout=_subprocess.PIPE, wait=True)
     if status != 0:
         _LOG.error("failed to run notmuch config")
-        sys.exit(1)
+        _sys.exit(1)
     return int(stdout.rstrip())
 
 def get_tags(prefix=None):
     "Get a list of tags with a given prefix."
     (status, stdout, stderr) = _spawn(
     return int(stdout.rstrip())
 
 def get_tags(prefix=None):
     "Get a list of tags with a given prefix."
     (status, stdout, stderr) = _spawn(
-        args=['notmuch', 'search', '--query=sexp', '--output=tags', _tag_query(prefix)],
+        args=['notmuch', 'search', '--exclude=false', '--query=sexp', '--output=tags', _tag_query(prefix)],
         stdout=_subprocess.PIPE, wait=True)
     return [tag for tag in stdout.splitlines()]
 
         stdout=_subprocess.PIPE, wait=True)
     return [tag for tag in stdout.splitlines()]
 
@@ -377,7 +376,7 @@ def check_safe_fraction(status):
 
     total = count_messages (TAG_PREFIX)
     if total == 0:
 
     total = count_messages (TAG_PREFIX)
     if total == 0:
-        _LOG.error('No existing tags with given prefix, stopping.'.format(safe))
+        _LOG.error('No existing tags with given prefix, stopping.')
         _LOG.error('Use --force to override.')
         exit(1)
     change = len(status['added'])+len(status['deleted'])
         _LOG.error('Use --force to override.')
         exit(1)
     change = len(status['added'])+len(status['deleted'])
@@ -719,7 +718,7 @@ class DatabaseCache:
                 self._known[id] = False
         else:
             (_, stdout, stderr) = _spawn(
                 self._known[id] = False
         else:
             (_, stdout, stderr) = _spawn(
-                args=['notmuch', 'search', '--output=files', 'id:{0}'.format(id)],
+                args=['notmuch', 'search', '--exclude=false', '--output=files', 'id:{0}'.format(id)],
                 stdout=_subprocess.PIPE,
                 wait=True)
             self._known[id] = stdout != None
                 stdout=_subprocess.PIPE,
                 wait=True)
             self._known[id] = stdout != None
index 346e64697aaf02763a38eb09e93ef428348aae4a..4a53e3ebcc064cc531b8cb6255c422ff35938b30 100644 (file)
@@ -413,6 +413,10 @@ add_file (notmuch_database_t *notmuch, const char *filename,
     case NOTMUCH_STATUS_FILE_NOT_EMAIL:
        fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
        break;
     case NOTMUCH_STATUS_FILE_NOT_EMAIL:
        fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
        break;
+    case NOTMUCH_STATUS_PATH_ERROR:
+       fprintf (stderr, "Note: Ignoring non-indexable path: %s\n", filename);
+       (void) print_status_database ("add_file", notmuch, status);
+       break;
     case NOTMUCH_STATUS_FILE_ERROR:
        /* Someone renamed/removed the file between scandir and now. */
        state->vanished_files++;
     case NOTMUCH_STATUS_FILE_ERROR:
        /* Someone renamed/removed the file between scandir and now. */
        state->vanished_files++;
index ee9efa7448d78c171ec618d561bb1fa450576864..7fb40ce9ab5d3f0179707a7c0ea88f9440673f25 100644 (file)
@@ -1159,6 +1159,18 @@ do_show_threaded (void *ctx,
     notmuch_thread_t *thread;
     notmuch_messages_t *messages;
     notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
     notmuch_thread_t *thread;
     notmuch_messages_t *messages;
     notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
+    int i;
+
+    if (params->offset < 0) {
+       unsigned count;
+       notmuch_status_t s = notmuch_query_count_threads (query, &count);
+       if (print_status_query ("notmuch show", query, s))
+           return 1;
+
+       params->offset += count;
+       if (params->offset < 0)
+           params->offset = 0;
+    }
 
     status = notmuch_query_search_threads (query, &threads);
     if (print_status_query ("notmuch show", query, status))
 
     status = notmuch_query_search_threads (query, &threads);
     if (print_status_query ("notmuch show", query, status))
@@ -1166,11 +1178,16 @@ do_show_threaded (void *ctx,
 
     sp->begin_list (sp);
 
 
     sp->begin_list (sp);
 
-    for (;
-        notmuch_threads_valid (threads);
-        notmuch_threads_move_to_next (threads)) {
+    for (i = 0;
+        notmuch_threads_valid (threads) && (params->limit < 0 || i < params->offset + params->limit);
+        notmuch_threads_move_to_next (threads), i++) {
        thread = notmuch_threads_get (threads);
 
        thread = notmuch_threads_get (threads);
 
+       if (i < params->offset) {
+           notmuch_thread_destroy (thread);
+           continue;
+       }
+
        messages = notmuch_thread_get_toplevel_messages (thread);
 
        if (messages == NULL)
        messages = notmuch_thread_get_toplevel_messages (thread);
 
        if (messages == NULL)
@@ -1201,6 +1218,18 @@ do_show_unthreaded (void *ctx,
     notmuch_message_t *message;
     notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
     notmuch_bool_t excluded;
     notmuch_message_t *message;
     notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
     notmuch_bool_t excluded;
+    int i;
+
+    if (params->offset < 0) {
+       unsigned count;
+       notmuch_status_t s = notmuch_query_count_messages (query, &count);
+       if (print_status_query ("notmuch show", query, s))
+           return 1;
+
+       params->offset += count;
+       if (params->offset < 0)
+           params->offset = 0;
+    }
 
     status = notmuch_query_search_messages (query, &messages);
     if (print_status_query ("notmuch show", query, status))
 
     status = notmuch_query_search_messages (query, &messages);
     if (print_status_query ("notmuch show", query, status))
@@ -1208,9 +1237,13 @@ do_show_unthreaded (void *ctx,
 
     sp->begin_list (sp);
 
 
     sp->begin_list (sp);
 
-    for (;
-        notmuch_messages_valid (messages);
-        notmuch_messages_move_to_next (messages)) {
+    for (i = 0;
+        notmuch_messages_valid (messages) && (params->limit < 0 || i < params->offset + params->limit);
+        notmuch_messages_move_to_next (messages), i++) {
+       if (i < params->offset) {
+           continue;
+       }
+
        sp->begin_list (sp);
        sp->begin_list (sp);
 
        sp->begin_list (sp);
        sp->begin_list (sp);
 
@@ -1287,6 +1320,8 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[])
     notmuch_show_params_t params = {
        .part = -1,
        .duplicate = 0,
     notmuch_show_params_t params = {
        .part = -1,
        .duplicate = 0,
+       .offset = 0,
+       .limit = -1, /* unlimited */
        .omit_excluded = true,
        .output_body = true,
        .crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
        .omit_excluded = true,
        .output_body = true,
        .crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
@@ -1328,6 +1363,8 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[])
        { .opt_bool = &params.output_body, .name = "body" },
        { .opt_bool = &params.include_html, .name = "include-html" },
        { .opt_int = &params.duplicate, .name = "duplicate" },
        { .opt_bool = &params.output_body, .name = "body" },
        { .opt_bool = &params.include_html, .name = "include-html" },
        { .opt_int = &params.duplicate, .name = "duplicate" },
+       { .opt_int = &params.limit, .name = "limit" },
+       { .opt_int = &params.offset, .name = "offset" },
        { .opt_inherit = notmuch_shared_options },
        { }
     };
        { .opt_inherit = notmuch_shared_options },
        { }
     };
index 37286b8f491af6428c0d22c3222a01f85039a369..814b9e42a59f46ae675f24f688005ec22ab58914 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -563,6 +563,12 @@ main (int argc, char *argv[])
                                               NULL,
                                               &notmuch,
                                               &status_string);
                                               NULL,
                                               &notmuch,
                                               &status_string);
+       if (status_string) {
+           fputs (status_string, stderr);
+           free (status_string);
+           status_string = NULL;
+       }
+
        switch (status) {
        case NOTMUCH_STATUS_NO_CONFIG:
            if (! (command->mode & NOTMUCH_COMMAND_CONFIG_CREATE)) {
        switch (status) {
        case NOTMUCH_STATUS_NO_CONFIG:
            if (! (command->mode & NOTMUCH_COMMAND_CONFIG_CREATE)) {
@@ -584,6 +590,8 @@ main (int argc, char *argv[])
        case NOTMUCH_STATUS_SUCCESS:
            break;
        default:
        case NOTMUCH_STATUS_SUCCESS:
            break;
        default:
+           fputs ("Error: unable to load config file.\n", stderr);
+           ret = 1;
            goto DONE;
        }
 
            goto DONE;
        }
 
index 59b37b1b8ff033092591ede74f9b1f7eb551ec62..1ca0df2f664c9e711a6ec0977ff76b8fce60036e 100644 (file)
@@ -24,11 +24,11 @@ Getting set up to run tests:
 First, you need to get the corpus.  If you don't already have the gpg
 key for David Bremner, run
 
 First, you need to get the corpus.  If you don't already have the gpg
 key for David Bremner, run
 
-   % gpg --search 'david@tethera.net'
+   % gpg --locate-external-key 'david@tethera.net'
 
 This should get you a key with fingerprint
 
 
 This should get you a key with fingerprint
 
-    815B 6398 2A79 F8E7 C727  86C4 762B 57BB 7842 06AD
+    7A18 807F 100A 4570 C596  8420 7E4E 65C8 720B 706B
 
 (the last 8 digits are printed as the "key id").
 
 
 (the last 8 digits are printed as the "key id").
 
index 9c895d6a910145266dde528039a61caabcc8fa70..47fdb0c27ab54df243403ba5a1cfe3595d256c8b 100755 (executable)
@@ -11,4 +11,13 @@ time_run 'tag * +existing_tag' "notmuch tag +new_tag '*'"
 time_run 'tag * -existing_tag' "notmuch tag -new_tag '*'"
 time_run 'tag * -missing_tag' "notmuch tag -new_tag '*'"
 
 time_run 'tag * -existing_tag' "notmuch tag -new_tag '*'"
 time_run 'tag * -missing_tag' "notmuch tag -new_tag '*'"
 
+time_run 'tag * +maildir_flag F' "notmuch tag +flagged '*'"
+time_run 'tag * -maildir_flag F' "notmuch tag -flagged '*'"
+time_run 'tag * +maildir_flag P' "notmuch tag +passed '*'"
+time_run 'tag * -maildir_flag P' "notmuch tag -passed '*'"
+time_run 'tag * +maildir_flag D' "notmuch tag +draft '*'"
+time_run 'tag * -maildir_flag D' "notmuch tag -draft '*'"
+time_run 'tag * +maildir_flag S' "notmuch tag -unread '*'"
+time_run 'tag * -maildir_flag S' "notmuch tag +unread '*'"
+
 time_done
 time_done
diff --git a/performance-test/download/notmuch-email-corpus-0.5.tar.xz.asc b/performance-test/download/notmuch-email-corpus-0.5.tar.xz.asc
new file mode 100644 (file)
index 0000000..2318c2f
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEkiyHYXwaY0SiY6fqA0U5G1WqFSEFAmR119gACgkQA0U5G1Wq
+FSHlSQ/+NSRj27PEZjaP2I+3j+rsMG3pnVckNcuOQyfgjJ+zEagMZyRu3vaIA/pX
+xtBrNIX4l4CQIkqwyNjsuqJdzh6S3DeCWSEr1Q+GSBki+wQCBiRuDYY2HQoDezEK
+4bMfniEWZpKJD8PfIabz0OOqMUsfXEYMd9kefew5/J4OGnDIv8E5pKfqvDNNO4rW
+MhZ9w9uR9wkvmfmpO66kAgTfLllwiyNHWoWnzQfNmqM8eULFn7XxM1PEZShUEqXf
+pTWCqqm5OyUcy8f+gy9Mb7DRRvnwLpHHRQlCzzH2c+ENQRpt1ErsgVKpHTVk4UsB
+EML+zwyWEaQg7xVKWXRJDuGCF47S1GCQNUtvtx57HJl6Ds6N2mlr2KEGaI7qtiz5
+5hdaTc0L/TVN0WS+uCdfdDDozFErf1kwhA6Jnpi0YNNdK+wpFzj7ISvA+DNHwJ75
+TLBuJIU/h3QfX3NDC5xDbsWAgpv7a84e7ePO6+kAVkHsNYDbFjiunr5fRbqDsJcJ
+B+aVGhKvFZbziC84Dn5Ae9Lpa40fQlxbdb+So2nDIiuR3P33vt7wr/e2ptVfrqkn
+a1DM96n03VWexwEDMye3b3rOTXsN5Ul87zucg9xWm5JT75NGuqJ1WDJN/wwNPDro
+ZXS1OHh7UKsU1tP2J9+gLiKYNBP4m4BQjEgYXpiYEoge9A1QplQ=
+=5/Ep
+-----END PGP SIGNATURE-----
index f02527a7061f05c5135263e6ff483efafd5f2af4..357b9dad2e8c2828ca75bcca4845115b453b612b 100644 (file)
@@ -1,3 +1,3 @@
 # this should be both a valid Makefile fragment and valid POSIX(ish) shell.
 
 # this should be both a valid Makefile fragment and valid POSIX(ish) shell.
 
-PERFTEST_VERSION=0.4
+PERFTEST_VERSION=0.5
index 10f127cbbef171be491b3bc8f5b742b8e8c67111..a81808b164f0cec0ec6c0010cb023fe77d7e098c 100644 (file)
@@ -137,6 +137,23 @@ detection of missing prerequisites. In the future we may treat tests
 unable to run because of missing prerequisites, but not explicitly
 skipped by the user, as failures.
 
 unable to run because of missing prerequisites, but not explicitly
 skipped by the user, as failures.
 
+Testing installed notmuch
+-------------------------
+
+Systems integrators (e.g. Linux distros) may wish to test an installed
+version of notmuch.  This can be done be running
+
+     $ NOTMUCH_TEST_INSTALLED=1 ./test/notmuch-test
+
+In this scenario the test suite does not assume a built tree, and in
+particular cannot rely on the output of 'configure'. You may want to
+set certain feature environment variables ('NOTMUCH_HAVE_*') directly
+if you know those apply to your installed notmuch). Consider also
+setting TERM=dumb if the value of TERM cannot be used (e.g. in a
+chroot with missing terminfo). Note that having a built tree may cause
+surprising/broken results for NOTMUCH_TEST_INSTALLED, so consider
+cleaning first.
+
 Writing Tests
 -------------
 The test script is written as a shell script. It is to be named as
 Writing Tests
 -------------
 The test script is written as a shell script. It is to be named as
index a2f4d93fd2652a832aad55466c602a51963dfc2f..642f918d20398c4b9b8f028183cfd10e130da5e8 100755 (executable)
@@ -66,6 +66,7 @@ test_begin_subtest 'NOTMUCH_CONFIG is set and points to an existing file'
 test_expect_success 'test -f "${NOTMUCH_CONFIG}"'
 
 test_begin_subtest 'PATH is set to build directory'
 test_expect_success 'test -f "${NOTMUCH_CONFIG}"'
 
 test_begin_subtest 'PATH is set to build directory'
+test_subtest_broken_for_installed
 test_expect_equal \
     "$(dirname ${TEST_DIRECTORY})" \
     "$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
 test_expect_equal \
     "$(dirname ${TEST_DIRECTORY})" \
     "$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
index da45d3aecf7ae7a0c6e86be06f6d21155c50129b..827edc149a727bb5427fcb53d8a11ab6516b9bc1 100755 (executable)
@@ -12,13 +12,16 @@ test_expect_success 'notmuch help'
 test_begin_subtest 'notmuch --version'
 test_expect_success 'notmuch --version'
 
 test_begin_subtest 'notmuch --version'
 test_expect_success 'notmuch --version'
 
-if [ $NOTMUCH_HAVE_MAN -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_MAN-0}" = "1" ]; then
     test_begin_subtest 'notmuch --help tag'
     test_expect_success 'notmuch --help tag'
 
     test_begin_subtest 'notmuch help tag'
     test_expect_success 'notmuch help tag'
 else
     test_begin_subtest 'notmuch --help tag'
     test_expect_success 'notmuch --help tag'
 
     test_begin_subtest 'notmuch help tag'
     test_expect_success 'notmuch help tag'
 else
+    if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+       test_done
+    fi
     test_begin_subtest 'notmuch --help tag (man pages not available)'
     test_expect_success 'test_must_fail notmuch --help tag >/dev/null'
 
     test_begin_subtest 'notmuch --help tag (man pages not available)'
     test_expect_success 'test_must_fail notmuch --help tag >/dev/null'
 
index 43bbce31057d4fc108621c505057618d5b0d9990..621e0b69721091a5f7383db7db726004fadc2c4f 100755 (executable)
@@ -3,6 +3,8 @@
 test_description='"notmuch config"'
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description='"notmuch config"'
 . $(dirname "$0")/test-lib.sh || exit 1
 
+cp notmuch-config initial-config
+
 test_begin_subtest "Get string value"
 test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
 
 test_begin_subtest "Get string value"
 test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
 
@@ -57,6 +59,7 @@ database.mail_root=MAIL_DIR
 database.path=MAIL_DIR
 foo.list=this;is another;list value;
 foo.string=this is another string value
 database.path=MAIL_DIR
 foo.list=this;is another;list value;
 foo.string=this is another string value
+index.as_text=
 maildir.synchronize_flags=true
 new.ignore=
 new.tags=unread;inbox
 maildir.synchronize_flags=true
 new.ignore=
 new.tags=unread;inbox
@@ -192,4 +195,17 @@ test_begin_subtest "get built_with.nonexistent prints false"
 output=$(notmuch config get built_with.nonexistent)
 test_expect_equal "$output" "false"
 
 output=$(notmuch config get built_with.nonexistent)
 test_expect_equal "$output" "false"
 
+test_begin_subtest "Bad utf8 reported as error"
+cp initial-config bad-config
+printf '[query]\nq3=from:\xff\n' >>bad-config
+test_expect_code 1 "notmuch --config=./bad-config config list"
+
+test_begin_subtest "Specific error message about bad utf8"
+notmuch --config=./bad-config config list 2>ERRORS
+cat <<EOF > EXPECTED
+GLib: Key file contains key “q3” with value “from:�” which is not UTF-8
+Error: unable to load config file.
+EOF
+test_expect_equal_file EXPECTED ERRORS
+
 test_done
 test_done
index 10b29ec33f3a726f261feb5df98d58789643cf3e..39846d34b7f32f3912619bf49d30d90c4ab67f4d 100755 (executable)
@@ -21,7 +21,8 @@ baz
 EOF
 
 expected_dir=$NOTMUCH_SRCDIR/test/setup.expected-output
 EOF
 
 expected_dir=$NOTMUCH_SRCDIR/test/setup.expected-output
-test_expect_equal_file ${expected_dir}/config-with-comments new-notmuch-config
+sed '/^$/d' < new-notmuch-config > filtered-config
+test_expect_equal_file ${expected_dir}/config-with-comments filtered-config
 
 test_begin_subtest "setup consistent with config-set for single items"
 # note this relies on the config state from the previous test.
 
 test_begin_subtest "setup consistent with config-set for single items"
 # note this relies on the config state from the previous test.
index 6791f87c5c62914b48f36b7804d90316db9807fe..52888be22a86acdf15a83a532c5d80316b738aae 100755 (executable)
@@ -383,7 +383,22 @@ No new mail. Removed 1 message.
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "Long file names have reasonable diagnostics"
+printf -v name 'f%.0s' {1..234}
+generate_message "[filename]=$name"
+notmuch new 2>&1 | notmuch_dir_sanitize >OUTPUT
+rm ${MAIL_DIR}/${name}
+cat <<EOF > EXPECTED
+Note: Ignoring non-indexable path: MAIL_DIR/$name
+add_file: Path supplied is illegal for this function
+filename too long for file-direntry term: MAIL_DIR/$name
+Processed 1 file in almost no time.
+No new mail.
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "Xapian exception: read only files"
 test_begin_subtest "Xapian exception: read only files"
+test_subtest_broken_for_root
 chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
 output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
 chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
 chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
 output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
 chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
index 58c824a299bdf0e00be9b0092795440e8a03a642..1feb5624c41b8af06fab0750f7bc70395b7a4504 100755 (executable)
@@ -92,7 +92,20 @@ xdg_config () {
     notmuch --config=${CONFIG_PATH} config set database.path
 }
 
     notmuch --config=${CONFIG_PATH} config set database.path
 }
 
-for config in traditional split XDG XDG+profile symlink home_mail maildir_env; do
+mailroot_only_config () {
+    local dir
+
+    backup_config
+    notmuch config set database.mail_root ${TMP_DIRECTORY}/mail
+    notmuch config set database.path
+    DATABASE_PATH="${HOME}/.local/share/notmuch/default"
+    rm -rf $DATABASE_PATH
+    mkdir -p $DATABASE_PATH
+    XAPIAN_PATH="${DATABASE_PATH}/xapian"
+    mv mail/.notmuch/xapian $DATABASE_PATH
+}
+
+for config in traditional split XDG XDG+profile symlink home_mail maildir_env mailroot_only; do
     #start each set of tests with an known set of messages
     add_email_corpus
 
     #start each set of tests with an known set of messages
     add_email_corpus
 
@@ -122,6 +135,9 @@ for config in traditional split XDG XDG+profile symlink home_mail maildir_env; d
        maildir_env)
            maildir_env_config
            ;;
        maildir_env)
            maildir_env_config
            ;;
+       mailroot_only)
+           mailroot_only_config
+           ;;
     esac
 
     test_begin_subtest "count ($config)"
     esac
 
     test_begin_subtest "count ($config)"
@@ -283,6 +299,7 @@ database.backup_dir
 database.hook_dir
 database.mail_root=MAIL_DIR
 database.path
 database.hook_dir
 database.mail_root=MAIL_DIR
 database.path
+index.as_text=
 maildir.synchronize_flags=true
 new.ignore=
 new.tags=unread;inbox
 maildir.synchronize_flags=true
 new.ignore=
 new.tags=unread;inbox
@@ -313,6 +330,7 @@ user.other_email
 user.primary_email
 EOF
    test_expect_equal_file EXPECTED OUTPUT
 user.primary_email
 EOF
    test_expect_equal_file EXPECTED OUTPUT
+
    case $config in
        XDG*)
           test_begin_subtest "Set shadowed config value in database ($config)"
    case $config in
        XDG*)
           test_begin_subtest "Set shadowed config value in database ($config)"
@@ -349,6 +367,17 @@ Added 1 new message to the database.
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Do not ignore, very important (inbox unread)
 EOF
           test_expect_equal_file EXPECTED OUTPUT
 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Do not ignore, very important (inbox unread)
 EOF
           test_expect_equal_file EXPECTED OUTPUT
+          ;&
+       mailroot_only)
+          test_begin_subtest "create database parent dir ($config)"
+          rm -r ${DATABASE_PATH}
+          notmuch new
+          test_expect_equal "$(xapian-metadata get ${XAPIAN_PATH} version)" 3
+          ;;
+       home_mail|maildir_env)
+          test_begin_subtest "No errors from config list ($config)"
+          notmuch config list 2>OUTPUT 1>/dev/null
+          test_expect_equal_file /dev/null OUTPUT
           ;;
        *)
           backup_database
           ;;
        *)
           backup_database
index 4814670681165322d4769487991ef4f12542ea64..6e855b591af5594677c73d1d0a7271e0eda05ece 100755 (executable)
@@ -157,7 +157,7 @@ print("4: {} messages".format(query.count_messages()))
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     test_begin_subtest "and of exact terms (query=sexp)"
     output=$(notmuch count --query=sexp '(and "wonderful" "wizard")')
 
     test_begin_subtest "and of exact terms (query=sexp)"
     output=$(notmuch count --query=sexp '(and "wonderful" "wizard")')
index 7d5f842d11285f0a7f7e808bcd001fd076f972fa..73953272bf505edaf5f4b2ac885afa0c9e50fcfe 100755 (executable)
@@ -293,7 +293,7 @@ for code in OUT_OF_MEMORY XAPIAN_EXCEPTION ; do
 done
 
 test_begin_subtest "insert converts mboxes on delivery"
 done
 
 test_begin_subtest "insert converts mboxes on delivery"
-notmuch insert +unmboxed < "${TEST_DIRECTORY}"/corpora/indexing/mbox-attachment.eml
+notmuch insert +unmboxed < "${TEST_DIRECTORY}"/corpora/insert/mbox-attachment.eml
 output=$(notmuch count tag:unmboxed)
 test_expect_equal "${output}" 1
 
 output=$(notmuch count tag:unmboxed)
 test_expect_equal "${output}" 1
 
index a3f0dead1420239fd654c89ea04531d1ee141729..515eb88f34b3f9c69bca5b13cd6c5cc9c1b8c44d 100755 (executable)
@@ -34,6 +34,12 @@ add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"
 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)"
 
 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 "Message-Id with spaces"
+test_subtest_known_broken
+add_message '[id]="message id@example.com"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(notmuch search --output=messages id:"message id@example.com")
+test_expect_equal "$output" "messageid@example.com"
+
 test_begin_subtest "Search by mid:"
 add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
 output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
 test_begin_subtest "Search by mid:"
 add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
 output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
@@ -132,6 +138,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; 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; Message-Id with spaces (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; 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)
index ce6b11b637674f663ff4cfcd44fefc027c1b8bf4..8800b545982751c1ac5dc0716fa605f4c72fe77c 100755 (executable)
@@ -2,7 +2,7 @@
 test_description='"notmuch search" in several variations'
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description='"notmuch search" in several variations'
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" != "1" ]; then
     printf "Skipping due to missing sfsexp library\n"
     test_done
 fi
     printf "Skipping due to missing sfsexp library\n"
     test_done
 fi
@@ -934,6 +934,14 @@ notmuch search lastmod:$revision..$revision | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(and (lastmod $revision))" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
 notmuch search --query=sexp  "(and (lastmod $revision))" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "lastmod query, one argument (negative)"
+notmuch tag +4EFC743A.3060609@april.org id:4EFC743A.3060609@april.org
+revision=$(notmuch count --lastmod '*' | cut -f3)
+revision1=$((revision - 1))
+notmuch search lastmod:$revision1..$revision1 | notmuch_search_sanitize > EXPECTED
+notmuch search --query=sexp  "(lastmod -1)" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
 test_begin_subtest "lastmod query, two arguments"
 notmuch tag +keithp from:keithp
 revision2=$(notmuch count --lastmod '*' | cut -f3)
 test_begin_subtest "lastmod query, two arguments"
 notmuch tag +keithp from:keithp
 revision2=$(notmuch count --lastmod '*' | cut -f3)
@@ -941,16 +949,38 @@ notmuch search lastmod:$revision..$revision2 | notmuch_search_sanitize > EXPECTE
 notmuch search --query=sexp  "(and (lastmod $revision $revision2))" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
 notmuch search --query=sexp  "(and (lastmod $revision $revision2))" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "lastmod query, two arguments, first negative"
+revdiff=$((revision2 - revision))
+notmuch search lastmod:$revision..$revision2 | notmuch_search_sanitize > EXPECTED
+notmuch search --query=sexp  "(lastmod -$revdiff $revision2)" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "lastmod query, two arguments, second negative"
+revdiff=$((revision2 - revision))
+notmuch search lastmod:..$revision | notmuch_search_sanitize > EXPECTED
+notmuch search --query=sexp  "(lastmod 0 -$revdiff)" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "lastmod query, lower bound only"
 notmuch search lastmod:$revision.. | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod $revision \"\")" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file_nonempty EXPECTED OUTPUT
 
 test_begin_subtest "lastmod query, lower bound only"
 notmuch search lastmod:$revision.. | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod $revision \"\")" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file_nonempty EXPECTED OUTPUT
 
+test_begin_subtest "lastmod query, lower bound only (negative)"
+notmuch search lastmod:$revision.. | notmuch_search_sanitize > EXPECTED
+notmuch search --query=sexp  "(lastmod -$revdiff \"\")" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
 test_begin_subtest "lastmod query, upper bound only"
 notmuch search lastmod:..$revision2 | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod \"\" $revision2)" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file_nonempty EXPECTED OUTPUT
 
 test_begin_subtest "lastmod query, upper bound only"
 notmuch search lastmod:..$revision2 | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod \"\" $revision2)" | notmuch_search_sanitize > OUTPUT
 test_expect_equal_file_nonempty EXPECTED OUTPUT
 
+test_begin_subtest "lastmod query, upper bound only (negative)"
+notmuch search lastmod:..$revision | notmuch_search_sanitize > EXPECTED
+notmuch search --query=sexp  "(lastmod \"\" -$revdiff)" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
 test_begin_subtest "lastmod query, lower bound only, using *"
 notmuch search lastmod:$revision.. | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod $revision *)" | notmuch_search_sanitize > OUTPUT
 test_begin_subtest "lastmod query, lower bound only, using *"
 notmuch search lastmod:$revision.. | notmuch_search_sanitize > EXPECTED
 notmuch search --query=sexp  "(lastmod $revision *)" | notmuch_search_sanitize > OUTPUT
index 8bb3627ac1f0e39307d134548b4a2122ddcba51d..0cafbe20f11a0140cac8df350d6e9900ec52251e 100755 (executable)
@@ -325,7 +325,7 @@ cat <<EOF >EXPECTED
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
-if [[ NOTMUCH_HAVE_SFSEXP = 1 ]]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
     test_begin_subtest "sexpr query: all messages"
     notmuch address '*' > EXPECTED
     notmuch address --query=sexp '()' > OUTPUT
     test_begin_subtest "sexpr query: all messages"
     notmuch address '*' > EXPECTED
     notmuch address --query=sexp '()' > OUTPUT
diff --git a/test/T131-show-limiting.sh b/test/T131-show-limiting.sh
new file mode 100755 (executable)
index 0000000..30d1f25
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+test_description='"notmuch show" --offset and --limit parameters'
+. $(dirname "$0")/test-lib.sh || exit 1
+
+add_email_corpus
+
+show () {
+    local kind="$1"
+    shift
+    if [ "$kind" = messages ]; then
+        set -- --unthreaded "$@"
+    fi
+    notmuch show --body=false --format=text --entire-thread=false "$@" "*" |
+        sed -nre 's/^.message\{.*\<depth:0\>.*/&/p'
+}
+
+for outp in messages threads; do
+    test_begin_subtest "$outp: limit does the right thing"
+    show $outp | head -n 20 >expected
+    show $outp --limit=20 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: concatenation of limited shows"
+    show $outp | head -n 20 >expected
+    show $outp --limit=10 >output
+    show $outp --limit=10 --offset=10 >>output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: limit larger than result set"
+    N=$(notmuch count --output=$outp "*")
+    show $outp >expected
+    show $outp --limit=$((1 + N)) >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: limit = 0"
+    test_expect_equal "$(show $outp --limit=0)" ""
+
+    test_begin_subtest "$outp: offset does the right thing"
+    # note: tail -n +N is 1-based
+    show $outp | tail -n +21 >expected
+    show $outp --offset=20 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: offset = 0"
+    show $outp >expected
+    show $outp --offset=0 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset"
+    show $outp | tail -n 20 >expected
+    show $outp --offset=-20 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset"
+    show $outp | tail -n 1 >expected
+    show $outp --offset=-1 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset combined with limit"
+    show $outp | tail -n 20 | head -n 10 >expected
+    show $outp --offset=-20 --limit=10 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset combined with equal limit"
+    show $outp | tail -n 20 >expected
+    show $outp --offset=-20 --limit=20 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset combined with large limit"
+    show $outp | tail -n 20 >expected
+    show $outp --offset=-20 --limit=50 >output
+    test_expect_equal_file expected output
+
+    test_begin_subtest "$outp: negative offset larger than results"
+    N=$(notmuch count --output=$outp "*")
+    show $outp >expected
+    show $outp --offset=-$((1 + N)) >output
+    test_expect_equal_file expected output
+done
+
+test_done
index 1a2fd77e4853708580293c9695a61cab0398fe8e..273c0af35927e092c37b7a9c47cacfc9b8aaac89 100755 (executable)
@@ -320,6 +320,7 @@ test_begin_subtest "Tag name beginning with -"
 test_expect_code 1 'notmuch tag +- One'
 
 test_begin_subtest "Xapian exception: read only files"
 test_expect_code 1 'notmuch tag +- One'
 
 test_begin_subtest "Xapian exception: read only files"
+test_subtest_broken_for_root
 chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
 output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
 chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
 chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
 output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
 chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
@@ -327,7 +328,7 @@ test_expect_equal "$output" "A Xapian exception occurred opening database"
 
 add_email_corpus
 
 
 add_email_corpus
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
     test_query_syntax '(or "php" "wizard")' 'php or wizard'
 
     test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
     test_query_syntax '(or "php" "wizard")' 'php or wizard'
index 4a797f6aad14dfe13c18c8a69d3eac617dcee80e..318c97880150d12dcb36f312c5794a04e3898af8 100755 (executable)
@@ -65,8 +65,9 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"tags\": [\"inbox\",
  \"unread\"]}]"
 
  \"tags\": [\"inbox\",
  \"unread\"]}]"
 
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
 test_begin_subtest "Search message: json, 64-bit timestamp"
 test_begin_subtest "Search message: json, 64-bit timestamp"
-if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
     test_subtest_known_broken
 fi
 add_message "[subject]=\"json-search-64bit-timestamp-subject\"" "[date]=\"Tue, 01 Jan 2999 12:00:00 -0000\"" "[body]=\"json-search-64bit-timestamp-message\""
     test_subtest_known_broken
 fi
 add_message "[subject]=\"json-search-64bit-timestamp-subject\"" "[date]=\"Tue, 01 Jan 2999 12:00:00 -0000\"" "[body]=\"json-search-64bit-timestamp-message\""
@@ -81,6 +82,7 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
  \"unread\"]}]"
  \"query\": [\"id:$gen_msg_id\", null],
  \"tags\": [\"inbox\",
  \"unread\"]}]"
+fi # NOTMUCH_TEST_INSTALLED undefined / empty
 
 test_begin_subtest "Format version: too low"
 test_expect_code 20 "notmuch search --format-version=0 \\*"
 
 test_begin_subtest "Format version: too low"
 test_expect_code 20 "notmuch search --format-version=0 \\*"
index 207f578810133643491dad884fafb879a8e62312..120d7138d61809fd46cb724501bce921de13db87 100755 (executable)
@@ -24,7 +24,7 @@ test_begin_subtest "Basic reply"
 notmuch reply id:${gen_msg_id} >OUTPUT 2>&1 && echo OK >> OUTPUT
 test_expect_equal_file basic.expected OUTPUT
 
 notmuch reply id:${gen_msg_id} >OUTPUT 2>&1 && echo OK >> OUTPUT
 test_expect_equal_file basic.expected OUTPUT
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     test_begin_subtest "Basic reply (query=sexp)"
     notmuch reply --query=sexp "(id ${gen_msg_id})" >OUTPUT 2>&1 && echo OK >> OUTPUT
 
     test_begin_subtest "Basic reply (query=sexp)"
     notmuch reply --query=sexp "(id ${gen_msg_id})" >OUTPUT 2>&1 && echo OK >> OUTPUT
index a86f0fb7e8f0440de6268075e91ba3b4262a38b1..c3f188398b87e6943d6e3a568191ed8303431605 100755 (executable)
@@ -118,7 +118,7 @@ notmuch dump -- from:cworth > dump-dash-cworth.actual
 test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
 
 
 test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
 
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     test_begin_subtest "dump --query=sexp -- '(from cworth)'"
     notmuch dump --query=sexp -- '(from cworth)' > dump-dash-cworth.actual2
 
     test_begin_subtest "dump --query=sexp -- '(from cworth)'"
     notmuch dump --query=sexp -- '(from cworth)' > dump-dash-cworth.actual2
@@ -139,6 +139,7 @@ notmuch dump --output=dump-outfile-dash-inbox.actual -- from:cworth
 test_expect_equal_file dump-cworth.expected dump-outfile-dash-inbox.actual
 
 test_begin_subtest "Check for a safe set of message-ids"
 test_expect_equal_file dump-cworth.expected dump-outfile-dash-inbox.actual
 
 test_begin_subtest "Check for a safe set of message-ids"
+test_subtest_broken_for_installed
 notmuch search --output=messages from:cworth | sed s/^id:// > EXPECTED
 notmuch search --output=messages from:cworth | sed s/^id:// |\
        $TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT
 notmuch search --output=messages from:cworth | sed s/^id:// > EXPECTED
 notmuch search --output=messages from:cworth | sed s/^id:// |\
        $TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT
@@ -246,6 +247,7 @@ notmuch dump --format=batch-tag > OUTPUT.$test_count
 test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
 
 test_begin_subtest 'format=batch-tag, checking encoded output'
 test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
 
 test_begin_subtest 'format=batch-tag, checking encoded output'
+test_subtest_broken_for_installed
 NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth |\
         awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
 NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth > OUTPUT.$test_count
 NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth |\
         awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
 NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth > OUTPUT.$test_count
index 9d0df187da73af4c4319a621442e6342f728bad2..e96c16013443f57eab16ae55581a73d4256e9dee 100755 (executable)
@@ -258,6 +258,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
+test_subtest_broken_for_installed
 notmuch new > /dev/null
 output=$(notmuch search 'subject:"testing message sent via SMTP"' | notmuch_search_sanitize)
 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; Testing message sent via SMTP (inbox)"
 notmuch new > /dev/null
 output=$(notmuch search 'subject:"testing message sent via SMTP"' | notmuch_search_sanitize)
 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; Testing message sent via SMTP (inbox)"
@@ -350,6 +351,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "Reply within emacs"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "Reply within emacs"
+test_subtest_broken_for_installed
 test_emacs '(let ((message-hidden-headers ''()))
            (notmuch-search "subject:\"testing message sent via SMTP\"")
            (notmuch-test-wait)
 test_emacs '(let ((message-hidden-headers ''()))
            (notmuch-search "subject:\"testing message sent via SMTP\"")
            (notmuch-test-wait)
@@ -1030,7 +1032,7 @@ End of search results.
 YYY/notmuch_fail exited with status 1 (see *Notmuch errors* for more details)
 === ERROR ===
 YYY/notmuch_fail exited with status 1
 YYY/notmuch_fail exited with status 1 (see *Notmuch errors* for more details)
 === ERROR ===
 YYY/notmuch_fail exited with status 1
-command: YYY/notmuch_fail search --format\=sexp --format-version\=5 --sort\=newest-first tag\:inbox
+command: YYY/notmuch_fail search --format\=sexp --format-version\=5 --sort\=newest-first --exclude\=false tag\:inbox
 exit status: 1"
 
 test_begin_subtest "Search handles subprocess warnings"
 exit status: 1"
 
 test_begin_subtest "Search handles subprocess warnings"
index 3c6626b41d3649f1c6ed56ebafb41665b24df5d1..27c0e86d42b672b6442c8ab6981a468a48bc34e0 100755 (executable)
@@ -30,6 +30,7 @@ msg_file=$(notmuch search --output=files subject:signed-message-sent-via-SMTP)
 test_expect_equal_message_body sent_message "$msg_file"
 
 test_begin_subtest "signed part content-type indexing"
 test_expect_equal_message_body sent_message "$msg_file"
 
 test_begin_subtest "signed part content-type indexing"
+test_subtest_broken_for_installed
 notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize > OUTPUT
 cat <<EOF >EXPECTED
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
 notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize > OUTPUT
 cat <<EOF >EXPECTED
 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
@@ -467,7 +468,7 @@ expected='[[[{"id": "XXXXX",
  "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
  "body": [{"id": 1,
  "sigstatus": [{"status": "error",
  "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
  "body": [{"id": 1,
  "sigstatus": [{"status": "error",
- "keyid": "6D92612D94E46381",
+ "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'",
  "errors": {"key-revoked": true}}],
  "content-type": "multipart/signed",
  "content": [{"id": 2,
  "errors": {"key-revoked": true}}],
  "content-type": "multipart/signed",
  "content": [{"id": 2,
index 809274ce14a2156ab56d68c0d0e524da3baecab6..d2118c0492efb9e3bd9bedf639b9a4f859a30ea5 100755 (executable)
@@ -183,8 +183,9 @@ test_begin_subtest "show PKCS#7 SignedData outputs valid JSON"
 output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
 test_valid_json "$output"
 
 output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
 test_valid_json "$output"
 
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
 test_begin_subtest "Verify signature on PKCS#7 SignedData message"
 test_begin_subtest "Verify signature on PKCS#7 SignedData message"
-if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
     test_subtest_known_broken
 fi
 output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
     test_subtest_known_broken
 fi
 output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
@@ -194,6 +195,7 @@ test_json_nodes <<<"$output" \
                 'expires:[0][0][0]["crypto"]["signed"]["status"][0]["expires"]=2611032858' \
                 'fingerprint:[0][0][0]["crypto"]["signed"]["status"][0]["fingerprint"]="702BA4B157F1E2B7D16B0C6A5FFC8A7DE2057DEB"' \
                 'status:[0][0][0]["crypto"]["signed"]["status"][0]["status"]="good"'
                 'expires:[0][0][0]["crypto"]["signed"]["status"][0]["expires"]=2611032858' \
                 'fingerprint:[0][0][0]["crypto"]["signed"]["status"][0]["fingerprint"]="702BA4B157F1E2B7D16B0C6A5FFC8A7DE2057DEB"' \
                 'status:[0][0][0]["crypto"]["signed"]["status"][0]["status"]="good"'
+fi # NOTMUCH_TEST_INSTALLED undefined / empty
 
 test_begin_subtest "Verify signature on PKCS#7 SignedData message signer User ID"
 if [ $NOTMUCH_GMIME_X509_CERT_VALIDITY -ne 1 ]; then
 
 test_begin_subtest "Verify signature on PKCS#7 SignedData message signer User ID"
 if [ $NOTMUCH_GMIME_X509_CERT_VALIDITY -ne 1 ]; then
index f0aba14eaa1d7d90296367ba1ce83981334e9175..9f64033112b0cf81b81dc3f929ba42d283889a5a 100755 (executable)
@@ -69,12 +69,12 @@ test_json_nodes <<<"$output" \
 test_begin_subtest "show cryptographic envelope on signed mail"
 output=$(notmuch show --verify --format=json id:simple-signed-mail@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
 test_begin_subtest "show cryptographic envelope on signed mail"
 output=$(notmuch show --verify --format=json id:simple-signed-mail@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
-                'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525609971, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}]}}'
+                'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1662554210, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}]}}'
 
 test_begin_subtest "verify signed protected header"
 output=$(notmuch show --verify --format=json id:signed-protected-header@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
 
 test_begin_subtest "verify signed protected header"
 output=$(notmuch show --verify --format=json id:signed-protected-header@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
-                'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525350527, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}], "headers": ["Subject"]}}'
+                'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1662554263, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}], "headers": ["Subject"]}}'
 
 test_begin_subtest "protected subject does not leak by default in replies"
 output=$(notmuch reply --decrypt=true --format=json id:protected-header@crypto.notmuchmail.org)
 
 test_begin_subtest "protected subject does not leak by default in replies"
 output=$(notmuch reply --decrypt=true --format=json id:protected-header@crypto.notmuchmail.org)
@@ -115,7 +115,7 @@ test_begin_subtest "verify protected header is both signed and encrypted"
 output=$(notmuch show --decrypt=true --format=json id:encrypted-signed@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
                 'crypto:[0][0][0]["crypto"]={
 output=$(notmuch show --decrypt=true --format=json id:encrypted-signed@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
                 'crypto:[0][0][0]["crypto"]={
-                   "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "created": 1525812676}],
+                   "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "created": 1662550328}],
                    "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full", "header-mask": {"Subject": "Subject Unavailable"}}}' \
                 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"'
 
                    "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full", "header-mask": {"Subject": "Subject Unavailable"}}}' \
                 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"'
 
@@ -123,7 +123,7 @@ test_begin_subtest "verify protected header is signed even when not masked"
 output=$(notmuch show --decrypt=true --format=json id:encrypted-signed-not-masked@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
                 'crypto:[0][0][0]["crypto"]={
 output=$(notmuch show --decrypt=true --format=json id:encrypted-signed-not-masked@crypto.notmuchmail.org)
 test_json_nodes <<<"$output" \
                 'crypto:[0][0][0]["crypto"]={
-                   "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "email": "'"$SELF_EMAIL"'", "created": 1525812676}],
+                   "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "email": "'"$SELF_EMAIL"'", "created": 1662550328}],
                    "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full"}}' \
                 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"'
 
                    "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full"}}' \
                 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"'
 
index 642457bf2c1f3220e7840631c76174e4a9cf9790..ff06ff691b785c96bbe5762a247868d663685864 100755 (executable)
@@ -11,6 +11,10 @@ test_description='exception symbol hiding'
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 test_begin_subtest 'running test' run_test
 mkdir -p ${PWD}/fakedb/.notmuch
 $TEST_DIRECTORY/symbol-test ${PWD}/fakedb ${PWD}/nonexistent 2>&1 \
 test_begin_subtest 'running test' run_test
 mkdir -p ${PWD}/fakedb/.notmuch
 $TEST_DIRECTORY/symbol-test ${PWD}/fakedb ${PWD}/nonexistent 2>&1 \
index 9f71ce3c414916a65bb20f18273d2635378a8ecb..21912431d3af15f6cc9cf83b728d918e17e3208c 100755 (executable)
@@ -4,6 +4,10 @@ test_description="python bindings"
 
 test_require_external_prereq ${NOTMUCH_PYTHON}
 
 
 test_require_external_prereq ${NOTMUCH_PYTHON}
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 add_email_corpus
 add_gnupg_home
 
 add_email_corpus
 add_gnupg_home
 
index 30872af0b9816a4e00da45a5f63b74844bcc84b2..0059b050c718a1452ae994e32d605d370e18c65b 100755 (executable)
@@ -2,10 +2,13 @@
 test_description="python bindings (pytest)"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="python bindings (pytest)"
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ $NOTMUCH_HAVE_PYTHON3_CFFI -eq 0 -o $NOTMUCH_HAVE_PYTHON3_PYTEST -eq 0 ]; then
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
     test_done
 fi
 
     test_done
 fi
 
+if [ "${NOTMUCH_HAVE_PYTHON3_CFFI-0}" = "0" -o "${NOTMUCH_HAVE_PYTHON3_PYTEST-0}" = "0" ]; then
+    test_done
+fi
 
 test_begin_subtest "python cffi tests (NOTMUCH_CONFIG set)"
 pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
 
 test_begin_subtest "python cffi tests (NOTMUCH_CONFIG set)"
 pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
index 15c8fc6bbe0b7dd76830df509678ebd35d235228..061612193cbe8d3f8373e7a4fe26bfddc9e41359 100755 (executable)
@@ -2,7 +2,7 @@
 test_description="python bindings (notmuch test suite)"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="python bindings (notmuch test suite)"
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ $NOTMUCH_HAVE_PYTHON3_CFFI -eq 0 -o $NOTMUCH_HAVE_PYTHON3_PYTEST -eq 0 ]; then
+if [ "${NOTMUCH_HAVE_PYTHON3_CFFI-0}" = "0" -o "${NOTMUCH_HAVE_PYTHON3_PYTEST-0}" = "0" ]; then
     test_done
 fi
 
     test_done
 fi
 
index e828efed3dbe4bca31ccf0f134c560b021cea928..d0c6bb17bdda217e1e4aff594f77592fa04636d8 100755 (executable)
@@ -2,7 +2,7 @@
 test_description="ruby bindings"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="ruby bindings"
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ "${NOTMUCH_HAVE_RUBY_DEV}" = "0" ]; then
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" -a "${NOTMUCH_HAVE_RUBY_DEV-0}" = "0" ]; then
     test_subtest_missing_external_prereq_["ruby development files"]=t
 fi
 
     test_subtest_missing_external_prereq_["ruby development files"]=t
 fi
 
@@ -12,10 +12,14 @@ test_ruby() {
     (
        cat <<-EOF
        require 'notmuch'
     (
        cat <<-EOF
        require 'notmuch'
-       db = Notmuch::Database.new('$MAIL_DIR')
+       db = Notmuch::Database.new()
        EOF
        cat
        EOF
        cat
-    ) | $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"> OUTPUT
+    ) | if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+       ruby
+    else
+       $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"
+    fi> OUTPUT
     test_expect_equal_file EXPECTED OUTPUT
 }
 
     test_expect_equal_file EXPECTED OUTPUT
 }
 
index d9aa8e2d01c811b77a0373cde8105e6e32e29965..40b625feddbfce84db3934ab8db429469efcf7d0 100755 (executable)
@@ -2,6 +2,10 @@
 test_description="argument parsing"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="argument parsing"
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 test_begin_subtest "sanity check"
 $TEST_DIRECTORY/arg-test pos1 --keyword=one --boolean --string=foo pos2 --int=7 --flag=one --flag=three > OUTPUT
 cat <<EOF > EXPECTED
 test_begin_subtest "sanity check"
 $TEST_DIRECTORY/arg-test pos1 --keyword=one --boolean --string=foo pos2 --int=7 --flag=one --flag=three > OUTPUT
 cat <<EOF > EXPECTED
index 83e902f1d8a626c88b391aab9070f2088dce3f93..559df8aaea3f15d73fab7e1f5b4d6739de130a20 100755 (executable)
@@ -338,6 +338,27 @@ when we detect the word "attachment" and there's no attach? :p
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "tar not inlined by default on refresh"
+test_emacs '(notmuch-show "id:874llc2bkp.fsf@curie.anarc.at")
+          (notmuch-show-refresh-view)
+       (test-visible-output "OUTPUT")'
+cat <<EOF > EXPECTED
+Antoine Beaupré <anarcat@orangeseeds.org> (2018-03-19) (attachment inbox)
+Subject: Re: bug: "no top level messages" crash on Zen email loops
+To: David Bremner <david@tethera.net>, notmuch@notmuchmail.org
+Date: Mon, 19 Mar 2018 13:56:54 -0400
+
+[ multipart/mixed ]
+[ text/plain ]
+And obviously I forget the frigging attachment.
+[ zendesk-email-loop2.tgz: application/x-gtar-compressed ]
+[ text/plain ]
+
+PS: don't we have a "you forgot to actually attach the damn file" plugin
+when we detect the word "attachment" and there's no attach? :p
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 add_email_corpus duplicate
 
 ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
 add_email_corpus duplicate
 
 ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
@@ -383,7 +404,6 @@ test_expect_equal_file_nonempty $EXPECTED/notmuch-show-duplicate-4 OUTPUT
 
 FILE4=$(notmuch search --output=files --duplicate=4 "id:${ID3}")
 test_begin_subtest "duplicate=4, raw"
 
 FILE4=$(notmuch search --output=files --duplicate=4 "id:${ID3}")
 test_begin_subtest "duplicate=4, raw"
-test_subtest_known_broken
 test_emacs "(notmuch-show \"id:${ID3}\")
           (notmuch-show-choose-duplicate 4)
           (notmuch-show-view-raw-message)
 test_emacs "(notmuch-show \"id:${ID3}\")
           (notmuch-show-choose-duplicate 4)
           (notmuch-show-view-raw-message)
index 3a1c449ef2b4350dd7d08397b5213ea1efb526fc..6ef5c54ab8579dfa7a22e2d04c71487fd2d3d352 100755 (executable)
@@ -100,7 +100,7 @@ test_emacs '(notmuch-hello)
            (notmuch-test-wait)
            (test-output)
            (delete-other-windows)'
            (notmuch-test-wait)
            (test-output)
            (delete-other-windows)'
-test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox OUTPUT
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-oldest-first OUTPUT
 
 test_begin_subtest "Tree view of a single thread (from search)"
 test_emacs '(notmuch-hello)
 
 test_begin_subtest "Tree view of a single thread (from search)"
 test_emacs '(notmuch-hello)
@@ -200,6 +200,30 @@ test_emacs '(test-log-error
                (notmuch-tree "*")))'
 test_expect_equal "$(cat MESSAGES)" "COMPLETE"
 
                (notmuch-tree "*")))'
 test_expect_equal "$(cat MESSAGES)" "COMPLETE"
 
+# reinitialize database for outline tests
+add_email_corpus
+
+test_begin_subtest "start in outline mode"
+test_emacs '(let ((notmuch-tree-outline-enabled t))
+       (notmuch-tree "tag:inbox")
+       (notmuch-test-wait)
+       (test-visible-output))'
+# folding all messages by height or depth should look the same
+test_expect_equal_file $EXPECTED/inbox-outline OUTPUT
+
+test_begin_subtest "outline-cycle-buffer"
+test_emacs '(let ((notmuch-tree-outline-enabled t))
+       (notmuch-tree "tag:inbox")
+       (notmuch-test-wait)
+       (outline-cycle-buffer)
+       (outline-cycle-buffer)
+       (notmuch-test-wait)
+       (test-visible-output))'
+# folding all messages by height or depth should look the same
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox OUTPUT
+
+test_done
+
 add_email_corpus duplicate
 
 ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
 add_email_corpus duplicate
 
 ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
diff --git a/test/T461-emacs-search-exclude.sh b/test/T461-emacs-search-exclude.sh
new file mode 100755 (executable)
index 0000000..47f7468
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/env bash
+
+test_description="exclude options persist between Emacs search and tree modes"
+. $(dirname "$0")/test-lib.sh || exit 1
+. $NOTMUCH_SRCDIR/test/test-lib-emacs.sh || exit 1
+
+EXPECTED=$NOTMUCH_SRCDIR/test/emacs-exclude.expected-output
+
+test_require_emacs
+add_email_corpus
+notmuch config set search.exclude_tags deleted
+notmuch tag +deleted -- 'from:"Stewart Smith"' or 'from:"Chris Wilson"'
+
+# Basic test cases just asserting exclude option is working and consistent.
+
+test_begin_subtest "Search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in search will show excluded mail"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-search-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Tree search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-tree-from-search-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in tree search will show excluded mail"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-tree-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Unthreaded search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-search-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in unthreaded will show excluded mail"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+# Cycling from search to tree to unthreaded and vice versa will persist the current
+# value of notmuch-search-hide-excluded.
+
+test_begin_subtest "Value of hide-excluded from search persists into tree search"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-search-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-tree-from-search-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from search persists into unthreaded"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-search-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-search-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from tree persists into search"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-tree-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-search-from-tree-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from tree persists into unthreaded"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-tree-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-tree-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from unthreaded persists into tree"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-tree-from-unthreaded-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from unthreaded persists into search"
+test_emacs '(notmuch-hello)
+           (goto-char (point-min))
+           (re-search-forward "inbox")
+           (widget-button-press (1- (point)))
+           (notmuch-test-wait)
+           (notmuch-unthreaded-from-search-current-query)
+           (notmuch-test-wait)
+           (notmuch-tree-toggle-hide-excluded)
+           (notmuch-test-wait)
+           (notmuch-search-from-tree-current-query)
+           (notmuch-test-wait)
+           (test-output)
+           (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_done
index b2eb80b901027ae2931d06f6ef9be33dac04722c..8bddf3e744c7f58d4db165b15905ccc83921b12c 100755 (executable)
@@ -2,6 +2,10 @@
 test_description="hex encoding and decoding"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="hex encoding and decoding"
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 test_begin_subtest "round trip"
 find $NOTMUCH_SRCDIR/test/corpora/default -type f -print | sort | xargs cat > EXPECTED
 $TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
 test_begin_subtest "round trip"
 find $NOTMUCH_SRCDIR/test/corpora/default -type f -print | sort | xargs cat > EXPECTED
 $TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
index f89755ed0e42cfe7d87040f85410e77b8002adfd..3b6e48c42aefe040ec926c1e634bab3c9ffbc7a0 100755 (executable)
@@ -2,6 +2,10 @@
 test_description="date/time parser module"
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description="date/time parser module"
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 # Sanity/smoke tests for the date/time parser independent of notmuch
 
 _date () {
 # Sanity/smoke tests for the date/time parser independent of notmuch
 
 _date () {
index c7b73a6d4a2bc2a9f892732f49052e1d97052183..6bcf109c76160c32fa0380fc6d2b68deb4d37474 100755 (executable)
@@ -35,7 +35,7 @@ notmuch show --entire-thread=true --sort=oldest-first $QUERY > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
 
 test_expect_equal_file EXPECTED OUTPUT
 
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
     test_query_syntax '(or "php" "wizard")' 'php or wizard'
 
     test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
     test_query_syntax '(or "php" "wizard")' 'php or wizard'
index 9d5a9e70a598089793d5d06b136dcbd0ae428ced..3048c7c4a5534c6a092836754ca35b33bc55fe26 100755 (executable)
@@ -3,6 +3,10 @@ test_description="database version and feature compatibility"
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 test_begin_subtest "future database versions abort open"
 ${TEST_DIRECTORY}/make-db-version ${MAIL_DIR} 9999 ""
 output=$(notmuch search x 2>&1 | sed 's/\(database at\) .*/\1 FILENAME/')
 test_begin_subtest "future database versions abort open"
 ${TEST_DIRECTORY}/make-db-version ${MAIL_DIR} 9999 ""
 output=$(notmuch search x 2>&1 | sed 's/\(database at\) .*/\1 FILENAME/')
index a2901ff6404f8ba1d4794bb9bf46c787be4312e0..78cae1cd8ee6f93da9412ae1b8d71b9f4226d9f5 100755 (executable)
@@ -91,7 +91,7 @@ EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
 == stderr ==
 cat <<'EOF' >EXPECTED
 == stdout ==
 == stderr ==
-Error: Cannot open database at CWD/nonexistent/foo: No such file or directory.
+Error: database path 'CWD/nonexistent/foo' does not exist or is not a directory.
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
@@ -102,16 +102,17 @@ test_C <<'EOF'
 int main (int argc, char** argv)
 {
     notmuch_status_t stat;
 int main (int argc, char** argv)
 {
     notmuch_status_t stat;
-    char *msg;
+    char *msg = NULL;
 
     stat = notmuch_database_create_with_config (NULL, "", NULL, NULL, &msg);
 
     stat = notmuch_database_create_with_config (NULL, "", NULL, NULL, &msg);
+    printf ("%s\n", notmuch_status_to_string (stat));
     if (msg) fputs (msg, stderr);
 }
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
     if (msg) fputs (msg, stderr);
 }
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
+No mail root found
 == stderr ==
 == stderr ==
-Error: could not locate database.
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
@@ -123,16 +124,17 @@ int main (int argc, char** argv)
 {
     notmuch_database_t *db;
     notmuch_status_t stat;
 {
     notmuch_database_t *db;
     notmuch_status_t stat;
-    char *msg;
+    char *msg = NULL;
 
     stat = notmuch_database_create_with_config (argv[1], "", NULL, &db, &msg);
 
     stat = notmuch_database_create_with_config (argv[1], "", NULL, &db, &msg);
+    printf ("%d\n", stat == NOTMUCH_STATUS_SUCCESS);
     if (msg) fputs (msg, stderr);
 }
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
     if (msg) fputs (msg, stderr);
 }
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
+1
 == stderr ==
 == stderr ==
-Error: Cannot open database at CWD/nonexistent/foo: No such file or directory.
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
index 511d56ca694e5c131d4d5815ad43d3e80ee5fbb1..6905193788a4b22419897119d2e1d14d50c405bc 100755 (executable)
@@ -3,6 +3,10 @@ test_description="API tests for notmuch_message_*"
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED}" ]; then
+    test_done
+fi
+
 add_email_corpus
 
 test_begin_subtest "building database"
 add_email_corpus
 
 test_begin_subtest "building database"
@@ -516,4 +520,31 @@ cat <<EOF > EXPECTED
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+TERMLIST_PATH=(${MAIL_DIR}/.notmuch/xapian/termlist.*)
+test_begin_subtest "remove message with corrupted db"
+backup_database
+cat c_head0 - c_tail <<'EOF' | test_private_C ${MAIL_DIR} ${TERMLIST_PATH}
+    {
+        notmuch_status_t status;
+
+        int fd = open(argv[2],O_WRONLY|O_TRUNC);
+        if (fd < 0) {
+            fprintf (stderr, "error opening %s\n", argv[1]);
+            exit (1);
+        }
+
+        stat = _notmuch_message_delete (message);
+        printf ("%d\n", stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION);
+    }
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+1
+== stderr ==
+A Xapian exception occurred at message.cc:XXX: EOF reading block YYY
+EOF
+sed 's/EOF reading block [0-9]*/EOF reading block YYY/' < OUTPUT > OUTPUT.clean
+test_expect_equal_file EXPECTED OUTPUT.clean
+restore_database
+
 test_done
 test_done
index e1cc684de35c32dbb67aed25e03a151668b59628..bcc97dd9396305c7b984d156e575bdde87198804 100755 (executable)
@@ -95,4 +95,31 @@ subtotal=$(notmuch count lastmod:..$lastmod)
 result=$(($subtotal == $total-1))
 test_expect_equal 1 "$result"
 
 result=$(($subtotal == $total-1))
 test_expect_equal 1 "$result"
 
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
+    test_begin_subtest 'exclude one message using negative lastmod (sexp)'
+    total=$(notmuch count '*')
+    notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
+    count=$(notmuch count --query=sexp '(lastmod -1 *)')
+    test_expect_equal 1 "$count"
+fi
+
+test_begin_subtest 'exclude one message using negative lastmod'
+total=$(notmuch count '*')
+notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
+count=$(notmuch count lastmod:-1..)
+test_expect_equal 1 "$count"
+
+test_begin_subtest 'exclude one message using negative lastmod (second param)'
+total=$(notmuch count '*')
+notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
+count=$(notmuch count lastmod:..-1)
+test_expect_equal 51 "$count"
+
+test_begin_subtest 'negative lastmod (two parameters)'
+notmuch tag +${RANDOM} '*'
+before=$(notmuch count --lastmod '*' | cut -f3)
+notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
+count=$(notmuch count lastmod:-100..$before)
+test_expect_equal 51 "$count"
+
 test_done
 test_done
index 26a1f033085bf4470cac95e9a3dd24c380b53bd9..9326ba3e3d72fa856a02458dfcfe0f67084ed1b4 100755 (executable)
@@ -440,6 +440,7 @@ cat <<'EOF' >EXPECTED
 10: 'USER_FULL_NAME'
 11: '8000'
 12: 'NULL'
 10: 'USER_FULL_NAME'
 11: '8000'
 12: 'NULL'
+13: ''
 == stderr ==
 EOF
 unset MAILDIR
 == stderr ==
 EOF
 unset MAILDIR
@@ -725,6 +726,7 @@ test_expect_equal_file EXPECTED OUTPUT
 test_begin_subtest "list by keys (ndlc)"
 notmuch config set search.exclude_tags "foo;bar;fub"
 notmuch config set new.ignore "sekrit_junk"
 test_begin_subtest "list by keys (ndlc)"
 notmuch config set search.exclude_tags "foo;bar;fub"
 notmuch config set new.ignore "sekrit_junk"
+notmuch config set index.as_text "text/"
 cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL%
 {
     notmuch_config_key_t key;
 cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL%
 {
     notmuch_config_key_t key;
@@ -751,6 +753,7 @@ cat <<'EOF' >EXPECTED
 10: 'Notmuch Test Suite'
 11: '8000'
 12: 'NULL'
 10: 'Notmuch Test Suite'
 11: '8000'
 12: 'NULL'
+13: 'text/'
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
@@ -785,6 +788,7 @@ cat <<'EOF' >EXPECTED
 10: 'USER_FULL_NAME'
 11: '8000'
 12: 'NULL'
 10: 'USER_FULL_NAME'
 11: '8000'
 12: 'NULL'
+13: ''
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT.clean
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT.clean
@@ -856,6 +860,7 @@ database.backup_dir MAIL_DIR/.notmuch/backups
 database.hook_dir MAIL_DIR/.notmuch/hooks
 database.mail_root MAIL_DIR
 database.path MAIL_DIR
 database.hook_dir MAIL_DIR/.notmuch/hooks
 database.mail_root MAIL_DIR
 database.path MAIL_DIR
+index.as_text text/
 key with spaces value, with, spaces!
 maildir.synchronize_flags true
 new.ignore sekrit_junk
 key with spaces value, with, spaces!
 maildir.synchronize_flags true
 new.ignore sekrit_junk
index 92a70e3eb12123d4ba5a947f794727cbb7d66899..2334fcaf5266b1f297ba4495342f5c95f35aaaf8 100755 (executable)
@@ -21,6 +21,10 @@ test_description='thread breakage during reindexing'
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 message_a () {
     mkdir -p ${MAIL_DIR}/cur
     cat > ${MAIL_DIR}/cur/a <<EOF
 message_a () {
     mkdir -p ${MAIL_DIR}/cur
     cat > ${MAIL_DIR}/cur/a <<EOF
index 2685f3b5f5b04c62b274c46e51475f6526587a20..a7cbe04842a78a20827c06d4b5d5f825cf0807c7 100755 (executable)
@@ -12,7 +12,7 @@ void print_properties (notmuch_message_t *message, const char *prefix, notmuch_b
     notmuch_message_properties_t *list;
     for (list = notmuch_message_get_properties (message, prefix, exact);
          notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {
     notmuch_message_properties_t *list;
     for (list = notmuch_message_get_properties (message, prefix, exact);
          notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {
-       printf("%s\n", notmuch_message_properties_value(list));
+       printf("%s = %s\n", notmuch_message_properties_key(list), notmuch_message_properties_value(list));
     }
     notmuch_message_properties_destroy (list);
 }
     }
     notmuch_message_properties_destroy (list);
 }
@@ -89,17 +89,6 @@ testkey2 = NULL
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
-test_begin_subtest "notmuch_message_remove_all_properties"
-cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
-EXPECT0(notmuch_message_remove_all_properties (message, NULL));
-print_properties (message, "", FALSE);
-EOF
-cat <<'EOF' >EXPECTED
-== stdout ==
-== stderr ==
-EOF
-test_expect_equal_file EXPECTED OUTPUT
-
 test_begin_subtest "testing string map binary search (via message properties)"
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 {
 test_begin_subtest "testing string map binary search (via message properties)"
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 {
@@ -157,7 +146,28 @@ print_properties (message, "testkey1", TRUE);
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
-testvalue1
+testkey1 = testvalue1
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_remove_all_properties"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_remove_all_properties (message, NULL));
+EXPECT0(notmuch_database_destroy(db));
+EXPECT0(notmuch_database_open_with_config (argv[1],
+                                           NOTMUCH_DATABASE_MODE_READ_WRITE,
+                                           "", NULL, &db, &msg));
+if (msg) fputs (msg, stderr);
+EXPECT0(notmuch_database_find_message(db, "4EFC743A.3060609@april.org", &message));
+if (message == NULL) {
+  fprintf (stderr, "unable to find message");
+  exit (1);
+}
+print_properties (message, "", FALSE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
@@ -171,10 +181,9 @@ print_properties (message, "testkey1", TRUE);
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
-alice
-bob
-testvalue1
-testvalue2
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
@@ -186,27 +195,14 @@ EXPECT0(notmuch_message_add_property (message, "testkey3", "testvalue3"));
 EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
 print_properties (message, "testkey", FALSE);
 EOF
 EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
 print_properties (message, "testkey", FALSE);
 EOF
-# expected: 4 values for testkey1, 3 values for testkey3
-# they are not guaranteed to be sorted, so sort them, leaving the first
-# line '== stdout ==' and the end ('== stderr ==' and whatever error
-# may have been printed) alone
-mv OUTPUT unsorted_OUTPUT
-awk ' NR == 1 { print; next } \
-      NR < 6  { print | "sort"; next } \
-      NR == 6 { close("sort") } \
-      NR < 9  { print | "sort"; next } \
-      NR == 9 { close("sort") } \
-      { print }' unsorted_OUTPUT > OUTPUT
-rm unsorted_OUTPUT
 cat <<'EOF' >EXPECTED
 == stdout ==
 cat <<'EOF' >EXPECTED
 == stdout ==
-alice
-bob
-testvalue1
-testvalue2
-alice3
-bob3
-testvalue3
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
+testkey3 = alice3
+testkey3 = bob3
+testkey3 = testvalue3
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
@@ -248,7 +244,7 @@ test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "dump message properties"
 cat <<EOF > PROPERTIES
 
 test_begin_subtest "dump message properties"
 cat <<EOF > PROPERTIES
-#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue1 testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
+#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
 EOF
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 EXPECT0(notmuch_message_add_property (message, "fancy key with áccènts", "import value with ="));
 EOF
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 EXPECT0(notmuch_message_add_property (message, "fancy key with áccènts", "import value with ="));
@@ -259,7 +255,7 @@ test_expect_equal_file PROPERTIES OUTPUT
 test_begin_subtest "dump _only_ message properties"
 cat <<EOF > EXPECTED
 #notmuch-dump batch-tag:3 properties
 test_begin_subtest "dump _only_ message properties"
 cat <<EOF > EXPECTED
 #notmuch-dump batch-tag:3 properties
-#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue1 testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
+#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
 EOF
 notmuch dump --include=properties > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 EOF
 notmuch dump --include=properties > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
@@ -328,7 +324,6 @@ EOF
 cat <<'EOF' > EXPECTED
 testkey1 = alice
 testkey1 = bob
 cat <<'EOF' > EXPECTED
 testkey1 = alice
 testkey1 = bob
-testkey1 = testvalue1
 testkey1 = testvalue2
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 testkey1 = testvalue2
 EOF
 test_expect_equal_file EXPECTED OUTPUT
@@ -344,7 +339,6 @@ EOF
 cat <<'EOF' > EXPECTED
 testkey1 = alice
 testkey1 = bob
 cat <<'EOF' > EXPECTED
 testkey1 = alice
 testkey1 = bob
-testkey1 = testvalue1
 testkey1 = testvalue2
 testkey3 = alice3
 testkey3 = bob3
 testkey1 = testvalue2
 testkey3 = alice3
 testkey3 = bob3
@@ -362,4 +356,49 @@ for (key,val) in msg.get_properties("testkey",True):
 EOF
 test_expect_equal_file /dev/null OUTPUT
 
 EOF
 test_expect_equal_file /dev/null OUTPUT
 
+test_begin_subtest "notmuch_message_remove_all_properties_with_prefix"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_remove_all_properties_with_prefix (message, "testkey3"));
+print_properties (message, "", FALSE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+fancy key with áccènts = import value with =
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "edit property on removed message without uncaught exception"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
+stat = notmuch_message_remove_property (message, "example", "example");
+if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
+    fprintf (stderr, "unable to remove properties on message");
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+== stderr ==
+unable to remove properties on message
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+add_email_corpus
+
+test_begin_subtest "remove all properties on removed message without uncaught exception"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
+stat = notmuch_message_remove_all_properties_with_prefix (message, "");
+if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
+    fprintf (stderr, "unable to remove properties on message");
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+== stderr ==
+unable to remove properties on message
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
 test_done
index 347f84838fa2e7d7310488f460f4ec6344ed405a..af34ad7cb9e756636377604c3f01adff88d0bf6f 100755 (executable)
@@ -5,7 +5,7 @@ test_description='reindexing messages'
 add_email_corpus
 
 
 add_email_corpus
 
 
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
 
     count=$(notmuch count --lastmod '*' | cut -f 3)
     for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
 
     count=$(notmuch count --lastmod '*' | cut -f 3)
     for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
index 5129d84c544dc5f0b101fed30a51da0e5cd7c590..a2d8ec71ecd12c043217bc09b122d3a8a3e02dfc 100755 (executable)
@@ -3,6 +3,10 @@ test_description="message id parsing"
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    test_done
+fi
+
 test_begin_subtest "good message ids"
 ${TEST_DIRECTORY}/message-id-parse <<EOF >OUTPUT
 <018b1a8f2d1df62e804ce88b65401304832dfbbf.1346614915.git.jani@nikula.org>
 test_begin_subtest "good message ids"
 ${TEST_DIRECTORY}/message-id-parse <<EOF >OUTPUT
 <018b1a8f2d1df62e804ce88b65401304832dfbbf.1346614915.git.jani@nikula.org>
diff --git a/test/T760-as-text.sh b/test/T760-as-text.sh
new file mode 100755 (executable)
index 0000000..744567f
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+test_description='index attachments as text'
+. $(dirname "$0")/test-lib.sh || exit 1
+
+add_email_corpus indexing
+test_begin_subtest "empty as_text; skip text/x-diff"
+messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
+count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
+test_expect_equal "$messages,$count" "1,0"
+
+notmuch config set index.as_text "^text/"
+add_email_corpus indexing
+
+test_begin_subtest "as_index is text/; find text/x-diff"
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "reindex with empty as_text, skips text/x-diff"
+notmuch config set index.as_text
+notmuch reindex '*'
+messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
+count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "reindex with empty as_text; skips application/pdf"
+notmuch config set index.as_text
+notmuch reindex '*'
+gmessages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
+count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "reindex with as_text as text/; finds text/x-diff"
+notmuch config set index.as_text "^text/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "reindex with as_text as text/; skips application/pdf"
+notmuch config set index.as_text "^text/"
+notmuch config set index.as_text
+notmuch reindex '*'
+messages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
+count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "as_text has multiple regexes"
+notmuch config set index.as_text "blahblah;^text/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is non-anchored regex"
+notmuch config set index.as_text "e.t/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is 'application/pdf'"
+notmuch config set index.as_text "^application/pdf$"
+notmuch reindex '*'
+notmuch search id:871qo9p4tf.fsf@tethera.net > EXPECTED
+notmuch search id:871qo9p4tf.fsf@tethera.net and '"not really PDF"' > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is bad regex"
+notmuch config set index.as_text '['
+notmuch reindex '*' >& OUTPUT
+cat<<EOF > EXPECTED
+Error in index.as_text: Invalid regular expression: [
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
index 8607732e176b9978bd72622a6e5ddf8a255e6710..9ce6baa7c80b34e767bd8900f2f74c8498676818 100755 (executable)
@@ -2,14 +2,19 @@
 test_description='run code with ASAN enabled against the library'
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description='run code with ASAN enabled against the library'
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ $NOTMUCH_HAVE_ASAN -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_ASAN-0}" != "1" ]; then
     printf "Skipping due to missing ASAN support\n"
     test_done
 fi
 
     printf "Skipping due to missing ASAN support\n"
     test_done
 fi
 
+if [ -n "${LD_PRELOAD-}" ]; then
+    printf "Skipping due to ASAN LD_PRELOAD restrictions\n"
+    test_done
+fi
+
 add_email_corpus
 
 add_email_corpus
 
-TEST_CFLAGS="-fsanitize=address"
+TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=address"
 
 test_begin_subtest "open and destroy"
 test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} <<EOF
 
 test_begin_subtest "open and destroy"
 test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} <<EOF
diff --git a/test/T810-tsan.sh b/test/T810-tsan.sh
new file mode 100755 (executable)
index 0000000..4071e29
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+
+test_directory=$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)
+
+test_description='run code with TSan enabled against the library'
+# Note it is hard to ensure race conditions are deterministic so this
+# only provides best effort detection.
+
+. "$test_directory"/test-lib.sh || exit 1
+
+if [ "${NOTMUCH_HAVE_TSAN-0}" != "1" ]; then
+    printf "Skipping due to missing TSan support\n"
+    test_done
+fi
+
+export TSAN_OPTIONS="suppressions=$test_directory/T810-tsan.suppressions"
+TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=thread"
+
+cp -r ${MAIL_DIR} ${MAIL_DIR}-2
+
+test_begin_subtest "create"
+test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
+#include <notmuch-test.h>
+#include <pthread.h>
+
+void *thread (void *arg) {
+  char *mail_dir = arg;
+  /*
+   * Calls into notmuch_query_search_messages which was using the thread-unsafe
+   * Xapian::Query::MatchAll.
+   */
+  EXPECT0(notmuch_database_create (mail_dir, NULL));
+  return NULL;
+}
+
+int main (int argc, char **argv) {
+  pthread_t t1, t2;
+  EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
+  EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
+  EXPECT0(pthread_join (t1, NULL));
+  EXPECT0(pthread_join (t2, NULL));
+  return 0;
+}
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+add_email_corpus
+rm -r ${MAIL_DIR}-2
+cp -r ${MAIL_DIR} ${MAIL_DIR}-2
+
+test_begin_subtest "query"
+test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
+#include <notmuch-test.h>
+#include <pthread.h>
+
+void *thread (void *arg) {
+  char *mail_dir = arg;
+  notmuch_database_t *db;
+  /*
+   * 'from' is NOTMUCH_FIELD_PROBABILISTIC | NOTMUCH_FIELD_PROCESSOR and an
+   * empty string gets us to RegexpFieldProcessor::operator which was using
+   * the tread-unsafe Xapian::Query::MatchAll.
+   */
+  EXPECT0(notmuch_database_open_with_config (mail_dir,
+                                             NOTMUCH_DATABASE_MODE_READ_ONLY,
+                                             NULL, NULL, &db, NULL));
+  notmuch_query_t *query = notmuch_query_create (db, "from:\"\"");
+  notmuch_messages_t *messages;
+  EXPECT0(notmuch_query_search_messages (query, &messages));
+  return NULL;
+}
+
+int main (int argc, char **argv) {
+  pthread_t t1, t2;
+  EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
+  EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
+  EXPECT0(pthread_join (t1, NULL));
+  EXPECT0(pthread_join (t2, NULL));
+  return 0;
+}
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
diff --git a/test/T810-tsan.suppressions b/test/T810-tsan.suppressions
new file mode 100644 (file)
index 0000000..80dc062
--- /dev/null
@@ -0,0 +1,3 @@
+# It's unclear how TSan-friendly GLib is:
+# https://gitlab.gnome.org/GNOME/glib/-/issues/1672
+called_from_lib:libglib*.so
index 55cec78a16391b3f01e4139d5086729ca7f94bfb..831e4678ef18a1ddc3c13378a0ae6d46d757d062 100755 (executable)
@@ -2,7 +2,7 @@
 test_description='"notmuch git" to save and restore tags'
 . $(dirname "$0")/test-lib.sh || exit 1
 
 test_description='"notmuch git" to save and restore tags'
 . $(dirname "$0")/test-lib.sh || exit 1
 
-if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" != "1" ]; then
     printf "Skipping due to missing sfsexp library\n"
     test_done
 fi
     printf "Skipping due to missing sfsexp library\n"
     test_done
 fi
@@ -233,6 +233,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "invoke as nmbug sets defaults"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "invoke as nmbug sets defaults"
+test_subtest_broken_for_installed
 "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = notmuch::
 "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = notmuch::
@@ -241,6 +242,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as nmbug"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as nmbug"
+test_subtest_broken_for_installed
 NOTMUCH_GIT_DIR=`pwd`/foo "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 repository = CWD/foo
 NOTMUCH_GIT_DIR=`pwd`/foo "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 repository = CWD/foo
@@ -256,6 +258,7 @@ test_expect_equal_file EXPECTED OUTPUT
 
 
 test_begin_subtest "env variable NOTMUCH_GIT_DIR overrides config when invoked as 'nmbug'"
 
 
 test_begin_subtest "env variable NOTMUCH_GIT_DIR overrides config when invoked as 'nmbug'"
+test_subtest_broken_for_installed
 notmuch config set git.path `pwd`/bar
 NOTMUCH_GIT_DIR=`pwd`/remote.git  "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
 notmuch config set git.path
 notmuch config set git.path `pwd`/bar
 NOTMUCH_GIT_DIR=`pwd`/remote.git  "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
 notmuch config set git.path
@@ -274,6 +277,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as 'nmbug'"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as 'nmbug'"
+test_subtest_broken_for_installed
 NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = env::
 NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = env::
@@ -281,6 +285,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as nmbug"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as nmbug"
+test_subtest_broken_for_installed
 NOTMUCH_GIT_PREFIX=foo:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = foo::
 NOTMUCH_GIT_PREFIX=foo:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 cat <<EOF > EXPECTED
 prefix = foo::
@@ -288,6 +293,7 @@ EOF
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX overrides config when invoked as 'nmbug'"
 test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "env variable NOTMUCH_GIT_PREFIX overrides config when invoked as 'nmbug'"
+test_subtest_broken_for_installed
 notmuch config set git.tag_prefix config::
 NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 notmuch config set git.path
 notmuch config set git.tag_prefix config::
 NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
 notmuch config set git.path
index 1ba4698a25eccca10f8d3104d4d939b37d8c6eac..b139a735431d10c4f1200f5964e8c4747da1405d 100644 (file)
@@ -17,12 +17,11 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBACp70e7KPy9OYaheIrkLzmhq1lRqmy51aL1jBL0K/qN7rfK
-BZEG1cR8jeLjTFdPKPLVKJI80r7FgKI0ywvWvl6R1aE1Ty5BnVXT9XzCrEH7fqCl
-SKK82EvolXTohAZHUrh6K66eQQTTIAC1n7B0A8hErzkgaM4+seN3LlvezT6TLNKM
-ATpqsEbM2MVrGgw0b3oUsGGAPEt2MmjNEYsriKnqwt6dJDZc//XyhjgMQayiD8da
-N1gT3oqgu/gKCpBZDYzHf9OtVi2UnlFDWy6rrMZLjWDnIv4ve9Pn/qolwHVjzdJ1
-ZfjNC5t0z3XADKGrjN9wutr4qm7STW1rHAXHP68TQTxI0qgJKjPXNKWEw6g=
-=pJG4
+hF4DHXHP849rSK8SAQdAYbv9NFaU2Fbd6JbfE87h/yZNyWLJYZ2EseU0WyOz7Agw
+/+KTbbIqRcEYhnpQhQXBQ2wqIN5gmdRhaqrj5q0VLV2BOKNJKqXGs/W4DghXwfAu
+0oMBqjTd/mMbF0nJLw3bPX+LW47RHQdZ8vUVPlPr0ALg8kqgcfy95Qqy5h796Uyq
+xs+I/UUOt7fzTDAw0B4qkRbdSangwYy80N4X43KrAfKSstBH3/7O4285XZr86YhF
+rEtsBuwhoXI+DaG3uYZBBMTkzfButmBKHwB2CmWutmVpQL087A==
+=lhSz
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 56fe31698d0e5f0e7af983c1f5111e719bd53edf..e7bad9b080ab25813e34728dd751e5eab169be94 100644 (file)
@@ -20,33 +20,28 @@ Content-Type: application/octet-stream; charset="us-ascii"
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBACGKSDv5/rcwScSf9n33cZZPPxltQgxkDaClMGY2DARgebE
-9rpE2O/4eoaEbdu+2shahPLIbD0wuRiGVpMIIloNNucl3f15h1wXPZbTwK7sNxJq
-HycSf8sT1fkolmC9s9X0r5xHgk0G4klAqr5C3GOk7Y6wsHTYGqzDvBFEB0LvaoUC
-DANw48DehwaEUQEP/iaiYeMDUsOzFZodKZOlQWese2JPTsRwF7KrTl8C93MrZqAh
-A1pQjUH9cafj8mwDXA9ZCsYZs7r84IxShI+dUhinBSCq8F61OlLP859wq+wpKU7n
-PNVA5bfd//4hRFvDT33ZlgeeeCcRo7h4IDjJwFDYsf0Ysqvo+IKipVNXXlAcGYYI
-DVBucB0fYaVHWRKxw50mo02zKP2/GW6K3p1nxGTf73cKjc9of+VOvvMByODaJ+ne
-WIuzZMqz0vfQ0UvRVBjlsXtB7VpCqJZWkubqqwwP6+2WOCA/c5LC3z2f/BK90EQh
-/JrKfDR083UNhu4SjNwL/TF4ET33JHf1u5Gmzqx+eO00pfhVvkyz6LYImkE8ky/+
-bXyJY8iDq7dxtfqhzZbeNe4fafU/avXxTA5UkWTnYhCqyd2bvAYH3Ep3L7lSv6SQ
-Tsy0jjTsWJoSq6jRIzJuo2mX2MBKPBfLZs4tH71/4RppECletNnS4ZlxiV4LNrWE
-LrXQvE1V+mJ82muucIe7w52nf3UWjQqTA73+Ml0aK+lIhbckRIovAw1sGzRrbTEX
-xLCgz7BYDMhs5mgtfiMAzGox4xGxi56Ge519vdbddan4G92mPlLl1IPOXkO8GyLO
-D4IiPp5ilPy6uThuxxIFemxxUREbPrfLJNA8W7aRPrHz4YcgZhrAV9I4C+xE0ukB
-i8MoJeFvbCGPyTwVDn8XfFKynlZYm1f8NIVMSj5JfV8J3Om9jzDp6hx+52iUQEbW
-C9g4kfPZY8h0RMggdOlZsaR8j26xuW+fEtz7ucJIqfJ/ElTH+4bm8MK2qPZniRWv
-ej2md4bP4Bo5DXydzxz7O7TBL6/Jsp7pJhHUUb36OnTWvInyg71LPT1QIxdRvXr9
-vNhrEBDX3MNf7RyXczvBcc+cLRo+zV+T4b8wd2kwXskWgKrGUJEe2TItdsafaQ9B
-BkuVGu6cIDa6STyCJiOB68KIXiDuADSWJiiR+gZr4eU6vzfhR27LMQt/g+oPW+U4
-1AvzUl9uXjTMC2vFuTQ4M2g0WmksCNpPpzOu/QlBmRqpP2Fg9UuLv6ITWeCxp439
-g5NT5KXE2IiruL/DS0KEpWVNe4ayGzRvMawFuU582xbIzXjvilUZrW+p6req+oeF
-QWTWHGDojTvULQPV2c91lWnLaNXVethfF4hrM5MIL+EwVs3sUXFMr1kX7VNrK0QH
-Uos7nc4G9xngpdvwF4ImldD83O8qxOVzIfk5Dhz+etTH4HbnnDvmQ/FIYvjzGviR
-ZeVwdCjv/9TC4yY3nJFKMwGp70jVa1vbmWL68HVNRyAVwnQnu2UlI8UR43iVZyUH
-ZY0Nr0rbse/pvZyX4//EVOFLUR7K4GG0N4Kz41q5ZB8rI4Fl6QJhgIFJds13iM77
-n+wqLQE7kllgI32E4U9B
-=YlXg
+hF4DHXHP849rSK8SAQdAtWMNBhjdh9Xyig/GYM1RN27B7LmCk0oRkguuFMROXk8w
+wLmcm3HiikqziJzlPY8sBLEx7cLQCkCrg6KarCHGvcqajUJluLAZgrwUsmUpOFy0
+0ukBQ6EnlpNlxdcmOElG9ZYn2Dgp1Gq4eo9rHb9f/TBLxuTr1Yr0vZ5f38bVn+tB
+0FupuYE5h/PAM2JPjVg4rh1pIN2yWvNdFBHCm0Yt3AquS9bwQymUOjh0ZCey5ERy
+WJtUQ7u+f2Hfm5K9CPPqlM7GPqeR8nv2/cgJxsA9nGn4tco7pHEkM1Kwe1dLlTbh
+ZqEMKu+dVK/RqRUjDVdAonM7wz3Uah6HJH3a6W4g2mPiPPkOpnbTClCLiK0H8NRv
+9rbO69kHoNar0YTpTAAbkxlKkdKeM/xAS2UFIdE+tXSofeCHmsFCmcohKH7Rt66l
+rU7BJE7dtTiaPFYgHBuzbrkA+oH8gU9l7PQ1L16zo1rRVRb8IIBPSHY64Ekpy3L4
+FQ3Ttg8e26d2X+6eGca6RIXksTfqOniC33Fal6gBIUqP1w4ky1wjJ+wujkSuf0QB
+yFWPP3o16o9X3nEIa2L8v/engSM5p7pezZfVJej/5hWnuPP3YmbDpn0ir21Qye96
+qxq7XI7GSWukxisxC8WakNA1LHnXo5DvHB8wm3lJIfEfIJ9RHhZqyRMptC563XCZ
+A1NvY+4sKgx9g8PBRai019ZaTMYJRQqE3VlU+xHbJWMf4aymYyeY8ut8HvFhC9Tk
+4D3eol7/LgHhXA9Db4L5MJX8iHtXhqyt62vmMXcFzC1Wi8Co/HnchzGQx2vXnUIZ
+IlomEAvN1RZC2UV8q2NHKzKnfr43WfnIsdt1fQwEfQeTKX6wfhq8FDR5NmEeLeTw
+ddGA95bZEkT2xYh+2g7G1c5Z33l5WLeriA/SUMWK1oafUtcx81lJnmK/xSIg3PKZ
+jKIbTwv4tKjmGUJE5xb/RTUfOTG+v7HOBo0avwofvqz5k7Do8v0BEEmhewjcIKBf
+h2Go8VxFtDj/OG0J98PS3OVQtnv4jzepXUxr2ZW7Z0aPFUHQ2F97Yio3nxb7r7um
+OjKhNgIPp+iAWisqqw+kwWxPx/5GHxVYsOM+fqpFEjELGGNv+ImTG7jS1V5agqIr
+qU+dxYydDKnQi/5xXeE4TO0MEFhCIttOQARw3DPtZmjLuXFjqvaasTV4YyXwrKCJ
+0sfemg3wxkZxY0NI13g3CaJGtSzXdZVfkzpdVxRAZoETT7rLNDbawuq0AzSava2u
+nB/vgcDWfPr4jW21
+=r4Vv
 -----END PGP MESSAGE-----
 
 --===============9060418334135509864==--
 -----END PGP MESSAGE-----
 
 --===============9060418334135509864==--
index 0345e3e94036ac218975fe2fe246b040fb763331..f5d5d1203870666c5b4986eb6804bf175f9ded45 100644 (file)
@@ -17,19 +17,18 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBAC9z781zV7QAInGMKHX6TKU5Xw/OkoWXahpDL88F6Ocm5R9
-7M9z2ocvlyrbgRhqE+nvFeGH/K7rVkBBT6TAcdIe/C8Qzbd3stPPcx1PlunGROj7
-H/WAcmDksK3HkXpHwmInUtzNw1pkhOoLy/sFSbPvtyg8GCUzXbafHAIIo0rB2tLB
-DwGWD3l4WdcyQWuYD9QJKuDIqdWo8E3TTcKkiOAt/6liwPNZ0jGzDeCuSTnWFj6Z
-AiXGeNtD3I1tCN/8T3NjEKOCQ+bdT5Y06dDaL61FpQ23eIuSUgksVxjnkEAb6iPe
-07gjzcyNuGP3WPI/0qu0wtZwpAQxvaNygDsQj/OjR5kn9luBd/VqodM3TWWS8miV
-m0z1tYbqYAQWW6TS7fXlsyXoOxTLW5MCfe3D36VSErL/NJItETklVKzNfKjMmRKx
-CI2ZUzugxPWSLQzOp5yl7iICk8e+vS9TkQw2j0nXAQYLYgmqZMhf4av5GlFv3tQu
-heO4XLT6NBDTHMFTDbgW42kE0N4MDPc29AqVFGImcTHvflF4Vp0qIbSJdIcHwKkU
-5LKqvicAa0lsIoJbsW3lHrzowyjov2vLH/VGd/wIX+MS3KT7cySdyp8HVMcwwyZu
-Y9nrTN/7G1FwKWlcGa4uJNcFFkYlcEymZj1EX2cyrdezPtX7K5vhwBYddptFD+Bn
-IVkghRut3UDeXe83F8OutWiZfK5EVYABq/aP3//hIbQl2o4Dkd3z9m+8LobrIV5s
-NXjAjU5WQOjRLoHBebG2HkMpFsWhXD/Fb/Bb58VOpdI=
-=x12v
+hF4DHXHP849rSK8SAQdAwRMXQWEiw2ZldkVtILgy2w/vFrKxAgAxFmyDGvtbiTow
+xLMHH7PgH+S0JIjEOM0jFglpyMdzvNBWII726THKbFnOcR38CsbK55lCYw2uhABS
+0sD1AU/yQZNNDwjuJT6wjtxMdfI4DaFMD5XTpioNtRcphLpN7MHbYr4MYCxszRY7
+ZLIAkUCoY/3D26dcOkB0EMGELsRsPmKaCq/m3FVvxHHku94MzLnjV/eGRE40AiSe
+JzteAKwXzUAYzYw+LCj9WPZvy1Rs37I4VgukEgSYXMidgc9fUQ4yYKesbyQ8/iMW
+Ryo+X2yu7Iv3a7pp2qdArsJwatWpyRuASVVA7nZlNQS0YGh/fuSX3x8TJuSPliFr
+sdTVuE6sJIlqttH9CRgxMjLY5YbpF3lBTqlv2tmz0VERhWKKsh5VOiUvJvZ3p5hn
+FqnD1bcoWoBPZRNOoF6PzGkvWQIqysGLgg24wZr7ZRgZ8mHRgykBN6cmZHQKf16m
+zqqf8sppaRal6d/L72EzmeHEusUn6FlWcEDlXLc5anghYdna7qhbLqsoY7X504SQ
+Mx4tj1P4XVhgoXdLRR2EHOLrzUCrkiQ9cKfoAcUFJTcbGGYYiYwzUCkZWhsHOKsQ
+y7tajvWUzGaJ8aiZ1dfdUraOzrvOOif4TdnFJrTpM0Agy6IH8tbm8EnhNOxkjQPr
+3t7eS3JcuC0=
+=qz8x
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
diff --git a/test/corpora/indexing/PATCH-1-2-system_data_types.7-srcfix.txt:2,S b/test/corpora/indexing/PATCH-1-2-system_data_types.7-srcfix.txt:2,S
new file mode 100644 (file)
index 0000000..1361c6f
--- /dev/null
@@ -0,0 +1,282 @@
+From mboxrd@z Thu Jan  1 00:00:00 1970
+Return-Path: <SRS0=/pzd=DH=vger.kernel.org=linux-man-owner@kernel.org>
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
+       aws-us-west-2-korg-lkml-1.web.codeaurora.org
+X-Spam-Level: 
+X-Spam-Status: No, score=-8.3 required=3.0 tests=BAYES_00,DKIM_SIGNED,
+       DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,
+       HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,
+       SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no
+       version=3.4.0
+Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
+       by smtp.lore.kernel.org (Postfix) with ESMTP id AFE3FC4727E
+       for <linux-man@archiver.kernel.org>; Wed, 30 Sep 2020 10:12:21 +0000 (UTC)
+Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
+       by mail.kernel.org (Postfix) with ESMTP id 4E0D62074A
+       for <linux-man@archiver.kernel.org>; Wed, 30 Sep 2020 10:12:21 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+       dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Osm9Pn67"
+Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
+        id S1725823AbgI3KMU (ORCPT <rfc822;linux-man@archiver.kernel.org>);
+        Wed, 30 Sep 2020 06:12:20 -0400
+Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50038 "EHLO
+        lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
+        with ESMTP id S1725779AbgI3KMU (ORCPT
+        <rfc822;linux-man@vger.kernel.org>); Wed, 30 Sep 2020 06:12:20 -0400
+Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443])
+        by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5026DC061755
+        for <linux-man@vger.kernel.org>; Wed, 30 Sep 2020 03:12:20 -0700 (PDT)
+Received: by mail-pf1-x443.google.com with SMTP id b124so832681pfg.13
+        for <linux-man@vger.kernel.org>; Wed, 30 Sep 2020 03:12:20 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=gmail.com; s=20161025;
+        h=date:from:to:cc:subject:message-id:references:mime-version
+         :content-disposition:in-reply-to:user-agent;
+        bh=qR1FJVXOhU6/g+m4SoSco3vMtV+CNvRvNyXS1xuG+T4=;
+        b=Osm9Pn67G380QiA1ORltntJShSHlKg/KZZfKV8ebvfEXJw9893EO0N6J6GDR+zkmHi
+         TOQuIe7x9y95Pipm54rWWEW33U3gwoXRHsPc2Kivm6L8Ixb+f0T0rMPKw/FOkL8OGo9t
+         WmmSvnlErAXHqBq9aRAJJsf2bSlDgdAyYY1Qe6PSq2hKi2rg+sOy1Vaj4RqZ6jTK/DWY
+         tX28Ql0XS3kKWp0Lc8MNsSP+SXlcdwHQYll5LeReAg1oi++hICgWphuMmo3OH+2B1WtO
+         hMH7VuUONqbuE1aLoZ6PyyUlCeN1soJd8bKY0cmY0TKCsw0Jvkuh/XzYDVNi6wOSM6Ez
+         okpA==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+        d=1e100.net; s=20161025;
+        h=x-gm-message-state:date:from:to:cc:subject:message-id:references
+         :mime-version:content-disposition:in-reply-to:user-agent;
+        bh=qR1FJVXOhU6/g+m4SoSco3vMtV+CNvRvNyXS1xuG+T4=;
+        b=TJU+duGLhruSES/5sJy4y1wfcltfokDpA58edkSUJyasvsooUo67VNtOB3ZK49iHm5
+         C/cjy0ExxTECB0aM6p+B1jcePdWoPUaVBY9bVd/Q5DNhm4KhTO8ON96gB43d2rLWLOiK
+         /Y1vCu+MwOpY0JQTojbC140s/JYccR/KPapTmbUkRzrpmeoYqw8CbBPV60rQxYCn9GUu
+         FeCXJY5q9OfaYW1viQZoBL5n1IMMpJDVa61Q8gZ33b3wRCvQv/x1eZCsVlYpjcqf7Umc
+         /Amx3i27cxvo8pSvvwiTzrlJHJv0Gkytz13i7s+zW+XKzZRyzy3yirtU2DFTGat6FeMn
+         H8Ig==
+X-Gm-Message-State: AOAM530Yon7xNOW6kiuy6bVpbpwbzR/9pldRB49OtZaSAHAZg7Gyf7qE
+        JXgAH20rZzYlwqOZyeZCeAwtWh09PeI=
+X-Google-Smtp-Source: ABdhPJxzyZAVDBtMwQ5+dUqVg37y/LgZByrSaTxvhS6wnx6sJuG8ROItw0CwDAg939XUVADeje/nZQ==
+X-Received: by 2002:a63:c547:: with SMTP id g7mr1563654pgd.234.1601460739764;
+        Wed, 30 Sep 2020 03:12:19 -0700 (PDT)
+Received: from localhost.localdomain ([1.129.172.177])
+        by smtp.gmail.com with ESMTPSA id k14sm1804437pjd.45.2020.09.30.03.12.17
+        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+        Wed, 30 Sep 2020 03:12:19 -0700 (PDT)
+Date:   Wed, 30 Sep 2020 20:12:15 +1000
+From:   "G. Branden Robinson" <g.branden.robinson@gmail.com>
+To:     "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>
+Cc:     Jakub Wilk <jwilk@jwilk.net>, linux-man@vger.kernel.org
+Subject: Re: [PATCH 1/2] system_data_types.7: srcfix
+Message-ID: <20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain>
+References: <20200925080330.184303-1-colomar.6.4.3@gmail.com>
+ <20200927061015.4obt73pdhyh7wecu@localhost.localdomain>
+ <20200928132959.x4koforqnzohxh5u@jwilk.net>
+ <9b8303fe-969e-c9f0-e3cd-0590b342d5bf@gmail.com>
+MIME-Version: 1.0
+Content-Type: multipart/signed; micalg=pgp-sha256;
+        protocol="application/pgp-signature"; boundary="jg2hlfugxpumieke"
+Content-Disposition: inline
+In-Reply-To: <9b8303fe-969e-c9f0-e3cd-0590b342d5bf@gmail.com>
+User-Agent: NeoMutt/20180716
+Precedence: bulk
+List-ID: <linux-man.vger.kernel.org>
+X-Mailing-List: linux-man@vger.kernel.org
+
+
+--jg2hlfugxpumieke
+Content-Type: multipart/mixed; boundary="wl6i3r6gpq7ibouc"
+Content-Disposition: inline
+
+
+--wl6i3r6gpq7ibouc
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+Hi Jakub and Michael,
+
+At 2020-09-29T14:13:26+0200, Michael Kerrisk (man-pages) wrote:
+> On 9/28/20 3:29 PM, Jakub Wilk wrote:
+> > Hi Branden!
+> >=20
+> > In groff_man_style(7) you wrote:
+> >> Unused macro arguments are more often simply omitted, or good style
+> >> suggests that a more appropriate macro be chosen, that earlier
+> >> arguments are more important than later ones, or that arguments
+> >> have identical significance such that skipping any is superfluous.
+> >=20
+> > After 15 minutes of gawking at this sentence, I still don't
+> > understand what are you trying to say here. The sentence should be
+> > either thoroughly rephrased or removed.
+>=20
+> I must say that I too found it hard to parse. I presume, Branden,
+> that you mean:
+>=20
+> [[
+> Unused macro arguments are more often simply omitted, or good style=20
+> suggests
+> EITHER (1)=20
+> that a more appropriate macro be chosen,=20
+> (2)
+> that earlier arguments are more important than later ones, or
+> (3)
+> that arguments have=20
+> identical significance such that skipping any is superfluous.
+> ]]
+
+You got it.  But it was too much work.
+
+> But it takes a few scans to work that out. Perhaps break this into
+> smaller pieces, or add some explicit structuring elements to the
+> sentence?
+
+I was trying to be comprehensive with respect to several anti-patterns I
+had in mind.  However, using the anti-patterns concretely is premature
+at that point in the page.  So I both expanded and relocated the
+material.
+
+I'm attaching what I've just committed to groff git.
+
+Further feedback is welcome, of course; revision of documentation is a
+process that is never completed, only abandoned.  And I haven't given up
+yet.  :)
+
+Thank you both for your reviews.
+
+Regards,
+Branden
+
+--wl6i3r6gpq7ibouc
+Content-Type: text/x-diff; charset=us-ascii
+Content-Disposition: attachment; filename="excise_standardese.diff"
+Content-Transfer-Encoding: quoted-printable
+
+commit dd2c4cf05a659ae7127e342924668ff0fa0deaa1
+Author: G. Branden Robinson <g.branden.robinson@gmail.com>
+Date:   Wed Sep 30 19:56:38 2020 +1000
+
+    groff_man_style(7): Clarify empty macro arguments.
+   =20
+    Rewrite some ersatz standardese I had managed to concoct regarding why
+    empty macro arguments are usually not needed.  Put an expanded
+    discussion, with anti-patterns and remedies, in section "Notes", with
+    forward reference from subsection "Macro reference preliminaries".
+   =20
+    Thanks to Jakub Wilk and Michael Kerrisk for the critique.
+
+diff --git a/tmac/groff_man.7.man.in b/tmac/groff_man.7.man.in
+index c62d97ba..b96cbaf4 100644
+--- a/tmac/groff_man.7.man.in
++++ b/tmac/groff_man.7.man.in
+@@ -281,23 +281,8 @@ but the
+ package is designed such that this should seldom be necessary.
+ _ifstyle()dnl
+ .
+-Unused macro arguments are more often simply omitted,
+-.\" antipattern: '.TP ""' (just '.TP' will do)
+-or good style suggests that a more appropriate macro be chosen,
+-.\" antipattern: '.BI "" italic bold' (use '.IB' instead)
+-that earlier arguments are more important than later ones,
+-.\" antipattern: '.TH foo 1 "" "foo "1.2.3"' (don't skip the date!)
+-.\" antipattern: '.IP "" 4n' (use .TP or .RS/.RE, depending on needs)
+-or that arguments have identical significance such that skipping any is
+-superfluous.
+-.\" antipattern: '.B one two "" three' (pointless)
+-.\"   Technically, the above has a side-effect of additional space
+-.\"   between "two" and "three", but there are much more obvious ways of
+-.\"   getting it if desired.
+-.\"     .B "one two  three"
+-.\"     .B one "two " three
+-.\"     .B one two " three"
+-.\"     .B one two\~ three
++See section \(lqNotes\(rq below for examples of cases where better
++alternatives to empty arguments in macro calls are available.
+ _endif()dnl
+ .
+ Most macro arguments are strings that will be output as text;
+@@ -3235,6 +3220,63 @@ Some tips on troubleshooting your man pages follow.
+ .
+ .
+ .TP
++\(bu Do I ever need to use an empty macro argument ("")?
++Probably not.
++.
++When this seems necessary,
++often a shorter or clearer alternative is available.
++.
++.\" antipattern: '.TP ""' (just '.TP' will do)
++.\" antipattern: '.BI "" italic bold' (use '.IB' instead)
++.\" antipattern: '.TH foo 1 "" "foo 1.2.3"' (don't skip the date!)
++.\" antipattern: '.IP "" 4n' (use .TP or .RS/.RE, depending on needs)
++.\" antipattern: '.B one two "" three' (pointless)
++.\"   Technically, the above has a side-effect of additional space
++.\"   between "two" and "three", but there are much more obvious ways of
++.\"   getting it if desired.
++.\"     .B "one two  three"
++.\"     .B one "two " three
++.\"     .B one two " three"
++.\"     .B one two\~ three
++.TS
++c c
++lfCB lfCB.
++Instead of.\|.\.      .\|.\|.do this.
++_
++\&.TP \(dq\(dq        .TP
++\&.BI \(dq\(dq italic-text bold-text  .IB italic-text bold-text
++\&.TH foo 1 \(dq\(dq \(dqfoo 1.2.3\(dq        .TH foo 1 \
++\f(CIyyyy\fP-\f(CImm\fP-\f(CIdd\fP \(dqfoo 1.2.3\(dq
++\&.IP \(dq\(dq 4n     .TP 4n
++\&.B one two \(dq\(dq three   .B one two three
++.TE
++.
++.
++.IP
++In the title heading
++.RB ( .TH ),
++the date of the page's last revision is more important than packaging
++information;
++it should not be omitted.
++.
++Ideally,
++a page maintainer will keep both up to date.
++.
++.
++.IP
++In the last example,
++the empty argument does have a subtly different effect than its
++suggested replacement;
++the empty argument becomes an additional space character\(embut it is a
++regular breaking space,
++so it can be discarded at the end of an output line.
++.
++It is better not to be subtle,
++particularly with space,
++which can be overlooked in source and rendered forms.
++.
++.
++.TP
+ .RB \(bu " .RS" " doesn't indent relative to my indented paragraph"
+ The
+ .B .RS
+
+--wl6i3r6gpq7ibouc--
+
+--jg2hlfugxpumieke
+Content-Type: application/pgp-signature; name="signature.asc"
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAEBCAAdFiEEh3PWHWjjDgcrENwa0Z6cfXEmbc4FAl90WfUACgkQ0Z6cfXEm
+bc5raQ/9GhXG/5U7McaEEu+aW1IgaTYTMbsMpew5u3tBlj3/IenGzsy8wDO912BD
+aHPSedYoc485k1Vh/Kowyx569RhyIXiMtH7uINCEtheMSUNgITNFqXo8mhaqVMlU
+3JoV12btQddOIqHnGX6c5V9Z38KXFmVctD6CxjLaWGLp/Bu9tSKwSaHOOmtUYyOv
+fYpMzr0amd4z9f+O8PPnToqBhwUitEvis1ZHYU6gIj8VwOjD0gNsWjA9HR3uC3c9
+GK/R5przMANrNejzSgofm0/yAL6a61WhqhYEtzLUYu2NFnsyNJWzITNsNnoxzgQ5
+liKL0Onmw0YWjOo4Z9Zht9Iyd6JhJxW0uRwlpFhE6UlCkFHK8nbv3NbHT2xlx/po
+rxY5jDC3Ap3+mdYHY8k5o8vFd4QOXc2bSTuDRZoWtFZQsjnl4Fpkqks1W54Txq4y
+o3Vu9aOPx//Jfi8sDc/qD/mFnyUu+AMFWjIj8UxQN4HmbrbXg/DEczRfP68DjOiX
+ssy/0Rmm/H1cu7oBMoSss63mpk/NvPTSzzCR+VhU4PHQ7rxSZYS105tzkBVfe37e
+hSS00rQVWe2YnI1KkfJHFjzveHiPXf+IxC0Z4PpJuLhl+pIZ/FgxJ5yEkX0XVUIy
+aYRzKI3JaJktYl6WvulKSBPzQxIyOgrqVkZW4lv/uTh64pE6E5w=
+=oeam
+-----END PGP SIGNATURE-----
+
+--jg2hlfugxpumieke--
+
diff --git a/test/corpora/indexing/fake-pdf:2,S b/test/corpora/indexing/fake-pdf:2,S
new file mode 100644 (file)
index 0000000..60a7a47
--- /dev/null
@@ -0,0 +1,11 @@
+From: David Bremner <david@tethera.net>
+To: example@example.com
+Subject: attachment content type
+Date: Thu, 05 Jan 2023 08:02:36 -0400
+Message-ID: <871qo9p4tf.fsf@tethera.net>
+MIME-Version: 1.0
+Content-Type: application/pdf
+Content-Disposition: attachment; filename=fake.pdf
+Content-Transfer-Encoding: base64
+
+dGhpcyBpcyBub3QgcmVhbGx5IFBERgo=
\ No newline at end of file
diff --git a/test/corpora/indexing/mbox-attachment.eml b/test/corpora/indexing/mbox-attachment.eml
deleted file mode 100644 (file)
index 98a8fc9..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-From david@tethera.net  Sat Feb  5 09:19:10 2022
-From: David Bremner <david@tethera.net>
-To: David Bremner <david@tethera.net>
-Subject: Re: [RFC PATCH v2 12/12] emacs: whitespace cleanup for keybindings
-Date: Sat, 05 Feb 2022 10:19:09 -0400
-Message-ID: <87k0e9o0pu.fsf@tethera.net>
-MIME-Version: 1.0
-Content-Type: multipart/mixed; boundary="=-=-="
-
---=-=-=
-Content-Type: text/plain
-Content-Disposition: inline
-
-
-I figured out the race condition in the tests. The previous test was
-still running when the failing test started, the joys of using a shared
-emacs for running all of the tests in one file.
-
-The attached diff is split into the the commits that introduce the tests
-in question in my working series, but you should be able to just apply
-it on top of the posted series if you want.
-
-
---=-=-=
-Content-Type: text/x-diff
-Content-Disposition: inline; filename=0001-test-fixups.patch
-
-From fc88cba7f1f37b9cf3b296eace2422dd0e173502 Mon Sep 17 00:00:00 2001
-From: David Bremner <david@tethera.net>
-Date: Thu, 3 Feb 2022 21:05:05 -0400
-Subject: [PATCH] test fixups
-
----
- test/T315-emacs-tagging.sh | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
-
-diff --git a/test/T315-emacs-tagging.sh b/test/T315-emacs-tagging.sh
-index c9e3e53a..c26413ce 100755
---- a/test/T315-emacs-tagging.sh
-+++ b/test/T315-emacs-tagging.sh
-@@ -119,7 +119,8 @@ for mode in search show tree unthreaded; do
-       (notmuch-$mode \"$os_x_darwin_thread\")
-       (notmuch-test-wait)
-       (execute-kbd-macro \"+tag-to-be-undone-$mode\")
--      (notmuch-tag-undo))"
-+      (notmuch-tag-undo)
-+      (notmuch-test-wait))"
-     count=$(notmuch count "tag:tag-to-be-undone-$mode")
-     test_expect_equal "$count" "0"
-@@ -128,9 +129,7 @@ for mode in search show tree unthreaded; do
-       (notmuch-$mode \"$os_x_darwin_thread\")
-       (notmuch-test-wait)
-       (execute-kbd-macro \"+one-$mode\")
--      (notmuch-test-wait)
-       (execute-kbd-macro \"+two-$mode\")
--      (notmuch-test-wait)
-       (notmuch-tag-undo)
-       (notmuch-test-wait)
-       (execute-kbd-macro \"+three-$mode\"))"
-@@ -143,7 +142,6 @@ for mode in search show tree unthreaded; do
-       (notmuch-$mode \"$os_x_darwin_thread\")
-       (notmuch-test-wait)
-       (execute-kbd-macro \"+one-$mode\")
--      (notmuch-test-wait)
-       (execute-kbd-macro \"+two-$mode\")
-       (notmuch-tag-undo)
-       (notmuch-test-wait)
-@@ -159,7 +157,8 @@ for mode in search show tree unthreaded; do
-       (notmuch-$mode \"$os_x_darwin_thread\")
-       (notmuch-test-wait)
-       (execute-kbd-macro \"+tag-to-be-undone-$mode\")
--      (execute-kbd-macro (kbd \"C-x u\")))"
-+      (execute-kbd-macro (kbd \"C-x u\"))
-+      (notmuch-test-wait))"
-     count=$(notmuch count "tag:tag-to-be-undone-$mode")
-     test_expect_equal "$count" "0"
- done
--- 
-2.30.2
-
-
---=-=-=--
diff --git a/test/corpora/insert/mbox-attachment.eml b/test/corpora/insert/mbox-attachment.eml
new file mode 100644 (file)
index 0000000..98a8fc9
--- /dev/null
@@ -0,0 +1,83 @@
+From david@tethera.net  Sat Feb  5 09:19:10 2022
+From: David Bremner <david@tethera.net>
+To: David Bremner <david@tethera.net>
+Subject: Re: [RFC PATCH v2 12/12] emacs: whitespace cleanup for keybindings
+Date: Sat, 05 Feb 2022 10:19:09 -0400
+Message-ID: <87k0e9o0pu.fsf@tethera.net>
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="=-=-="
+
+--=-=-=
+Content-Type: text/plain
+Content-Disposition: inline
+
+
+I figured out the race condition in the tests. The previous test was
+still running when the failing test started, the joys of using a shared
+emacs for running all of the tests in one file.
+
+The attached diff is split into the the commits that introduce the tests
+in question in my working series, but you should be able to just apply
+it on top of the posted series if you want.
+
+
+--=-=-=
+Content-Type: text/x-diff
+Content-Disposition: inline; filename=0001-test-fixups.patch
+
+From fc88cba7f1f37b9cf3b296eace2422dd0e173502 Mon Sep 17 00:00:00 2001
+From: David Bremner <david@tethera.net>
+Date: Thu, 3 Feb 2022 21:05:05 -0400
+Subject: [PATCH] test fixups
+
+---
+ test/T315-emacs-tagging.sh | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/test/T315-emacs-tagging.sh b/test/T315-emacs-tagging.sh
+index c9e3e53a..c26413ce 100755
+--- a/test/T315-emacs-tagging.sh
++++ b/test/T315-emacs-tagging.sh
+@@ -119,7 +119,8 @@ for mode in search show tree unthreaded; do
+       (notmuch-$mode \"$os_x_darwin_thread\")
+       (notmuch-test-wait)
+       (execute-kbd-macro \"+tag-to-be-undone-$mode\")
+-      (notmuch-tag-undo))"
++      (notmuch-tag-undo)
++      (notmuch-test-wait))"
+     count=$(notmuch count "tag:tag-to-be-undone-$mode")
+     test_expect_equal "$count" "0"
+@@ -128,9 +129,7 @@ for mode in search show tree unthreaded; do
+       (notmuch-$mode \"$os_x_darwin_thread\")
+       (notmuch-test-wait)
+       (execute-kbd-macro \"+one-$mode\")
+-      (notmuch-test-wait)
+       (execute-kbd-macro \"+two-$mode\")
+-      (notmuch-test-wait)
+       (notmuch-tag-undo)
+       (notmuch-test-wait)
+       (execute-kbd-macro \"+three-$mode\"))"
+@@ -143,7 +142,6 @@ for mode in search show tree unthreaded; do
+       (notmuch-$mode \"$os_x_darwin_thread\")
+       (notmuch-test-wait)
+       (execute-kbd-macro \"+one-$mode\")
+-      (notmuch-test-wait)
+       (execute-kbd-macro \"+two-$mode\")
+       (notmuch-tag-undo)
+       (notmuch-test-wait)
+@@ -159,7 +157,8 @@ for mode in search show tree unthreaded; do
+       (notmuch-$mode \"$os_x_darwin_thread\")
+       (notmuch-test-wait)
+       (execute-kbd-macro \"+tag-to-be-undone-$mode\")
+-      (execute-kbd-macro (kbd \"C-x u\")))"
++      (execute-kbd-macro (kbd \"C-x u\"))
++      (notmuch-test-wait))"
+     count=$(notmuch count "tag:tag-to-be-undone-$mode")
+     test_expect_equal "$count" "0"
+ done
+-- 
+2.30.2
+
+
+--=-=-=--
index a09f6191954ac5079c406e4699c0c8e2c2e1b4eb..d4702798c0f4346020ed362e1bf9267560499469 100644 (file)
@@ -21,13 +21,9 @@ VmVyc2lvbjogMQ0K
 Content-Type: application/octet-stream
 Content-Transfer-Encoding: base64
 
 Content-Type: application/octet-stream
 Content-Transfer-Encoding: base64
 
-LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tDQoNCmhJd0R4RTAyM3ExVXF4WUJCQUNwNzBlN0tQ
-eTlPWWFoZUlya0x6bWhxMWxScW15NTFhTDFqQkwwSy9xTjdyZksNCkJaRUcxY1I4amVMalRGZFBL
-UExWS0pJODByN0ZnS0kweXd2V3ZsNlIxYUUxVHk1Qm5WWFQ5WHpDckVIN2ZxQ2wNClNLSzgyRXZv
-bFhUb2hBWkhVcmg2SzY2ZVFRVFRJQUMxbjdCMEE4aEVyemtnYU00K3NlTjNMbHZlelQ2VExOS00N
-CkFUcHFzRWJNMk1WckdndzBiM29Vc0dHQVBFdDJNbWpORVlzcmlLbnF3dDZkSkRaYy8vWHloamdN
-UWF5aUQ4ZGENCk4xZ1Qzb3FndS9nS0NwQlpEWXpIZjlPdFZpMlVubEZEV3k2cnJNWkxqV0RuSXY0
-dmU5UG4vcW9sd0hWanpkSjENClpmak5DNXQwejNYQURLR3JqTjl3dXRyNHFtN1NUVzFySEFYSFA2
-OFRRVHhJMHFnSktqUFhOS1dFdzZnPQ0KPXBKRzQNCi0tLS0tRU5EIFBHUCBNRVNTQUdFLS0tLS0N
-Cg==
+wV4DHXHP849rSK8SAQdA4L/4ntrLU9OGEHy0JIryOhNPoVCN1MgZieW5E+1wDjMw
+GZL3EGlGTYWPhAm6wmDXsMHWMtuBVawUN0lZDuUoQtWzXYZrn3HiKQZn2ahfIrrs
+0oMBLz48JurPlrHCIHfsVa/YbfZOTun/TPa5zcjX/Vi0+FgOHEFCmHzK/VqlqsdW
+PYgQPvn4rQL25GACLzzJGrDvvJKS4fEo2p3pf6SGDFtBeyKb0AdyXoBWfXelS+ST
+rMTVqEDTT+71MToOcmYPX2QJRIMEVix8tCmvMkUXni8AjurehQ==
 --=-=-=--
 --=-=-=--
index b05cb545cb201927f1657270eb6d50d55b68c540..115019b0f17dc329fd038ed3d6412994d66bb65b 100644 (file)
@@ -17,22 +17,25 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBACkvfKZEkuRUQ2ujdel8U2ufplGxE2oNOK+CI5S1O8cS9vE
-DIkVIXAtpZcCc31pYBTRl0TwCrLKFT/siYfshbxyWjMZjX/Jc38Yjg9pDFTIZ312
-LoM5uH22f1X8O8020HgH+CQk9T4s9bBuvxTvJ6GQvK/ssnoYsGr9TGcjjh3uMdLp
-AXkkF76a2iimkq2163ee/8X0vgI+2fx6EjJJvlcSIlDcUvhYHIt8kjnlADSBMpho
-gaMa90baGlE1RAK9nSBC+4ty0fIlfsgcecRtFEifFRj6foYPFIFzkgwhRkXovouG
-FyXi8QrDVS8cz61I03PMVsFHo4FtJw9cAfvTh45QFGl+inW2pSvZyRnyu6uHDe61
-NqUTJOVN4B+dFPbKafUKuJ4YGXLsDoQoE8VF0lwznA7AOATmqPQpp+Anq40C/4Su
-Zf1hGaBTuYjlChSTMxX+wV22+PQwJmK3tl1NQRFGlR1pQZWdNcu6/6RGooiVZSg+
-VsmtZjgpZa8aaEEnrsIEVPfvbIZ4OQhmgNi4CYNB306UOjIh3/8m+8JmlkxPiGXW
-gnzNUTuwKytlZnIgT1o9a7PAkz+ZiHhMLmk5nPN+dlwsVN7Ff1FHqLIMbKaZbeKK
-txvhw7/NdaCALnjamqtDJTc4kL50F44DC0im0U9hcoy8X/HBrYkTGfHgRttCp5V/
-XisGT6/rzyUzTi2usZpRtl3WhHrE0Uj0w2Bm/Qqe64vNd3F8xwuJ5qMZ3QLVxoX0
-MPTajY1pLgfMViqLaLV8fR8hLmattxaO92sbVuxHiaba8er3jzO2HfmRLqesio7u
-8FXZQnBgeqBkoRlrHhvScuZLJVU1I4UHd9s3mcR+IY5VvjxdPMcnxTNqcRB/He4H
-MrrH26P0uSFe6WJYQVXEDt4OO73ROyFZE0+rSw1z+VnjmHVIzUVvvFqwJZo6Y/0v
-1+3ab4TGMPJSkfQYHY8/O1RF67BNlA==
-=gizc
+hF4DHXHP849rSK8SAQdAhuTX3AYQs007gCtcGsYQmtZg5DrD3ev6Dm+1Fq9vfjQw
+bHP9+UKDAmWL5XW2+zlFQVb1CcWn8QUXwjJBZvHEpwyxRWJNYqNlhsnXsX+5woGs
+0ukB6Jq0OJydXSKubEnI5Bxs7UC7rekUfxUH2ij6ZXmz5Xyc/h5rF2rJO1uaPVVx
+LuVOF+ZX0muBzegGMiUtunHmY0Akis7m3xDl2ZRVViRdW+LPoxb4oAGoPq5LHfHp
+5adDtrno13K6oO0NriVEPsSl6xFCLXOqTj600F8658o16yA8fiZj4kY8G8NunmMD
+lN4UNw/EQuWIe343dKaQo+iH52atihw90OG4ahmjvkhBC/iIiXZ3J5m10VoJ7Sxy
+G6O84UW06pCAqvPmkjnkgpflGdpM3Qv66Uu9ss6jAnRLP2LVv+IVWrwle/Yp6B8V
+1adoFUMphkp534vTR4v0xJ/6WaI1YzIwlT2zd2zCMoqwT5weuX509pTbae0iGLRG
+Q+l0ImN4AxsUdgWIW+GtMn3GVWCXk2BDLcr1xkl5lJVlOIbIvbpTwqYFMVAfnDGc
+s6JZS3Bwg9bfmxSkM4GhZlDiCdZE7f0IUBSnRRHPcMkaox0g7ibF8aG0himZRqhD
+3z6gtPmWO+c5i1iV6pQbntB7MY80vprz7gzmvmadbGFS+A4uCaH2afWr1eBb6nGx
+W6deJxHaCQrrxujz20y5osSMhdAk47WPkZhphU/8ERncZ1F8aYJhUprAbKFxNjt6
+I4p8lrfAe7iM4UxqtSfVx2rPV9/Nqm8rFVH5l4f/0P93qsBNdF7rVQl9Ry2kVqkk
+86ct9ZK2QrOtsnuSYFzhlaDo9pOHkhlMOmQXAgSb12VP87z65NTYRGbElypmQl8F
+MXMxrljqnCbPaQaPq/37GEHTRJ7rrUvCQ2L6Ljp+F0m555eYHNiZRaxYA17uABOf
+RIr5gfB5ICmnH2EGIYiEkSeX3k8+8xHffrzTpOAqv/5oJBDlRcu6qyVSAumNMPYX
+fKqlNDhKh9xmK7K88vWwTgeOBm/sOXcfuAkr9nXqDqdLHb+duLiH+xjvBdl+ewTx
+gpzIkoTSsd0fgmNqmmfwmmU4oIQu4QX3/zh5HiQS70xogRxxU3przSFrrtNkiSkI
+Oe5fIqQ3tlUSzutTEoaSxeU=
+=4vL7
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index eea66a947c7323a2f4303f512d2ed25f7e548f0c..d43331bde5e888ac2055fa37a5d55c8080000524 100644 (file)
@@ -17,17 +17,22 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBAC9RgjF0vsqVqHMB8fauhazs2XoTMKkANrDS6ECANm0wcvO
-tU1huRepG8ezoow/OgZ0Yd9y/zw6w+Frrx1PhVEr01lQsUdRq7INq2FRia015Q6Q
-eOgSv9Q8wg4Vcy9XD1wI2Un71nDvbNwqx+hiR9m8vhiWfXH1MvxVQUWcUocUMtLA
-uAEB+fx5ag3Qr42VAgyymvNrHJKtuhdj7CvdT/a5oVbZV7ilflFlYms7Wq0jSex+
-Jrb+/CnNLow4LehrOpf+IfgPumo0nBbseB17rAM9vtjNy+tHEqPsB0YFIpVR9FOp
-zJITbWeFyGbOd5vMk9xbEFbw58JR8PPqsYJK41RleU2QoPEO69hoV0tXzjby5JQZ
-2G/SrH+m9tggi3rWxHx9XuNKJP4iK9wZnO4k5DFaUXq6PGCYkgDi/K1RuUcJjcv7
-ob6Yp/cTLxHMmIS9VNNjUnnoaD71ndzYsZoaI6MTMX7/4eu5roeE3887NU5af/wS
-ep6POG8WFJzKwc4dvAPd0NBVojdrftJkYKONsYL5KN8TY8SqUPxiXReGwg2evQqb
-aGEU02zdRGYtmNSneGl20dJ39cHoW7B66ek9OQkgilSHQq4adPleq07r3HSv87jk
-xNYoQ7xH2fahqbosW8N5uI9L2sdGVmTBNZgejiNyZoUn47tFEt4Uocg=
-=/ZB1
+hF4DHXHP849rSK8SAQdACh9CzQl7cqCVO0bpHfyqL0Kr/V2TtUO68yhOYuMMWXEw
+v+aH1aLYervLMNDSC8Fj6XY9myqaybbOfHnLZIQg0XkR3JIKhWR3LpZtfpFGSr/H
+0ukBgdihDN26YqD+UETkBN0lg/fd4+cvVyOJSwuU5DQFdsOk1znvEercz1UVpKxz
+gg1lniZzRYCyPSl9NcZVtNXggz6z9XqxT0cVE3WCH2IsVrJPfgnFu/P63pAhp43X
+IxJe5mB6y5eaX5Dcvj48Z2E+3tVVn1gKGwLzPH40WIy98KM4dv59I0ZghM8h1dVr
+LUUgdiz17fo5oWphzdgn57ERk9B/pApkzujrB4Sum9qy9y/Q2DWFKdOARNJSZ/Li
+KZVXZLVEyp1WeAU262blQRtqWXq30wU9PazFo3wsUUVoLCu5SWsRpircSIWrh3gH
+iBE/YdPYQNJ6kJoz17AdIq0a4jH3ae881P6eBW22zMxdqD4zfkT43iVQAtuki4JS
+iBJ2vHoMU3z+rJ59ea+P595QHCGNyfkgl50e0E8rh9j+9/CExyD6F4GwAZe9VA6o
+hYFQ3U089Cp/Cd5jVojUWIAOWqwb6nB7w3SabPZIbhhJSBdQEGe4Xh3TN3k5cpLr
+TxDJz4zf220EQ2pt0BJwDu8fdskMXC6ytQettvR46+UtFOOG9eClnAFkgeuqwKmv
+k1YyYMFWQ3Bv/IHOFrcu3negBQpP4ln5px6zggNoeNLzaZ9PN9Y2lHnoQTkw/93L
+qyjLD+xEnzgdPYZvVsNA1iI6LMrCandDwKySQyfZadj/G3/nLFcoThvn03NNUyCK
+Sh0Vy2gJhxD04HF8nkR/E5MLFCQ3x0qpGbOoanctgs/glxCpnzWRcSZERlilQ+3Y
+0r5UkO5XJU3Z3CP4uJnjykgB8Qjq/WzERgOtOQ/bVaWBWkKzxS/Pj1sJ47kKMtBJ
+3r5LXymlkA70RA0cJIv1F/At
+=vLN3
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 8dfd7c399437d7ac9900e46fdd54d861d49d1679..9f0e51b96b786bb9ec2a9ced96a9d67e99c3d08e 100644 (file)
@@ -17,18 +17,17 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBADAJ03D4w48sefkQsBWXUc1spTljROjVN+y5a2yCKtYMt3M
-wWMeQyem5hwLpLYRCfeIzXCrlBfpZffuOkA5okGGVEWFvJ5a1kZNZnH5Wg0ccBp7
-KBGnJY0gS/BlrKK2Sjmk9Z3ww7GAgDGPbc7mc3Csj9G38UvneBdrQgm6kZR3GNLA
-6AGLN3KJETruI3Js6++aG+7tSkJ8Vo4WCVUR7oQROwF601X0QF/XghCoJCrx8B/1
-cw6Yb2wQj2nv3gw1rqWVsPVpAKsMc1yHx/2Vsee/VPtt4f67fSAMuJF3EJ6JkcK7
-tM761v69GoJGgvsie45pb1N2l/GfVMuwWU0wZhEsF7eXxqPzoE/kIGX1XIqleLaw
-On2kPSM5RgqV6gLOcw4WaFPi0oMbDhltNs72SV9cV6ZhhuwEQRq+u/K76NKLwte2
-R1JutAiuPZVF0WanmmiN6RbIpWOB5XxQfWagfr4vcf/03TaLP4hJMnqUdFMk20HP
-eI8TMQxkfryZK2Z6VxEBVdXhK05VEdkolmc4j9U+76A96Gd5zbYPApirkebmZatS
-X3rKKAiBqwWrFXi/7LNDoCwhRRmqDuHXruh3vZEcz+xiPfJh0G31GJQgIpE15Sv6
-trf20u3CXAFjHg9zPpSFV7uAOsqv7bg+xtG9PgN4aLCiVbXHsT0z6PAz+6K+SiKw
-QW8ZOtLikj5HyLAz/TDcsIShFaM3QHk2qq9RY10kmxlQVrf9Oyh3Wmc=
-=om0O
+hF4DHXHP849rSK8SAQdAhRhcdC3r33MMW+D1PgLAoIhstxnEWOjI0s5wyH2gKTIw
+ceJ7nVvmnqLNWbEaoLp2tVH1+cI4guvgqzV60BoxNU5G5YMGqzMS4VQ47N4BENmn
+0sDEAWcBT1+PGFlXAeotmryF5ErMXesEVJJHru/KHZxsP3wwRp3qZjrwIWVgVlVo
+SpJJ+hwIRqCTbdsw0ejKY0+BJwQ/z+GPmYkWE+ARxkzwMzfA47PW+iNudrQNEJuu
+ALnsbyVX0/JA6E8jhvIA2OHb6G2yqFA499I6kWiSkT3m2SikuyKGybwWbaUDZVJW
+Y+JN2L8snDUHJKfl5JMhAgu2+fx/joE9PxM6fdx8rJJbpmTrPqrYf6vYyuq5BGYV
+snGJozwiN/cqR+PruMT7i5/Dhs/EDl3Z9D8iH7FEDtIzpSJNvGFIHetXC4JXgO7d
+C48g+0uuUL3SSuZviz+OgLJbyDu1Pc3tCrtBUs0zYJGio5ghJljU5tUnCNhbBwd7
+oWgYxOmSzbZrs73E5Lpvnq+juZpXSGNoYzaZHacp2FTpo0LlZ2k6o8kx6eYfOlHs
+JN+43CnzTnR6eZYkfjIaBbjYKi0rMH2DRJjMXyeYRLjEi9ET2fFX3WWn487snIjw
+om8EPhsOxQ==
+=wKPm
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index c97d8c3cafbed58a287daa7ed4150de5d6e45611..f64b99bfecb2b742f94e076deb936c1cd2f91385 100644 (file)
@@ -17,18 +17,17 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBADAJ03D4w48sefkQsBWXUc1spTljROjVN+y5a2yCKtYMt3M
-wWMeQyem5hwLpLYRCfeIzXCrlBfpZffuOkA5okGGVEWFvJ5a1kZNZnH5Wg0ccBp7
-KBGnJY0gS/BlrKK2Sjmk9Z3ww7GAgDGPbc7mc3Csj9G38UvneBdrQgm6kZR3GNLA
-6AGLN3KJETruI3Js6++aG+7tSkJ8Vo4WCVUR7oQROwF601X0QF/XghCoJCrx8B/1
-cw6Yb2wQj2nv3gw1rqWVsPVpAKsMc1yHx/2Vsee/VPtt4f67fSAMuJF3EJ6JkcK7
-tM761v69GoJGgvsie45pb1N2l/GfVMuwWU0wZhEsF7eXxqPzoE/kIGX1XIqleLaw
-On2kPSM5RgqV6gLOcw4WaFPi0oMbDhltNs72SV9cV6ZhhuwEQRq+u/K76NKLwte2
-R1JutAiuPZVF0WanmmiN6RbIpWOB5XxQfWagfr4vcf/03TaLP4hJMnqUdFMk20HP
-eI8TMQxkfryZK2Z6VxEBVdXhK05VEdkolmc4j9U+76A96Gd5zbYPApirkebmZatS
-X3rKKAiBqwWrFXi/7LNDoCwhRRmqDuHXruh3vZEcz+xiPfJh0G31GJQgIpE15Sv6
-trf20u3CXAFjHg9zPpSFV7uAOsqv7bg+xtG9PgN4aLCiVbXHsT0z6PAz+6K+SiKw
-QW8ZOtLikj5HyLAz/TDcsIShFaM3QHk2qq9RY10kmxlQVrf9Oyh3Wmc=
-=om0O
+hF4DHXHP849rSK8SAQdAliiUK1XTMeUUmjJ6n4yEEBGVPmQuVTD4wdJZx4r2J3Mw
+uSVIq8qBJ7NrZfvDa63807usyKpk0Io3tdH83hn3wIKKmUMTroaRZMP1BdJ3aVdh
+0sDEAf18AhE5POknHzzolNbTXmQkPNspdNpu0ANdKkukvUZjfWvssZ1WN3jB08Fc
+Wr2Byez+UyLggj1bm+HuzbcZGPfyMOpoajFG0+yK4Ccqpf3XapNJn7v1ic2QhR/B
+pmWpJR0cXDigNLYQ/RoNEiSur2+0hzeVkDiYQtDYD02Cv4rnhyJdCalyriRaLOZr
+4Tau4xfK9PdOydahZZHEFllDU+yfEb9xtBZ+DEGh5AyR1/sG8ORnJc+5m/z54zmJ
+W3MmZ7M+4O1q5l5MbDwHq1TrQF5R9JSXyeGTW2XscsIPdvY5bExMwyMoW/XY4E8+
+GJ12UVpC/EWt2Nisfx2LhIoxtwaZm2r0Xkt6hY5DSMkpHLZtGPOOe1QxtXF1qXH2
+owTZynRxlmaWslOXdhtFRHyfGiFK4pNoV6fVB0e2khKKfXynN9Zx99GJ+DoJsOFT
+AYOadP1WlbIbSaimv/xSpaijE2XReKTLfN6aK1vSe90r96nCWr31fcd6x9ax0nVx
+jDReMRJrHA==
+=8mRD
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index f1a72f0dd9ebcda0ce5d92761e98d574bcee3842..c93ce0f7feea52841b39029d7bad6cdbefcde8c5 100644 (file)
@@ -17,19 +17,27 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBACwbgx3N72gYKIU63tNE6kf6UA5ed39VFXh3zdM6eDdA0bG
-DWt5yROckkCeCvMoFaRswK8MiX8aGG0GdH6VKhyn7HjT/Dm84QLwoB0ccZs3MnwU
-aJ9yTC9HbX3yfTVZYOu0w47NZho/LXX2Yd1pi8OUgrPg44fjgvx2kNRQ9EsNBdLA
-/AGMhwwcTPHjyWQ4XYZoL6WeVJfq2C0m3hQ3bxrKuAzW53HrSa4tPCXzX3G8KEz5
-sSk3ZOmajSvLde0LG8bxwexgAHC/Wd07e2HgHtZ/H+Cw9oYLgwcgVyXg7sGVrMrs
-IlwW0Njf93DJmJZuTD8P9XJc3h1VzKA+YhbtnofFZw4JexpHcC+R8Lcso16Mkp91
-7Ig0E8WTZ+K+judGS010b5ND2ETyc+TYY4/XJ2R90pbNrRLNTFG+P2HUob6PBCwE
-rXot6TeBSgm+k4bvl9aMKyrBSplKktQey4WsdblbJnJUxSl/rMpW6xwglkyIgrCU
-vbhffqgB8y1JLmK6Ow/A6Pzi3T6Zn95zu2GN8+yAOzDhGwlAfIV85TYnX6ybOkX/
-Amoh7qNS17pzc6ch/mif/RsSPYo+y2UQuVFhG+kOy9oGAQOOHeiCWZPa09o3R2Jn
-myMg1FPgoDgsjE6QpD0mx9ORdPGC2e8jwrifS/W9eHJ2QG+mNkcKlAr5b8WiUTkq
-hEZ+BaaVhbXN8EuHHTJT6YojusCIsXI0BMF1su1KupQw+dwQnys8wuy45Fr3H58x
-zqHoU9KzdQGLbeJTgA==
-=+EWE
+hF4DHXHP849rSK8SAQdAlqPAqdaaB751ZhN8drQheW77zbyPrbofTZgTa/32UFow
+ShGDg7SQxQD+LssHmGT0g4pUPo8JGor8BIvnvcZa4qRiZJI1i/VWUVoLc+TBT442
+0ukBxtUeKC0V35/zRgS1ZXrbkiBh8TGy0lee/eM9yvfT5FmFhotzoQkexDSEPxjb
+g8Qr/IcH0v2XOEmHux3hQpngY/LRYoCv1c8Niu2Zfan1p7zefOZjAxRraeihHi6I
+KyyA8WIdiIac97vO1CRyXXATJabjeijH/BaUDlPvQ39c9Mdie+HeaVYcaC3e9oW3
+sjn8fN+KjkjLXwPWhgMDpvP9f3ZD8oCHkN7Utq4OTwz8gb0IbUIkElF4G6O3AckV
+UXwrASodKBL58IWYz6VWhyjYxoV2R2hLNtnQWWvKgYzru2Mdb/ONZBM/JMXMjFUt
+oxDJs2pb2sun2q6n1sWKTrS9MXbxeFEcp2v3hMXrmP8nLeNiPJ+HlerFCSZasDOm
+c/3X97zIneJUosm3ltqLunSSE4vp+FAGIRaibMjyE2u2niDReINxX58E7o9cfJL0
+9Af6olZA1gQ/8t5qMei5qTN3wi4a1ieqTN4yD4v7r8yZE5PmlQfyY0joXVepm8Tx
+9/rDLM/gU/zogoo17enlU3ipvLZKsVDkLIlv2SdT1AF0ROnjLBGJ2iWzKst9Rg7/
+mXzEqv9CSVM2lXd3qUqra7reeaVD3vd00zmLq3yM/2sHeuLAc40R0MkIOSa89eRP
+iXu4k9+/m4WU4bNPugaH8Szm7OuLQNoB7mAB6t9GJGq7Y8DKxMn5FSUwLtKkGkUQ
+YdGCw2/salvqoQIDJVMteKpM4pWi9sFoVbxAU+djinJejSjSmY+iKHcMYeQwOpja
+33+W2RM40JOUZ7yc+LzgWy/ahyD27cdS1TPaghlQxPeSjcEfekrjgGW+2wIMmCxy
+xyMPWeN+Mf7e/fNh6YDbld9BKk6zY4fNVWlC+gR/aMVapomNgW1/FS7F7vk5qY0Q
+pAf1GS1YR4pKpo3sSEaLHw5rhpI0pT5ZvB09+GYRhsBQzP3LvnBCsxcVvi7yERY2
+QVlHejpTWwuRcTQCXP9UXa7z9UhEOieHwy6xNRTi4HVWHbXMxVunvlUnBCnQdFIr
+s4bcOjY94Q29FeRjaweYIZBUSabXDLJhLZNH1u6Z9Z8dBZ6Th1+ou77m0rEN6B3d
+mf83pKPrOR8ASw88rRGq8O9yVpFR4mD7HiE7YNofsPBtk0Cz178WLCi/D8b9A80h
+R/jVyxLmrCPHQUFfu46JgytBta+VBYwnYFHDynnYczuB0gydvuPJ4cJvfn3vPA==
+=DmA/
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 059783cef4b9b13a378c60fb76158280f592ecad..4d5073bb1f470a82ccd510f89195a08da002f871 100644 (file)
@@ -17,16 +17,17 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBADCWqobSSS78XdrxhBh5W01OZbUMdnrwrYJsiG9fQoVfFHN
-eALvOfviTcSBD97/jO2IRL2W8hyF7k1BVAYMwSuxe4qLbLdsxK1i4KBRIFRkm990
-ipBddgFXV16WNO2cTK7boEJ7Xfjp/zjoS2z2YUXsdGx3OSJciyHBVJki2UfkL9LA
-egHa7dsw6BxoNbAkrD+ijVbsFrKHeeJIlWkNbSYOk/YLmqLAEy1CYvSvC8ZSBtQT
-fVYc37fc3RB0vQC+Vu5k5d/I5Z1/Yz+McBJDMNvcn4yoFiXemY8YVFvj7iC0sbuq
-lwitvgMYaljhb8RUQAa3Dy08Jju09DIBcCgRsx32U+3aqZ0MhU6CRgt8kc9oK1g4
-yBVppqpX6hCXjtt9LUArY3DIchRb+IWTXsb+eDR700GXDyNMk1G5WUl0eLuw75uz
-EqU5Tjh36fP0ceMESjaxuxyhhw1jjE3ON7vqFQRVcs7UtazbxznWQH3Z73mDmY3G
-q9JGMOOqVnnFdnEq8vDFF7m+Cp3N1ieyXUXjn3aLtvSRMmVV20Q5QXSFg8nP6juT
-Yn1xZjqOodSeig1ITZZF58Whv+LHGtzDHwV8
-=cNYF
+hF4DHXHP849rSK8SAQdAc+vNxgvGe1T23qYt8zZ2dtmU4+DzCiMlKBFrI64sICMw
+foE2ym+RPLXzL2SbgDaUqgYbkiKmo6HrFSURtlDae0lFHrmLYZHToVWXF14DGsyu
+0sDgAcsIt7i8j6XWpAI9slRqjDAEPBp+4EFJKL+BdIuEYa6z1ULrv5BUimUi6D1o
+UE+k49xE6iFOpgSEghF1+ZneE3bj8rqJJwA+sAjth/Kp8vNccA42mCyn3Avxvk9q
+aMw7GWvTRJ5oc+RGo6BZukQtApQTbLzOeI92w68XNmQaSq4+LKUA4+CTZpasR/WA
+CR2/MWfwW3vmZilPbW2249Nj8CAawaDxTsIY9i5bHE0HjbfJhBBNffDPoNCh/+Pb
+6wIZ9/6xLHAzxFtY+qvDhVO/nWOLrdd9ACZudoD/x4qITc9IFo4F8bWF5iKPs67q
+wtw1qFTT8ODc2WWhOizDByOkk/D+Z3mrlsOC/x7ioho0IIeWldkfaET2ucc9FI9S
+SPX+huu6vnPAGO21T4EMqevwDLNGWMQBolHSlU3SRnNyU1bqUNDF+/9RiOk/NFj9
+FTwMj8FAI6/q0kZLQUF34h4BPF8/v1TmVZKniaVXqQIE78MvFWXV4FXYvP4w+IdK
+q634Ah+cC9NVEB+U6H4aSB9IojUurd+RvD+4x7rd+EtLFdc=
+=HmgM
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 880f60e33642e3b3d12472ca69622a1edbaa0175..cf786c024985bab0bb8554c18aaeb765d80cfbe7 100644 (file)
@@ -17,13 +17,13 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBA/9GY8NN4NDwpNttr/hTXpS701Z8TDr3hC89obZNnNpYxSct
-p+YkS+FsPMLimIDfU1meG8R+YgtQOJIhmKPHW8CLQ1heBsX0Dcv2oLxXodqNGD7M
-/szVRR6duVnALPgmV66vkcBHKbsiuv8EO86C7G1hAnXfs0H47WoeUz9dQ6RaHdKw
-AVbxw7KWVbiP+S4SO1rvNsAL1xiRPA0FFmDRMyoFRC/618dGS6HitkD0UR708oVt
-PooD4Rk22c8b549wvZ88flGk+WBCLhyXAuWYPHwag1DLzLjWH5r+XmK2O7JoQZeq
-k7JM/M8QM+xetFaPmsWs52IynhXyWpXBBanm9NEsNEiIB59480D7tJ0oivo8T24d
-izSAMGATP26ReatoXltCl9x8uUfUSAjWt8iJ1+n/3ds=
-=hGDA
+hF4DHXHP849rSK8SAQdAQd0btUvfUMmCgmDv3mG8d2tfmr3MYsOdE4TeSqk6sFsw
+8Wsp5J4s2t9ua6ScvqCVtlUVUL4Z6BsACArwy0/XwGQ8JQ6BUuYH7JSWb6O6tzed
+0r8BYDEY7/8+QCgXneo6k3wvPHrzTsvg9fxmCSTbvA+8JCrEzbvM5l/wQmSDf18x
+difPsrCT75x3eYgOy7NNYIAg97teybVWZ4raPQ/SdJ9J0TmPTjQF07HPndrsYGQC
+rEKvu6oq2/HL4NWOWMNNixs0u6ALRpPuUUXKgwSaZUG8+juOZ3yFe56bd1IvwkWK
+ZkKwa9gBn7WA+eNpcJauux/ta6LuXiNvNHUGUnd9puVepi9GO3XAxYcOzqF6ly1V
+iw==
+=c3OU
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 15dc08ab8a22ac43ff01b7ecef0d99611b502fb2..d0e11a105d4c0d4b84158b1df283480153cafa0d 100644 (file)
@@ -18,13 +18,10 @@ Subject: this should not show up as a protected header
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBA/9ZaOuxGtLVWiA7KQfB+4td1AILd1uy039UDb+9YwlhmJTq
-mNqVJu+ZkFniZPMliM0z1QRBkBeL2Q7MrHAdYxYBKrDHKVja4O7jwqeKjy5BzQCW
-fnyT+sb2Mh+dz5P2voF3XJHgqzhFY1rtVEatXSZADwwIVU6oZqGZ8GOELNGSd9KX
-ASNElH7WGZB/TQ5X+MktzOLExx5QWaRK9skogI2RRoOquS7KpMcjzb2FWaJDjr1s
-hd8FCQVjWuUDrolMGH8cgeq9iUBlHMzfPY6/jeGHNrjk12wwhBNcq6O95uzXtIRS
-BM2xnwCYec6wYJ46fHukTgv+286nSQcV0XT6a+qM5GMgV5DMHW2vSyl6kTszJ3EP
-xvQBfPCItA==
-=Gkxz
+BADBADBAD49rSK8SAQdAeybb8KrIaEFV5+Ks5loaz651PudVdzS8ombK8EW7Mnsw
+kEppTiE4jo6ZocHvhjSzPdEK4MPh0qmKvu1RrHa23dc1n7Cutg1FjOb6ZRloTisz
+0jEB3YxBhFDBZyWSGeAeZx93JaNcV6CBjOfZ6GJhzkqmSs73VdwFUWQxcoV4q5sL
+GYCW
+=BADC
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index dec822c2bb7d26cd9bd6d3927ce17521cabc908e..a10612f98dd9293115022d08afdd4c4311a148f7 100644 (file)
@@ -18,13 +18,12 @@ Subject: this should not show up as a protected header
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBA/9ZaOuxGtLVWiA7KQfB+4td1AILd1uy039UDb+9YwlhmJTq
-mNqVJu+ZkFniZPMliM0z1QRBkBeL2Q7MrHAdYxYBKrDHKVja4O7jwqeKjy5BzQCW
-fnyT+sb2Mh+dz5P2voF3XJHgqzhFY1rtVEatXSZADwwIVU6oZqGZ8GOELNGSd9KX
-ASNElH7WGZB/TQ5X+MktzOLExx5QWaRK9skogI2RRoOquS7KpMcjzb2FWaJDjr1s
-RGboX7NG3xCvNUV2ByFTvLOeo7eO1GfUsabTUbMMvh3AE1UvHgCu8VJiRrMdmPln
-BM2xnwCYec6wYJ46fHukTgv+286nSQcV0XT6a+qM5GMgV5DMHW2vSyl6kTszJ3EP
-xvQBfPCItA==
-=Gkxz
+hF4DHXHP849rSK8SAQdA3xy46BwN9R4tHbyAqwTMeOSfrrNzqsvCT9hqcVfRIzQw
+ThEINU6n9x5QgU2L/mtSaAMkw7ikOmzrJkvjEEE913dvUsw80+Q3QDYODETYzXBN
+0qIBrEpD0pYlXiQECDAYqox9JBkOPi3K6c4TLdACG2q7oOtHzbApzHC636oOFAXB
+uhARzvr/TN5/Fr4KDM2j4LqdsxSwE2mOJn4lM8EfPAm0jxbDmHKOpjpk/QnKR7ry
+BbctXwYIwlkp6voRsAJ/zG3XcLpbO/w+a5U14P6qCp2RM+bNWKtZTT4Gl0yCBk3A
+CYGvWb797ZA+5BhraXCWAQcscec=
+=WKBy
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 8c5dd251a59c2c35859aaeb3028ba0683e776d0b..9a3c7644ce098c4cefaabdf5c9a771cac6aa275b 100644 (file)
@@ -17,24 +17,26 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBBACkgwtKOAP+UlKYDzYkZY+gDuMNKnHjWIvv2Cdnovy40QzL
-5sbuib40y7orO+MqYMCWpoFtgBVsGiOUE3bZAg8n3Ji38/zVGwQveu6sh7SAy0Q9
-zFEvLhtajw17nPe+QH2UmIyfVikA57Mot13THq4i6C4ozVCyhyIltx+sNJkmw9Lp
-AdQd+cgCMRSMbi++eRwIi4zgxKrfAoGOmdMiVzBrh3yZqnbI0rCxJIKu7gEWuQLT
-7BuvN2bJUkPGLAUhUanFararVoD7WWOl67IlWFkyncES0PRskUf9coV68WZnYjsR
-Y3LdLnha1sdMwUNeBKQ44XBd2e7mXbDSp1cSjTDf9euwB4m7uQFTLwoQ8Of+LmQD
-KMHzjmucbkNAIpfAjcDusTA/oaaqUiEgGIgYYMDqG1CaaxdT55S7tMjW5yJryQmo
-pg65jrUMgEn5XHZ+KI2OsCmwGdoBYNau8p1a2hsiKhHJmLUeEAu34gFI3hylIOC0
-0KC40d0zTSb0s7SZuTrD6vYgiXG9aFktHvAWFH0ATCts7qyiRN7k5jt7yWfRntE2
-UCexTGE3TH7aju+IqDPC1XsaKF4T3CVhdr8WmKCa+0VOaw7xHRGYnzq9y91GcaCx
-8AcoZ3kYs+f2LIn+T667A0KKP4Z6OmLjCx3b1RvRUQYR9taruEMAQbIuAajiyTe9
-KfUrsUULZfInE50x+OneYvDhzoSgSJoHIK+18X/wo6YcyleJ9fZxCQ/vaXTDkAeF
-ve7TFcbIqmJ4MHygXILHUuDwp7P4t/tIL7SZwja70P3digjsgoNZY29VTnU8uyIb
-d6eOjgpeNVhRjDWxbUvhFD7i4rHCi/bbXFlW0cCXoiaVQBtYmiNysRoRZOv0h3TW
-q/+/UmqkaQFnF3zp5sr87y+ValItgPWmb9Ds0lyAoSvQx35zVh8DFfH04m7hmsb7
-gcvemlPTAnQWkIMC3c/bZWgt8tNcG7tQeUMWd9n4281y/hApbm90x2NLzEqvVcRq
-K0iIgVxbCHSKqGh4TtbIwpNhzSP+KHYkZ8h6+QUDRwGEV9QqZKg=
-=2O0V
+hF4DHXHP849rSK8SAQdAGiLZx0/sI1uoQ27OPpwunlzzlY7ba4E2YNU+AErRA1gw
+YYKlhgfzSgO0LpbxHJfithVAkrGYvj5HNWGxriXEsOyfy+Ax0FtAJuzYr6DGKGx1
+0ukBxLoRfWuoo2C9gXwojieSI9lTh7V+FaVUoVmTXhd/WFjWLtHbkIVmvXI1WVyi
+wM5NfDi3Ho995P+DMZxTKkdqtbdeYgUK7oCw3FHsYsNSTf3XFazjEvHg/TvOWd5u
+m9SbZAKfOBrEGGCzNHfgyluaBKdzVX04GPfZ2GblHlnU9AnGSWys1i8kxmuQYAKp
+UrXDlMcVB4V5bcGd1KMvGyhnKzICXWhXiJhEiNOc+uhl97jxXRujflfT6S1+8thv
+o86332XixGu8o5svVAEWobN8LUXpHZZlnK9a0Zftf4v8ATHEzQLAa5vdx+BYN8ua
+e4dmCtxA4XCfRD58FJ6EwjDqhv45KYnJP2W5eZujQ7Pl1m3HJXGwFQmtnOSB/9dw
+M+y1Aif07VBYE3LmUUqmS0HLZoqmOEoh6rKldzyxFmtfZyn73n/zcUoQblEWTE7z
+lxIqpCmo8jHPcs1tm9QD3sUmqQ/YXwmqZbD3pOn0PIXZKVY8/DaeggMWKQ/UhCWa
+7Z8g2GVq17AjHsS9n3ShDhf6B/8qI+jjaZQqH0W6KLmDQixjf1BoPnTrXNjcloJk
+uf0YAuol05fXNAiyPbFNO9zoFPxm8ZVEZG9nbcnNOz7ac/Aea6hqhxHnzNFPU09K
+J92FZ08XXDlrt0jw11Z/i606U/7kX6Zy4vCtZjGB4h04msBiLQwI0POIcY28SJ0U
+W1AqcReye6lQTz47AkOKAfVQl9hQP++G7nZXlxUQ+z0VRqBEqd/QJdHgoe6X4ctd
+r8093odiz6/DXJNwDTHPkaV5IseghzSLYyjmbLR5DUjnfuxKw5zpG+mK3X2PDx1B
+LtUNfBGmnLN3jBa8Q/i2WYxYpAuMZzJcCcocxW0H+yBf8+rZNpIvi/RsTklKkaap
+EOgP9sZXlgJePUbBmdd4Wwx7WTsjna6ckNp/9WE8CuDy6x9Zkc97Rkd+Oxc/KKtF
+1mQ/VdRZj3trlABnHmF0H/H4Qlrt//P/PCl3qRZpE5v34OHDlTT6UjLh5ahWZ3hf
+pj3cSKy9uajnWPFf9tnI0/9cWYbllaCMhIMbDZXRM3F4H03bi2k=
+=VKCz
 -----END PGP MESSAGE-----
 
 --=-=-=--
 -----END PGP MESSAGE-----
 
 --=-=-=--
index c3a21b851cd6b5aca8861e7b321ef171f86b58c2..f5efaff0086732177591fa10fec28dbb155ad5fc 100644 (file)
@@ -6,7 +6,7 @@ Message-ID: <signed-protected-header@crypto.notmuchmail.org>
 MIME-Version: 1.0
 Content-Type: multipart/signed; boundary="=-=-=";
  protocol="application/pgp-signature";
 MIME-Version: 1.0
 Content-Type: multipart/signed; boundary="=-=-=";
  protocol="application/pgp-signature";
- micalg=pgp-sha512
+ micalg=pgp-sha256
 
 --=-=-=
 Content-Type: text/plain; protected-headers="v1"
 
 --=-=-=
 Content-Type: text/plain; protected-headers="v1"
@@ -20,10 +20,9 @@ Content-Type: application/pgp-signature
 
 -----BEGIN PGP SIGNATURE-----
 
 
 -----BEGIN PGP SIGNATURE-----
 
-iLMEAQEKAB0WIQRa6rEfXjPc6HXdt1ttkmEtlORjgQUCWusAfwAKCRBtkmEtlORj
-geIJA/0WcyxlwDfXRMbiGE/crLBYhLpXK6ZMzjEn6HQDntMIk3Kr61rAwL8edKGx
-gbxr1+XlMYRt+PJDhi8iI0odDI1YjiBjjc0bXUoDn60UcjL2MPGshI3426CA7cqB
-cMaoRHajfdxYjSzzfh8duVgi0vmUnsyoePBhANRbDIVmCQS11g==
-=c4cq
+iHUEARYIAB0WIQSaOv5sYAZaFI/UtYp+ar6SRkXMYAUCYxiQlwAKCRB+ar6SRkXM
+YIm6AP0UlyfUbhd7bG4Azs0rby3qPUXOC1DtbSpQegSuR7nGgAEAub3WeYgEVVOS
+fsnuNE9Q/LnPTS5m85eMa1s1bS8fcAE=
+=O+fm
 -----END PGP SIGNATURE-----
 --=-=-=--
 -----END PGP SIGNATURE-----
 --=-=-=--
index ebf4b786dd615a6a098683fae72439f236836644..cd1e9fc34c628d466ef6f5537007ada51d607235 100644 (file)
@@ -6,7 +6,7 @@ Message-ID: <simple-signed-mail@crypto.notmuchmail.org>
 MIME-Version: 1.0
 Content-Type: multipart/signed; boundary="=-=-=";
  protocol="application/pgp-signature";
 MIME-Version: 1.0
 Content-Type: multipart/signed; boundary="=-=-=";
  protocol="application/pgp-signature";
- micalg=pgp-sha512
+ micalg=pgp-sha256
 
 --=-=-=
 Content-Type: text/plain
 
 --=-=-=
 Content-Type: text/plain
@@ -19,10 +19,9 @@ Content-Type: application/pgp-signature
 
 -----BEGIN PGP SIGNATURE-----
 
 
 -----BEGIN PGP SIGNATURE-----
 
-iLMEAQEKAB0WIQRa6rEfXjPc6HXdt1ttkmEtlORjgQUCWu718wAKCRBtkmEtlORj
-gUXaA/4/m6CPRgC9JODRKRWo3Szi5D3zg7uf29DIJu9m2vVRw5o0ZeHcxLb26UPe
-qdjPq6GBclkXdeTH9Nv2TW5cToJmMA9UvESeRRzbe6ytvswNEYdSbiYAsv/k9t6K
-KQO2ZSbsbVlkh8xVYC3ORiUS775YrPxVT6QlPkMKAXw3l3Zwcg==
-=jnDO
+iHUEARYIAB0WIQSaOv5sYAZaFI/UtYp+ar6SRkXMYAUCYxiQYgAKCRB+ar6SRkXM
+YJkmAP9TEGDYF4GZcHaxWDZYf6EKHmNqu1RPYuwEN8QdVbUIxAEA7IiFYPQtKXgr
+wyEYNcJ8aD1CYCGhR8pTA9oT/Vp16Qk=
+=a+TS
 -----END PGP SIGNATURE-----
 --=-=-=--
 -----END PGP SIGNATURE-----
 --=-=-=--
index 7163b9ae344ff40bddb6be74ad32dcee6834d64b..8c7fb3ebadb68bd8a00309a3e6b0fc742c7b6b61 100644 (file)
@@ -17,13 +17,12 @@ Subject: this should not show up as a protected header
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBA/9ZaOuxGtLVWiA7KQfB+4td1AILd1uy039UDb+9YwlhmJTq
-mNqVJu+ZkFniZPMliM0z1QRBkBeL2Q7MrHAdYxYBKrDHKVja4O7jwqeKjy5BzQCW
-fnyT+sb2Mh+dz5P2voF3XJHgqzhFY1rtVEatXSZADwwIVU6oZqGZ8GOELNGSd9KX
-ASNElH7WGZB/TQ5X+MktzOLExx5QWaRK9skogI2RRoOquS7KpMcjzb2FWaJDjr1s
-RGboX7NG3xCvNUV2ByFTvLOeo7eO1GfUsabTUbMMvh3AE1UvHgCu8VJiRrMdmPln
-BM2xnwCYec6wYJ46fHukTgv+286nSQcV0XT6a+qM5GMgV5DMHW2vSyl6kTszJ3EP
-xvQBfPCItA==
-=Gkxz
+hF4DHXHP849rSK8SAQdAxAZy4nBUDdm2u4sgr1inLki0LMCVcsVlax6Pd0AiZAow
+iYz940UtZwQNRRb640w1bB2pAvg5Nn8hJK5ye3qtyUWNW1VEvAa+GXndI/Qt0+7x
+0qIBOXRBCrkOxB10iCvSDVoOMZPj8GgvQwpsnslATJbsp9jV74fU7eFCKE5VWKUw
+FTos+VX1YFZyf2RsznHXdi0CrL2rkUNoLby4SEUa/urd6GKb3xuOjJlIYN4Fh9xz
+e33+Dl3NHohNooytxoJuTNiXbNWe7kidfOwMGzvdYsegk/WMqMLg8DmZPvl0BcYI
+o+4ZU3kuhbk5Pup5nOV6OLrs7A0=
+=BF8X
 -----END PGP MESSAGE-----
 --=-=-=--
 -----END PGP MESSAGE-----
 --=-=-=--
index 9a3c13848194391cc039e77c4b593803b6e86131..87f3f8da961eeb400be0d4987f7ecdbfb5921163 100644 (file)
@@ -20,14 +20,13 @@ Content-Type: application/octet-stream
 
 -----BEGIN PGP MESSAGE-----
 
 
 -----BEGIN PGP MESSAGE-----
 
-hIwDxE023q1UqxYBA/9ZaOuxGtLVWiA7KQfB+4td1AILd1uy039UDb+9YwlhmJTq
-mNqVJu+ZkFniZPMliM0z1QRBkBeL2Q7MrHAdYxYBKrDHKVja4O7jwqeKjy5BzQCW
-fnyT+sb2Mh+dz5P2voF3XJHgqzhFY1rtVEatXSZADwwIVU6oZqGZ8GOELNGSd9KX
-ASNElH7WGZB/TQ5X+MktzOLExx5QWaRK9skogI2RRoOquS7KpMcjzb2FWaJDjr1s
-RGboX7NG3xCvNUV2ByFTvLOeo7eO1GfUsabTUbMMvh3AE1UvHgCu8VJiRrMdmPln
-BM2xnwCYec6wYJ46fHukTgv+286nSQcV0XT6a+qM5GMgV5DMHW2vSyl6kTszJ3EP
-xvQBfPCItA==
-=Gkxz
+hF4DHXHP849rSK8SAQdAbnAG8Oxige+8PXg1B/Ex8Nc/IcBW7R4Cmnq3rArI3g0w
+rb1P2LngDMpqMxRGAkucBU/omYHuyDyLIoQZc84XYQy9N+M/u4HK187tyXaKx970
+0qIBnZhdiVm9RFn8CvQLG1hhw8E6UFm/YlURkMoaP66HIU9WLFAlmHrZPOnXJBr5
+2qOWnqSttuD/1Bjt1R2dguoltYqv1iBkwDlE2mWubSTkDp3Pf3QeJGz3Q727+bHV
+MI3k/5sNfJyyx9lIB3nyjwa/+Ap5orrPBwe+Y8tRdLO9xtvIFO+U9l9L6yPTYPyz
+4P+LVzDS+6tnWxPiLeEz/sRGmtA=
+=pPju
 -----END PGP MESSAGE-----
 --=-=-=--
 
 -----END PGP MESSAGE-----
 --=-=-=--
 
diff --git a/test/emacs-exclude.expected-output/notmuch-search-tag-inbox-with-excluded b/test/emacs-exclude.expected-output/notmuch-search-tag-inbox-with-excluded
new file mode 100644 (file)
index 0000000..ce1d711
--- /dev/null
@@ -0,0 +1,25 @@
+  2009-11-17 [5/5]   Mikhail Gusarov, Carl Worth, Keith Packard  [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17 [7/7]   Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth  [notmuch] Working with Maildir storage? (inbox signed unread)
+  2009-11-17 [2/2]   Alex Botero-Lowry, Carl Worth  [notmuch] preliminary FreeBSD support (attachment inbox unread)
+  2009-11-17 [1/1]   Mikhail Gusarov      [notmuch] [PATCH] Handle rename of message file (inbox unread)
+  2009-11-17 [2/2]   Keith Packard, Carl Worth    [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-17 [2/2]   Jan Janak, Carl Worth        [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-17 [3/3]   Jan Janak, Carl Worth        [notmuch] What a great idea! (inbox unread)
+  2009-11-17 [3/3]   Israel Herraiz, Keith Packard, Carl Worth   [notmuch] New to the list (inbox unread)
+  2009-11-17 [3/3]   Adrian Perez de Castro, Keith Packard, Carl Worth  [notmuch] Introducing myself (inbox signed unread)
+  2009-11-17 [3/3]   Aron Griffis, Keith Packard, Carl Worth     [notmuch] archive (inbox unread)
+  2009-11-17 [2/2]   Ingmar Vanhassel, Carl Worth  [notmuch] [PATCH] Typsos (inbox unread)
+  2009-11-18 [2/2]   Alex Botero-Lowry, Carl Worth  [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18 [2/2]   Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+  2009-11-18 [1/1]   Stewart Smith        [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (deleted inbox unread)
+  2009-11-18 [1/1]   Stewart Smith        [notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+  2009-11-18 [1/1]   Stewart Smith        [notmuch] [PATCH] count_files: sort directory in inode order before statting (deleted inbox unread)
+  2009-11-18 [4/4]   Jjgod Jiang, Alexander Botero-Lowry      [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+  2009-11-18 [1/1]   Jan Janak            [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+  2009-11-18 [1/1]   Rolland Santimano    [notmuch] Link to mailing list archives ? (inbox unread)
+  2009-11-18 [1/1]   Alexander Botero-Lowry  [notmuch] request for pull (inbox unread)
+  2009-11-18 [2/2]   Keith Packard, Alexander Botero-Lowry    [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18 [1/1]   Chris Wilson         [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+  2010-12-16 [1/1]   Olivier Berger       Essai accentué (inbox unread)
+  2010-12-29 [1/1]   François Boulogne    [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
diff --git a/test/emacs-exclude.expected-output/notmuch-search-tag-inbox-without-excluded b/test/emacs-exclude.expected-output/notmuch-search-tag-inbox-without-excluded
new file mode 100644 (file)
index 0000000..8a87432
--- /dev/null
@@ -0,0 +1,21 @@
+  2009-11-17 [5/5]   Mikhail Gusarov, Carl Worth, Keith Packard  [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17 [7/7]   Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth  [notmuch] Working with Maildir storage? (inbox signed unread)
+  2009-11-17 [2/2]   Alex Botero-Lowry, Carl Worth  [notmuch] preliminary FreeBSD support (attachment inbox unread)
+  2009-11-17 [1/1]   Mikhail Gusarov      [notmuch] [PATCH] Handle rename of message file (inbox unread)
+  2009-11-17 [2/2]   Keith Packard, Carl Worth    [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-17 [2/2]   Jan Janak, Carl Worth        [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-17 [3/3]   Jan Janak, Carl Worth        [notmuch] What a great idea! (inbox unread)
+  2009-11-17 [3/3]   Israel Herraiz, Keith Packard, Carl Worth   [notmuch] New to the list (inbox unread)
+  2009-11-17 [3/3]   Adrian Perez de Castro, Keith Packard, Carl Worth  [notmuch] Introducing myself (inbox signed unread)
+  2009-11-17 [3/3]   Aron Griffis, Keith Packard, Carl Worth     [notmuch] archive (inbox unread)
+  2009-11-17 [2/2]   Ingmar Vanhassel, Carl Worth  [notmuch] [PATCH] Typsos (inbox unread)
+  2009-11-18 [2/2]   Alex Botero-Lowry, Carl Worth  [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18 [2/2]   Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+  2009-11-18 [4/4]   Jjgod Jiang, Alexander Botero-Lowry      [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+  2009-11-18 [1/1]   Jan Janak            [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+  2009-11-18 [1/1]   Rolland Santimano    [notmuch] Link to mailing list archives ? (inbox unread)
+  2009-11-18 [1/1]   Alexander Botero-Lowry  [notmuch] request for pull (inbox unread)
+  2009-11-18 [2/2]   Keith Packard, Alexander Botero-Lowry    [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2010-12-16 [1/1]   Olivier Berger       Essai accentué (inbox unread)
+  2010-12-29 [1/1]   François Boulogne    [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
diff --git a/test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-with-excluded b/test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-with-excluded
new file mode 100644 (file)
index 0000000..5c6b2d7
--- /dev/null
@@ -0,0 +1,53 @@
+  2009-11-17  Mikhail Gusarov       ┬►[notmuch] [PATCH 1/2] Close message file after parsing message       headers (inbox unread)
+  2009-11-17  Mikhail Gusarov       ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++   file with gcc 4.4 (inbox unread)
+  2009-11-17  Carl Worth            ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Keith Packard          ╰┬► ...                                              (inbox unread)
+  2009-11-18  Carl Worth              ╰─► ...                                             (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman  ┬►[notmuch] Working with Maildir storage?             (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       ├┬► ...                                               (inbox signed unread)
+  2009-11-17  Lars Kellogg-Stedman  │╰┬► ...                                              (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       │ ├─► ...                                             (inbox unread)
+  2009-11-17  Keith Packard         │ ╰┬► ...                                             (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  │  ╰─► ...                                            (inbox signed unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Alex Botero-Lowry     ┬►[notmuch] preliminary FreeBSD support               (attachment inbox unread)
+  2009-11-17  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Mikhail Gusarov       ─►[notmuch] [PATCH] Handle rename of message file     (inbox unread)
+  2009-11-17  Keith Packard         ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove    inbox (and unread) tags (inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] What a great idea!                        (inbox unread)
+  2009-11-17  Jan Janak             ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Israel Herraiz        ┬►[notmuch] New to the list                           (inbox unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Adrian Perez de Cast  ┬►[notmuch] Introducing myself                        (inbox signed unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Aron Griffis          ┬►[notmuch] archive                                   (inbox unread)
+  2009-11-18  Keith Packard         ╰┬► ...                                               (inbox unread)
+  2009-11-18  Carl Worth             ╰─► ...                                              (inbox unread)
+  2009-11-17  Ingmar Vanhassel      ┬►[notmuch] [PATCH] Typsos                            (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-18  Alex Botero-Lowry     ┬►[notmuch] [PATCH] Error out if no query is supplied to search        instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  ┬►[notmuch] "notmuch help" outputs to stderr?         (attachment inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman  ╰─► ...                                               (attachment inbox signed unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++     libs. (deleted inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] count_files: sort directory in inode order before  statting (deleted inbox unread)
+  2009-11-18  Jjgod Jiang           ┬►[notmuch] Mac OS X/Darwin compatibility issues      (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰┬► ...                                               (inbox unread)
+  2009-11-18  Jjgod Jiang            ╰┬► ...                                              (inbox unread)
+  2009-11-18  Alexander Botero-Low    ╰─► ...                                             (inbox unread)
+  2009-11-18  Jan Janak             ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool       subdirectories into tags (inbox unread)
+  2009-11-18  Rolland Santimano     ─►[notmuch] Link to mailing list archives ?           (inbox unread)
+  2009-11-18  Alexander Botero-Low  ─►[notmuch] request for pull                          (inbox unread)
+  2009-11-18  Keith Packard         ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that    highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Chris Wilson          ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+  2010-12-16  Olivier Berger        ─►Essai accentué                                      (inbox unread)
+  2010-12-29  François Boulogne     ─►[aur-general] Guidelines: cp, mkdir vs install      (inbox unread)
+End of search results.
diff --git a/test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-without-excluded b/test/emacs-exclude.expected-output/notmuch-tree-tag-inbox-without-excluded
new file mode 100644 (file)
index 0000000..55806d1
--- /dev/null
@@ -0,0 +1,49 @@
+  2009-11-17  Mikhail Gusarov       ┬►[notmuch] [PATCH 1/2] Close message file after parsing message       headers (inbox unread)
+  2009-11-17  Mikhail Gusarov       ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++   file with gcc 4.4 (inbox unread)
+  2009-11-17  Carl Worth            ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Keith Packard          ╰┬► ...                                              (inbox unread)
+  2009-11-18  Carl Worth              ╰─► ...                                             (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman  ┬►[notmuch] Working with Maildir storage?             (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       ├┬► ...                                               (inbox signed unread)
+  2009-11-17  Lars Kellogg-Stedman  │╰┬► ...                                              (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       │ ├─► ...                                             (inbox unread)
+  2009-11-17  Keith Packard         │ ╰┬► ...                                             (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  │  ╰─► ...                                            (inbox signed unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Alex Botero-Lowry     ┬►[notmuch] preliminary FreeBSD support               (attachment inbox unread)
+  2009-11-17  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Mikhail Gusarov       ─►[notmuch] [PATCH] Handle rename of message file     (inbox unread)
+  2009-11-17  Keith Packard         ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove    inbox (and unread) tags (inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] What a great idea!                        (inbox unread)
+  2009-11-17  Jan Janak             ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Israel Herraiz        ┬►[notmuch] New to the list                           (inbox unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Adrian Perez de Cast  ┬►[notmuch] Introducing myself                        (inbox signed unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Aron Griffis          ┬►[notmuch] archive                                   (inbox unread)
+  2009-11-18  Keith Packard         ╰┬► ...                                               (inbox unread)
+  2009-11-18  Carl Worth             ╰─► ...                                              (inbox unread)
+  2009-11-17  Ingmar Vanhassel      ┬►[notmuch] [PATCH] Typsos                            (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-18  Alex Botero-Lowry     ┬►[notmuch] [PATCH] Error out if no query is supplied to search        instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  ┬►[notmuch] "notmuch help" outputs to stderr?         (attachment inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman  ╰─► ...                                               (attachment inbox signed unread)
+  2009-11-18  Jjgod Jiang           ┬►[notmuch] Mac OS X/Darwin compatibility issues      (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰┬► ...                                               (inbox unread)
+  2009-11-18  Jjgod Jiang            ╰┬► ...                                              (inbox unread)
+  2009-11-18  Alexander Botero-Low    ╰─► ...                                             (inbox unread)
+  2009-11-18  Jan Janak             ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool       subdirectories into tags (inbox unread)
+  2009-11-18  Rolland Santimano     ─►[notmuch] Link to mailing list archives ?           (inbox unread)
+  2009-11-18  Alexander Botero-Low  ─►[notmuch] request for pull                          (inbox unread)
+  2009-11-18  Keith Packard         ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that    highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2010-12-16  Olivier Berger        ─►Essai accentué                                      (inbox unread)
+  2010-12-29  François Boulogne     ─►[aur-general] Guidelines: cp, mkdir vs install      (inbox unread)
+End of search results.
diff --git a/test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-with-excluded b/test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-with-excluded
new file mode 100644 (file)
index 0000000..d55818e
--- /dev/null
@@ -0,0 +1,53 @@
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH 1/2] Close message file after parsing message      headers (inbox unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++     file with gcc 4.4 (inbox unread)
+  2009-11-17  Carl Worth           [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Alex Botero-Lowry    [notmuch] preliminary FreeBSD support                  (attachment inbox unread)
+  2009-11-17  Carl Worth           [notmuch] preliminary FreeBSD support                  (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH] Handle rename of message file        (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove   inbox (and unread) tags (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] What a great idea!                           (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] What a great idea!                           (inbox unread)
+  2009-11-17  Israel Herraiz       [notmuch] New to the list                              (inbox unread)
+  2009-11-17  Adrian Perez de Cast [notmuch] Introducing myself                           (inbox signed unread)
+  2009-11-17  Aron Griffis         [notmuch] archive                                      (inbox unread)
+  2009-11-17  Ingmar Vanhassel     [notmuch] [PATCH] Typsos                               (inbox unread)
+  2009-11-18  Alex Botero-Lowry    [notmuch] [PATCH] Error out if no query is supplied to search       instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr?            (attachment inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr?            (attachment inbox signed unread)
+  2009-11-18  Stewart Smith        [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++    libs. (deleted inbox unread)
+  2009-11-18  Stewart Smith        [notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+  2009-11-18  Keith Packard        [notmuch] New to the list                              (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] Introducing myself                           (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] archive                                      (inbox unread)
+  2009-11-18  Stewart Smith        [notmuch] [PATCH] count_files: sort directory in inode order before statting (deleted inbox unread)
+  2009-11-18  Jjgod Jiang          [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Jan Janak            [notmuch] [PATCH] notmuch new: Support for conversion of spool      subdirectories into tags (inbox unread)
+  2009-11-18  Rolland Santimano    [notmuch] Link to mailing list archives ?              (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Jjgod Jiang          [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] request for pull                             (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] [PATCH] Create a default notmuch-show-hook that   highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] archive                                      (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] What a great idea!                           (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] New to the list                              (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] Introducing myself                           (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Typsos                               (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+  2009-11-18  Chris Wilson         [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+  2010-12-16  Olivier Berger       Essai accentué                                         (inbox unread)
+  2010-12-29  François Boulogne    [aur-general] Guidelines: cp, mkdir vs install         (inbox unread)
+End of search results.
diff --git a/test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-without-excluded b/test/emacs-exclude.expected-output/notmuch-unthreaded-tag-inbox-without-excluded
new file mode 100644 (file)
index 0000000..80c67d0
--- /dev/null
@@ -0,0 +1,49 @@
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH 1/2] Close message file after parsing message      headers (inbox unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++     file with gcc 4.4 (inbox unread)
+  2009-11-17  Carl Worth           [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Alex Botero-Lowry    [notmuch] preliminary FreeBSD support                  (attachment inbox unread)
+  2009-11-17  Carl Worth           [notmuch] preliminary FreeBSD support                  (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-17  Mikhail Gusarov      [notmuch] [PATCH] Handle rename of message file        (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-17  Keith Packard        [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove   inbox (and unread) tags (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] What a great idea!                           (inbox unread)
+  2009-11-17  Jan Janak            [notmuch] What a great idea!                           (inbox unread)
+  2009-11-17  Israel Herraiz       [notmuch] New to the list                              (inbox unread)
+  2009-11-17  Adrian Perez de Cast [notmuch] Introducing myself                           (inbox signed unread)
+  2009-11-17  Aron Griffis         [notmuch] archive                                      (inbox unread)
+  2009-11-17  Ingmar Vanhassel     [notmuch] [PATCH] Typsos                               (inbox unread)
+  2009-11-18  Alex Botero-Lowry    [notmuch] [PATCH] Error out if no query is supplied to search       instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] Working with Maildir storage?                (inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr?            (attachment inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr?            (attachment inbox signed unread)
+  2009-11-18  Keith Packard        [notmuch] New to the list                              (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] Introducing myself                           (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] archive                                      (inbox unread)
+  2009-11-18  Jjgod Jiang          [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Jan Janak            [notmuch] [PATCH] notmuch new: Support for conversion of spool      subdirectories into tags (inbox unread)
+  2009-11-18  Rolland Santimano    [notmuch] Link to mailing list archives ?              (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Jjgod Jiang          [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues         (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] request for pull                             (inbox unread)
+  2009-11-18  Keith Packard        [notmuch] [PATCH] Create a default notmuch-show-hook that   highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] Working with Maildir storage?                (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] archive                                      (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] What a great idea!                           (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] New to the list                              (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] Introducing myself                           (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Typsos                               (inbox unread)
+  2009-11-18  Carl Worth           [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+  2010-12-16  Olivier Berger       Essai accentué                                         (inbox unread)
+  2010-12-29  François Boulogne    [aur-general] Guidelines: cp, mkdir vs install         (inbox unread)
+End of search results.
diff --git a/test/emacs-tree.expected-output/inbox-outline b/test/emacs-tree.expected-output/inbox-outline
new file mode 100644 (file)
index 0000000..9119a91
--- /dev/null
@@ -0,0 +1,25 @@
+  2010-12-29  François Boulogne     ─►[aur-general] Guidelines: cp, mkdir vs install      (inbox unread)
+  2010-12-16  Olivier Berger        ─►Essai accentué                                      (inbox unread)
+  2009-11-18  Chris Wilson          ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+  2009-11-18  Alex Botero-Lowry     ┬►[notmuch] [PATCH] Error out if no query is supplied to search        instead of going into an infinite loop (attachment inbox unread)
+  2009-11-17  Ingmar Vanhassel      ┬►[notmuch] [PATCH] Typsos                            (inbox unread)
+  2009-11-17  Adrian Perez de Cast  ┬►[notmuch] Introducing myself                        (inbox signed unread)
+  2009-11-17  Israel Herraiz        ┬►[notmuch] New to the list                           (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] What a great idea!                        (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-17  Aron Griffis          ┬►[notmuch] archive                                   (inbox unread)
+  2009-11-17  Keith Packard         ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove    inbox (and unread) tags (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman  ┬►[notmuch] Working with Maildir storage?             (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       ┬►[notmuch] [PATCH 1/2] Close message file after parsing message       headers (inbox unread)
+  2009-11-18  Keith Packard         ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that    highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low  ─►[notmuch] request for pull                          (inbox unread)
+  2009-11-18  Jjgod Jiang           ┬►[notmuch] Mac OS X/Darwin compatibility issues      (inbox unread)
+  2009-11-18  Rolland Santimano     ─►[notmuch] Link to mailing list archives ?           (inbox unread)
+  2009-11-18  Jan Janak             ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool       subdirectories into tags (inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] count_files: sort directory in inode order before  statting (inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++     libs. (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  ┬►[notmuch] "notmuch help" outputs to stderr?         (attachment inbox signed unread)
+  2009-11-17  Mikhail Gusarov       ─►[notmuch] [PATCH] Handle rename of message file     (inbox unread)
+  2009-11-17  Alex Botero-Lowry     ┬►[notmuch] preliminary FreeBSD support               (attachment inbox unread)
+End of search results.
diff --git a/test/emacs-tree.expected-output/notmuch-tree-tag-inbox-oldest-first b/test/emacs-tree.expected-output/notmuch-tree-tag-inbox-oldest-first
new file mode 100644 (file)
index 0000000..588fc58
--- /dev/null
@@ -0,0 +1,53 @@
+  2009-11-17  Mikhail Gusarov       ┬►[notmuch] [PATCH 1/2] Close message file after parsing message       headers (inbox unread)
+  2009-11-17  Mikhail Gusarov       ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++   file with gcc 4.4 (inbox unread)
+  2009-11-17  Carl Worth            ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+  2009-11-17  Keith Packard          ╰┬► ...                                              (inbox unread)
+  2009-11-18  Carl Worth              ╰─► ...                                             (inbox unread)
+  2009-11-17  Lars Kellogg-Stedman  ┬►[notmuch] Working with Maildir storage?             (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       ├┬► ...                                               (inbox signed unread)
+  2009-11-17  Lars Kellogg-Stedman  │╰┬► ...                                              (inbox signed unread)
+  2009-11-17  Mikhail Gusarov       │ ├─► ...                                             (inbox unread)
+  2009-11-17  Keith Packard         │ ╰┬► ...                                             (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  │  ╰─► ...                                            (inbox signed unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Alex Botero-Lowry     ┬►[notmuch] preliminary FreeBSD support               (attachment inbox unread)
+  2009-11-17  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Mikhail Gusarov       ─►[notmuch] [PATCH] Handle rename of message file     (inbox unread)
+  2009-11-17  Keith Packard         ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove    inbox (and unread) tags (inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Jan Janak             ┬►[notmuch] What a great idea!                        (inbox unread)
+  2009-11-17  Jan Janak             ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Israel Herraiz        ┬►[notmuch] New to the list                           (inbox unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Adrian Perez de Cast  ┬►[notmuch] Introducing myself                        (inbox signed unread)
+  2009-11-18  Keith Packard         ├─► ...                                               (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-17  Aron Griffis          ┬►[notmuch] archive                                   (inbox unread)
+  2009-11-18  Keith Packard         ╰┬► ...                                               (inbox unread)
+  2009-11-18  Carl Worth             ╰─► ...                                              (inbox unread)
+  2009-11-17  Ingmar Vanhassel      ┬►[notmuch] [PATCH] Typsos                            (inbox unread)
+  2009-11-18  Carl Worth            ╰─► ...                                               (inbox unread)
+  2009-11-18  Alex Botero-Lowry     ┬►[notmuch] [PATCH] Error out if no query is supplied to search        instead of going into an infinite loop (attachment inbox unread)
+  2009-11-18  Carl Worth            ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+  2009-11-18  Lars Kellogg-Stedman  ┬►[notmuch] "notmuch help" outputs to stderr?         (attachment inbox signed unread)
+  2009-11-18  Lars Kellogg-Stedman  ╰─► ...                                               (attachment inbox signed unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++     libs. (inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
+  2009-11-18  Stewart Smith         ─►[notmuch] [PATCH] count_files: sort directory in inode order before  statting (inbox unread)
+  2009-11-18  Jjgod Jiang           ┬►[notmuch] Mac OS X/Darwin compatibility issues      (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰┬► ...                                               (inbox unread)
+  2009-11-18  Jjgod Jiang            ╰┬► ...                                              (inbox unread)
+  2009-11-18  Alexander Botero-Low    ╰─► ...                                             (inbox unread)
+  2009-11-18  Jan Janak             ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool       subdirectories into tags (inbox unread)
+  2009-11-18  Rolland Santimano     ─►[notmuch] Link to mailing list archives ?           (inbox unread)
+  2009-11-18  Alexander Botero-Low  ─►[notmuch] request for pull                          (inbox unread)
+  2009-11-18  Keith Packard         ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that    highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Alexander Botero-Low  ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+  2009-11-18  Chris Wilson          ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+  2010-12-16  Olivier Berger        ─►Essai accentué                                      (inbox unread)
+  2010-12-29  François Boulogne     ─►[aur-general] Guidelines: cp, mkdir vs install      (inbox unread)
+End of search results.
index 0a048e1fe66940b914182c78400ad4dea8a8a94c..9bc99a2cf3588fcb2dbc3ac32933b9e425ebd7f6 100644 (file)
@@ -24,7 +24,7 @@ find_builddir () {
 if [[ -z "${NOTMUCH_BUILDDIR}" ]]; then
        export NOTMUCH_BUILDDIR="$(find_builddir "$(pwd)")"
 
 if [[ -z "${NOTMUCH_BUILDDIR}" ]]; then
        export NOTMUCH_BUILDDIR="$(find_builddir "$(pwd)")"
 
-       if [[ -z "${NOTMUCH_BUILDDIR}" ]]; then
+       if [ -z "${NOTMUCH_BUILDDIR}" -a "${NOTMUCH_TEST_INSTALLED-0}" = "0" ]; then
                echo "Run tests in a subdir of built notmuch tree." >&2
                exit 1
        fi
                echo "Run tests in a subdir of built notmuch tree." >&2
                exit 1
        fi
diff --git a/test/gnupg-secret-key.NOTE b/test/gnupg-secret-key.NOTE
deleted file mode 100644 (file)
index 604496c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-How the crypto test gnupg secret was generated:
-
-GNUPGHOME=gnupghome gpg --quick-random --gen-key
-kind: 1 (RSA/RSA)
-size: 1024
-expire: 0
-name: Notmuch Test Suite
-email: test_suite@notmuchmail.org
-(no passphrase)
diff --git a/test/gnupg-secret-key.asc b/test/gnupg-secret-key.asc
deleted file mode 100644 (file)
index 6431b56..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN PGP PRIVATE KEY BLOCK-----
-Version: GnuPG v1.4.10 (GNU/Linux)
-
-lQHYBE1Mm18BBADlMsMlUeO6usp/XuulgimqlCSphHcYZvH6+Sy7u7W4TpJzid7e
-jEOCrk3UZi2XMPW9+snDMhV9e28HeRz61zAO9G/gedn4N+mKOyTaELEmj9SP2IG2
-ZTvdUvn30vWIHyfRIww3qEiSzNULKn6zTDfcg6BIY6ZDQ6GFSfH5EioxuQARAQAB
-AAP8CM2/sS9JZWLHZHJrmsU6fygxlaarlxmyhxwLG9WZ+qUJ+xDQqWZkhssrMigP
-7ZQehwLwZ7mvbvfOy/qwTPJMZjQMMuTGEzclwBTOTttSxEDS+kgYmZ05CBjIgXbo
-8+k+L347l+kVRBFsi1cqOkCr+VZQwhOnbeNb8uJsUx27aAECAPD7jsBP73LRgoXQ
-x650D2fzjjuomGVsIxSAPjkDRYmtorsRftaEy7DkvX3Ihu5WN6YRRjJavoL+f8ar
-4escR40CAPN7NOFOGmiFZYzQcfJYQI2m7YDk4B51JxORFvLrvGT+LJnVwhtFsdGS
-QnMyO4eNpKH0qeEkT5Zqha2oyAc0Yd0B/3f962YCmYlbDAvWjcbMvhV7G4DbazVp
-2TNR0BhhEMiOlHuwmTO59s2iukuE5ifaVbwrj+NgpipTsaffKnhALlGjV7Q7Tm90
-bXVjaCBUZXN0IFN1aXRlIDx0ZXN0X3N1aXRlQG5vdG11Y2htYWlsLm9yZz4gKElO
-U0VDVVJFISmIuAQTAQIAIgUCTUybXwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgEC
-F4AACgkQbZJhLZTkY4GJFAP9E0mOw+RUGdmqbxSbd2rm0/inUSYOC0Pvt/D05pUY
-xzXDAMZwsy1DWhfS7bSgdD3YTM/22b/LJ2FmbLUF1cU6cNslmdPdfHDZ5+C4qpa1
-uW11y7djlBFAwxc3NBypT6Bmh/iIixrx413cw8CEU0lSZbSXUvbxZ7Rg4JYm2K6f
-Y7SdAdgETUybXwEEAM74QJJWzPavquSF0IkKDFjEvI44WC1HGNsJF3JVuKv9G00P
-RaHavNNcHEG8MorbfaWk7pipaEJ3+zbPKgp2vRCSJnLL6z813JIQqXJTZzu1ip63
-s4icfOfXkxFJ5AaFd/pVdi+wjmEwvv+YMtJT9DyXANo6b2eQu+0bMtP4Xuv/ABEB
-AAEAA/wJArUJw450070K6eoXeg22wT0iq/O0aCExSzoI5Kmywytj6KnnAmp9TftL
-WVgrkQntVjrhzPsYoB40JEMrGKd7QL/6LPTNWq3eFW38PSpCiG83T0rtmKCKqHB1
-Uo0B78AHfYYX7MUOEuCq2AhKTAdZukesoCpmVxcEFtjDEbOB8QIA3cvXrPJN/J2S
-W61mdMT7KlaXZZD8Phs/TY2ZLAiMKUAP1dVYNDvRSDjZLvQrqKQjEAN5jM81cWAV
-pvOIavLhOwIA7uMVIiaQ3vIy10C7ltiLT6YuJL/O6XDnXY/PDuXOatQahd/gmI0q
-dGQLSaHIxYILPZPaW6t0orx+dduQ0ES0DQIA21nEKX0MZpYOY1eIt6OlKemsjL2a
-UTdFhq/OgwVv+QRVHNdYQXmKpKDeW30lN/+BI3zyDTZjtehwKMMxNTu4AJu/iJ8E
-GAECAAkFAk1Mm18CGwwACgkQbZJhLZTkY4H8kgQA4vHsTt8dlJdWJAu2SKZGOPRs
-bIPu5XtRXe3RYbW5H7PqbAnrKIzlIKpkPNTwLL4wVXaF+R/aHa8ZKX3paohrPL74
-qpbffwtHXyVEwyWlw3m9mgti0de1dy1YvVasCe/UQ8Frc6uNmOwtlQE20k4R4cLI
-SWXT1JrwPoKh9xe++90=
-=rvTR
------END PGP PRIVATE KEY BLOCK-----
index 14747bdbfc44d040cc0118d3d84328a7c69e6e06..5d27e4d1d143c74daa4b3921a151876e8d441ce0 100755 (executable)
@@ -20,6 +20,14 @@ fi
 
 set -eu
 
 
 set -eu
 
+# Where to run the tests
+# XXX FIXME this code is duplicated with test-lib.sh
+if [[ -n "${NOTMUCH_BUILDDIR}" ]]; then
+    TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+else
+    TEST_DIRECTORY=$NOTMUCH_SRCDIR/test
+fi
+
 TESTS=
 for test in ${NOTMUCH_TESTS-}; do
     TESTS="$TESTS $NOTMUCH_SRCDIR/test/$test"
 TESTS=
 for test in ${NOTMUCH_TESTS-}; do
     TESTS="$TESTS $NOTMUCH_SRCDIR/test/$test"
@@ -80,7 +88,7 @@ for file in $TESTS
 do
     file=${file##*/} # drop leading path components
     file=${file%.sh} # drop trailing '.sh'
 do
     file=${file##*/} # drop leading path components
     file=${file%.sh} # drop trailing '.sh'
-    RESULT_FILES="$RESULT_FILES $NOTMUCH_BUILDDIR/test/test-results/$file"
+    RESULT_FILES="$RESULT_FILES $TEST_DIRECTORY/test-results/$file"
 done
 
 echo
 done
 
 echo
@@ -94,6 +102,6 @@ if [ -n "$META_FAILURE" ]; then
 fi
 
 # Clean up
 fi
 
 # Clean up
-rm -rf $NOTMUCH_BUILDDIR/test/test-results
+rm -rf $TEST_DIRECTORY/test-results
 
 exit $ev
 
 exit $ev
diff --git a/test/openpgp4-secret-key.asc b/test/openpgp4-secret-key.asc
new file mode 100644 (file)
index 0000000..182a824
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lFgEYxhtlxYJKwYBBAHaRw8BAQdA0PoNKr90DaQV1dIK77wbWm4RT+JQzqBkwIjA
+HQM9RHYAAQDQ5wSfkOGXvKYroALWgibztISzXS5b8boGXykcHERo6w/ctDtOb3Rt
+dWNoIFRlc3QgU3VpdGUgKElOU0VDVVJFISkgPHRlc3Rfc3VpdGVAbm90bXVjaG1h
+aWwub3JnPoiQBBMWCAA4AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEmjr+
+bGAGWhSP1LWKfmq+kkZFzGAFAmMYbZwACgkQfmq+kkZFzGDtrwEAjQRn3xhEomah
+wICjQjfi4RKNbvnRViZgosijDBANUAgA/28GrK1tPnQsXWqmuZxQ1Cd5ry4NAnj/
+4jsxD3cTbnEHnF0EYxhtlxIKKwYBBAGXVQEFAQEHQEOd3EyCD5qo4+QuHz0lruCG
+VM6n6RI4dtAh3cX9uHwiAwEIBwAA/1oe+p5jNjNE5lEj4yTpYjCxCeC98MolbiAy
+0yY7526wECqIeAQYFggAIBYhBJo6/mxgBloUj9S1in5qvpJGRcxgBQJjGG2XAhsM
+AAoJEH5qvpJGRcxgBdsA/R9ZECoxai5QhOitDIAUZVCRr59Pm1VMPiJOOIla2N1p
+AQCNESwJ9IJOdO/06q+bR2GG4WyEkB4VoVBiA3hFx/zZAA==
+=uGTo
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/openpgp4-secret-key.asc.NOTE b/test/openpgp4-secret-key.asc.NOTE
new file mode 100644 (file)
index 0000000..4693768
--- /dev/null
@@ -0,0 +1,5 @@
+The OpenPGPv4 secret key for the crypto tests was generated using:
+
+$ gpg --quick-generate-key \
+  'Notmuch Test Suite (INSECURE!) <test_suite@notmuchmail.org>' \
+  future-default default never
index d8397714874cbc4236422aa61bdda53f7e322205..d925acea352e41dd3133d4062cdf4ac025a075e8 100644 (file)
@@ -1,7 +1,6 @@
 # .notmuch-config - Configuration file for the notmuch mail system
 #
 # For more information about notmuch, see https://notmuchmail.org
 # .notmuch-config - Configuration file for the notmuch mail system
 #
 # For more information about notmuch, see https://notmuchmail.org
-
 # Database configuration
 #
 # The only value supported here is 'path' which should be the top-level
 # Database configuration
 #
 # The only value supported here is 'path' which should be the top-level
@@ -12,7 +11,6 @@
 #
 [database]
 path=/path/to/maildir
 #
 [database]
 path=/path/to/maildir
-
 # User configuration
 #
 # Here is where you can let notmuch know how you would like to be
 # User configuration
 #
 # Here is where you can let notmuch know how you would like to be
@@ -32,7 +30,6 @@ path=/path/to/maildir
 name=Test Suite
 primary_email=test.suite@example.com
 other_email=another.suite@example.com
 name=Test Suite
 primary_email=test.suite@example.com
 other_email=another.suite@example.com
-
 # Configuration for "notmuch new"
 #
 # The following options are supported here:
 # Configuration for "notmuch new"
 #
 # The following options are supported here:
@@ -49,7 +46,6 @@ other_email=another.suite@example.com
 #
 [new]
 tags=foo;bar;
 #
 [new]
 tags=foo;bar;
-
 # Search configuration
 #
 # The following option is supported here:
 # Search configuration
 #
 # The following option is supported here:
@@ -61,7 +57,6 @@ tags=foo;bar;
 #
 [search]
 exclude_tags=baz
 #
 [search]
 exclude_tags=baz
-
 # Maildir compatibility configuration
 #
 # The following option is supported here:
 # Maildir compatibility configuration
 #
 # The following option is supported here:
index 18fa29c0dd86d3b7eb8ab5c3b69bd7f9a35cf89a..f5d72e12c5c4873700c7814bf550cd0510c1a15c 100644 (file)
@@ -24,7 +24,7 @@
 #
 type die >/dev/null 2>&1 || die () { echo "$@" >&2; exit 1; }
 
 #
 type die >/dev/null 2>&1 || die () { echo "$@" >&2; exit 1; }
 
-if [[ -z "$NOTMUCH_SRCDIR" ]] || [[ -z "$NOTMUCH_BUILDDIR" ]]; then
+if [[ -z "$NOTMUCH_SRCDIR" ]] || [ -z "${NOTMUCH_TEST_INSTALLED-}" -a -z "$NOTMUCH_BUILDDIR" ]; then
        echo "internal: srcdir or builddir not set" >&2
        exit 1
 fi
        echo "internal: srcdir or builddir not set" >&2
        exit 1
 fi
@@ -61,7 +61,9 @@ LD_LIBRARY_PATH=${TEST_DIRECTORY%/*}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
 export LD_LIBRARY_PATH
 
 # configure output
 export LD_LIBRARY_PATH
 
 # configure output
-. "$NOTMUCH_BUILDDIR/sh.config" || exit 1
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+   . "$NOTMUCH_BUILDDIR/sh.config" || exit 1
+fi
 
 # load OS specifics
 if [[ -e "$NOTMUCH_SRCDIR/test/test-lib-$PLATFORM.sh" ]]; then
 
 # load OS specifics
 if [[ -e "$NOTMUCH_SRCDIR/test/test-lib-$PLATFORM.sh" ]]; then
@@ -315,7 +317,12 @@ export PATH MANPATH
 
 # Test repository
 test="tmp.$(basename "$0" .sh)"
 
 # Test repository
 test="tmp.$(basename "$0" .sh)"
-TMP_DIRECTORY="$TEST_DIRECTORY/$test"
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+    TMP_DIRECTORY="$TEST_DIRECTORY/$test"
+else
+    TMP_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}/notmuch-$test.XXXXXX")
+fi
+
 test ! -z "$debug" || remove_tmp=$TMP_DIRECTORY
 rm -rf "$TMP_DIRECTORY" || {
        GIT_EXIT_OK=t
 test ! -z "$debug" || remove_tmp=$TMP_DIRECTORY
 rm -rf "$TMP_DIRECTORY" || {
        GIT_EXIT_OK=t
@@ -323,6 +330,10 @@ rm -rf "$TMP_DIRECTORY" || {
        exit 1
 }
 
        exit 1
 }
 
+# Provide a guess at a usable Python, to support running tests without
+# running configure first.
+NOTMUCH_PYTHON=${NOTMUCH_PYTHON-python3}
+
 # A temporary home directory is needed by at least:
 # - emacs/"Sending a message via (fake) SMTP"
 # - emacs/"Reply within emacs"
 # A temporary home directory is needed by at least:
 # - emacs/"Sending a message via (fake) SMTP"
 # - emacs/"Reply within emacs"
index ad4c4aeb621afd02d5d3b4cf71b34cbe2f5b6d4e..0ab58fc2c4f12c5b311b47f359edf7b90987aa8a 100644 (file)
@@ -30,6 +30,7 @@ test_require_emacs () {
 # to the message and encrypting/signing.
 emacs_deliver_message () {
     local subject body smtp_dummy_pid smtp_dummy_port
 # to the message and encrypting/signing.
 emacs_deliver_message () {
     local subject body smtp_dummy_pid smtp_dummy_port
+    test_subtest_broken_for_installed
     subject="$1"
     body="$2"
     shift 2
     subject="$1"
     body="$2"
     shift 2
@@ -144,6 +145,13 @@ emacs_generate_script () {
        # Construct a little test script here for the benefit of the user,
        # (who can easily run "run_emacs" to get the same emacs environment
        # for investigating any failures).
        # Construct a little test script here for the benefit of the user,
        # (who can easily run "run_emacs" to get the same emacs environment
        # for investigating any failures).
+    if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+       find_notmuch_el='--directory "$NOTMUCH_BUILDDIR/emacs"'
+    else
+       ### XXX FIXME: this should really use the installed emacs lisp files
+       find_notmuch_el='--directory "$NOTMUCH_SRCDIR/emacs"'
+    fi
+
        cat <<EOF >"$TMP_DIRECTORY/run_emacs"
 #!/bin/sh
 export PATH=$PATH
        cat <<EOF >"$TMP_DIRECTORY/run_emacs"
 #!/bin/sh
 export PATH=$PATH
@@ -158,8 +166,8 @@ export NOTMUCH_CONFIG=$NOTMUCH_CONFIG
 #
 # --load               Force loading of notmuch.el and test-lib.el
 
 #
 # --load               Force loading of notmuch.el and test-lib.el
 
-exec ${TEST_EMACS} --quick \
-       --directory "$NOTMUCH_BUILDDIR/emacs" --load notmuch.el \
+exec ${TEST_EMACS} ${find_notmuch_el} --quick \
+       ${EXTRA_DIR} --load notmuch.el \
        --directory "$NOTMUCH_SRCDIR/test" --load test-lib.el \
        "\$@"
 EOF
        --directory "$NOTMUCH_SRCDIR/test" --load test-lib.el \
        "\$@"
 EOF
index 79a9d4d6fc5b574cbd21e6e9bd27039689a2d01a..4cfb8ef163aac196558c81adae112091661036ff 100644 (file)
 
 ;;; Code:
 
 
 ;;; Code:
 
+;; minimize impact of native compilation on the test suite.
+;; These are the Emacs 29.1 version of the variables.
+;; Leave trampolines enabled per Emacs upstream recommendations.
+;; It is important to set these variables before loading any
+;; .elc files.
+(setq native-comp-jit-compilation nil)
+(setq native-comp-speed -1)
+(setq native-comp-async-jobs-number 1)
+
 (require 'cl-lib)
 
 ;; Ensure that the dynamic variables that are defined by this library
 (require 'cl-lib)
 
 ;; Ensure that the dynamic variables that are defined by this library
@@ -205,3 +214,8 @@ running, quit if it terminated."
 ;; environments
 
 (setq mm-text-html-renderer 'html2text)
 ;; environments
 
 (setq mm-text-html-renderer 'html2text)
+
+;; Set our own default for message-hidden-headers, to avoid tests
+;; breaking when the Emacs default changes.
+(setq message-hidden-headers
+      '("^References:" "^Face:" "^X-Face:" "^X-Draft-From:"))
index d664812f610f91c3d38b1b96aa905ae756896c73..059e110c87d540bb5bdd8baca0ef6e2140a1bfc4 100644 (file)
@@ -29,8 +29,8 @@ shopt -u xpg_echo
 # Ensure NOTMUCH_SRCDIR and NOTMUCH_BUILDDIR are set.
 . $(dirname "$0")/export-dirs.sh || exit 1
 
 # Ensure NOTMUCH_SRCDIR and NOTMUCH_BUILDDIR are set.
 . $(dirname "$0")/export-dirs.sh || exit 1
 
-# It appears that people try to run tests without building...
-if [[ ! -x "$NOTMUCH_BUILDDIR/notmuch" ]]; then
+# We need either a built tree, or a promise of an installed notmuch
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" -a ! -x "$NOTMUCH_BUILDDIR/notmuch" ]; then
        echo >&2 'You do not seem to have built notmuch yet.'
        exit 1
 fi
        echo >&2 'You do not seem to have built notmuch yet.'
        exit 1
 fi
@@ -71,7 +71,7 @@ add_gnupg_home () {
     _gnupg_exit () { gpgconf --kill all 2>/dev/null || true; }
     at_exit_function _gnupg_exit
     mkdir -p -m 0700 "$GNUPGHOME"
     _gnupg_exit () { gpgconf --kill all 2>/dev/null || true; }
     at_exit_function _gnupg_exit
     mkdir -p -m 0700 "$GNUPGHOME"
-    gpg --no-tty --import <$NOTMUCH_SRCDIR/test/gnupg-secret-key.asc >"$GNUPGHOME"/import.log 2>&1
+    gpg --no-tty --import <$NOTMUCH_SRCDIR/test/openpgp4-secret-key.asc >"$GNUPGHOME"/import.log 2>&1
     test_debug "cat $GNUPGHOME/import.log"
     if (gpg --quick-random --version >/dev/null 2>&1) ; then
        echo quick-random >> "$GNUPGHOME"/gpg.conf
     test_debug "cat $GNUPGHOME/import.log"
     if (gpg --quick-random --version >/dev/null 2>&1) ; then
        echo quick-random >> "$GNUPGHOME"/gpg.conf
@@ -81,8 +81,8 @@ add_gnupg_home () {
     echo no-emit-version >> "$GNUPGHOME"/gpg.conf
 
     # Change this if we ship a new test key
     echo no-emit-version >> "$GNUPGHOME"/gpg.conf
 
     # Change this if we ship a new test key
-    FINGERPRINT="5AEAB11F5E33DCE875DDB75B6D92612D94E46381"
-    SELF_USERID="Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"
+    FINGERPRINT="9A3AFE6C60065A148FD4B58A7E6ABE924645CC60"
+    SELF_USERID="Notmuch Test Suite (INSECURE!) <test_suite@notmuchmail.org>"
     SELF_EMAIL="test_suite@notmuchmail.org"
     printf '%s:6:\n' "$FINGERPRINT" | gpg --quiet --batch --no-tty --import-ownertrust
 }
     SELF_EMAIL="test_suite@notmuchmail.org"
     printf '%s:6:\n' "$FINGERPRINT" | gpg --quiet --batch --no-tty --import-ownertrust
 }
@@ -388,6 +388,14 @@ test_expect_equal_message_body () {
     test "$#" = 2 ||
        error "bug in the test script: not 2 parameters to test_expect_equal_file"
 
     test "$#" = 2 ||
        error "bug in the test script: not 2 parameters to test_expect_equal_file"
 
+    for file in "$1" "$2"; do
+       if [ ! -s "$file" ]; then
+           test_failure_ "Missing or zero length file: $file"
+           inside_subtest=
+           return 1
+       fi
+    done
+
     expected=$(sed '1,/^$/d' "$1")
     output=$(sed '1,/^$/d' "$2")
     test_expect_equal "$expected" "$output"
     expected=$(sed '1,/^$/d' "$1")
     output=$(sed '1,/^$/d' "$2")
     test_expect_equal "$expected" "$output"
@@ -740,6 +748,18 @@ test_subtest_known_broken () {
        test_subtest_known_broken_=t
 }
 
        test_subtest_known_broken_=t
 }
 
+test_subtest_broken_for_installed () {
+    if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+       test_subtest_known_broken_=t
+    fi
+}
+
+test_subtest_broken_for_root () {
+   if [ "$EUID" = "0" ]; then
+       test_subtest_known_broken_=t
+    fi
+}
+
 test_expect_success () {
        exec 1>&6 2>&7          # Restore stdout and stderr
        if [ -z "$inside_subtest" ]; then
 test_expect_success () {
        exec 1>&6 2>&7          # Restore stdout and stderr
        if [ -z "$inside_subtest" ]; then
@@ -915,11 +935,16 @@ make_shim () {
 }
 
 notmuch_with_shim () {
 }
 
 notmuch_with_shim () {
-    local base_name shim_file
-    base_name="$1"
+    local base_name shim_file notmuch_cmd
+    if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+       notmuch_cmd="notmuch"
+    else
+       notmuch_cmd="notmuch-shared"
+    fi
+    base_name=$1
     shift
     shim_file="${base_name}.so"
     shift
     shim_file="${base_name}.so"
-    LD_PRELOAD=${LD_PRELOAD:+:$LD_PRELOAD}:./${shim_file} notmuch-shared "$@"
+    LD_PRELOAD=${LD_PRELOAD:+:$LD_PRELOAD}:./${shim_file} $notmuch_cmd "$@"
 }
 
 # Creates a script that counts how much time it is executed and calls
 }
 
 # Creates a script that counts how much time it is executed and calls
@@ -971,7 +996,11 @@ test_init_ () {
 
 
 # Where to run the tests
 
 
 # Where to run the tests
-TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+if [[ -n "${NOTMUCH_BUILDDIR}" ]]; then
+    TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+else
+    TEST_DIRECTORY=$NOTMUCH_SRCDIR/test
+fi
 
 . "$NOTMUCH_SRCDIR/test/test-lib-common.sh" || exit 1
 
 
 . "$NOTMUCH_SRCDIR/test/test-lib-common.sh" || exit 1
 
diff --git a/util/xapian-extra.h b/util/xapian-extra.h
new file mode 100644 (file)
index 0000000..39c7f48
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _XAPIAN_EXTRA_H
+#define _XAPIAN_EXTRA_H
+
+#include <string>
+#include <xapian.h>
+
+inline Xapian::Query
+xapian_query_match_all (void)
+{
+    // Xapian::Query::MatchAll isn't thread safe (a static object with reference
+    // counting) so instead reconstruct the equivalent on demand.
+    return Xapian::Query (std::string ());
+}
+
+#endif
index 2037dfa6c43dd66de1007cff562b14ebed056c1a..f2687f32e8878bb36f76e6cb14a4b09169e25f8b 100644 (file)
@@ -1 +1 @@
-0.36
+0.38.3
index c137bacdc0f4f1e3af78cb9617d5fe92f527c53f..777c20c0e6f0b8a695fe2d997ddb7284660e5de2 100644 (file)
@@ -53,10 +53,10 @@ Enjoy ;)
 As an example to configure a key mapping to add the tag 'to-do' and archive,
 this is what I use:
 
 As an example to configure a key mapping to add the tag 'to-do' and archive,
 this is what I use:
 
-let g:notmuch_rb_custom_search_maps = {
+let g:notmuch_custom_search_maps = {
        \ 't':          'search_tag("+to-do -inbox")',
        \ }
 
        \ 't':          'search_tag("+to-do -inbox")',
        \ }
 
-let g:notmuch_rb_custom_show_maps = {
+let g:notmuch_custom_show_maps = {
        \ 't':          'show_tag("+to-do -inbox")',
        \ }
        \ 't':          'show_tag("+to-do -inbox")',
        \ }
index 43741022e13580cafd7f1190a601608b14afcafe..c98f2b53d80df5c50fa13142a73ebc53b50e5075 100644 (file)
@@ -89,7 +89,7 @@ s     Send
 CONFIGURATION                                  *notmuch-config*
 
 You can add the following configurations to your `.vimrc`, or
 CONFIGURATION                                  *notmuch-config*
 
 You can add the following configurations to your `.vimrc`, or
-`~/.vim/plugin/notmuch.vim`.
+`~/.vim/after/plugin/notmuch.vim`.
 
                                                *g:notmuch_folders*
 
 
                                                *g:notmuch_folders*
 
@@ -138,13 +138,13 @@ You can do the same for the thread view:
 
 If you want to count the threads instead of the messages in the folder view:
 >
 
 If you want to count the threads instead of the messages in the folder view:
 >
-       let g:notmuch_folders_count_threads = 0
+       let g:notmuch_folders_count_threads = 1
 <
 
                                                *g:notmuch_reader*
                                                *g:notmuch_sendmail*
 
 <
 
                                                *g:notmuch_reader*
                                                *g:notmuch_sendmail*
 
-You can also configure your externail mail reader and sendemail program:
+You can also configure your external mail reader and sendmail program:
 >
        let g:notmuch_reader = 'mutt -f %s'
        let g:notmuch_sendmail = 'sendmail'
 >
        let g:notmuch_reader = 'mutt -f %s'
        let g:notmuch_sendmail = 'sendmail'