.first-build-message
Makefile.config
+version.stamp
TAGS
tags
*cscope*
Dependencies
------------
-Notmuch depends on three libraries: Xapian, GMime 2.4 or 2.6, and
-Talloc which are each described below:
+Notmuch depends on four libraries: Xapian, GMime 2.4 or 2.6,
+Talloc, and zlib which are each described below:
Xapian
------
Talloc is available from http://talloc.samba.org/
+ zlib
+ ----
+
+ zlib is an extremely popular compression library. It is used
+ by Xapian, so if you installed that you will already have
+ zlib. You may need to install the zlib headers separately.
+
+ Notmuch needs the transparent write feature of zlib introduced
+ in version 1.2.5.2 (Dec. 2011).
+
+ zlib is available from http://zlib.net
+
+Building Documentation
+----------------------
+
+By default the documentation for notmuch is built using sphinx.
+
+Sphinx is available from www.sphinx-doc.org.
+
+If you prefer, you can build the man pages using rst2man, from the
+python docutils package. See doc/INSTALL for details.
+
+
+Installing Dependencies from Packages
+-------------------------------------
+
On a modern, package-based operating system you can install all of the
dependencies with a simple simple command line. For example:
For Debian and similar:
- sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
+ sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev zlib1g-dev python-sphinx
For Fedora and similar:
- sudo yum install xapian-core-devel gmime-devel libtalloc-devel
+ sudo yum install xapian-core-devel gmime-devel libtalloc-devel zlib-devel python-sphinx
On other systems, a similar command can be used, but the details of
the package names may be different.
# given explicitly on the command line) so mention it first.
all:
-# List all subdirectories here. Each contains its own Makefile.local.
-# Use of '=', without '+=', seems to be required for out-of-tree
-# builds to work.
-subdirs = compat completion emacs lib man parse-time-string performance-test util test
-
-# We make all targets depend on the Makefiles themselves.
-global_deps = Makefile Makefile.config Makefile.local \
- $(subdirs:%=%/Makefile) $(subdirs:%=%/Makefile.local)
-
# Sub-directory Makefile.local fragments can append to these variables
# to have directory-specific cflags as necessary.
srcdir ?= .
include Makefile.config
+
+# We make all targets depend on the Makefiles themselves.
+global_deps = Makefile Makefile.config Makefile.local \
+ $(subdirs:%=%/Makefile) $(subdirs:%=%/Makefile.local)
+
Makefile.config: $(srcdir)/configure
ifeq ($(configure_options),)
@echo ""
ifeq ($(filter release release-message pre-release update-versions,$(MAKECMDGOALS)),)
ifeq ($(IS_GIT),yes)
VERSION:=$(shell git describe --match '[0-9.]*'|sed -e s/_/~/ -e s/-/+/ -e s/-/~/)
+# Write the file 'version.stamp' in case its contents differ from $(VERSION)
+FILE_VERSION:=$(shell test -f version.stamp && read vs < version.stamp || vs=; echo $$vs)
+ifneq ($(FILE_VERSION),$(VERSION))
+ $(shell echo "$(VERSION)" > version.stamp)
+endif
endif
endif
# Smash together user's values with our extra values
FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(CPPFLAGS) $(CFLAGS) $(WARN_CFLAGS) $(extra_cflags) $(CONFIGURE_CFLAGS)
FINAL_CXXFLAGS = $(CPPFLAGS) $(CXXFLAGS) $(WARN_CXXFLAGS) $(extra_cflags) $(extra_cxxflags) $(CONFIGURE_CXXFLAGS)
-FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch $(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS)
+FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch
+ifeq ($(LIBDIR_IN_LDCONFIG),0)
+FINAL_NOTMUCH_LDFLAGS += $(RPATH_LDFLAGS)
+endif
+FINAL_NOTMUCH_LDFLAGS += $(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS) $(ZLIB_LDFLAGS)
FINAL_NOTMUCH_LINKER = CC
ifneq ($(LINKER_RESOLVES_LIBRARY_DEPENDENCIES),1)
FINAL_NOTMUCH_LDFLAGS += $(CONFIGURE_LDFLAGS)
FINAL_NOTMUCH_LINKER = CXX
endif
-ifeq ($(LIBDIR_IN_LDCONFIG),0)
-FINAL_NOTMUCH_LDFLAGS += $(RPATH_LDFLAGS)
-endif
FINAL_LIBNOTMUCH_LDFLAGS = $(LDFLAGS) $(AS_NEEDED_LDFLAGS) $(CONFIGURE_LDFLAGS)
.PHONY: all
-all: notmuch notmuch-shared
+all: notmuch notmuch-shared build-man
ifeq ($(MAKECMDGOALS),)
ifeq ($(shell cat .first-build-message 2>/dev/null),)
@NOTMUCH_FIRST_BUILD=1 $(MAKE) --no-print-directory all
endif
endif
+# Depend (also) on the file 'version'. In case of ifeq ($(IS_GIT),yes)
+# this file may already have been updated.
+version.stamp: $(srcdir)/version
+ echo $(VERSION) > $@
+
$(TAR_FILE):
- if git tag -v $(VERSION) >/dev/null 2>&1; then \
- ref=$(VERSION); \
+ if git tag -v $(UPSTREAM_TAG) >/dev/null 2>&1; then \
+ ref=$(UPSTREAM_TAG); \
else \
ref="HEAD" ; \
echo "Warning: No signed tag for $(VERSION)"; \
.PHONY: update-versions
-update-versions: update-man-versions
+update-versions:
sed -i "s/^__VERSION__[[:blank:]]*=.*$$/__VERSION__ = \'${VERSION}\'/" $(PV_FILE)
# We invoke make recursively only to force ordering of our phony
quiet ?= $($(shell echo $1 | sed -e s'/ .*//'))
%.o: %.cc $(global_deps)
- @mkdir -p .deps/$(@D)
+ @mkdir -p $(patsubst %/.,%,.deps/$(@D))
$(call quiet,CXX $(CPPFLAGS) $(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@ -MD -MP -MF .deps/$*.d
%.o: %.c $(global_deps)
- @mkdir -p .deps/$(@D)
+ @mkdir -p $(patsubst %/.,%,.deps/$(@D))
$(call quiet,CC $(CPPFLAGS) $(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@ -MD -MP -MF .deps/$*.d
.PHONY : clean
notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
+notmuch.o: version.stamp
+
notmuch: $(notmuch_client_modules) lib/libnotmuch.a util/libutil.a parse-time-string/libparse-time-string.a
$(call quiet,CXX $(CFLAGS)) $^ $(FINAL_LIBNOTMUCH_LDFLAGS) -o $@
desktop-file-install --mode 0644 --dir "$(DESTDIR)$(desktop_dir)" notmuch.desktop
SRCS := $(SRCS) $(notmuch_client_srcs)
-CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) notmuch.elc
+CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) version.stamp
DISTCLEAN := $(DISTCLEAN) .first-build-message Makefile.config
DEPS := $(SRCS:%.c=.deps/%.d)
DEPS := $(DEPS:%.cc=.deps/%.d)
-include $(DEPS)
+
+.SUFFIXES: # Delete the default suffixes. Old-Fashioned Suffix Rules not used.
+Notmuch 0.18.1 (2014-06-25)
+===========================
+
+This is a bug fix and portability release.
+
+Build System
+------------
+
+Add a workaround for systems without zlib.pc
+
+Make emacs install robust against the non-existence of emacs
+
+Put notmuch lib directory first in RPATH
+
+Fix handling of html_static_path in sphinx
+
+ Both the python bindings and the main docs had spurious settings of
+ this variable.
+
+Test Suite
+----------
+
+Use --quick when starting emacs
+
+ This avoids a hang in the T160-json tests.
+
+Allow pending break points in atomicity script
+
+ This allows the atomicity tests to run on several more architectures/OSes.
+
+Command-Line Interface
+----------------------
+
+To improve portability use fsync instead of fdatasync in
+`notmuch-dump`. There should be no functional difference.
+
+Library changes
+---------------
+
+Resurrect support for single-message mbox files
+
+ The removal introduced a bug with previously indexed single-message
+ mboxes. This support remains deprecated.
+
+Fix for phrase indexing
+
+ There were several bugs where words intermingled from different
+ headers and MIME parts could match a single phrase query. This fix
+ will affect only newly indexed messages.
+
+Emacs Interface
+---------------
+
+Make sure tagging on an empty query is harmless
+
+ Previously tagging an empty query could lead to tags being
+ unintentionally removed.
+
+Notmuch 0.18 (2014-05-06)
+=========================
+
+Overview
+--------
+
+This new release includes some enhancements to searching for messages
+by filesystem location (`folder:` and `path:` prefixes under *General*
+below). Saved searches in *Emacs* have also been enhanced to allow
+distinct search orders for each one. Another enhancement to the
+*Emacs* interface is that replies to encrypted messages are now
+encrypted, reducing the risk of unintentional information disclosure.
+The default dump output format has changed to the more robust
+`batch-tag` format. The previously deprecated parsing of single
+message mboxes has been removed. For detailed release notes, see
+below.
+
+General
+-------
+
+The `folder:` search prefix now requires an exact match
+
+ The `folder:` prefix has been changed to search for email messages
+ by the exact, case sensitive maildir or MH folder name. Wildcard
+ matching (`folder:foo*`) is no longer supported. The new behaviour
+ allows for more accurate mail folder based searches, makes it
+ possible to search for messages in the top-level folder, and should
+ lead to less surprising results than the old behaviour. Users are
+ advised to see the `notmuch-search-terms` manual page for details,
+ and review how the change affects their existing `folder:` searches.
+
+There is a new `path:` search prefix.
+
+ The new `path:` search prefix complements the `folder:` prefix. The
+ `path:` prefix searches for email messages that are in particular
+ directories within the mail store, optionally recursively using a
+ special syntax. See the `notmuch-search-terms` manual page for
+ details.
+
+Notmuch database upgrade due to `folder:` and `path:` changes
+
+ The above mentioned changes to the `folder:` prefix and the addition
+ of `path:` prefix require a Notmuch database upgrade. This will be
+ done automatically, without prompting on the next time `notmuch new`
+ is run after the upgrade. The upgrade is not reversible, and the
+ upgraded database will not be readable by older versions of
+ Notmuch. As a safeguard, a database dump will be created in the
+ `.notmuch` directory before upgrading.
+
+Library changes
+---------------
+
+Notmuch database upgrade
+
+ The libnotmuch consumers are reminded to handle database upgrades
+ properly, either by relying on running `notmuch new`, or checking
+ `notmuch_database_needs_upgrade()` and calling
+ `notmuch_database_upgrade()` as necessary. This has always been the
+ case, but in practise there have been no database upgrades in any
+ released version of Notmuch before now.
+
+Support for indexing mbox files has been dropped
+
+ There has never been proper support for mbox files containing
+ multiple messages, and the support for single-message mbox files has
+ been deprecated since Notmuch 0.15. The support has now been
+ dropped, and all mbox files will be rejected during indexing.
+
+Message header parsing changes
+
+ Notmuch previously had an internal parser for message headers. The
+ parser has now been dropped in favour of letting GMime parse both
+ the headers and the message MIME structure at the same pass. This is
+ mostly an internal change, but the GMime parser is stricter in its
+ interpretation of the headers. This may result in messages with
+ slightly malformed message headers being now rejected.
+
+Command-Line Interface
+----------------------
+
+`notmuch dump` now defaults to `batch-tag` format
+
+ The old format is still available with `--format=sup`.
+
+`notmuch new` has a --quiet option
+
+ This option suppresses the progress and summary reports.
+
+`notmuch insert` respects maildir.synchronize_flags config option
+
+ Do not synchronize tags to maildir flags in `notmuch insert` if the
+ user does not want it.
+
+The commands set consistent exit status codes on failures
+
+ The cli commands now consistently set exit status of 1 on failures,
+ except where explicitly otherwise noted. The notable expections are
+ the status codes for format version mismatches for commands that
+ support formatted output.
+
+Bug fix for checking configured new.tags for invalid tags
+
+ `notmuch new` and `notmuch insert` now check the user configured
+ new.tags for invalid tags, and refuse to apply them, similar to
+ `notmuch tag`. Invalid tags are currently the empty string and tags
+ starting with `-`.
+
+Emacs Interface
+---------------
+
+Init file
+
+ If the file pointed by new variable `notmuch-init-file` (typically
+ `~/.emacs.d/notmuch-config.el`) exists, it is loaded at the end of
+ `notmuch.el`. Users can put their personal notmuch emacs lisp based
+ configuration/customization items there instead of filling
+ `~/.emacs` with these.
+
+Changed format for saved searches
+
+ The format for `notmuch-saved-searches` has changed, but old style
+ saved searches are still supported. The new style means that a saved
+ search can store the desired sort order for the search, and it can
+ store a separate query to use for generating the count notmuch
+ shows.
+
+ The variable is fully customizable and any configuration done
+ through customize should *just work*, with the additional options
+ mentioned above. For manual customization see the documentation for
+ `notmuch-saved-searches`.
+
+ IMPORTANT: a new style notmuch-saved-searches variable will break
+ previous versions of notmuch-emacs (even search will not work); to
+ fix remove the customization for notmuch-saved-searches.
+
+ If you have a custom saved search sort function (not unsorted or
+ alphabetical) then the sort function will need to be
+ modified. Replacing (car saved-search) by (notmuch-saved-search-get
+ saved-search :name) and (cdr saved-search) by
+ (notmuch-saved-search-get saved-search :query) should be sufficient.
+
+The keys of `notmuch-tag-formats` are now regexps
+
+ Previously, the keys were literal strings. Customized settings of
+ `notmuch-tag-formats` will continue to work as before unless tags
+ contain regexp special characters like `.` or `*`.
+
+Changed tags are now shown in the buffer
+
+ Previously tag changes made in a buffer were shown immediately. In
+ some cases (particularly automatic tag changes like marking read)
+ this made it hard to see what had happened (e.g., whether the
+ message had been unread).
+
+ The changes are now shown explicitly in the buffer: by default
+ deleted tags are displayed with red strike-through and added tags
+ are displayed underlined in green (inverse video is used for deleted
+ tags if the terminal does not support strike-through).
+
+ The variables `notmuch-tag-deleted-formats` and
+ `notmuch-tag-added-formats`, which have the same syntax as
+ `notmuch-tag-formats`, allow this to be customized.
+
+ Setting `notmuch-tag-deleted-formats` to `'((".*" nil))` and
+ `notmuch-tag-added-formats` to `'((".*" tag))` will give the old
+ behavior of hiding deleted tags and showing added tags identically
+ to tags already present.
+
+Version variable
+
+ The new, build-time generated variable `notmuch-emacs-version` is used
+ to distinguish between notmuch cli and notmuch emacs versions.
+ The function `notmuch-hello-versions` (bound to 'v' in notmuch-hello
+ window) prints both notmuch cli and notmuch emacs versions in case
+ these differ from each other.
+ This is especially useful when using notmuch remotely.
+
+Ido-completing-read initialization in Emacs 23
+
+ `ido-completing-read` in Emacs 23 versions 1 through 3 freezes unless
+ it is initialized. Defadvice-based *Ido* initialization is defined
+ for these Emacs versions.
+
+Bug fix for saved searches with newlines in them
+
+ Split lines confuse `notmuch count --batch`, so we remove embedded
+ newlines before calling notmuch count.
+
+Bug fixes for sender identities
+
+ Previously, Emacs would rewrite some sender identities in unexpected
+ and undesirable ways. Now it will use identities exactly as
+ configured in `notmuch-identities`.
+
+Replies to encrypted messages will be encrypted by default
+
+ In the interest of maintaining confidentiality of communications,
+ the Notmuch Emacs interface now automatically adds the mml tag to
+ encrypt replies to encrypted messages. This should make it less
+ likely to accidentally reply to encrypted messages in plain text.
+
+Reply pushes mark before signature
+
+ We push mark and set point on reply so that the user can easily cut
+ the quoted text. The mark is now pushed before the signature, if
+ any, instead of end of buffer so the signature is preserved.
+
+Message piping uses the originating buffer's working directory
+
+ `notmuch-show-pipe-message` now uses the originating buffer's
+ current default directory instead of that of the `*notmuch-pipe*`
+ buffer's.
+
+nmbug
+-----
+
+nmbug adds a `clone` command for setting up the initial repository and
+uses `@{upstream}` instead of `FETCH_HEAD` to track upstream changes.
+
+ The `@{upstream}` change reduces ambiguity when fetching multiple
+ branches, but requires existing users update their `NMBGIT`
+ repository (usually `~/.nmbug`) to distinguish between local and
+ remote-tracking branches. The easiest way to do this is:
+
+ 1. If you have any purely local commits (i.e. they aren't in the
+ nmbug repository on nmbug.tethera.net), push them to a remote
+ repository. We'll restore them from the backup in step 4.
+ 2. Remove your `NMBGIT` repository (e.g. `mv .nmbug .nmbug.bak`).
+ 3. Use the new `clone` command to create a fresh clone:
+
+ nmbug clone http://nmbug.tethera.net/git/nmbug-tags.git
+
+ 4. If you had local commits in step 1, add a remote for that
+ repository and fetch them into the new repository.
+
Notmuch 0.17 (2013-12-30)
=========================
Notmuch installs a full-featured email interface for use within
emacs. To use this, first add the following line to your .emacs file:
- (require 'notmuch)
+ (autoload 'notmuch "notmuch" "Notmuch mail" t)
Then, either run "emacs -f notmuch" or execute the command "M-x
notmuch" from within a running emacs.
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['../html']
+html_static_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# this file should be kept in sync with ../../../version
-__VERSION__ = '0.17'
+__VERSION__ = '0.18.1'
}
/*
- * call-seq: MESSAGE.filanames => FILENAMES
+ * call-seq: MESSAGE.filenames => FILENAMES
*
* Get all filenames for the email corresponding to MESSAGE.
*/
const notmuch_opt_desc_t *try;
for (try = options; try->opt_type != NOTMUCH_OPT_END; try++) {
- if (try->name && strncmp (arg, try->name, strlen (try->name)) == 0) {
- char next = arg[strlen (try->name)];
- const char *value= arg+strlen(try->name)+1;
-
- /* If we have not reached the end of the argument
- (i.e. the next character is not a space or delimiter)
- then the argument could still match a longer option
- name later in the option table.
- */
- if (next != '=' && next != ':' && next != '\0')
- continue;
-
- if (try->output_var == NULL)
- INTERNAL_ERROR ("output pointer NULL for option %s", try->name);
-
- switch (try->opt_type) {
- case NOTMUCH_OPT_KEYWORD:
- return _process_keyword_arg (try, next, value);
- break;
- case NOTMUCH_OPT_BOOLEAN:
- return _process_boolean_arg (try, next, value);
- break;
- case NOTMUCH_OPT_INT:
- return _process_int_arg (try, next, value);
- break;
- case NOTMUCH_OPT_STRING:
- return _process_string_arg (try, next, value);
- break;
- case NOTMUCH_OPT_POSITION:
- case NOTMUCH_OPT_END:
- default:
- INTERNAL_ERROR ("unknown or unhandled option type %d", try->opt_type);
- /*UNREACHED*/
- }
+ if (! try->name)
+ continue;
+
+ if (strncmp (arg, try->name, strlen (try->name)) != 0)
+ continue;
+
+ char next = arg[strlen (try->name)];
+ const char *value = arg + strlen(try->name) + 1;
+
+ /*
+ * If we have not reached the end of the argument (i.e. the
+ * next character is not a space or delimiter) then the
+ * argument could still match a longer option name later in
+ * the option table.
+ */
+ if (next != '=' && next != ':' && next != '\0')
+ continue;
+
+ if (try->output_var == NULL)
+ INTERNAL_ERROR ("output pointer NULL for option %s", try->name);
+
+ switch (try->opt_type) {
+ case NOTMUCH_OPT_KEYWORD:
+ return _process_keyword_arg (try, next, value);
+ case NOTMUCH_OPT_BOOLEAN:
+ return _process_boolean_arg (try, next, value);
+ case NOTMUCH_OPT_INT:
+ return _process_int_arg (try, next, value);
+ case NOTMUCH_OPT_STRING:
+ return _process_string_arg (try, next, value);
+ case NOTMUCH_OPT_POSITION:
+ case NOTMUCH_OPT_END:
+ default:
+ INTERNAL_ERROR ("unknown or unhandled option type %d", try->opt_type);
+ /*UNREACHED*/
}
}
fprintf (stderr, "Unrecognized option: --%s\n", arg);
notmuch_compat_srcs :=
+ifneq ($(HAVE_CANONICALIZE_FILE_NAME),1)
+notmuch_compat_srcs += $(dir)/canonicalize_file_name.c
+endif
+
ifneq ($(HAVE_GETLINE),1)
notmuch_compat_srcs += $(dir)/getline.c $(dir)/getdelim.c
endif
--- /dev/null
+#include "compat.h"
+#include <limits.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+
+char *
+canonicalize_file_name (const char * path)
+{
+#ifdef PATH_MAX
+ char *resolved_path = malloc (PATH_MAX+1);
+ if (resolved_path == NULL)
+ return NULL;
+
+ return realpath (path, resolved_path);
+#else
+#error undefined PATH_MAX _and_ missing canonicalize_file_name not supported
+#endif
+}
#define _POSIX_PTHREAD_SEMANTICS 1
#endif
+#if !HAVE_CANONICALIZE_FILE_NAME
+/* we only call this function from C, and this makes testing easier */
+#ifndef __cplusplus
+char *
+canonicalize_file_name (const char *path);
+#endif
+#endif
+
#if !HAVE_GETLINE
#include <stdio.h>
#include <unistd.h>
--- /dev/null
+#include <stdio.h>
+#include <zlib.h>
+
+static const char *template =
+ "prefix=/usr\n"
+ "exec_prefix=${prefix}\n"
+ "libdir=${exec_prefix}/lib\n"
+ "\n"
+ "Name: zlib\n"
+ "Description: zlib compression library\n"
+ "Version: %s\n"
+ "Libs: -lz\n";
+
+int main(void)
+{
+ printf(template, ZLIB_VERSION);
+ return 0;
+}
--- /dev/null
+#define _GNU_SOURCE
+#include <stdlib.h>
+
+int main()
+{
+ char *found;
+ char *string;
+
+ found = canonicalize_file_name (string);
+}
--- /dev/null
+#include <dirent.h>
+
+int main()
+{
+ struct dirent ent;
+
+ (void) ent.d_type;
+
+ return 0;
+}
from:*)
COMPREPLY=( $(compgen -P "from:" -W "`_notmuch_user_emails`" -- ${cur##from:}) )
;;
+ path:*)
+ local path=`notmuch config get database.path`
+ compopt -o nospace
+ COMPREPLY=( $(compgen -d "$path/${cur##path:}" | sed "s|^$path/||" ) )
+ ;;
+ folder:*)
+ local path=`notmuch config get database.path`
+ compopt -o nospace
+ COMPREPLY=( $(compgen -d "$path/${cur##folder:}" | \
+ sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
+ ;;
*)
- local search_terms="from: to: subject: attachment: tag: id: thread: folder: date:"
+ local search_terms="from: to: subject: attachment: tag: id: thread: folder: path: date:"
compopt -o nospace
COMPREPLY=( $(compgen -W "${search_terms}" -- ${cur}) )
;;
$split &&
case "${prev}" in
--backup)
- _filedir
+ _filedir -d
return
;;
esac
;;
# these will also complete on config get, but we don't care
database.path)
- _filedir
+ _filedir -d
;;
maildir.synchronize_flags)
COMPREPLY=( $(compgen -W "true false" -- ${cur}) )
case "${cur}" in
-*)
- local options="--no-hooks"
+ local options="--no-hooks --quiet"
COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
;;
esac
srcdir=$(dirname "$0")
+subdirs="util compat lib parse-time-string completion doc emacs"
+subdirs="${subdirs} performance-test test test/test-databases"
+
# For a non-srcdir configure invocation (such as ../configure), create
# the directory structure and copy Makefiles.
if [ "$srcdir" != "." ]; then
- for dir in . $(grep "^subdirs *=" "$srcdir"/Makefile | sed -e "s/subdirs *= *//"); do
+ for dir in . ${subdirs}; do
mkdir -p "$dir"
cp "$srcdir"/"$dir"/Makefile.local "$dir"
cp "$srcdir"/"$dir"/Makefile "$dir"
errors=$((errors + 1))
fi
+if ! pkg-config --exists zlib; then
+ ${CC} ${zlib_cflags} -o compat/gen_zlib_pc \
+ "$srcdir"/compat/gen_zlib_pc.c ${zlib_ldflags} > /dev/null 2>&1 &&
+ compat/gen_zlib_pc > compat/zlib.pc &&
+ PKG_CONFIG_PATH="$PKG_CONFIG_PATH":compat &&
+ export PKG_CONFIG_PATH
+ rm -f compat/gen_zlib_pc
+fi
+
+printf "Checking for zlib (>= 1.2.5.2)... "
+have_zlib=0
+if pkg-config --atleast-version=1.2.5.2 zlib; then
+ printf "Yes.\n"
+ have_zlib=1
+ zlib_cflags=$(pkg-config --cflags zlib)
+ zlib_ldflags=$(pkg-config --libs zlib)
+else
+ printf "No.\n"
+ errors=$((errors + 1))
+fi
+
printf "Checking for talloc development files... "
if pkg-config --exists talloc; then
printf "Yes.\n"
have_valgrind=0
fi
+printf "Checking for bash-completion (>= 1.90)... "
+if pkg-config --atleast-version=1.90 bash-completion; then
+ printf "Yes.\n"
+else
+ printf "No (will not install bash completion).\n"
+ WITH_BASH=0
+fi
+
if [ -z "${EMACSLISPDIR}" ]; then
if pkg-config --exists emacs; then
EMACSLISPDIR=$(pkg-config emacs --variable sitepkglispdir)
have_emacs=0
fi
+printf "Checking if sphinx is available and supports nroff output... "
+if hash sphinx-build > /dev/null 2>&1 && python -m sphinx.writers.manpage > /dev/null 2>&1 ; then
+ printf "Yes.\n"
+ have_sphinx=1
+ have_rst2man=0
+else
+ printf "No (falling back to rst2man).\n"
+ have_sphinx=0
+
+ printf "Checking if rst2man is available... "
+ if rst2man -V > /dev/null 2>&1; then
+ printf "Yes.\n"
+ have_rst2man=1
+ else
+ printf "No (so will not install man pages).\n"
+ have_rst2man=0
+ fi
+fi
+
libdir_in_ldconfig=0
printf "Checking which platform we are on... "
echo " Xapian library (including development files such as headers)"
echo " http://xapian.org/"
fi
+ if [ $have_zlib -eq 0 ]; then
+ echo " zlib library (>= version 1.2.5.2, including development files such as headers)"
+ echo " http://zlib.net/"
+ echo
+ fi
if [ $have_gmime -eq 0 ]; then
echo " Either GMime 2.4 library" $GMIME_24_VERSION_CTR "or GMime 2.6 library" $GMIME_26_VERSION_CTR
echo " (including development files such as headers)"
On Debian and similar systems:
- sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
+ sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev zlib1g-dev
Or on Fedora and similar systems:
- sudo yum install xapian-core-devel gmime-devel libtalloc-devel
+ sudo yum install xapian-core-devel gmime-devel libtalloc-devel zlib-devel
On other systems, similar commands can be used, but the details of the
package names may be different.
exit 1
fi
+printf "Checking for canonicalize_file_name... "
+if ${CC} -o compat/have_canonicalize_file_name "$srcdir"/compat/have_canonicalize_file_name.c > /dev/null 2>&1
+then
+ printf "Yes.\n"
+ have_canonicalize_file_name=1
+else
+ printf "No (will use our own instead).\n"
+ have_canonicalize_file_name=0
+fi
+rm -f compat/have_canonicalize_file_name
+
+
printf "Checking for getline... "
if ${CC} -o compat/have_getline "$srcdir"/compat/have_getline.c > /dev/null 2>&1
then
fi
rm -f compat/have_timegm
+printf "Checking for dirent.d_type... "
+if ${CC} -o compat/have_d_type "$srcdir"/compat/have_d_type.c > /dev/null 2>&1
+then
+ printf "Yes.\n"
+ have_d_type="1"
+else
+ printf "No (will use stat instead).\n"
+ have_d_type="0"
+fi
+rm -f compat/have_d_type
+
printf "Checking for standard version of getpwuid_r... "
if ${CC} -o compat/check_getpwuid "$srcdir"/compat/check_getpwuid.c > /dev/null 2>&1
then
# directory (the current directory at the time configure was run).
srcdir = ${srcdir}
+# subdirectories to build
+subdirs = ${subdirs}
+
configure_options = $@
# We use vpath directives (rather than the VPATH variable) since the
# files, (which is quite ugly).
vpath %.c \$(srcdir)
vpath %.cc \$(srcdir)
-vpath %.1 \$(srcdir)
vpath Makefile.% \$(srcdir)
+vpath %.py \$(srcdir)
+vpath %.rst \$(srcdir)
# The C compiler to use
CC = ${CC}
# Whether there's an emacs binary available for byte-compiling
HAVE_EMACS = ${have_emacs}
+# Whether there's a sphinx-build binary available for building documentation
+HAVE_SPHINX=${have_sphinx}
+
+# Whether there's a rst2man binary available for building documentation
+HAVE_RST2MAN=${have_rst2man}
+
# The directory to which desktop files should be installed
desktop_dir = \$(prefix)/share/applications
# The directory to which zsh completions files should be installed
zsh_completion_dir = ${ZSHCOMLETIONDIR:=\$(prefix)/share/zsh/functions/Completion/Unix}
+# Whether the canonicalize_file_name function is available (if not, then notmuch will
+# build its own version)
+HAVE_CANONICALIZE_FILE_NAME = ${have_canonicalize_file_name}
+
# Whether the getline function is available (if not, then notmuch will
# build its own version)
HAVE_GETLINE = ${have_getline}
# build its own version)
HAVE_STRSEP = ${have_strsep}
+# Whether struct dirent has d_type (if not, then notmuch will use stat)
+HAVE_D_TYPE = ${have_d_type}
+
# Whether the Xapian version in use supports compaction
HAVE_XAPIAN_COMPACT = ${have_xapian_compact}
GMIME_CFLAGS = ${gmime_cflags}
GMIME_LDFLAGS = ${gmime_ldflags}
+# Flags needed to compile and link against zlib
+ZLIB_CFLAGS = ${zlib_cflags}
+ZLIB_LDFLAGS = ${zlib_ldflags}
+
# Flags needed to compile and link against talloc
TALLOC_CFLAGS = ${talloc_cflags}
TALLOC_LDFLAGS = ${talloc_ldflags}
# Combined flags for compiling and linking against all of the above
CONFIGURE_CFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS) \\
+ -DHAVE_CANONICALIZE_FILE_NAME=\$(HAVE_CANONICALIZE_FILE_NAME) \\
+ \$(ZLIB_CFLAGS) \\
\$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
\$(VALGRIND_CFLAGS) \\
-DHAVE_STRCASESTR=\$(HAVE_STRCASESTR) \\
-DHAVE_STRSEP=\$(HAVE_STRSEP) \\
+ -DHAVE_D_TYPE=\$(HAVE_D_TYPE) \\
-DSTD_GETPWUID=\$(STD_GETPWUID) \\
-DSTD_ASCTIME=\$(STD_ASCTIME) \\
-DHAVE_XAPIAN_COMPACT=\$(HAVE_XAPIAN_COMPACT) \\
-DUTIL_BYTE_ORDER=\$(UTIL_BYTE_ORDER)
CONFIGURE_CXXFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS) \\
+ -DHAVE_CANONICALIZE_FILE_NAME=\$(HAVE_CANONICALIZE_FILE_NAME) \\
+ \$(ZLIB_CFLAGS) \\
\$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
\$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS) \\
-DHAVE_STRCASESTR=\$(HAVE_STRCASESTR) \\
-DHAVE_STRSEP=\$(HAVE_STRSEP) \\
+ -DHAVE_D_TYPE=\$(HAVE_D_TYPE) \\
-DSTD_GETPWUID=\$(STD_GETPWUID) \\
-DSTD_ASCTIME=\$(STD_ASCTIME) \\
-DHAVE_XAPIAN_COMPACT=\$(HAVE_XAPIAN_COMPACT) \\
-DUTIL_BYTE_ORDER=\$(UTIL_BYTE_ORDER)
-CONFIGURE_LDFLAGS = \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \$(XAPIAN_LDFLAGS)
+CONFIGURE_LDFLAGS = \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \$(ZLIB_LDFLAGS) \$(XAPIAN_LDFLAGS)
EOF
+notmuch (0.18~rc0-1) experimental; urgency=low
+
+ * This release of notmuch requires a non-reversable database upgrade
+ to support the new path: and updated folder: prefixes. Notmuch
+ will backup your tags for your before doing the upgrade, but it
+ never hurts to make your own backup with notmuch dump before
+ next running 'notmuch new'
+
+ -- David Bremner <bremner@debian.org> Tue, 22 Apr 2014 09:32:11 +0900
+
notmuch (0.17-1) unstable; urgency=low
* Previously on big endian architectures like sparc and powerpc the
-notmuch (0.17-3~bpo70+1) wheezy-backports; urgency=medium
+notmuch (0.18.1-2) unstable; urgency=medium
- * Rebuild for wheezy-backports.
+ * Update build-deps to use emacs24 on buildd (Closes: #756085)
+ * Disable gdb atomicity test for arm64 as gdb is currently broken on
+ the (unofficial) buildds
+ * Re-enable atomicity test on armhf; upstream fix seems to have
+ worked.
+
+ -- David Bremner <bremner@debian.org> Sat, 09 Aug 2014 11:48:10 -0300
+
+notmuch (0.18.1-1) unstable; urgency=medium
+
+ * New upstream bug fix release
+ - Re-enable support for single-message mbox files
+ - Fix for phrase indexing
+ - Make tagging empty query in Emacs harmless
+
+ -- David Bremner <bremner@debian.org> Wed, 25 Jun 2014 07:20:45 -0300
+
+notmuch (0.18.1~rc0-1) experimental; urgency=medium
+
+ * New upstream bug fix release (candidate)
+ * Tighten dependence of python packages on libnotmuch
+ (Closes: #749881).
+ * Redo emacsen-install script from sample in emacsen-common
+ (Closes: #739839).
+
+ -- David Bremner <bremner@debian.org> Sat, 14 Jun 2014 07:50:28 -0300
+
+notmuch (0.18-3) unstable; urgency=medium
+
+ * Disable atomicity tests on armel.
+
+ -- David Bremner <bremner@debian.org> Thu, 08 May 2014 14:26:45 +0900
+
+notmuch (0.18-2) unstable; urgency=medium
+
+ * Disable atomicity tests on armhf. These should be re-enabled when
+ upstream relases a fix for this (in progress).
+
+ -- David Bremner <bremner@debian.org> Thu, 08 May 2014 08:28:33 +0900
+
+notmuch (0.18-1) unstable; urgency=medium
+
+ * New upstream release. For detailed release notes see
+ see /usr/share/doc/notmuch/NEWS.gz. Some highlights:
+ - Changes/enhancements to searching for messages by filesystem
+ location ('folder:' and 'path:' prefixes).
+ - Saved searches in Emacs have also been enhanced to allow
+ distinct search orders for each one.
+ - Another enhancement to the Emacs interface is that replies to
+ encrypted messages are now encrypted, reducing the risk of
+ unintentional information disclosure.
+ - The default dump output format has changed to the more robust
+ 'batch-tag' format.
+ - The previously deprecated parsing of single message mboxes has
+ been removed.
- -- David Bremner <bremner@debian.org> Wed, 29 Jan 2014 20:20:56 -0400
+ -- David Bremner <bremner@debian.org> Tue, 06 May 2014 16:20:39 +0900
+
+notmuch (0.18~rc1-1) experimental; urgency=low
+
+ * Upstream release candidate
+ - include encoding fix for vim client.
+
+ -- David Bremner <bremner@debian.org> Sun, 04 May 2014 07:29:51 +0900
+
+notmuch (0.18~rc0-1) experimental; urgency=low
+
+ * Upstream release candidate.
+ * Bug fix: "insufficient sanitization of arguments to notmuch CLI",
+ thanks to Antoine Beaupré (Closes: #737496).
+ * Bug fix: "notmuch(1) manpage: typo: int -> in", thanks to Jakub
+ Wilk (Closes: #739556).
+ * Bug fix: "get a quiet option", thanks to Joerg Jaspert (Closes:
+ #666027).
+ * Bug fix: "Please remove me from Uploaders", thanks to martin f
+ krafft (Closes: #719100).
+ * Bug fix: "M-x notmuch-show-reply on an encrypted message should
+ insert encryption tags into the mml buffer", thanks to Daniel Kahn
+ Gillmor (Closes: #704648).
+
+ -- David Bremner <bremner@debian.org> Tue, 22 Apr 2014 09:27:29 +0900
+
+notmuch (0.17-5) unstable; urgency=medium
+
+ * Bug fix: "unowned directory after purge: /0755/", thanks to
+ Andreas Beckmann (Closes: #740325).
+
+ -- David Bremner <bremner@debian.org> Mon, 03 Mar 2014 07:29:06 -0400
+
+notmuch (0.17-4) unstable; urgency=medium
+
+ * Bug fix: "Please update ruby binary extension install path",
+ thanks to Christian Hofstaedtler (Closes: #739120).
+
+ -- David Bremner <bremner@debian.org> Tue, 18 Feb 2014 21:37:44 -0400
notmuch (0.17-3) unstable; urgency=medium
* Rebuild for wheezy-backports.
-- David Bremner <bremner@debian.org> Sun, 01 Sep 2013 19:04:32 -0300
+
notmuch (0.16-1) unstable; urgency=low
* New upstream feature release
Maintainer: Carl Worth <cworth@debian.org>
Uploaders:
Jameson Graef Rollins <jrollins@finestructure.net>,
- martin f. krafft <madduck@debian.org>,
David Bremner <bremner@debian.org>
+Build-Conflicts: ruby1.8
Build-Depends:
debhelper (>= 9),
pkg-config,
libz-dev,
python-all (>= 2.6.6-3~),
python3-all (>= 3.1.2-7~),
+ python-sphinx (>= 1.0),
ruby, ruby-dev (>>1:1.9.3~),
- emacs23-nox | emacs23 (>=23~) | emacs23-lucid (>=23~) |
- emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~),
- gdb [!s390x !ia64],
- dtach (>= 0.8)
+ emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~) |
+ emacs23-nox | emacs23 (>=23~) | emacs23-lucid (>=23~),
+ gdb [!s390x !ia64 !armel !arm64],
+ dtach (>= 0.8),
+ bash-completion (>=1.9.0~)
Standards-Version: 3.9.4
Homepage: http://notmuchmail.org/
Vcs-Git: git://notmuchmail.org/git/notmuch
Package: python-notmuch
Architecture: all
Section: python
-Depends: ${misc:Depends}, ${python:Depends}, libnotmuch3
+Depends: ${misc:Depends}, ${python:Depends}, libnotmuch3 (>= ${source:Version})
Description: python interface to the notmuch mail search and index library
Notmuch is a system for indexing, searching, reading, and tagging
large collections of email messages in maildir or mh format. It uses
Package: python3-notmuch
Architecture: all
Section: python
-Depends: ${misc:Depends}, ${python3:Depends}, libnotmuch3
+Depends: ${misc:Depends}, ${python3:Depends}, libnotmuch3 (>= ${source:Version})
Description: Python 3 interface to the notmuch mail search and index library
Notmuch is a system for indexing, searching, reading, and tagging
large collections of email messages in maildir or mh format. It uses
Section: mail
Breaks: notmuch (<<0.6~254~)
Replaces: notmuch (<<0.6~254~)
-Conflicts: emacsen-common (<< 2.0.0)
Depends: ${misc:Depends}, notmuch (>= ${source:Version}),
emacs23 (>= 23~) | emacs23-nox (>=23~) | emacs23-lucid (>=23~) |
- emacs24 (>= 24~) | emacs24-nox (>=24~) | emacs24-lucid (>=24~)
+ emacs24 (>= 24~) | emacs24-nox (>=24~) | emacs24-lucid (>=24~),
+ emacsen-common (>= 2.0.8)
Description: thread-based email index, search and tagging (emacs interface)
Notmuch is a system for indexing, searching, reading, and tagging
large collections of email messages in maildir or mh format. It uses
-#! /bin/sh -e
+#!/bin/sh
# /usr/lib/emacsen-common/packages/install/notmuch-emacs
-
-# Written by Jim Van Zandt <jrv@debian.org>, borrowing heavily
-# from the install scripts for gettext by Santiago Vila
-# <sanvila@ctv.es> and octave by Dirk Eddelbuettel <edd@debian.org>.
+set -e
FLAVOR=$1
PACKAGE=notmuch
-# We know that the notmuch emacs code doesn't work with emacs before emacs23
-if [ ${FLAVOR} = emacs21 ]; then exit 0; fi
-if [ ${FLAVOR} = emacs22 ]; then exit 0; fi
-if [ ${FLAVOR} = xemacs21 ]; then exit 0; fi
-if [ ${FLAVOR} = xemacs22 ]; then exit 0; fi
-
-echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR}
-
-#FLAVORTEST=`echo $FLAVOR | cut -c-6`
-#if [ ${FLAVORTEST} = xemacs ] ; then
-# SITEFLAG="-no-site-file"
-#else
-# SITEFLAG="--no-site-file"
-#fi
-#FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile"
-FLAGS="--no-site-file -q -batch -l path.el -f batch-byte-compile"
-
-ELDIR=/usr/share/emacs/site-lisp/${PACKAGE}
-ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE}
-
-install -m 755 -d ${ELCDIR}
-cd ${ELDIR}
-FILES=`echo *.el`
-cd ${ELCDIR}
-for file in ${FILES}; do
- ln -sf ${ELDIR}/${file} .
-done
-
-cat << EOF > path.el
-(setq load-path (cons "." load-path) byte-compile-warnings nil)
-EOF
-${FLAVOR} ${FLAGS} ${FILES}
-rm -f *.el
-
-exit 0
+case "${FLAVOR}" in
+ emacs)
+ return 0
+ ;;
+ xemacs*|emacs2[12])
+ # patches welcome.
+ echo install/${PACKAGE}: skipping install for unsupported emacsen flavor ${FLAVOR}
+ exit 0
+ ;;
+ *)
+ echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR}
+esac
+
+
+elc_dir=/usr/share/${FLAVOR}/site-lisp/${PACKAGE}
+el_dir=/usr/share/emacs/site-lisp/${PACKAGE}
+
+byte_compile_options="--quick --directory=${el_dir} -batch -f batch-byte-compile"
+
+echo install/${PACKAGE}: byte-compiling for ${FLAVOR}
+
+[ -d ${elc_dir} ] || mkdir ${elc_dir}
+
+# Create symlinks to the .el files (see section 6E in debian-emacs
+# polcy). This makes complation easy, and also allows find-function
+# and find-library to work properly.
+(cd ${elc_dir} && cp -s ${el_dir}/*.el .)
+
+# Byte compile them
+(cd ${elc_dir}
+ set +e
+ ${FLAVOR} ${byte_compile_options} *.el > Install.log 2>&1
+ if test $? -ne 0
+ then
+ cat Install.log
+ exit 1
+ fi
+ set -e
+ gzip -9 Install.log)
+
+exit 0;
-#!/bin/sh -e
-# /usr/lib/emacsen-common/packages/remove/notmuch-emacs
+#!/bin/sh
+# /usr/lib/emacsen-common/packages/remove/notmuch
+
+set -e
FLAVOR=$1
PACKAGE=notmuch
+elc_dir=/usr/share/${FLAVOR}/site-lisp/${PACKAGE}
+
+case "${FLAVOR}" in
+ emacs)
+ return 0
+ ;;
+ xemacs*|emacs2[12])
+ # patches welcome.
+ echo install/${PACKAGE}: skipping removal for unsupported emacsen flavor ${FLAVOR}
+ exit 0
+ ;;
+ *)
+ echo remove/${PACKAGE}: Handling removal for emacsen flavor ${FLAVOR}
+esac
+
+echo remove/${PACKAGE}: Handling removal of emacsen flavor ${FLAVOR}
+
+echo emacsen-common: purging byte-compiled files for ${FLAVOR}
+rm -f ${elc_dir}/*.elc
+rm -f ${elc_dir}/*.el
+rm -f ${elc_dir}/Install.log*
+if test -e "${elc_dir}"
+then
+ rmdir --ignore-fail-on-non-empty "${elc_dir}"
+fi
-echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR}
-rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE}
+exit 0;
dir="/var/lib/emacsen-common/state/package/installed"
-mkdir -p 0755 ${dir}
+mkdir -p -m 0755 ${dir}
touch ${dir}/notmuch-emacs
#DEBHELPER#
+if [ -d /0755 ]; then
+ rmdir /0755 || true
+fi
-usr/lib/ruby/vendor_ruby/*/*/notmuch.so
+usr/lib/*/*ruby/*/*/notmuch.so
single-debian-patch
+tar-ignore
+tar-ignore=performance-test/download/*.tar.xz
--- /dev/null
+#!/usr/bin/env bash
+#
+# NAME
+# gen-testdb.sh - generate test databases
+#
+# SYNOPSIS
+# gen-testdb.sh -v NOTMUCH-VERSION [-c CORPUS-PATH] [-s TAR-SUFFIX]
+#
+# DESCRIPTION
+# Generate a tarball containing the specified test corpus and
+# the corresponding notmuch database, indexed using a specific
+# version of notmuch, resulting in a specific version of the
+# database.
+#
+# The specific version of notmuch will be built on the fly.
+# Therefore the script must be run within a git repository to be
+# able to build the old versions of notmuch.
+#
+# This script reuses the test infrastructure, and the script
+# must be run from within the test directory.
+#
+# The output tarballs, named database-<TAR-SUFFIX>.tar.gz, are
+# placed in the test/test-databases directory.
+#
+# OPTIONS
+# -v NOTMUCH-VERSION
+# Notmuch version in terms of a git tag or commit to use
+# for generating the database. Required.
+#
+# -c CORPUS-PATH
+# Path to a corpus to use for generating the
+# database. Due to CWD changes within the test
+# infrastructure, use absolute paths. Defaults to the
+# test corpus.
+#
+# -s TAR-SUFFIX
+# Suffix for the tarball basename. Empty by default.
+#
+# EXAMPLE
+#
+# Generate a database indexed with notmuch 0.17. Use the default
+# test corpus. Name the tarball database-v1.tar.gz to reflect
+# the fact that notmuch 0.17 used database version 1.
+#
+# $ cd test
+# $ ../devel/gen-testdb.sh -v 0.17 -s v1
+#
+# CAVEATS
+# Test infrastructure options won't work.
+#
+# Any existing databases with the same name will be overwritten.
+#
+# It may not be possible to build old versions of notmuch with
+# the set of dependencies that satisfy building the current
+# version of notmuch.
+#
+# AUTHOR
+# Jani Nikula <jani@nikula.org>
+#
+# LICENSE
+# Same as notmuch test infrastructure (GPLv2+).
+#
+
+test_description="database generation abusing test infrastructure"
+
+# immediate exit on subtest failure; see test_failure_ in test-lib.sh
+immediate=t
+
+VERSION=
+CORPUS=
+SUFFIX=
+
+while getopts v:c:s: opt; do
+ case "$opt" in
+ v) VERSION="$OPTARG";;
+ c) CORPUS="$OPTARG";;
+ s) SUFFIX="-$OPTARG";;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+. ./test-lib.sh
+
+SHORT_CORPUS=$(basename ${CORPUS:-database})
+DBNAME=${SHORT_CORPUS}${SUFFIX}
+TARBALLNAME=${DBNAME}.tar.xz
+
+CORPUS=${CORPUS:-${TEST_DIRECTORY}/corpus}
+
+test_expect_code 0 "notmuch version specified on the command line" \
+ "test -n ${VERSION}"
+
+test_expect_code 0 "the specified version ${VERSION} refers to a commit" \
+ "git show ${VERSION} >/dev/null 2>&1"
+
+BUILD_DIR="notmuch-${VERSION}"
+test_expect_code 0 "generate snapshot of notmuch version ${VERSION}" \
+ "git -C $TEST_DIRECTORY/.. archive --prefix=${BUILD_DIR}/ --format=tar ${VERSION} | tar x"
+
+# force version string
+git describe --match '[0-9.]*' ${VERSION} > ${BUILD_DIR}/version
+
+test_expect_code 0 "configure and build notmuch version ${VERSION}" \
+ "make -C ${BUILD_DIR}"
+
+# use the newly built notmuch
+export PATH=./${BUILD_DIR}:$PATH
+
+test_begin_subtest "verify the newly built notmuch version"
+test_expect_equal "`notmuch --version`" "notmuch `cat ${BUILD_DIR}/version`"
+
+# replace the existing mails, if any, with the specified corpus
+rm -rf ${MAIL_DIR}
+cp -a ${CORPUS} ${MAIL_DIR}
+
+test_expect_code 0 "index the corpus" \
+ "notmuch new"
+
+# wrap the resulting mail store and database in a tarball
+
+cp -a ${MAIL_DIR} ${TMP_DIRECTORY}/${DBNAME}
+tar Jcf ${TMP_DIRECTORY}/${TARBALLNAME} -C ${TMP_DIRECTORY} ${DBNAME}
+mkdir -p ${TEST_DIRECTORY}/test-databases
+cp -a ${TMP_DIRECTORY}/${TARBALLNAME} ${TEST_DIRECTORY}/test-databases
+test_expect_code 0 "create the output tarball ${TARBALLNAME}" \
+ "test -f ${TEST_DIRECTORY}/test-databases/${TARBALLNAME}"
+
+# generate a checksum file
+test_expect_code 0 "compute checksum" \
+ "(cd ${TEST_DIRECTORY}/test-databases/ && sha256sum ${TARBALLNAME} > ${TARBALLNAME}.sha256)"
+test_done
my %command = (
archive => \&do_archive,
checkout => \&do_checkout,
+ clone => \&do_clone,
commit => \&do_commit,
fetch => \&do_fetch,
help => \&do_help,
system ('git', "--git-dir=$NMBGIT", 'archive', 'HEAD');
}
+sub do_clone {
+ my $repository = shift;
+
+ my $tempwork = tempdir ('/tmp/nmbug-clone.XXXXXX', CLEANUP => 1);
+ system ('git', 'clone', '--no-checkout', '--separate-git-dir', $NMBGIT,
+ $repository, $tempwork) == 0
+ or die "'git clone' exited with nonzero value\n";
+ git ('config', '--unset', 'core.worktree');
+ git ('config', 'core.bare', 'true');
+}
sub is_committed {
my $status = shift;
sub do_pull {
my $remote = shift || 'origin';
+ my $branch = shift || 'master';
git ( 'fetch', $remote);
- do_merge ();
+ do_merge ("$remote/$branch");
}
sub do_merge {
+ my $commit = shift || '@{upstream}';
+
insist_committed ();
my $tempwork = tempdir ('/tmp/nmbug-merge.XXXXXX', CLEANUP => 1);
git ( { GIT_WORK_TREE => $tempwork }, 'checkout', '-f', 'HEAD');
- git ( { GIT_WORK_TREE => $tempwork }, 'merge', 'FETCH_HEAD');
+ git ( { GIT_WORK_TREE => $tempwork }, 'merge', $commit);
do_checkout ();
}
sub is_unmerged {
+ my $commit = shift || '@{upstream}';
- return 0 if (! -f $NMBGIT.'/FETCH_HEAD');
-
- my $fetch_head = git ('rev-parse', 'FETCH_HEAD');
- my $base = git ( 'merge-base', 'HEAD', 'FETCH_HEAD');
+ my $fetch_head = git ('rev-parse', $commit);
+ my $base = git ( 'merge-base', 'HEAD', $commit);
return ($base ne $fetch_head);
sub diff_refs {
my $filter = shift;
my $ref1 = shift || 'HEAD';
- my $ref2 = shift || 'FETCH_HEAD';
+ my $ref2 = shift || '@{upstream}';
my $fh= git_pipe ( 'diff', "--diff-filter=$filter", '--name-only',
$ref1, $ref2);
push local nmbug git state to remote repo
-=item B<pull> [remote]
+=item B<pull> [remote] [branch]
pull (merge) remote repo changes to notmuch. B<pull> is equivalent to
-B<fetch> followed by B<merge>.
+B<fetch> followed by B<merge>. The default remote is C<origin>, and
+the default branch is C<master>.
=back
=over 8
+=item B<clone> repository
+
+Create a local nmbug repository from a remote source. This wraps
+C<git clone>, adding some options to avoid creating a working tree
+while preserving remote-tracking branches and upstreams.
+
=item B<checkout>
Update the notmuch database from git. This is mainly useful to discard
=item B<log> [parameters]
A simple wrapper for git log. After running C<nmbug fetch>, you can
-inspect the changes with C<nmbug log HEAD..FETCH_HEAD>
+inspect the changes with C<nmbug log HEAD..@{upstream}>
-=item B<merge>
+=item B<merge> [commit]
-Merge changes from FETCH_HEAD into HEAD, and load the result into
-notmuch.
+Merge changes from C<commit> into HEAD, and load the result into
+notmuch. The default commit is C<@{upstream}>.
=item B<status>
# - python 2.6 for json
# - argparse; either python 2.7, or install separately
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import codecs
+import collections
import datetime
-import rfc822
-import urllib
+import email.utils
+try: # Python 3
+ from urllib.parse import quote
+except ImportError: # Python 2
+ from urllib import quote
import json
import argparse
import os
+import re
import sys
import subprocess
+import xml.sax.saxutils
+
+
+_ENCODING = 'UTF-8'
+_PAGES = {}
+
+
+if not hasattr(collections, 'OrderedDict'): # Python 2.6 or earlier
+ class _OrderedDict (dict):
+ "Just enough of a stub to get through Page._get_threads"
+ def __init__(self, *args, **kwargs):
+ super(_OrderedDict, self).__init__(*args, **kwargs)
+ self._keys = [] # record key order
+
+ def __setitem__(self, key, value):
+ super(_OrderedDict, self).__setitem__(key, value)
+ self._keys.append(key)
-# parse command line arguments
+ def values(self):
+ for key in self._keys:
+ yield self[key]
+
+
+ collections.OrderedDict = _OrderedDict
+
+
+def read_config(path=None, encoding=None):
+ "Read config from json file"
+ if not encoding:
+ encoding = _ENCODING
+ if path:
+ fp = open(path)
+ else:
+ nmbhome = os.getenv('NMBGIT', os.path.expanduser('~/.nmbug'))
+
+ # read only the first line from the pipe
+ sha1_bytes = subprocess.Popen(
+ ['git', '--git-dir', nmbhome, 'show-ref', '-s', 'config'],
+ stdout=subprocess.PIPE).stdout.readline()
+ sha1 = sha1_bytes.decode(encoding).rstrip()
+
+ fp_byte_stream = subprocess.Popen(
+ ['git', '--git-dir', nmbhome, 'cat-file', 'blob',
+ sha1+':status-config.json'],
+ stdout=subprocess.PIPE).stdout
+ fp = codecs.getreader(encoding=encoding)(stream=fp_byte_stream)
+
+ return json.load(fp)
+
+
+class Thread (list):
+ def __init__(self):
+ self.running_data = {}
+
+
+class Page (object):
+ def __init__(self, header=None, footer=None):
+ self.header = header
+ self.footer = footer
+
+ def write(self, database, views, stream=None):
+ if not stream:
+ try: # Python 3
+ byte_stream = sys.stdout.buffer
+ except AttributeError: # Python 2
+ byte_stream = sys.stdout
+ stream = codecs.getwriter(encoding=_ENCODING)(stream=byte_stream)
+ self._write_header(views=views, stream=stream)
+ for view in views:
+ self._write_view(database=database, view=view, stream=stream)
+ self._write_footer(views=views, stream=stream)
+
+ def _write_header(self, views, stream):
+ if self.header:
+ stream.write(self.header)
+
+ def _write_footer(self, views, stream):
+ if self.footer:
+ stream.write(self.footer)
+
+ def _write_view(self, database, view, stream):
+ if 'query-string' not in view:
+ query = view['query']
+ view['query-string'] = ' and '.join(query)
+ q = notmuch.Query(database, view['query-string'])
+ q.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
+ threads = self._get_threads(messages=q.search_messages())
+ self._write_view_header(view=view, stream=stream)
+ self._write_threads(threads=threads, stream=stream)
+
+ def _get_threads(self, messages):
+ threads = collections.OrderedDict()
+ for message in messages:
+ thread_id = message.get_thread_id()
+ if thread_id in threads:
+ thread = threads[thread_id]
+ else:
+ thread = Thread()
+ threads[thread_id] = thread
+ thread.running_data, display_data = self._message_display_data(
+ running_data=thread.running_data, message=message)
+ thread.append(display_data)
+ return list(threads.values())
+
+ def _write_view_header(self, view, stream):
+ pass
+
+ def _write_threads(self, threads, stream):
+ for thread in threads:
+ for message_display_data in thread:
+ stream.write(
+ ('{date:10.10s} {from:20.20s} {subject:40.40s}\n'
+ '{message-id-term:>72}\n'
+ ).format(**message_display_data))
+ if thread != threads[-1]:
+ stream.write('\n')
+
+ def _message_display_data(self, running_data, message):
+ headers = ('thread-id', 'message-id', 'date', 'from', 'subject')
+ data = {}
+ for header in headers:
+ if header == 'thread-id':
+ value = message.get_thread_id()
+ elif header == 'message-id':
+ value = message.get_message_id()
+ data['message-id-term'] = 'id:"{0}"'.format(value)
+ elif header == 'date':
+ value = str(datetime.datetime.utcfromtimestamp(
+ message.get_date()).date())
+ else:
+ value = message.get_header(header)
+ if header == 'from':
+ (value, addr) = email.utils.parseaddr(value)
+ if not value:
+ value = addr.split('@')[0]
+ data[header] = value
+ next_running_data = data.copy()
+ for header, value in data.items():
+ if header in ['message-id', 'subject']:
+ continue
+ if value == running_data.get(header, None):
+ data[header] = ''
+ return (next_running_data, data)
+
+
+class HtmlPage (Page):
+ _slug_regexp = re.compile('\W+')
+
+ def _write_header(self, views, stream):
+ super(HtmlPage, self)._write_header(views=views, stream=stream)
+ stream.write('<ul>\n')
+ for view in views:
+ if 'id' not in view:
+ view['id'] = self._slug(view['title'])
+ stream.write(
+ '<li><a href="#{id}">{title}</a></li>\n'.format(**view))
+ stream.write('</ul>\n')
+
+ def _write_view_header(self, view, stream):
+ stream.write('<h3 id="{id}">{title}</h3>\n'.format(**view))
+ stream.write('<p>\n')
+ if 'comment' in view:
+ stream.write(view['comment'])
+ stream.write('\n')
+ for line in [
+ 'The view is generated from the following query:',
+ '</p>',
+ '<p>',
+ ' <code>',
+ view['query-string'],
+ ' </code>',
+ '</p>',
+ ]:
+ stream.write(line)
+ stream.write('\n')
+
+ def _write_threads(self, threads, stream):
+ if not threads:
+ return
+ stream.write('<table>\n')
+ for thread in threads:
+ stream.write(' <tbody>\n')
+ for message_display_data in thread:
+ stream.write((
+ ' <tr class="message-first">\n'
+ ' <td>{date}</td>\n'
+ ' <td><code>{message-id-term}</code></td>\n'
+ ' </tr>\n'
+ ' <tr class="message-last">\n'
+ ' <td>{from}</td>\n'
+ ' <td>{subject}</td>\n'
+ ' </tr>\n'
+ ).format(**message_display_data))
+ stream.write(' </tbody>\n')
+ if thread != threads[-1]:
+ stream.write(
+ ' <tbody><tr><td colspan="2"><br /></td></tr></tbody>\n')
+ stream.write('</table>\n')
+
+ def _message_display_data(self, *args, **kwargs):
+ running_data, display_data = super(
+ HtmlPage, self)._message_display_data(
+ *args, **kwargs)
+ if 'subject' in display_data and 'message-id' in display_data:
+ d = {
+ 'message-id': quote(display_data['message-id']),
+ 'subject': xml.sax.saxutils.escape(display_data['subject']),
+ }
+ display_data['subject'] = (
+ '<a href="http://mid.gmane.org/{message-id}">{subject}</a>'
+ ).format(**d)
+ for key in ['message-id', 'from']:
+ if key in display_data:
+ display_data[key] = xml.sax.saxutils.escape(display_data[key])
+ return (running_data, display_data)
+
+ def _slug(self, string):
+ return self._slug_regexp.sub('-', string)
parser = argparse.ArgumentParser()
parser.add_argument('--text', help='output plain text format',
action='store_true')
-parser.add_argument('--config', help='load config from given file')
+parser.add_argument('--config', help='load config from given file',
+ metavar='PATH')
parser.add_argument('--list-views', help='list views',
action='store_true')
-parser.add_argument('--get-query', help='get query for view')
+parser.add_argument('--get-query', help='get query for view',
+ metavar='VIEW')
args = parser.parse_args()
-# read config from json file
-
-if args.config != None:
- fp = open(args.config)
-else:
- nmbhome = os.getenv('NMBGIT', os.path.expanduser('~/.nmbug'))
-
- # read only the first line from the pipe
- sha1 = subprocess.Popen(['git', '--git-dir', nmbhome,
- 'show-ref', '-s', 'config'],
- stdout=subprocess.PIPE).stdout.readline()
+config = read_config(path=args.config)
- sha1 = sha1.rstrip()
-
- fp = subprocess.Popen(['git', '--git-dir', nmbhome,
- 'cat-file', 'blob', sha1+':status-config.json'],
- stdout=subprocess.PIPE).stdout
-
-config = json.load(fp)
+_PAGES['text'] = Page()
+_PAGES['html'] = HtmlPage(
+ header='''<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset={encoding}" />
+ <title>{title}</title>
+ <style media="screen" type="text/css">
+ table {{
+ border-spacing: 0;
+ }}
+ tr.message-first td {{
+ padding-top: {inter_message_padding};
+ }}
+ tr.message-last td {{
+ padding-bottom: {inter_message_padding};
+ }}
+ td {{
+ padding-left: {border_radius};
+ padding-right: {border_radius};
+ }}
+ tr:first-child td:first-child {{
+ border-top-left-radius: {border_radius};
+ }}
+ tr:first-child td:last-child {{
+ border-top-right-radius: {border_radius};
+ }}
+ tr:last-child td:first-child {{
+ border-bottom-left-radius: {border_radius};
+ }}
+ tr:last-child td:last-child {{
+ border-bottom-right-radius: {border_radius};
+ }}
+ tbody:nth-child(4n+1) tr td {{
+ background-color: #ffd96e;
+ }}
+ tbody:nth-child(4n+3) tr td {{
+ background-color: #bce;
+ }}
+ </style>
+</head>
+<body>
+<h2>{title}</h2>
+<p>
+Generated: {date}<br />
+{blurb}
+</p>
+<h3>Views</h3>
+'''.format(date=datetime.datetime.utcnow().date(),
+ title=config['meta']['title'],
+ blurb=config['meta']['blurb'],
+ encoding=_ENCODING,
+ inter_message_padding='0.25em',
+ border_radius='0.5em'),
+ footer='</body>\n</html>\n',
+ )
if args.list_views:
for view in config['views']:
- print view['title']
+ print(view['title'])
sys.exit(0)
elif args.get_query != None:
for view in config['views']:
if args.get_query == view['title']:
- print ' and '.join(view['query'])
+ print(' and '.join(view['query']))
sys.exit(0)
else:
# only import notmuch if needed
import notmuch
if args.text:
- output_format = 'text'
+ page = _PAGES['text']
else:
- output_format = 'html'
-
-class Thread:
- def __init__(self, last, lines):
- self.last = last
- self.lines = lines
-
- def join_utf8_with_newlines(self):
- return '\n'.join( (line.encode('utf-8') for line in self.lines) )
-
-def output_with_separator(threadlist, sep):
- outputs = (thread.join_utf8_with_newlines() for thread in threadlist)
- print sep.join(outputs)
-
-headers = ['date', 'from', 'subject']
-
-def print_view(title, query, comment):
-
- query_string = ' and '.join(query)
- q_new = notmuch.Query(db, query_string)
- q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
-
- last_thread_id = ''
- threads = {}
- threadlist = []
- out = {}
- last = None
- lines = None
-
- if output_format == 'html':
- print '<h3><a name="%s" />%s</h3>' % (title, title)
- print comment
- print 'The view is generated from the following query:'
- print '<blockquote>'
- print query_string
- print '</blockquote>'
- print '<table>\n'
-
- for m in q_new.search_messages():
-
- thread_id = m.get_thread_id()
-
- if thread_id != last_thread_id:
- if threads.has_key(thread_id):
- last = threads[thread_id].last
- lines = threads[thread_id].lines
- else:
- last = {}
- lines = []
- thread = Thread(last, lines)
- threads[thread_id] = thread
- for h in headers:
- last[h] = ''
- threadlist.append(thread)
- last_thread_id = thread_id
-
- for header in headers:
- val = m.get_header(header)
-
- if header == 'date':
- val = str.join(' ', val.split(None)[1:4])
- val = str(datetime.datetime.strptime(val, '%d %b %Y').date())
- elif header == 'from':
- (val, addr) = rfc822.parseaddr(val)
- if val == '':
- val = addr.split('@')[0]
-
- if header != 'subject' and last[header] == val:
- out[header] = ''
- else:
- out[header] = val
- last[header] = val
-
- mid = m.get_message_id()
- out['id'] = 'id:"%s"' % mid
-
- if output_format == 'html':
-
- out['subject'] = '<a href="http://mid.gmane.org/%s">%s</a>' \
- % (urllib.quote(mid), out['subject'])
-
- lines.append(' <tr><td>%s' % out['date'])
- lines.append('</td><td>%s' % out['id'])
- lines.append('</td></tr>')
- lines.append(' <tr><td>%s' % out['from'])
- lines.append('</td><td>%s' % out['subject'])
- lines.append('</td></tr>')
- else:
- lines.append('%(date)-10.10s %(from)-20.20s %(subject)-40.40s\n%(id)72s' % out)
-
- if output_format == 'html':
- output_with_separator(threadlist,
- '\n<tr><td colspan="2"><br /></td></tr>\n')
- print '</table>'
- else:
- output_with_separator(threadlist, '\n\n')
-
-# main program
-
-db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
-
-if output_format == 'html':
- print '''<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title>Notmuch Patches</title>
-</head>
-<body>'''
- print '<h2>Notmuch Patches</h2>'
- print 'Generated: %s<br />' % datetime.datetime.utcnow().date()
- print 'For more infomation see <a href="http://notmuchmail.org/nmbug">nmbug</a>'
-
- print '<h3>Views</h3>'
- print '<ul>'
- for view in config['views']:
- print '<li><a href="#%(title)s">%(title)s</a></li>' % view
- print '</ul>'
-
-for view in config['views']:
- print_view(**view)
+ page = _PAGES['html']
-if output_format == 'html':
- print '</body>\n</html>'
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
+page.write(database=db, views=config['views'])
{
+ "meta": {
+ "title": "Notmuch Patches",
+ "blurb": "For more information see <a href=\"http://notmuchmail.org/nmbug\">nmbug</a>"
+ },
+
"views": [
{
"comment": "Unresolved bugs (or just need tag updating).",
echo -n "Checking that '$VERSION' is good with digits and periods... "
case $VERSION in
- *[^0-9.]*)
+ *[!0-9.]*)
verfail "'$VERSION' contains other characters than digits and periods" ;;
.*) verfail "'$VERSION' begins with a period" ;;
*.) verfail "'$VERSION' ends with a period" ;;
append_emsg "Date '$news_date' in NEWS file is not in format (yyyy-mm-dd)"
esac
-readonly DATE=${news_date//[()]/} # bash feature
-manthdata ()
-{
- set x $*
- if [ $# != 7 ]
- then
- append_emsg "'$mp' has too many '.TH' lines"
- man_mismatch=1
- fi
- man_date=${5-} man_version=${7-}
-}
-
-echo -n "Checking that manual page dates and versions are $DATE and $VERSION... "
-manfiles=`find man -type f | sort`
-man_pages_ok=Yes
-for mp in $manfiles
-do
- case $mp in
- *.[0-9]) ;; # fall below this 'case ... esac'
-
- */Makefile.local | */Makefile ) continue ;;
- */.gitignore) continue ;;
- *.bak) continue ;;
-
- *) append_emsg "'$mp': extra file"
- man_pages_ok=No
- continue
- esac
- manthdata `sed -n '/^[.]TH NOTMUCH/ { y/"/ /; p; }' "$mp"`
- if [ "$man_version" != "$VERSION" ]
- then append_emsg "Version '$man_version' is not '$VERSION' in $mp"
- mman_pages_ok=No
- fi
- if [ "$man_date" != "$DATE" ]
- then append_emsg "DATE '$man_date' is not '$DATE' in $mp"
- man_pages_ok=No
- fi
-done
-echo $man_pages_ok.
-
if [ -n "$emsgs" ]
then
echo
--- /dev/null
+docdeps.mk
+_build
--- /dev/null
+This file contains some more detailed information about building and
+installing the documentation.
+
+Building with sphinx.
+---------------------
+
+- You need sphinx at least version 1.0.
+
+- You can build build and install man pages with 'make install-man'
+
+- You can build man, info, html, and pdf versions of the docs
+ (currently only the man pages) with
+
+ 'make install-{man|info|html|pdf}'
+
+Building the man pages
+----------------------
+
+- You can build the man pages with rst2man (from python-docutils) with
+ 'make rst2man'.
+
+- Currently there is no support to automagically install the resulting
+ nroff files, but it should work to modify the target install-man
+ in doc/Makefile.local.
--- /dev/null
+all:
+ $(MAKE) -C .. all
+
+.DEFAULT:
+ $(MAKE) -C .. $@
--- /dev/null
+# -*- makefile -*-
+
+dir := doc
+
+# You can set these variables from the command line.
+SPHINXOPTS := -q
+SPHINXBUILD = sphinx-build
+DOCBUILDDIR := $(dir)/_build
+
+prerst2man := python $(srcdir)/$(dir)/prerst2man.py
+mkdocdeps := python $(srcdir)/$(dir)/mkdocdeps.py
+
+# Internal variables.
+ALLSPHINXOPTS := -d $(DOCBUILDDIR)/doctrees $(SPHINXOPTS) $(srcdir)/$(dir)
+
+.PHONY: sphinx-html sphinx-texinfo sphinx-info
+
+.PHONY: install-man build-man
+
+%.gz: %
+ rm -f $@ && gzip --stdout $^ > $@
+
+sphinx-html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(DOCBUILDDIR)/html
+
+sphinx-texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(DOCBUILDDIR)/texinfo
+
+sphinx-info: sphinx-texinfo
+ make -C $(DOCBUILDDIR)/texinfo info
+
+-include $(dir)/docdeps.mk
+
+MAN_GZIP_FILES := $(addsuffix .gz,${MAN_ROFF_FILES})
+
+# Use the man page converter that is available. We should never depend
+# on MAN_ROFF_FILES if a converter is not available.
+${MAN_ROFF_FILES}: $(DOCBUILDDIR)/.roff.stamp
+
+# By using $(DOCBUILDDIR)/.roff.stamp instead of ${MAN_ROFF_FILES}, we
+# convey to make that a single invocation of this recipe builds all
+# of the roff files. This prevents parallel make from starting an
+# instance of this recipe for each roff file.
+$(DOCBUILDDIR)/.roff.stamp: ${MAN_RST_FILES}
+ifeq ($(HAVE_SPHINX),1)
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(DOCBUILDDIR)/man
+ for section in 1 5 7; do \
+ mkdir -p $(DOCBUILDDIR)/man/man$${section}; \
+ mv $(DOCBUILDDIR)/man/*.$${section} $(DOCBUILDDIR)/man/man$${section}; \
+ done
+else ifeq ($(HAVE_RST2MAN),1)
+ $(prerst2man) $(srcdir)/doc $(DOCBUILDDIR)/man
+else
+ @echo "Fatal: build dependency fail."
+ @false
+endif
+ touch ${MAN_ROFF_FILES} $@
+
+# Do not try to build or install man pages if a man page converter is
+# not available.
+ifeq ($(HAVE_SPHINX)$(HAVE_RST2MAN),00)
+build-man:
+install-man:
+ @echo "No sphinx or rst2man, will not install man pages."
+else
+build-man: ${MAN_GZIP_FILES}
+install-man: ${MAN_GZIP_FILES}
+ mkdir -p "$(DESTDIR)$(mandir)/man1"
+ mkdir -p "$(DESTDIR)$(mandir)/man5"
+ mkdir -p "$(DESTDIR)$(mandir)/man7"
+ install -m0644 $(DOCBUILDDIR)/man/man1/*.1.gz $(DESTDIR)/$(mandir)/man1
+ install -m0644 $(DOCBUILDDIR)/man/man5/*.5.gz $(DESTDIR)/$(mandir)/man5
+ install -m0644 $(DOCBUILDDIR)/man/man7/*.7.gz $(DESTDIR)/$(mandir)/man7
+ cd $(DESTDIR)/$(mandir)/man1 && ln -sf notmuch.1.gz notmuch-setup.1.gz
+endif
+
+$(dir)/docdeps.mk: $(dir)/conf.py $(dir)/mkdocdeps.py
+ $(mkdocdeps) $(srcdir)/doc $(DOCBUILDDIR) $@
+
+CLEAN := $(CLEAN) $(DOCBUILDDIR) $(dir)/docdeps.mk $(DOCBUILDDIR)/.roff.stamp
+CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc
--- /dev/null
+
+# -*- coding: utf-8 -*-
+
+import sys
+import os
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'notmuch'
+copyright = u'2014, Carl Worth and many others'
+
+location = os.path.dirname(__file__)
+
+for pathdir in ['.', '..']:
+ version_file = os.path.join(location,pathdir,'version')
+ if os.path.exists(version_file):
+ with open(version_file,'r') as infile:
+ version=infile.read().replace('\n','')
+
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build', 'notmuch-emacs.rst']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'notmuchdoc'
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+
+man_pages = [
+
+('man1/notmuch','notmuch',
+ u'thread-based email index, search, and tagging',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-compact','notmuch-compact',
+ u'compact the notmuch database',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-config','notmuch-config',
+ u'access notmuch configuration file',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-count','notmuch-count',
+ u'count messages matching the given search terms',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-dump','notmuch-dump',
+ u'creates a plain-text dump of the tags of each message',
+ [u'Carl Worth and many others'], 1),
+
+('man5/notmuch-hooks','notmuch-hooks',
+ u'hooks for notmuch',
+ [u'Carl Worth and many others'], 5),
+
+('man1/notmuch-insert','notmuch-insert',
+ u'add a message to the maildir and notmuch database',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-new','notmuch-new',
+ u'incorporate new mail into the notmuch database',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-reply','notmuch-reply',
+ u'constructs a reply template for a set of messages',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-restore','notmuch-restore',
+ u'restores the tags from the given file (see notmuch dump)',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-search','notmuch-search',
+ u'search for messages matching the given search terms',
+ [u'Carl Worth and many others'], 1),
+
+('man7/notmuch-search-terms','notmuch-search-terms',
+ u'syntax for notmuch queries',
+ [u'Carl Worth and many others'], 7),
+
+('man1/notmuch-show','notmuch-show',
+ u'show messages matching the given search terms',
+ [u'Carl Worth and many others'], 1),
+
+('man1/notmuch-tag','notmuch-tag',
+ u'add/remove tags for all messages matching the search terms',
+ [u'Carl Worth and many others'], 1),
+
+
+]
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+texinfo_no_detailmenu = True
+
+texinfo_documents = [
+ ('notmuch-emacs', 'notmuch-emacs', u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-emacs',
+ 'emacs based front-end for notmuch', 'Miscellaneous'),
+('man1/notmuch','notmuch',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch',
+ 'thread-based email index, search, and tagging','Miscellaneous'),
+('man1/notmuch-compact','notmuch-compact',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-compact',
+ 'compact the notmuch database','Miscellaneous'),
+('man1/notmuch-config','notmuch-config',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-config',
+ 'access notmuch configuration file','Miscellaneous'),
+('man1/notmuch-count','notmuch-count',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-count',
+ 'count messages matching the given search terms','Miscellaneous'),
+('man1/notmuch-dump','notmuch-dump',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-dump',
+ 'creates a plain-text dump of the tags of each message','Miscellaneous'),
+('man5/notmuch-hooks','notmuch-hooks',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-hooks',
+ 'hooks for notmuch','Miscellaneous'),
+('man1/notmuch-insert','notmuch-insert',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-insert',
+ 'add a message to the maildir and notmuch database','Miscellaneous'),
+('man1/notmuch-new','notmuch-new',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-new',
+ 'incorporate new mail into the notmuch database','Miscellaneous'),
+('man1/notmuch-reply','notmuch-reply',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-reply',
+ 'constructs a reply template for a set of messages','Miscellaneous'),
+('man1/notmuch-restore','notmuch-restore',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-restore',
+ 'restores the tags from the given file (see notmuch dump)','Miscellaneous'),
+('man1/notmuch-search','notmuch-search',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-search',
+ 'search for messages matching the given search terms','Miscellaneous'),
+('man7/notmuch-search-terms','notmuch-search-terms',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-search-terms',
+ 'syntax for notmuch queries','Miscellaneous'),
+('man1/notmuch-show','notmuch-show',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-show',
+ 'show messages matching the given search terms','Miscellaneous'),
+('man1/notmuch-tag','notmuch-tag',u'notmuch Documentation',
+ u'Carl Worth and many others', 'notmuch-tag',
+ 'add/remove tags for all messages matching the search terms','Miscellaneous'),
+]
--- /dev/null
+# Doxyfile 1.8.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "Notmuch 0.18"
+PROJECT_NUMBER =
+PROJECT_BRIEF =
+PROJECT_LOGO =
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+TCL_SUBST =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = YES
+LOOKUP_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = NO
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = NO
+GENERATE_DEPRECATEDLIST= NO
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_FILES = NO
+SHOW_NAMESPACES = NO
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = lib/notmuch.h
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS =
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = NO
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = YES
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = __DOXYGEN__
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+EXTERNAL_PAGES = NO
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = NO
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = YES
+GENERATE_LEGEND = NO
+DOT_CLEANUP = YES
--- /dev/null
+
+Welcome to notmuch's documentation!
+===================================
+
+Contents:
+
+.. toctree::
+ :titlesonly:
+
+ man1/notmuch
+ man1/notmuch-compact
+ man1/notmuch-config
+ man1/notmuch-count
+ man1/notmuch-dump
+ man5/notmuch-hooks
+ man1/notmuch-insert
+ man1/notmuch-new
+ man1/notmuch-reply
+ man1/notmuch-restore
+ man1/notmuch-search
+ man7/notmuch-search-terms
+ man1/notmuch-show
+ man1/notmuch-tag
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
--- /dev/null
+===============
+notmuch-compact
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **compact** [--quiet] [--backup=<*directory*>]
+
+DESCRIPTION
+===========
+
+The **compact** command can be used to compact the notmuch database.
+This can both reduce the space required by the database and improve
+lookup performance.
+
+The compacted database is built in a temporary directory and is later
+moved into the place of the origin database. The original uncompacted
+database is discarded, unless the ``--backup=``\ <directory> option is
+used.
+
+Note that the database write lock will be held during the compaction
+process (which may be quite long) to protect data integrity.
+
+Supported options for **compact** include
+
+ ``--backup=``\ <directory>
+ Save the current database to the given directory before
+ replacing it with the compacted database. The backup directory
+ must not exist and it must reside on the same mounted filesystem
+ as the current database.
+
+ ``--quiet``
+ Do not report database compaction progress to stdout.
+
+ENVIRONMENT
+===========
+
+The following environment variables can be used to control the behavior
+of notmuch.
+
+**NOTMUCH\_CONFIG**
+ Specifies the location of the notmuch configuration file. Notmuch
+ will use ${HOME}/.notmuch-config if this variable is not set.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-count(1)**, **notmuch-dump(1)**,
+**notmuch-hooks(5)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+==============
+notmuch-config
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **config** **get** <*section*>.<*item*>
+
+**notmuch** **config** **set** <*section*>.<*item*> [*value* ...]
+
+**notmuch** **config** **list**
+
+DESCRIPTION
+===========
+
+The **config** command can be used to get or set settings in the notmuch
+configuration file.
+
+ **get**
+ The value of the specified configuration item is printed to
+ stdout. If the item has multiple values (it is a list), each
+ value is separated by a newline character.
+
+ **set**
+ The specified configuration item is set to the given value. To
+ specify a multiple-value item (a list), provide each value as a
+ separate command-line argument.
+
+ If no values are provided, the specified configuration item will
+ be removed from the configuration file.
+
+ **list**
+ Every configuration item is printed to stdout, each on a
+ separate line of the form:
+
+ *section*.\ *item*\ =\ *value*
+
+ No additional whitespace surrounds the dot or equals sign
+ characters. In a multiple-value item (a list), the values are
+ separated by semicolon characters.
+
+The available configuration items are described below.
+
+ **database.path**
+ The top-level directory where your mail currently exists and to
+ where mail will be delivered in the future. Files should be
+ individual email messages. Notmuch will store its database
+ within a sub-directory of the path configured here named
+ ``.notmuch``.
+
+ **user.name**
+ Your full name.
+
+ **user.primary\_email**
+ Your primary email address.
+
+ **user.other\_email**
+ A list of other email addresses at which you receive email.
+
+ **new.tags**
+ A list of tags that will be added to all messages incorporated
+ by **notmuch new**.
+
+ **new.ignore**
+ A list of file and directory names, without path, that will not
+ be searched for messages by **notmuch new**. All the files and
+ directories matching any of the names specified here will be
+ ignored, regardless of the location in the mail store directory
+ hierarchy.
+
+ **search.exclude\_tags**
+ A list of tags that will be excluded from search results by
+ default. Using an excluded tag in a query will override that
+ exclusion.
+
+ **maildir.synchronize\_flags**
+ If true, then the following maildir flags (in message filenames)
+ will be synchronized with the corresponding notmuch tags:
+
+ +--------+-----------------------------------------------+
+ | Flag | Tag |
+ +========+===============================================+
+ | D | draft |
+ +--------+-----------------------------------------------+
+ | F | flagged |
+ +--------+-----------------------------------------------+
+ | P | passed |
+ +--------+-----------------------------------------------+
+ | R | replied |
+ +--------+-----------------------------------------------+
+ | S | unread (added when 'S' flag is not present) |
+ +--------+-----------------------------------------------+
+
+ The **notmuch new** command will notice flag changes in
+ filenames and update tags, while the **notmuch tag** and
+ **notmuch restore** commands will notice tag changes and update
+ flags in filenames.
+
+ If there have been any changes in the maildir (new messages
+ added, old ones removed or renamed, maildir flags changed,
+ etc.), it is advisable to run **notmuch new** before **notmuch
+ tag** or **notmuch restore** commands to ensure the tag changes
+ are properly synchronized to the maildir flags, as the commands
+ expect the database and maildir to be in sync.
+
+ENVIRONMENT
+===========
+
+The following environment variables can be used to control the behavior
+of notmuch.
+
+**NOTMUCH\_CONFIG**
+ Specifies the location of the notmuch configuration file. Notmuch
+ will use ${HOME}/.notmuch-config if this variable is not set.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-count(1)**, **notmuch-dump(1)**,
+**notmuch-hooks(5)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+=============
+notmuch-count
+=============
+
+SYNOPSIS
+========
+
+**notmuch** **count** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Count messages matching the search terms.
+
+The number of matching messages (or threads) is output to stdout.
+
+With no search terms, a count of all messages (or threads) in the
+database will be displayed.
+
+See **notmuch-search-terms(7)** for details of the supported syntax for
+<search-terms>.
+
+Supported options for **count** include
+
+ ``--output=(messages|threads|files)``
+
+ **messages**
+ Output the number of matching messages. This is the default.
+
+ **threads**
+ Output the number of matching threads.
+
+ **files**
+ Output the number of files associated with matching
+ messages. This may be bigger than the number of matching
+ messages due to duplicates (i.e. multiple files having the
+ same message-id).
+
+ ``--exclude=(true|false)``
+ Specify whether to omit messages matching search.tag\_exclude
+ from the count (the default) or not.
+
+ ``--batch``
+ Read queries from a file (stdin by default), one per line, and
+ output the number of matching messages (or threads) to stdout,
+ one per line. On an empty input line the count of all messages
+ (or threads) in the database will be output. This option is not
+ compatible with specifying search terms on the command line.
+
+ ``--input=``\ <filename>
+ Read input from given file, instead of from stdin. Implies
+ ``--batch``.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-dump(1)**,
+**notmuch-hooks(5)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+============
+notmuch-dump
+============
+
+SYNOPSIS
+========
+
+**notmuch** **dump** [--format=(batch-tag|sup)] [--] [--output=<*file*>] [--] [<*search-term*> ...]
+
+DESCRIPTION
+===========
+
+Dump tags for messages matching the given search terms.
+
+Output is to the given filename, if any, or to stdout.
+
+These tags are the only data in the notmuch database that can't be
+recreated from the messages themselves. The output of notmuch dump is
+therefore the only critical thing to backup (and much more friendly to
+incremental backup than the native database files.)
+
+``--gzip``
+ Compress the output in a format compatible with **gzip(1)**.
+
+``--format=(sup|batch-tag)``
+ Notmuch restore supports two plain text dump formats, both with one
+ message-id per line, followed by a list of tags.
+
+ **batch-tag**
+ The default **batch-tag** dump format is intended to more robust
+ against malformed message-ids and tags containing whitespace or
+ non-\ **ascii(7)** characters. Each line has the form
+
+ +<*encoded-tag*\ > +<*encoded-tag*\ > ... --
+ id:<*quoted-message-id*\ >
+
+ Tags are hex-encoded by replacing every byte not matching the
+ regex **[A-Za-z0-9@=.,\_+-]** with **%nn** where nn is the two
+ digit hex encoding. The message ID is a valid Xapian query,
+ quoted using Xapian boolean term quoting rules: if the ID
+ contains whitespace or a close paren or starts with a double
+ quote, it must be enclosed in double quotes and double quotes
+ inside the ID must be doubled. The astute reader will notice
+ this is a special case of the batch input format for
+ **notmuch-tag(1)**; note that the single message-id query is
+ mandatory for **notmuch-restore(1)**.
+
+ **sup**
+ The **sup** dump file format is specifically chosen to be
+ compatible with the format of files produced by sup-dump. So if
+ you've previously been using sup for mail, then the **notmuch
+ restore** command provides you a way to import all of your tags
+ (or labels as sup calls them). Each line has the following form
+
+ <*message-id*\ > **(** <*tag*\ > ... **)**
+
+ with zero or more tags are separated by spaces. Note that
+ (malformed) message-ids may contain arbitrary non-null
+ characters. Note also that tags with spaces will not be
+ correctly restored with this format.
+
+ With no search terms, a dump of all messages in the database will be
+ generated. A "--" argument instructs notmuch that the remaining
+ arguments are search terms.
+
+ See **notmuch-search-terms(7)** for details of the supported syntax
+ for <search-terms>.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-hooks(5)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+==============
+notmuch-insert
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **insert** [option ...] [+<*tag*>|-<*tag*> ...]
+
+DESCRIPTION
+===========
+
+**notmuch insert** reads a message from standard input and delivers it
+into the maildir directory given by configuration option
+**database.path**, then incorporates the message into the notmuch
+database. It is an alternative to using a separate tool to deliver the
+message then running **notmuch new** afterwards.
+
+The new message will be tagged with the tags specified by the
+**new.tags** configuration option, then by operations specified on the
+command-line: tags prefixed by '+' are added while those prefixed by '-'
+are removed.
+
+If the new message is a duplicate of an existing message in the database
+(it has same Message-ID), it will be added to the maildir folder and
+notmuch database, but the tags will not be changed.
+
+Option arguments must appear before any tag operation arguments.
+Supported options for **insert** include
+
+ ``--folder=<``\ folder\ **>**
+ Deliver the message to the specified folder, relative to the
+ top-level directory given by the value of **database.path**. The
+ default is to deliver to the top-level directory.
+
+ ``--create-folder``
+ Try to create the folder named by the ``--folder`` option, if it
+ does not exist. Otherwise the folder must already exist for mail
+ delivery to succeed.
+
+EXIT STATUS
+===========
+
+This command returns exit status 0 if the message was successfully added
+to the mail directory, even if the message could not be indexed and
+added to the notmuch database. In the latter case, a warning will be
+printed to standard error but the message file will be left on disk.
+
+If the message could not be written to disk then a non-zero exit status
+is returned.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-reply(1)**,
+**notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+===========
+notmuch-new
+===========
+
+SYNOPSIS
+========
+
+**notmuch** **new** [options]
+
+DESCRIPTION
+===========
+
+Find and import any new messages to the database.
+
+The **new** command scans all sub-directories of the database,
+performing full-text indexing on new messages that are found. Each new
+message will automatically be tagged with both the **inbox** and
+**unread** tags.
+
+You should run **notmuch new** once after first running **notmuch
+setup** to create the initial database. The first run may take a long
+time if you have a significant amount of mail (several hundred thousand
+messages or more). Subsequently, you should run **notmuch new** whenever
+new mail is delivered and you wish to incorporate it into the database.
+These subsequent runs will be much quicker than the initial run.
+
+Invoking ``notmuch`` with no command argument will run **new** if
+**notmuch setup** has previously been completed, but **notmuch new** has
+not previously been run.
+
+**notmuch new** updates tags according to maildir flag changes if the
+**maildir.synchronize\_flags** configuration option is enabled. See
+**notmuch-config(1)** for details.
+
+The **new** command supports hooks. See **notmuch-hooks(5)** for more
+details on hooks.
+
+Supported options for **new** include
+
+ ``--no-hooks``
+ Prevents hooks from being run.
+
+ ``--quiet``
+ Do not print progress or results.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+=============
+notmuch-reply
+=============
+
+SYNOPSIS
+========
+
+**notmuch** **reply** [option ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Constructs a reply template for a set of messages.
+
+To make replying to email easier, **notmuch reply** takes an existing
+set of messages and constructs a suitable mail template. The Reply-to:
+header (if any, otherwise From:) is used for the To: address. Unless
+``--reply-to=sender`` is specified, values from the To: and Cc: headers
+are copied, but not including any of the current user's email addresses
+(as configured in primary\_mail or other\_email in the .notmuch-config
+file) in the recipient list.
+
+It also builds a suitable new subject, including Re: at the front (if
+not already present), and adding the message IDs of the messages being
+replied to to the References list and setting the In-Reply-To: field
+correctly.
+
+Finally, the original contents of the emails are quoted by prefixing
+each line with '> ' and included in the body.
+
+The resulting message template is output to stdout.
+
+Supported options for **reply** include
+
+ ``--format=``\ (**default**\ \|\ **json**\ \|\ **sexp**\ \|\ **headers-only**)
+
+ **default**
+ Includes subject and quoted message body as an RFC 2822
+ message.
+
+ **json**
+ Produces JSON output containing headers for a reply message
+ and the contents of the original message. This output can be
+ used by a client to create a reply message intelligently.
+
+ **sexp**
+ Produces S-Expression output containing headers for a reply
+ message and the contents of the original message. This
+ output can be used by a client to create a reply message
+ intelligently.
+
+ **headers-only**
+ Only produces In-Reply-To, References, To, Cc, and Bcc
+ headers.
+
+ ``--format-version=N``
+ Use the specified structured output format version. This is
+ intended for programs that invoke **notmuch(1)** internally. If
+ omitted, the latest supported version will be used.
+
+ ``--reply-to=``\ (**all**\ \|\ **sender**)
+
+ **all** (default)
+ Replies to all addresses.
+
+ **sender**
+ Replies only to the sender. If replying to user's own
+ message (Reply-to: or From: header is one of the user's
+ configured email addresses), try To:, Cc:, and Bcc: headers
+ in this order, and copy values from the first that contains
+ something other than only the user's addresses.
+
+ ``--decrypt``
+ Decrypt any MIME encrypted parts found in the selected content
+ (ie. "multipart/encrypted" parts). Status of the decryption will
+ be reported (currently only supported with --format=json and
+ --format=sexp) and on successful decryption the
+ multipart/encrypted part will be replaced by the decrypted
+ content.
+
+ Decryption expects a functioning **gpg-agent(1)** to provide any
+ needed credentials. Without one, the decryption will fail.
+
+See **notmuch-search-terms(7)** for details of the supported syntax for
+<search-terms>.
+
+Note: It is most common to use **notmuch reply** with a search string
+matching a single message, (such as id:<message-id>), but it can be
+useful to reply to several messages at once. For example, when a series
+of patches are sent in a single thread, replying to the entire thread
+allows for the reply to comment on issues found in multiple patches. The
+default format supports replying to multiple messages at once, but the
+JSON and S-Expression formats do not.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+===============
+notmuch-restore
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **restore** [--accumulate] [--format=(auto|batch-tag|sup)] [--input=<*filename*>]
+
+DESCRIPTION
+===========
+
+Restores the tags from the given file (see **notmuch dump**).
+
+The input is read from the given filename, if any, or from stdin.
+
+Supported options for **restore** include
+
+ ``--accumulate``
+ The union of the existing and new tags is applied, instead of
+ replacing each message's tags as they are read in from the dump
+ file.
+
+ ``--format=(sup|batch-tag|auto)``
+ Notmuch restore supports two plain text dump formats, with each
+ line specifying a message-id and a set of tags. For details of
+ the actual formats, see **notmuch-dump(1)**.
+
+ **sup**
+ The **sup** dump file format is specifically chosen to be
+ compatible with the format of files produced by sup-dump. So
+ if you've previously been using sup for mail, then the
+ **notmuch restore** command provides you a way to import all
+ of your tags (or labels as sup calls them).
+
+ **batch-tag**
+ The **batch-tag** dump format is intended to more robust
+ against malformed message-ids and tags containing whitespace
+ or non-\ **ascii(7)** characters. See **notmuch-dump(1)**
+ for details on this format.
+
+ **notmuch restore** updates the maildir flags according to
+ tag changes if the **maildir.synchronize\_flags**
+ configuration option is enabled. See **notmuch-config(1)**
+ for details.
+
+ **auto**
+ This option (the default) tries to guess the format from the
+ input. For correctly formed input in either supported
+ format, this heuristic, based the fact that batch-tag format
+ contains no parentheses, should be accurate.
+
+GZIPPED INPUT
+=============
+
+\ **notmuch restore** will detect if the input is compressed in
+**gzip(1)** format and automatically decompress it while reading. This
+detection does not depend on file naming and in particular works for
+standard input.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-reply(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+==============
+notmuch-search
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **search** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Search for messages matching the given search terms, and display as
+results the threads containing the matched messages.
+
+The output consists of one line per thread, giving a thread ID, the date
+of the newest (or oldest, depending on the sort option) matched message
+in the thread, the number of matched messages and total messages in the
+thread, the names of all participants in the thread, and the subject of
+the newest (or oldest) message.
+
+See **notmuch-search-terms(7)** for details of the supported syntax for
+<search-terms>.
+
+Supported options for **search** include
+
+ ``--format=``\ (**json**\ \|\ **sexp**\ \|\ **text**\ \|\ **text0**)
+ Presents the results in either JSON, S-Expressions, newline
+ character separated plain-text (default), or null character
+ separated plain-text (compatible with **xargs(1)** -0 option
+ where available).
+
+ ``--format-version=N``
+ Use the specified structured output format version. This is
+ intended for programs that invoke **notmuch(1)** internally. If
+ omitted, the latest supported version will be used.
+
+ ``--output=(summary|threads|messages|files|tags)``
+
+ **summary**
+ 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 the total number), the authors of the thread and
+ the subject.
+
+ **threads**
+ Output the thread IDs of all threads with any message
+ matching the search terms, either one per line
+ (--format=text), separated by null characters
+ (--format=text0), as a JSON array (--format=json), or an
+ S-Expression list (--format=sexp).
+
+ **messages**
+ Output the message IDs of all messages matching the search
+ terms, either one per line (--format=text), separated by
+ null characters (--format=text0), as a JSON array
+ (--format=json), or as an S-Expression list (--format=sexp).
+
+ **files**
+ Output the filenames of all messages matching the search
+ terms, either one per line (--format=text), separated by
+ null characters (--format=text0), as a JSON array
+ (--format=json), or as an S-Expression list (--format=sexp).
+
+ Note that each message may have multiple filenames
+ associated with it. All of them are included in the output
+ (unless limited with the --duplicate=N option). This may
+ be particularly confusing for **folder:** or **path:**
+ searches in a specified directory, as the messages may
+ have duplicates in other directories that are included in
+ the output, although these files alone would not match the
+ search.
+
+ **tags**
+ Output all tags that appear on any message matching the
+ search terms, either one per line (--format=text), separated
+ by null characters (--format=text0), as a JSON array
+ (--format=json), or as an S-Expression list (--format=sexp).
+
+ ``--sort=``\ (**newest-first**\ \|\ **oldest-first**)
+ This option can be used to present results in either
+ chronological order (**oldest-first**) or reverse chronological
+ order (**newest-first**).
+
+ Note: The thread order will be distinct between these two
+ options (beyond being simply reversed). When sorting by
+ **oldest-first** the threads will be sorted by the oldest
+ message in each thread, but when sorting by **newest-first** the
+ threads will be sorted by the newest message in each thread.
+
+ By default, results will be displayed in reverse chronological
+ order, (that is, the newest results will be displayed first).
+
+ ``--offset=[-]N``
+ Skip displaying the first N results. With the leading '-', start
+ at the Nth result from the end.
+
+ ``--limit=N``
+ Limit the number of displayed results to N.
+
+ ``--exclude=(true|false|all|flag)``
+ A message is called "excluded" if it matches at least one tag in
+ search.tag\_exclude that does not appear explicitly in the
+ search terms. This option specifies whether to omit excluded
+ messages in the search process.
+
+ The default value, **true**, prevents excluded messages from
+ matching the search terms.
+
+ **all** additionally prevents excluded messages from appearing
+ in displayed results, in effect behaving as though the excluded
+ messages do not exist.
+
+ **false** allows excluded messages to match search terms and
+ appear in displayed results. Excluded messages are still marked
+ in the relevant outputs.
+
+ **flag** only has an effect when ``--output=summary``. The
+ output is almost identical to **false**, but the "match count"
+ is the number of matching non-excluded messages in the thread,
+ rather than the number of matching messages.
+
+ ``--duplicate=N``
+ Effective with ``--output=files``, output the Nth filename
+ associated with each message matching the query (N is 1-based).
+ If N is greater than the number of files associated with the
+ message, don't print anything.
+
+ Note that this option is orthogonal with the **folder:** search
+ prefix. The prefix matches messages based on filenames. This
+ option filters filenames of the matching messages.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-reply(1)**, **notmuch-restore(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+============
+notmuch-show
+============
+
+SYNOPSIS
+========
+
+**notmuch** **show** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Shows all messages matching the search terms.
+
+See **notmuch-search-terms(7)** for details of the supported syntax for
+<search-terms>.
+
+The messages will be grouped and sorted based on the threading (all
+replies to a particular message will appear immediately after that
+message in date order). The output is not indented by default, but depth
+tags are printed so that proper indentation can be performed by a
+post-processor (such as the emacs interface to notmuch).
+
+Supported options for **show** include
+
+ ``--entire-thread=(true|false)``
+ If true, **notmuch show** outputs all messages in the thread of
+ any message matching the search terms; if false, it outputs only
+ the matching messages. For ``--format=json`` and
+ ``--format=sexp`` this defaults to true. For other formats, this
+ defaults to false.
+
+ ``--format=(text|json|sexp|mbox|raw)``
+
+ **text** (default for messages)
+ The default plain-text format has all text-content MIME
+ parts decoded. Various components in the output,
+ (**message**, **header**, **body**, **attachment**, and MIME
+ **part**), will be delimited by easily-parsed markers. Each
+ marker consists of a Control-L character (ASCII decimal 12),
+ the name of the marker, and then either an opening or
+ closing brace, ('{' or '}'), to either open or close the
+ component. For a multipart MIME message, these parts will be
+ nested.
+
+ **json**
+ The output is formatted with Javascript Object Notation
+ (JSON). This format is more robust than the text format for
+ automated processing. The nested structure of multipart MIME
+ messages is reflected in nested JSON output. By default JSON
+ output includes all messages in a matching thread; that is,
+ by default,
+ ``--format=json`` sets ``--entire-thread``. The caller can
+ disable this behaviour by setting ``--entire-thread=false``.
+ The JSON output is always encoded as UTF-8 and any message
+ content included in the output will be charset-converted to
+ UTF-8.
+
+ **sexp**
+ The output is formatted as the Lisp s-expression (sexp)
+ equivalent of the JSON format above. Objects are formatted
+ as property lists whose keys are keywords (symbols preceded
+ by a colon). True is formatted as ``t`` and both false and
+ null are formatted as ``nil``. As for JSON, the s-expression
+ output is always encoded as UTF-8.
+
+ **mbox**
+ All matching messages are output in the traditional, Unix
+ mbox format with each message being prefixed by a line
+ beginning with "From " and a blank line separating each
+ message. Lines in the message content beginning with "From "
+ (preceded by zero or more '>' characters) have an additional
+ '>' character added. This reversible escaping is termed
+ "mboxrd" format and described in detail here:
+
+ http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
+
+ **raw** (default if --part is given)
+ Write the raw bytes of the given MIME part of a message to
+ standard out. For this format, it is an error to specify a
+ query that matches more than one message.
+
+ If the specified part is a leaf part, this outputs the
+ body of the part after performing content transfer
+ decoding (but no charset conversion). This is suitable for
+ saving attachments, for example.
+
+ For a multipart or message part, the output includes the
+ part headers as well as the body (including all child
+ parts). No decoding is performed because multipart and
+ message parts cannot have non-trivial content transfer
+ encoding. Consumers of this may need to implement MIME
+ decoding and similar functions.
+
+ ``--format-version=N``
+ Use the specified structured output format version. This is
+ intended for programs that invoke **notmuch(1)** internally. If
+ omitted, the latest supported version will be used.
+
+ ``--part=N``
+ Output the single decoded MIME part N of a single message. The
+ search terms must match only a single message. Message parts are
+ numbered in a depth-first walk of the message MIME structure,
+ and are identified in the 'json', 'sexp' or 'text' output
+ formats.
+
+ Note that even a message with no MIME structure or a single
+ body part still has two MIME parts: part 0 is the whole
+ message (headers and body) and part 1 is just the body.
+
+ ``--verify``
+ Compute and report the validity of any MIME cryptographic
+ signatures found in the selected content (ie. "multipart/signed"
+ parts). Status of the signature will be reported (currently only
+ supported with --format=json and --format=sexp), and the
+ multipart/signed part will be replaced by the signed data.
+
+ ``--decrypt``
+ Decrypt any MIME encrypted parts found in the selected content
+ (ie. "multipart/encrypted" parts). Status of the decryption will
+ be reported (currently only supported with --format=json and
+ --format=sexp) and on successful decryption the
+ multipart/encrypted part will be replaced by the decrypted
+ content.
+
+ Decryption expects a functioning **gpg-agent(1)** to provide any
+ needed credentials. Without one, the decryption will fail.
+
+ Implies --verify.
+
+ ``--exclude=(true|false)``
+ Specify whether to omit threads only matching
+ search.tag\_exclude from the search results (the default) or
+ not. In either case the excluded message will be marked with the
+ exclude flag (except when output=mbox when there is nowhere to
+ put the flag).
+
+ If --entire-thread is specified then complete threads are
+ returned regardless (with the excluded flag being set when
+ appropriate) but threads that only match in an excluded message
+ are not returned when ``--exclude=true.``
+
+ The default is ``--exclude=true.``
+
+ ``--body=(true|false)``
+ If true (the default) **notmuch show** includes the bodies of
+ the messages in the output; if false, bodies are omitted.
+ ``--body=false`` is only implemented for the json and sexp
+ formats and it is incompatible with ``--part > 0.``
+
+ This is useful if the caller only needs the headers as body-less
+ output is much faster and substantially smaller.
+
+ ``--include-html``
+ Include "text/html" parts as part of the output (currently only
+ supported with --format=json and --format=sexp). By default,
+ unless ``--part=N`` is used to select a specific part or
+ ``--include-html`` is used to include all "text/html" parts, no
+ part with content type "text/html" is included in the output.
+
+A common use of **notmuch show** is to display a single thread of email
+messages. For this, use a search term of "thread:<thread-id>" as can be
+seen in the first column of output from the **notmuch search** command.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-reply(1)**, **notmuch-restore(1)**,
+**notmuch-search(1)**, **notmuch-search-terms(7)**, **notmuch-tag(1)**
--- /dev/null
+===========
+notmuch-tag
+===========
+
+SYNOPSIS
+========
+
+**notmuch** **tag** [options ...] +<*tag*>|-<*tag*> [--] <*search-term*> ...
+
+**notmuch** **tag** **--batch** [--input=<*filename*>]
+
+DESCRIPTION
+===========
+
+Add/remove tags for all messages matching the search terms.
+
+See **notmuch-search-terms(7)** for details of the supported syntax for
+<*search-term*\ >.
+
+Tags prefixed by '+' are added while those prefixed by '-' are removed.
+For each message, tag changes are applied in the order they appear on
+the command line.
+
+The beginning of the search terms is recognized by the first argument
+that begins with neither '+' nor '-'. Support for an initial search term
+beginning with '+' or '-' is provided by allowing the user to specify a
+"--" argument to separate the tags from the search terms.
+
+**notmuch tag** updates the maildir flags according to tag changes if
+the **maildir.synchronize\_flags** configuration option is enabled. See
+**notmuch-config(1)** for details.
+
+Supported options for **tag** include
+
+ ``--remove-all``
+ Remove all tags from each message matching the search terms
+ before applying the tag changes appearing on the command line.
+ This means setting the tags of each message to the tags to be
+ added. If there are no tags to be added, the messages will have
+ no tags.
+
+ ``--batch``
+ Read batch tagging operations from a file (stdin by default).
+ This is more efficient than repeated **notmuch tag**
+ invocations. See `TAG FILE FORMAT <#tag_file_format>`__ below
+ for the input format. This option is not compatible with
+ specifying tagging on the command line.
+
+ ``--input=``\ <filename>
+ Read input from given file, instead of from stdin. Implies
+ ``--batch``.
+
+TAG FILE FORMAT
+===============
+
+The input must consist of lines of the format:
+
++<*tag*\ >\|-<*tag*\ > [...] [--] <*query*\ >
+
+Each line is interpreted similarly to **notmuch tag** command line
+arguments. The delimiter is one or more spaces ' '. Any characters in
+<*tag*\ > **may** be hex-encoded with %NN where NN is the hexadecimal
+value of the character. To hex-encode a character with a multi-byte
+UTF-8 encoding, hex-encode each byte. Any spaces in <tag> **must** be
+hex-encoded as %20. Any characters that are not part of <*tag*\ > **must
+not** be hex-encoded.
+
+In the future tag:"tag with spaces" style quoting may be supported for
+<*tag*\ > as well; for this reason all double quote characters in
+<*tag*\ > **should** be hex-encoded.
+
+The <*query*\ > should be quoted using Xapian boolean term quoting
+rules: if a term contains whitespace or a close paren or starts with a
+double quote, it must be enclosed in double quotes (not including any
+prefix) and double quotes inside the term must be doubled (see below for
+examples).
+
+Leading and trailing space ' ' is ignored. Empty lines and lines
+beginning with '#' are ignored.
+
+EXAMPLE
+-------
+
+The following shows a valid input to batch tagging. Note that only the
+isolated '\*' acts as a wildcard. Also note the two different quotings
+of the tag **space in tags**
+
+::
+
+ +winner *
+ +foo::bar%25 -- (One and Two) or (One and tag:winner)
+ +found::it -- tag:foo::bar%
+ # ignore this line and the next
+
+ +space%20in%20tags -- Two
+ # add tag '(tags)', among other stunts.
+ +crazy{ +(tags) +&are +#possible\ -- tag:"space in tags"
+ +match*crazy -- tag:crazy{
+ +some_tag -- id:"this is ""nauty)"""
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-reply(1)**, **notmuch-restore(1)**,
+**notmuch-search(1)**, **notmuch-search-terms(7)**, **notmuch-show(1)**,
--- /dev/null
+=======
+notmuch
+=======
+
+SYNOPSIS
+========
+
+**notmuch** [option ...] **command** [arg ...]
+
+DESCRIPTION
+===========
+
+Notmuch is a command-line based program for indexing, searching,
+reading, and tagging large collections of email messages.
+
+This page describes how to get started using notmuch from the command
+line, and gives a brief overview of the commands available. For more
+information on e.g. **notmuch show** consult the **notmuch-show(1)** man
+page, also accessible via **notmuch help show**
+
+The quickest way to get started with Notmuch is to simply invoke the
+``notmuch`` command with no arguments, which will interactively guide
+you through the process of indexing your mail.
+
+NOTE
+====
+
+While the command-line program ``notmuch`` provides powerful
+functionality, it does not provide the most convenient interface for
+that functionality. More sophisticated interfaces are expected to be
+built on top of either the command-line interface, or more likely, on
+top of the notmuch library interface. See http://notmuchmail.org for
+more about alternate interfaces to notmuch. The emacs-based interface to
+notmuch (available under **emacs/** in the Notmuch source distribution)
+is probably the most widely used at this time.
+
+OPTIONS
+=======
+
+Supported global options for ``notmuch`` include
+
+ ``--help``
+ Print a synopsis of available commands and exit.
+
+ ``--version``
+ Print the installed version of notmuch, and exit.
+
+ ``--config=FILE``
+ Specify the configuration file to use. This overrides any
+ configuration file specified by ${NOTMUCH\_CONFIG}.
+
+COMMANDS
+========
+
+SETUP
+-----
+
+The **notmuch setup** command is used to configure Notmuch for first
+use, (or to reconfigure it later).
+
+The setup command will prompt for your full name, your primary email
+address, any alternate email addresses you use, and the directory
+containing your email archives. Your answers will be written to a
+configuration file in ${NOTMUCH\_CONFIG} (if set) or
+${HOME}/.notmuch-config . This configuration file will be created with
+descriptive comments, making it easy to edit by hand later to change the
+configuration. Or you can run **notmuch setup** again to change the
+configuration.
+
+The mail directory you specify can contain any number of sub-directories
+and should primarily contain only files with individual email messages
+(eg. maildir or mh archives are perfect). If there are other, non-email
+files (such as indexes maintained by other email programs) then notmuch
+will do its best to detect those and ignore them.
+
+Mail storage that uses mbox format, (where one mbox file contains many
+messages), will not work with notmuch. If that's how your mail is
+currently stored, it is recommended you first convert it to maildir
+format with a utility such as mb2md before running **notmuch setup .**
+
+Invoking ``notmuch`` with no command argument will run **setup** if the
+setup command has not previously been completed.
+
+OTHER COMMANDS
+--------------
+
+Several of the notmuch commands accept search terms with a common
+syntax. See **notmuch-search-terms**\ (7) for more details on the
+supported syntax.
+
+The **search**, **show** and **count** commands are used to query the
+email database.
+
+The **reply** command is useful for preparing a template for an email
+reply.
+
+The **tag** command is the only command available for manipulating
+database contents.
+
+The **dump** and **restore** commands can be used to create a textual
+dump of email tags for backup purposes, and to restore from that dump.
+
+The **config** command can be used to get or set settings in the notmuch
+configuration file.
+
+ENVIRONMENT
+===========
+
+The following environment variables can be used to control the behavior
+of notmuch.
+
+**NOTMUCH\_CONFIG**
+ Specifies the location of the notmuch configuration file. Notmuch
+ will use ${HOME}/.notmuch-config if this variable is not set.
+
+**NOTMUCH\_TALLOC\_REPORT**
+ Location to write a talloc memory usage report. See
+ **talloc\_enable\_leak\_report\_full** in **talloc(3)** for more
+ information.
+
+**NOTMUCH\_DEBUG\_QUERY**
+ If set to a non-empty value, the notmuch library will print (to
+ stderr) Xapian queries it constructs.
+
+SEE ALSO
+========
+
+**notmuch-config(1)**, **notmuch-count(1)**, **notmuch-dump(1)**,
+**notmuch-hooks(5)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
+
+The notmuch website: **http://notmuchmail.org**
+
+CONTACT
+=======
+
+Feel free to send questions, comments, or kudos to the notmuch mailing
+list <notmuch@notmuchmail.org> . Subscription is not required before
+posting, but is available from the notmuchmail.org website.
+
+Real-time interaction with the Notmuch community is available via IRC
+(server: irc.freenode.net, channel: #notmuch).
--- /dev/null
+=============
+notmuch-hooks
+=============
+
+SYNOPSIS
+========
+
+ $DATABASEDIR/.notmuch/hooks/*
+
+DESCRIPTION
+===========
+
+Hooks are scripts (or arbitrary executables or symlinks to such) that
+notmuch invokes before and after certain actions. These scripts reside
+in the .notmuch/hooks directory within the database directory and must
+have executable permissions.
+
+The currently available hooks are described below.
+
+ **pre-new**
+ This hook is invoked by the **new** command before scanning or
+ importing new messages into the database. If this hook exits
+ with a non-zero status, notmuch will abort further processing of
+ the **new** command.
+
+ Typically this hook is used for fetching or delivering new mail
+ to be imported into the database.
+
+ **post-new**
+ This hook is invoked by the **new** command after new messages
+ have been imported into the database and initial tags have been
+ applied. The hook will not be run if there have been any errors
+ during the scan or import.
+
+ Typically this hook is used to perform additional query-based
+ tagging on the imported messages.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-insert(1)**, **notmuch-new(1)**,
+**notmuch-reply(1)**, **notmuch-restore(1)**, **notmuch-search(1)**,
+**notmuch-search-terms(7)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+====================
+notmuch-search-terms
+====================
+
+SYNOPSIS
+========
+
+**notmuch** **count** [option ...] <*search-term*> ...
+
+**notmuch** **dump** [--format=(batch-tag|sup)] [--] [--output=<*file*>] [--] [<*search-term*> ...]
+
+**notmuch** **search** [option ...] <*search-term*> ...
+
+**notmuch** **show** [option ...] <*search-term*> ...
+
+**notmuch** **tag** +<*tag*> ... -<*tag*> [--] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Several notmuch commands accept a common syntax for search terms.
+
+The search terms can consist of free-form text (and quoted phrases)
+which will match all messages that contain all of the given
+terms/phrases in the body, the subject, or any of the sender or
+recipient headers.
+
+As a special case, a search string consisting of exactly a single
+asterisk ("\*") will match all messages.
+
+In addition to free text, the following prefixes can be used to force
+terms to match against specific portions of an email, (where <brackets>
+indicate user-supplied values):
+
+- from:<name-or-address>
+
+- to:<name-or-address>
+
+- subject:<word-or-quoted-phrase>
+
+- attachment:<word>
+
+- tag:<tag> (or is:<tag>)
+
+- id:<message-id>
+
+- thread:<thread-id>
+
+- folder:<maildir-folder>
+
+- path:<directory-path> or path:<directory-path>/**
+
+- date:<since>..<until>
+
+The **from:** prefix is used to match the name or address of the sender
+of an email message.
+
+The **to:** prefix is used to match the names or addresses of any
+recipient of an email message, (whether To, Cc, or Bcc).
+
+Any term prefixed with **subject:** will match only text from the
+subject of an email. Searching for a phrase in the subject is supported
+by including quotation marks around the phrase, immediately following
+**subject:**.
+
+The **attachment:** prefix can be used to search for specific filenames
+(or extensions) of attachments to email messages.
+
+For **tag:** and **is:** valid tag values include **inbox** and
+**unread** by default for new messages added by **notmuch new** as well
+as any other tag values added manually with **notmuch tag**.
+
+For **id:**, message ID values are the literal contents of the
+Message-ID: header of email messages, but without the '<', '>'
+delimiters.
+
+The **thread:** prefix can be used with the thread ID values that are
+generated internally by notmuch (and do not appear in email messages).
+These thread ID values can be seen in the first column of output from
+**notmuch search**
+
+The **path:** prefix searches for email messages that are in
+particular directories within the mail store. The directory must be
+specified relative to the top-level maildir (and without the leading
+slash). By default, **path:** matches messages in the specified
+directory only. The "/\*\*" suffix can be used to match messages in
+the specified directory and all its subdirectories recursively.
+**path:""** matches messages in the root of the mail store and,
+likewise, **path:\*\*** matches all messages.
+
+The **folder:** prefix searches for email messages by maildir or MH
+folder. For MH-style folders, this is equivalent to **path:**. For
+maildir, this includes messages in the "new" and "cur"
+subdirectories. The exact syntax for maildir folders depends on your
+mail configuration. For maildir++, **folder:""** matches the inbox
+folder (which is the root in maildir++), other folder names always
+start with ".", and nested folders are separated by "."s, such as
+**folder:.classes.topology**. For "file system" maildir, the inbox is
+typically **folder:INBOX** and nested folders are separated by
+slashes, such as **folder:classes/topology**.
+
+Both **path:** and **folder:** will find a message if *any* copy of
+that message is in the specific directory/folder.
+
+The **date:** prefix can be used to restrict the results to only
+messages within a particular time range (based on the Date: header) with
+a range syntax of:
+
+date:<since>..<until>
+
+See **DATE AND TIME SEARCH** below for details on the range expression,
+and supported syntax for <since> and <until> date and time expressions.
+
+The time range can also be specified using timestamps with a syntax of:
+
+<initial-timestamp>..<final-timestamp>
+
+Each timestamp is a number representing the number of seconds since
+1970-01-01 00:00:00 UTC.
+
+In addition to individual terms, multiple terms can be combined with
+Boolean operators ( **and**, **or**, **not** , etc.). Each term in the
+query will be implicitly connected by a logical AND if no explicit
+operator is provided, (except that terms with a common prefix will be
+implicitly combined with OR until we get Xapian defect #402 fixed).
+
+Parentheses can also be used to control the combination of the Boolean
+operators, but will have to be protected from interpretation by the
+shell, (such as by putting quotation marks around any parenthesized
+expression).
+
+DATE AND TIME SEARCH
+====================
+
+notmuch understands a variety of standard and natural ways of expressing
+dates and times, both in absolute terms ("2012-10-24") and in relative
+terms ("yesterday"). Any number of relative terms can be combined ("1
+hour 25 minutes") and an absolute date/time can be combined with
+relative terms to further adjust it. A non-exhaustive description of the
+syntax supported for absolute and relative terms is given below.
+
+The range expression
+--------------------
+
+date:<since>..<until>
+
+The above expression restricts the results to only messages from <since>
+to <until>, based on the Date: header.
+
+<since> and <until> can describe imprecise times, such as "yesterday".
+In this case, <since> is taken as the earliest time it could describe
+(the beginning of yesterday) and <until> is taken as the latest time it
+could describe (the end of yesterday). Similarly, date:january..february
+matches from the beginning of January to the end of February.
+
+Currently, we do not support spaces in range expressions. You can
+replace the spaces with '\_', or (in most cases) '-', or (in some cases)
+leave the spaces out altogether. Examples in this man page use spaces
+for clarity.
+
+Open-ended ranges are supported (since Xapian 1.2.1), i.e. it's possible
+to specify date:..<until> or date:<since>.. to not limit the start or
+end time, respectively. Pre-1.2.1 Xapian does not report an error on
+open ended ranges, but it does not work as expected either.
+
+Entering date:expr without ".." (for example date:yesterday) won't work,
+as it's not interpreted as a range expression at all. You can achieve
+the expected result by duplicating the expr both sides of ".." (for
+example date:yesterday..yesterday).
+
+Relative date and time
+----------------------
+
+[N\|number]
+(years\|months\|weeks\|days\|hours\|hrs\|minutes\|mins\|seconds\|secs)
+[...]
+
+All refer to past, can be repeated and will be accumulated.
+
+Units can be abbreviated to any length, with the otherwise ambiguous
+single m being m for minutes and M for months.
+
+Number can also be written out one, two, ..., ten, dozen, hundred.
+Additionally, the unit may be preceded by "last" or "this" (e.g., "last
+week" or "this month").
+
+When combined with absolute date and time, the relative date and time
+specification will be relative from the specified absolute date and
+time.
+
+Examples: 5M2d, two weeks
+
+Supported absolute time formats
+-------------------------------
+
+- H[H]:MM[:SS] [(am\|a.m.\|pm\|p.m.)]
+
+- H[H] (am\|a.m.\|pm\|p.m.)
+
+- HHMMSS
+
+- now
+
+- noon
+
+- midnight
+
+- Examples: 17:05, 5pm
+
+Supported absolute date formats
+-------------------------------
+
+- YYYY-MM[-DD]
+
+- DD-MM[-[YY]YY]
+
+- MM-YYYY
+
+- M[M]/D[D][/[YY]YY]
+
+- M[M]/YYYY
+
+- D[D].M[M][.[YY]YY]
+
+- D[D][(st\|nd\|rd\|th)] Mon[thname] [YYYY]
+
+- Mon[thname] D[D][(st\|nd\|rd\|th)] [YYYY]
+
+- Wee[kday]
+
+Month names can be abbreviated at three or more characters.
+
+Weekday names can be abbreviated at three or more characters.
+
+Examples: 2012-07-31, 31-07-2012, 7/31/2012, August 3
+
+Time zones
+----------
+
+- (+\|-)HH:MM
+
+- (+\|-)HH[MM]
+
+Some time zone codes, e.g. UTC, EET.
+
+SEE ALSO
+========
+
+**notmuch(1)**, **notmuch-config(1)**, **notmuch-count(1)**,
+**notmuch-dump(1)**, **notmuch-hooks(5)**, **notmuch-insert(1)**,
+**notmuch-new(1)**, **notmuch-reply(1)**, **notmuch-restore(1)**,
+**notmuch-search(1)**, **notmuch-show(1)**, **notmuch-tag(1)**
--- /dev/null
+import sys
+
+srcdir = sys.argv[1]
+builddir = sys.argv[2]
+outfile = sys.argv[3]
+
+sys.path.insert(0, srcdir)
+import conf
+
+roff_files = []
+rst_files = []
+for page in conf.man_pages:
+ rst_files = rst_files + ["{0:s}/{1:s}.rst".format(srcdir,page[0])]
+ roff_files = roff_files + ["{0:s}/man/{1:s}.{2:d}".format(builddir,page[0],page[4])]
+
+with open(outfile, 'w') as out:
+ out.write('MAN_ROFF_FILES := ' + ' \\\n\t'.join(roff_files) + '\n')
+ out.write('MAN_RST_FILES := ' + ' \\\n\t'.join(rst_files) + '\n')
--- /dev/null
+=============
+notmuch-emacs
+=============
+
+About this Manual
+=================
+
+This manual covers only the Emacs interface to Notmuch. For information
+on the command line interface, see See section “Description” in Notmuch
+Manual Pager. To save typing, we will sometimes use *notmuch* in this
+manual to refer to the Emacs interface to Notmuch. If the distinction
+should every be important, we’ll refer to the Emacs interface as
+*notmuch-emacs*.
+
+Notmuch-emacs is highly customizable via the 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, but you can usually find the most detailed
+description in the variables docstring.
+
+notmuch-hello
+=============
+
+.. index::
+ single: notmuch-hello
+ single: notmuch
+
+``notmuch-hello`` is the main entry point for Notmuch. You can start it
+with ``M-x notmuch`` or ``M-x notmuch-hello``. The startup screen looks
+something like the following. There are some hints at the bottom of the
+screen. There are three main parts to the notmuch-hello screen,
+discussed below. The **bold** text indicates buttons you can click with
+a mouse or by positioning the cursor and pressing ``<return>``
+
+| Welcome to **notmuch** You have 52 messages.
+|
+| Saved searches: **[edit]**
+|
+| 52 **inbox** 52 **unread**
+|
+| Search: ____________________________________
+|
+| All tags: **[show]**
+|
+| Type a search query and hit RET to view matching threads.
+| Edit saved searches with the ``edit`` button.
+| Hit RET or click on a saved search or tag name to view matching threads.
+| ``=`` to refresh this screen. ``s`` to search messages. ``q`` to quit.
+| **Customize** this page.
+
+You can change the overall appearance of the notmuch-hello screen by
+customizing the variable :index:`notmuch-hello-sections`.
+
+
+
+notmuch-hello key bindings
+--------------------------
+
+``<tab>``
+ Move to the next widget (button or text entry field)
+
+``<backspace>``
+ Move to the previous widget.
+
+``<return>``
+ Activate the current widget.
+
+``=``
+ Refresh the buffer; mainly update the counts of messages for various
+ saved searches.
+
+``G``
+ Import mail, See :ref:`importing`
+
+``m``
+ Compose a message
+
+``s``
+ Search the notmuch database using :ref:`notmuch-search`
+
+``v``
+ Print notmuch version
+
+``q``
+ Quit
+
+.. _saved-searches:
+
+Saved Searches
+--------------
+
+Notmuch replaces the static assignment of messages with the more dynamic
+notion of searching. Notmuch-hello presents the user with a customizable
+set of saved searches. The initial defaults are ``tag:inbox`` and
+``tag:unread``, but you can customize the following variables
+
+:index:`notmuch-saved-searches`
+ A list of cons pairs, the first being the name to display, the
+ second being a query string for Notmuch. See section “Description”
+ in Notmuch Query Syntax.
+
+:index:`notmuch-saved-searches-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
+ in ‘notmuch-saved-searches’.
+
+:index:`notmuch-column-control`
+ Controls the number of columns for displaying saved-searches/tags
+
+Search Box
+----------
+
+The search box lets the user enter a Notmuch query. See section
+“Description” in Notmuch Query Syntax, for more info on Notmuch query
+syntax. A history of recent searches is also displayed by default. The
+latter is controlled by the variable :index:`notmuch-hello-recent-searches-max`.
+
+Known Tags
+----------
+
+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.
+
+:index:`notmuch-hello-tag-list-make-query`
+ Control how to construct a search (“virtual folder”) from a given
+ tag.
+
+:index:`notmuch-hello-hide-tags`
+ Which tags not to display at all.
+
+:index:`notmuch-column-control`
+ Controls the number of columns for displaying saved-searches/tags
+
+.. _notmuch-search:
+
+notmuch-search
+==============
+
+``notmuch-search-mode`` is used to display the results from executing
+a query via ``notmuch-search``. The syntax for these queries is the
+the same as :ref:`saved-searches`. For details of this syntax see
+info:notmuch-search-terms
+
+By default the output approximates that of the command line See section
+“Description” in notmuch search command.
+
+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.
+
+``n,C-n,<down>``
+ Move to next line
+
+``p,C-p,<up>``
+ Move to previous line
+
+``<return>``
+ Open thread on current line in :ref:`notmuch-show` mode
+
+``?``
+ Display full set of key bindings
+
+The presentation of results can be controlled by the following
+variables.
+
+:index:`notmuch-search-result-format`
+ Control how each thread of messages is presented in the
+ ``notmuch-show-mode`` buffer
+
+:index:`notmuch-search-oldest-first`
+ Display the oldest threads at the top of the buffer
+
+.. _notmuch-show:
+
+notmuch-show
+============
+
+notmuch-tree
+============
+
+Configuration
+=============
+
+.. _importing:
+
+Importing Mail
+--------------
+
+:index:`notmuch-poll`
+
+:index:`notmuch-poll-script`
+
+Init File
+---------
+
+When Notmuch is loaded, it will read the ``notmuch-init-file``
+(``~/.emacs.d/notmuch-config`` by default) file. This is normal Emacs Lisp
+file and can be used to avoid cluttering your ``~/.emacs`` with Notmuch
+stuff. If the file with ``.elc``, ``.elc.gz``, ``.el`` or ``.el.gz``
+suffix exist it will be read instead (just one of these, chosen in this
+order). Most often users create ``~/.emacs.d/notmuch-config.el`` and just
+work with it. If Emacs was invoked with the ``-q`` or ``--no-init-file``
+options, ``notmuch-init-file`` is not read.
--- /dev/null
+from sys import argv
+from datetime import date
+from os.path import dirname, isdir
+from os import makedirs, system
+import re
+
+sourcedir = argv[1]
+outdir = argv[2]
+
+if not isdir(outdir):
+ makedirs(outdir, 0o755)
+
+execfile(sourcedir + "/conf.py")
+
+
+def header(file, startdocname, command, description, authors, section):
+ file.write("""
+{0:s}
+{1:s}
+{2:s}
+
+:Date: {3:s}
+:Version: {4:s}
+:Manual section: {5:d}
+:Manual group: {6:s}
+
+""".format(
+'-' * len(description),
+description,
+'-' * len(description),
+date.today().isoformat(), release, section, project))
+
+blankre = re.compile("^\s*$")
+for page in man_pages:
+ outdirname = outdir + '/' + dirname(page[0])
+ if not isdir(outdirname):
+ makedirs(outdirname, 0o755)
+ filename = outdir + '/' + page[0] + '.rst'
+ outfile = open(filename, 'w')
+ infile = open(sourcedir + '/' + page[0] + '.rst', 'r')
+
+ # this is a crude hack. We look for the first blank line, and
+ # insert the rst2man header there.
+ #
+ # XXX consider really parsing input
+
+ count = 0
+ lines = infile.readlines()
+ for line in lines:
+ outfile.write(line)
+ if (blankre.match(line)):
+ break
+ count = count + 1
+
+ del lines[0:count + 1]
+
+ header(outfile, *page)
+
+ outfile.write("".join(lines))
+ outfile.close()
+
+ system('set -x; rst2man {0} {1}/{2}.{3}'
+ .format(filename, outdir, page[0], page[4]))
+++ /dev/null
-#ifndef DUMP_RESTORE_PRIVATE_H
-#define DUMP_RESTORE_PRIVATE_H
-
-#include "hex-escape.h"
-#include "command-line-arguments.h"
-
-typedef enum dump_formats {
- DUMP_FORMAT_AUTO,
- DUMP_FORMAT_BATCH_TAG,
- DUMP_FORMAT_SUP
-} dump_format_t;
-
-#endif
.eldeps*
*.elc
+notmuch-version.el
$(dir)/notmuch-crypto.el \
$(dir)/notmuch-tag.el \
$(dir)/coolj.el \
- $(dir)/notmuch-print.el
+ $(dir)/notmuch-print.el \
+ $(dir)/notmuch-version.el
+
+$(dir)/notmuch-version.el: $(dir)/Makefile.local version.stamp
+$(dir)/notmuch-version.el: $(srcdir)/$(dir)/notmuch-version.el.tmpl
+ @sed -e 's/%AG%/Generated file (from $(<F)) -- do not edit!/' \
+ -e 's/%VERSION%/"$(VERSION)"/' $< > $@
+
emacs_images := \
$(srcdir)/$(dir)/notmuch-logo.png
# the byte compiler may load an old .elc file when processing a
# "require" or we may fail to rebuild a .elc that depended on a macro
# from an updated file.
+ifeq ($(HAVE_EMACS),1)
$(dir)/.eldeps: $(dir)/Makefile.local $(dir)/make-deps.el $(emacs_sources)
$(call quiet,EMACS) --directory emacs -batch -l make-deps.el \
-f batch-make-deps $(emacs_sources) > $@.tmp && \
- (cmp -s $@.tmp $@ || mv $@.tmp $@)
--include $(dir)/.eldeps
-CLEAN+=$(dir)/.eldeps $(dir)/.eldeps.tmp
+ mv $@.tmp $@
+# We could include .eldeps directly, but that would cause a make
+# restart whenever any .el file was modified, even if dependencies
+# didn't change, because the mtime of .eldeps will change. Instead,
+# we include a second file, .eldeps.x, which we ensure always has the
+# same content as .eldeps, but its mtime only changes when dependency
+# information changes, in which case a make restart is necessary
+# anyway.
+$(dir)/.eldeps.x: $(dir)/.eldeps
+ @cmp -s $^ $@ || cp $^ $@
+-include $(dir)/.eldeps.x
+endif
+CLEAN+=$(dir)/.eldeps $(dir)/.eldeps.tmp $(dir)/.eldeps.x
+ifeq ($(HAVE_EMACS),1)
%.elc: %.el $(global_deps)
$(call quiet,EMACS) --directory emacs -batch -f batch-byte-compile $<
+endif
ifeq ($(WITH_EMACS),1)
ifeq ($(HAVE_EMACS),1)
all: $(emacs_bytecode)
+install-emacs: $(emacs_bytecode)
endif
install: install-emacs
endif
.PHONY: install-emacs
-install-emacs:
+install-emacs: $(emacs_sources) $(emacs_images)
mkdir -p "$(DESTDIR)$(emacslispdir)"
install -m0644 $(emacs_sources) "$(DESTDIR)$(emacslispdir)"
ifeq ($(HAVE_EMACS),1)
mkdir -p "$(DESTDIR)$(emacsetcdir)"
install -m0644 $(emacs_images) "$(DESTDIR)$(emacsetcdir)"
-CLEAN := $(CLEAN) $(emacs_bytecode)
+CLEAN := $(CLEAN) $(emacs_bytecode) $(dir)/notmuch-version.el
(declare-function notmuch-search "notmuch" (&optional query oldest-first target-thread target-line continuation))
(declare-function notmuch-poll "notmuch" ())
+(defun notmuch-saved-search-get (saved-search field)
+ "Get FIELD from SAVED-SEARCH.
+
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY)."
+ (cond
+ ((keywordp (car saved-search))
+ (plist-get saved-search field))
+ ;; It is not a plist so it is an old-style entry.
+ ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+ (case field
+ (:name (first saved-search))
+ (:query (second saved-search))
+ (:count-query (third saved-search))
+ (t nil)))
+ (t ;; It is a cons-cell (NAME . QUERY)
+ (case field
+ (:name (car saved-search))
+ (:query (cdr saved-search))
+ (t nil)))))
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+ "Return a copy of SAVED-SEARCH in plist form.
+
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatibility, convert to plist form and
+return that."
+ (if (keywordp (car saved-search))
+ (copy-seq saved-search)
+ (let ((fields (list :name :query :count-query))
+ plist-search)
+ (dolist (field fields plist-search)
+ (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+ (setq plist-search (append plist-search (list field string)))))))))
+
+(defun notmuch-hello--saved-searches-to-plist (symbol)
+ "Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatibility we use this function to extract old style saved
+searches so they still work in customize."
+ (let ((saved-searches (default-value symbol)))
+ (mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+ "A single saved search property list."
+ :tag "Saved Search"
+ :args '((list :inline t
+ :format "%v"
+ (group :format "%v" :inline t (const :format " Name: " :name) (string :format "%v"))
+ (group :format "%v" :inline t (const :format " Query: " :query) (string :format "%v")))
+ (checklist :inline t
+ :format "%v"
+ (group :format "%v" :inline t (const :format "Count-Query: " :count-query) (string :format "%v"))
+ (group :format "%v" :inline t (const :format "" :sort-order)
+ (choice :tag " Sort Order"
+ (const :tag "Default" nil)
+ (const :tag "Oldest-first" oldest-first)
+ (const :tag "Newest-first" newest-first))))))
+
+(defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
+ (:name "unread" :query "tag:unread"))
+ "A list of saved searches to display.
+
+The saved search can be given in 3 forms. The preferred way is as
+a plist. Supported properties are
+
+ :name Name of the search (required).
+ :query Search to run (required).
+ :count-query Optional extra query to generate the count
+ shown. If not present then the :query property
+ is used.
+ :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.
+
+Other accepted forms are a cons cell of the form (NAME . QUERY)
+or a list of the form (NAME QUERY COUNT-QUERY)."
+;; The saved-search format is also used by the all-tags notmuch-hello
+;; section. This section generates its own saved-search list in one of
+;; the latter two forms.
+
+ :get 'notmuch-hello--saved-searches-to-plist
+ :type '(repeat notmuch-saved-search-plist)
+ :tag "List of Saved Searches"
+ :group 'notmuch-hello)
+
(defcustom notmuch-hello-recent-searches-max 10
"The number of recent searches to display."
:type 'integer
:type 'boolean
:group 'notmuch-hello)
-(defun notmuch-sort-saved-searches (alist)
- "Generate an alphabetically sorted saved searches alist."
- (sort (copy-sequence alist) (lambda (a b) (string< (car a) (car b)))))
+(defun notmuch-sort-saved-searches (saved-searches)
+ "Generate an alphabetically sorted saved searches list."
+ (sort (copy-sequence saved-searches)
+ (lambda (a b)
+ (string< (notmuch-saved-search-get a :name)
+ (notmuch-saved-search-get b :name)))))
(defcustom notmuch-saved-search-sort-function nil
"Function used to sort the saved searches for the notmuch-hello view.
stored in `notmuch-saved-searches'. Sort alphabetically sorts the
saved searches in alphabetical order. Custom sort function should
be a function or a lambda expression that takes the saved
-searches alist as a parameter, and returns a new saved searches
-alist to be used."
+searches list as a parameter, and returns a new saved searches
+list to be used. For compatibility with the various saved-search
+formats it should use notmuch-saved-search-get to access the
+fields of the search."
:type '(choice (const :tag "No sorting" nil)
(const :tag "Sort alphabetically" notmuch-sort-saved-searches)
(function :tag "Custom sort function"
(setq notmuch-saved-searches
(loop for elem in notmuch-saved-searches
if (not (equal name
- (car elem)))
+ (notmuch-saved-search-get elem :name)))
collect elem))
;; Add the new one.
(customize-save-variable 'notmuch-saved-searches
(add-to-list 'notmuch-saved-searches
- (cons name search) t))
+ (list :name name :query search) t))
(message "Saved '%s' as '%s'." search name)
(notmuch-hello-update)))
(defun notmuch-hello-longest-label (searches-alist)
(or (loop for elem in searches-alist
- maximize (length (car elem)))
+ maximize (length (notmuch-saved-search-get elem :name)))
0))
(defun notmuch-hello-reflect-generate-row (ncols nrows row list)
(defun notmuch-hello-widget-search (widget &rest ignore)
(notmuch-search (widget-get widget
:notmuch-search-terms)
- notmuch-search-oldest-first))
+ (widget-get widget
+ :notmuch-search-oldest-first)))
(defun notmuch-saved-search-count (search)
(car (process-lines notmuch-command "count" search)))
(concat "(" query ") and (" filter ")"))
(t query)))
-(defun notmuch-hello-query-counts (query-alist &rest options)
- "Compute list of counts of matched messages from QUERY-ALIST.
+(defun notmuch-hello-query-counts (query-list &rest options)
+ "Compute list of counts of matched messages from QUERY-LIST.
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated query.
+QUERY-LIST must be a list of saved-searches. Ideally each of
+these is a plist but other options are available for backwards
+compatibility: see `notmuch-saved-searches' for details.
-The result is the list of elements of the form (NAME QUERY COUNT).
+The result is a list of plists each of which includes the
+properties :name NAME, :query QUERY and :count COUNT, together
+with any properties in the original saved-search.
The values :show-empty-searches, :filter and :filter-count from
options will be handled as specified for
`notmuch-hello-insert-searches'."
(with-temp-buffer
- (dolist (elem query-alist nil)
- (let ((count-query (if (consp (cdr elem))
- ;; do we have a different query for the message count?
- (third elem)
- (cdr elem))))
+ (dolist (elem query-list nil)
+ (let ((count-query (or (notmuch-saved-search-get elem :count-query)
+ (notmuch-saved-search-get elem :query))))
(insert
- (notmuch-hello-filtered-query count-query
- (or (plist-get options :filter-count)
- (plist-get options :filter)))
- "\n")))
+ (replace-regexp-in-string
+ "\n" " "
+ (notmuch-hello-filtered-query count-query
+ (or (plist-get options :filter-count)
+ (plist-get options :filter))))
+ "\n")))
(unless (= (call-process-region (point-min) (point-max) notmuch-command
t t nil "count" "--batch") 0)
#'identity
(mapcar
(lambda (elem)
- (let ((name (car elem))
- (search-query (if (consp (cdr elem))
- ;; do we have a different query for the message count?
- (second elem)
- (cdr elem)))
- (message-count (prog1 (read (current-buffer))
+ (let* ((elem-plist (notmuch-hello-saved-search-to-plist elem))
+ (search-query (plist-get elem-plist :query))
+ (filtered-query (notmuch-hello-filtered-query
+ search-query (plist-get options :filter)))
+ (message-count (prog1 (read (current-buffer))
(forward-line 1))))
- (and (or (plist-get options :show-empty-searches) (> message-count 0))
- (list name (notmuch-hello-filtered-query
- search-query (plist-get options :filter))
- message-count))))
- query-alist))))
+ (when (and filtered-query (or (plist-get options :show-empty-searches) (> message-count 0)))
+ (setq elem-plist (plist-put elem-plist :query filtered-query))
+ (plist-put elem-plist :count message-count))))
+ query-list))))
(defun notmuch-hello-insert-buttons (searches)
"Insert buttons for SEARCHES.
-SEARCHES must be a list containing lists of the form (NAME QUERY COUNT), where
-QUERY is the query to start when the button for the corresponding entry is
-activated. COUNT should be the number of messages matching the query.
-Such a list can be computed with `notmuch-hello-query-counts'."
+SEARCHES must be a list of plists each of which should contain at
+least the properties :name NAME :query QUERY and :count COUNT,
+where QUERY is the query to start when the button for the
+corresponding entry is activated, and COUNT should be the number
+of messages matching the query. Such a plist can be computed
+with `notmuch-hello-query-counts'."
(let* ((widest (notmuch-hello-longest-label searches))
(tags-and-width (notmuch-hello-tags-per-line widest))
(tags-per-line (car tags-and-width))
(when elem
(if (> column-indent 0)
(widget-insert (make-string column-indent ? )))
- (let* ((name (first elem))
- (query (second elem))
- (msg-count (third elem)))
+ (let* ((name (plist-get elem :name))
+ (query (plist-get elem :query))
+ (oldest-first (case (plist-get elem :sort-order)
+ (newest-first nil)
+ (oldest-first t)
+ (otherwise notmuch-search-oldest-first)))
+ (msg-count (plist-get elem :count)))
(widget-insert (format "%8s "
(notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
:notify #'notmuch-hello-widget-search
:notmuch-search-terms query
+ :notmuch-search-oldest-first oldest-first
name)
(setq column-indent
(1+ (max 0 (- column-width (length name)))))))
(remove-hook 'window-configuration-change-hook
#'notmuch-hello-window-configuration-change))))
+;; the following variable is defined as being defconst in notmuch-version.el
+(defvar notmuch-emacs-version)
+
+(defun notmuch-hello-versions ()
+ "Display the notmuch version(s)"
+ (interactive)
+ (let ((notmuch-cli-version (notmuch-version)))
+ (message "notmuch version %s"
+ (if (string= notmuch-emacs-version notmuch-cli-version)
+ notmuch-cli-version
+ (concat notmuch-cli-version
+ " (emacs mua version " notmuch-emacs-version ")")))))
(defvar notmuch-hello-mode-map
(let ((map (if (fboundp 'make-composed-keymap)
;; it's unlikely to change.
(copy-keymap widget-keymap))))
(set-keymap-parent map notmuch-common-keymap)
- (define-key map "v" (lambda () "Display the notmuch version" (interactive)
- (message "notmuch version %s" (notmuch-version))))
+ (define-key map "v" 'notmuch-hello-versions)
(define-key map (kbd "<C-tab>") 'widget-backward)
map)
"Keymap for \"notmuch hello\" buffers.")
(indent-rigidly start (point) notmuch-hello-indent))
nil))
-(defun notmuch-hello-insert-searches (title query-alist &rest options)
- "Insert a section with TITLE showing a list of buttons made from QUERY-ALIST.
+(defun notmuch-hello-insert-searches (title query-list &rest options)
+ "Insert a section with TITLE showing a list of buttons made from QUERY-LIST.
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated item.
+QUERY-LIST should ideally be a plist but for backwards
+compatibility other forms are also accepted (see
+`notmuch-saved-searches' for details). The plist should
+contain keys :name and :query; if :count-query is also present
+then it specifies an alternate query to be used to generate the
+count for the associated search.
Supports the following entries in OPTIONS as a plist:
:initially-hidden - if non-nil, section will be hidden on startup
"hide"))
(widget-insert "\n")
(when (not is-hidden)
- (let ((searches (apply 'notmuch-hello-query-counts query-alist options)))
+ (let ((searches (apply 'notmuch-hello-query-counts query-list options)))
(when (or (not (plist-get options :hide-if-empty))
searches)
(widget-insert "\n")
"Run notmuch and display saved searches, known tags, etc."
(interactive)
+ (notmuch-assert-cli-sane)
;; This may cause a window configuration change, so if the
;; auto-refresh hook is already installed, avoid recursive refresh.
(let ((notmuch-hello-auto-refresh nil))
(defvar notmuch-search-history nil
"Variable to store notmuch searches history.")
-(defcustom notmuch-saved-searches '(("inbox" . "tag:inbox")
- ("unread" . "tag:unread"))
- "A list of saved searches to display."
- :type '(alist :key-type string :value-type string)
- :group 'notmuch-hello)
-
(defcustom notmuch-archive-tags '("-inbox")
"List of tag changes to apply to a message or a thread when it is archived.
(notmuch-check-exit-status status (cons notmuch-command args) output)
output)))
+(defvar notmuch--cli-sane-p nil
+ "Cache whether the CLI seems to be configured sanely.")
+
+(defun notmuch-cli-sane-p ()
+ "Return t if the cli seems to be configured sanely."
+ (unless notmuch--cli-sane-p
+ (let ((status (call-process notmuch-command nil nil nil
+ "config" "get" "user.primary_email")))
+ (setq notmuch--cli-sane-p (= status 0))))
+ notmuch--cli-sane-p)
+
+(defun notmuch-assert-cli-sane ()
+ (unless (notmuch-cli-sane-p)
+ (notmuch-logged-error
+ "notmuch cli seems misconfigured or unconfigured."
+"Perhaps you haven't run \"notmuch setup\" yet? Try running this
+on the command line, and then retry your notmuch command")))
+
(defun notmuch-version ()
"Return a string with the notmuch version number."
(let ((long-string
(defun notmuch-config-get (item)
"Return a value from the notmuch configuration."
- ;; Trim off the trailing newline
- (substring (notmuch-command-to-string "config" "get" item) 0 -1))
+ (let* ((val (notmuch-command-to-string "config" "get" item))
+ (len (length val)))
+ ;; Trim off the trailing newline (if the value is empty or not
+ ;; configured, there will be no newline)
+ (if (and (> len 0) (= (aref val (- len 1)) ?\n))
+ (substring val 0 -1)
+ val)))
(defun notmuch-database-path ()
"Return the database.path value from the notmuch configuration."
(defun notmuch-user-other-email ()
"Return the user.other_email value (as a list) from the notmuch configuration."
- (split-string (notmuch-config-get "user.other_email") "\n"))
+ (split-string (notmuch-config-get "user.other_email") "\n" t))
(defun notmuch-poll ()
"Run \"notmuch new\" or an external script to import mail.
"Given a prefix key code, return a human-readable string representation.
This is basically just `format-kbd-macro' but we also convert ESC to M-."
- (let ((desc (format-kbd-macro (vector key))))
+ (let* ((key-vector (if (vectorp key) key (vector key)))
+ (desc (format-kbd-macro key-vector)))
(if (string= desc "ESC")
"M-"
(concat desc " "))))
(set-buffer-modified-p nil)
(view-buffer (current-buffer) 'kill-buffer-if-not-modified))))
+(defun notmuch-subkeymap-help ()
+ "Show help for a subkeymap."
+ (interactive)
+ (let* ((key (this-command-keys-vector))
+ (prefix (make-vector (1- (length key)) nil))
+ (i 0))
+ (while (< i (length prefix))
+ (aset prefix i (aref key i))
+ (setq i (1+ i)))
+
+ (let* ((subkeymap (key-binding prefix))
+ (ua-keys (where-is-internal 'universal-argument nil t))
+ (prefix-string (notmuch-prefix-key-description prefix))
+ (desc-alist (notmuch-describe-keymap subkeymap ua-keys subkeymap prefix-string))
+ (desc-list (mapcar (lambda (arg) (concat (car arg) "\t" (cdr arg))) desc-alist))
+ (desc (mapconcat #'identity desc-list "\n")))
+ (with-help-window (help-buffer)
+ (with-current-buffer standard-output
+ (insert "\nPress 'q' to quit this window.\n\n")
+ (insert desc)))
+ (pop-to-buffer (help-buffer)))))
+
(defvar notmuch-buffer-refresh-function nil
"Function to call to refresh the current buffer.")
(make-variable-buffer-local 'notmuch-buffer-refresh-function)
(save-match-data
(if (or (equal term "")
- (string-match "[ ()]\\|^\"" term))
+ ;; To be pessimistic, only pass through terms composed
+ ;; entirely of ASCII printing characters other than ", (,
+ ;; and ).
+ (string-match "[^!#-'*-~]" term))
;; Requires escaping
(concat "\"" (replace-regexp-in-string "\"" "\"\"" term t t) "\"")
term)))
(if (>= emacs-major-version 24)
(defadvice mm-shr (before load-gnus-arts activate)
(require 'gnus-art nil t)
- (ad-disable-advice 'mm-shr 'before 'load-gnus-arts)))
+ (ad-disable-advice 'mm-shr 'before 'load-gnus-arts)
+ (ad-activate 'mm-shr)))
(defun notmuch-mm-display-part-inline (msg part nth content-type process-crypto)
"Use the mm-decode/mm-view functions to display a part in the
face
(list face)))
-(defun notmuch-combine-face-text-property (start end face &optional below object)
- "Combine FACE into the 'face text property between START and END.
+(defun notmuch-apply-face (object face &optional below start 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 (which defaults to the current buffer).
-Attributes specified by FACE take precedence over existing
-attributes unless BELOW is non-nil. FACE must be a face name (a
-symbol or string), a property list of face attributes, or a list
-of these. For convenience when applied to strings, this returns
-OBJECT."
+and END in OBJECT. Attributes specified by FACE take precedence
+over existing attributes unless BELOW is non-nil.
+
+OBJECT may be a string, a buffer, or nil (which means the current
+buffer). If object is a string, START and END are 0-based;
+otherwise they are buffer positions (integers or markers). FACE
+must be a face name (a symbol or string), a property list of face
+attributes, or a list of these. If START and/or END are omitted,
+they default to the beginning/end of OBJECT. For convenience
+when applied to strings, this returns OBJECT."
;; A face property can have three forms: a face name (a string or
;; symbol), a property list, or a list of these two forms. In the
;; list case, the faces will be combined, with the earlier faces
;; taking precedent. Here we canonicalize everything to list form
;; to make it easy to combine.
- (let ((pos start)
+ (let ((pos (cond (start start)
+ ((stringp object) 0)
+ (t 1)))
+ (end (cond (end end)
+ ((stringp object) (length object))
+ (t (1+ (buffer-size object)))))
(face-list (notmuch-face-ensure-list-form face)))
(while (< pos end)
(let* ((cur (get-text-property pos 'face object))
(setq pos next))))
object)
-(defun notmuch-combine-face-text-property-string (string face &optional below)
- (notmuch-combine-face-text-property
- 0
- (length string)
- face
- below
- string))
-
(defun notmuch-map-text-property (start end prop func &optional object)
"Transform text property PROP using FUNC.
(push header message-hidden-headers)))
notmuch-mua-hidden-headers))
+(defun notmuch-mua-reply-crypto (parts)
+ "Add mml sign-encrypt flag if any part of original message is encrypted."
+ (loop for part in parts
+ if (notmuch-match-content-type (plist-get part :content-type) "multipart/encrypted")
+ do (mml-secure-message-sign-encrypt)
+ else if (notmuch-match-content-type (plist-get part :content-type) "multipart/*")
+ do (notmuch-mua-reply-crypto (plist-get part :content))))
+
(defun notmuch-mua-get-quotable-parts (parts)
(loop for part in parts
if (notmuch-match-content-type (plist-get part :content-type) "multipart/alternative")
(defun notmuch-mua-reply (query-string &optional sender reply-all)
(let ((args '("reply" "--format=sexp" "--format-version=1"))
+ (process-crypto notmuch-show-process-crypto)
reply
original)
- (when notmuch-show-process-crypto
+ (when process-crypto
(setq args (append args '("--decrypt"))))
(if reply-all
(set-mark (point))
(goto-char start)
;; Quote the original message according to the user's configured style.
- (message-cite-original))))
+ (message-cite-original)))
- (goto-char (point-max))
+ ;; Crypto processing based crypto content of the original message
+ (when process-crypto
+ (notmuch-mua-reply-crypto (plist-get original :body))))
+
+ ;; Push mark right before signature, if any.
+ (message-goto-signature)
+ (unless (eobp)
+ (end-of-line -1))
(push-mark)
+
(message-goto-body)
(set-buffer-modified-p nil))
-(defun notmuch-mua-forward-message ()
- (funcall (notmuch-mua-get-switch-function) (current-buffer))
- (message-forward)
-
- (when notmuch-mua-user-agent-function
- (let ((user-agent (funcall notmuch-mua-user-agent-function)))
- (when (not (string= "" user-agent))
- (message-add-header (format "User-Agent: %s" user-agent)))))
- (message-sort-headers)
- (message-hide-headers)
- (set-buffer-modified-p nil)
- (notmuch-mua-maybe-set-window-dedicated)
-
- (message-goto-to))
-
(defun notmuch-mua-mail (&optional to subject other-headers &rest other-args)
"Invoke the notmuch mail composition window.
(defvar notmuch-mua-sender-history nil)
+;; Workaround: Running `ido-completing-read' in emacs 23.1, 23.2 and 23.3
+;; without some explicit initialization fill freeze the operation.
+;; Hence, we advice `ido-completing-read' to ensure required initialization
+;; is done.
+(if (and (= emacs-major-version 23) (< emacs-minor-version 4))
+ (defadvice ido-completing-read (before notmuch-ido-mode-init activate)
+ (ido-init-completion-maps)
+ (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
+ (add-hook 'choose-completion-string-functions
+ 'ido-choose-completion-string)
+ (ad-disable-advice 'ido-completing-read 'before 'notmuch-ido-mode-init)
+ (ad-activate 'ido-completing-read)))
+
(defun notmuch-mua-prompt-for-sender ()
- (interactive)
- (let (name addresses one-name-only)
- ;; If notmuch-identities is non-nil, check if there is a fixed user name.
- (if notmuch-identities
- (let ((components (mapcar 'mail-extract-address-components notmuch-identities)))
- (setq name (caar components)
- addresses (mapcar 'cadr components)
- one-name-only (eval
- (cons 'and
- (mapcar (lambda (identity)
- (string-equal name (car identity)))
- components)))))
- ;; If notmuch-identities is nil, use values from the notmuch configuration file.
- (setq name (notmuch-user-name)
- addresses (cons (notmuch-user-primary-email) (notmuch-user-other-email))
- one-name-only t))
- ;; Now prompt the user, either for an email address only or for a full identity.
- (if one-name-only
- (let ((address
- (ido-completing-read (concat "Sender address for " name ": ") addresses
- nil nil nil 'notmuch-mua-sender-history (car addresses))))
- (concat name " <" address ">"))
- (ido-completing-read "Send mail From: " notmuch-identities
- nil nil nil 'notmuch-mua-sender-history (car notmuch-identities)))))
+ "Prompt for a sender from the user's configured identities."
+ (if notmuch-identities
+ (ido-completing-read "Send mail from: " notmuch-identities
+ nil nil nil 'notmuch-mua-sender-history
+ (car notmuch-identities))
+ (let* ((name (notmuch-user-name))
+ (addrs (cons (notmuch-user-primary-email)
+ (notmuch-user-other-email)))
+ (address
+ (ido-completing-read (concat "Sender address for " name ": ") addrs
+ nil nil nil 'notmuch-mua-sender-history
+ (car addrs))))
+ (concat name " <" address ">"))))
(put 'notmuch-mua-new-mail 'notmuch-prefix-doc "... and prompt for sender")
(defun notmuch-mua-new-mail (&optional prompt-for-sender)
If PROMPT-FOR-SENDER is non-nil, the user will be prompted for
the From: address first."
- (if (or prompt-for-sender notmuch-always-prompt-for-sender)
- (let* ((sender (notmuch-mua-prompt-for-sender))
- (address-components (mail-extract-address-components sender))
- (user-full-name (car address-components))
- (user-mail-address (cadr address-components)))
- (notmuch-mua-forward-message))
- (notmuch-mua-forward-message)))
+ (let* ((cur (current-buffer))
+ (message-forward-decoded-p nil)
+ (subject (message-make-forward-subject))
+ (other-headers
+ (when (or prompt-for-sender notmuch-always-prompt-for-sender)
+ (list (cons 'From (notmuch-mua-prompt-for-sender))))))
+ (notmuch-mua-mail nil subject other-headers nil (notmuch-mua-get-switch-function))
+ (message-forward-make-body cur)
+ ;; `message-forward-make-body' shows the User-agent header. Hide
+ ;; it again.
+ (message-hide-headers)))
(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender reply-all)
"Compose a reply to the message identified by QUERY-STRING.
(defcustom notmuch-show-stash-mlarchive-link-alist
'(("Gmane" . "http://mid.gmane.org/")
("MARC" . "http://marc.info/?i=")
- ("Mail Archive, The" . "http://mail-archive.com/search?l=mid&q=")
+ ("Mail Archive, The" . "http://mid.mail-archive.com/")
("LKML" . "http://lkml.kernel.org/r/")
;; FIXME: can these services be searched by `Message-Id' ?
;; ("MarkMail" . "http://markmail.org/")
(if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
(let ((inhibit-read-only t))
(replace-match (concat "("
- (notmuch-tag-format-tags tags)
+ (notmuch-tag-format-tags tags (notmuch-show-get-prop :orig-tags))
")"))))))
(defun notmuch-clean-address (address)
" ("
date
") ("
- (notmuch-tag-format-tags tags)
+ (notmuch-tag-format-tags tags tags)
")\n")
(overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face)))
(while (and handlers
(not (condition-case err
(funcall (car handlers) msg part content-type nth depth button)
- (error (progn
+ ;; Specifying `debug' here lets the debugger
+ ;; run if `debug-on-error' is non-nil.
+ ((debug error)
+ (progn
(insert "!!! Bodypart insert error: ")
(insert (error-message-string err))
(insert " !!!\n") nil)))))
;; Don't track undo information for this buffer
(set 'buffer-undo-list t)
+ (notmuch-tag-clear-cache)
(erase-buffer)
(goto-char (point-min))
(save-excursion
(jit-lock-register #'notmuch-show-buttonise-links)
+ (notmuch-show-mapc (lambda () (notmuch-show-set-prop :orig-tags (notmuch-show-get-tags))))
+
;; Set the header line to the subject of the first message.
(setq header-line-format (notmuch-sanitize (notmuch-show-strip-re (notmuch-show-get-subject))))
(define-key map "t" 'notmuch-show-stash-to)
(define-key map "l" 'notmuch-show-stash-mlarchive-link)
(define-key map "L" 'notmuch-show-stash-mlarchive-link-and-go)
+ (define-key map "?" 'notmuch-subkeymap-help)
map)
"Submap for stash commands")
(fset 'notmuch-show-stash-map notmuch-show-stash-map)
(define-key map "v" 'notmuch-show-view-part)
(define-key map "o" 'notmuch-show-interactively-view-part)
(define-key map "|" 'notmuch-show-pipe-part)
+ (define-key map "?" 'notmuch-subkeymap-help)
map)
"Submap for part commands")
(fset 'notmuch-show-part-map notmuch-show-part-map)
(setq shell-command
(concat notmuch-command " show --format=raw "
(shell-quote-argument (notmuch-show-get-message-id)) " | " command)))
- (let ((buf (get-buffer-create (concat "*notmuch-pipe*"))))
+ (let ((cwd default-directory)
+ (buf (get-buffer-create (concat "*notmuch-pipe*"))))
(with-current-buffer buf
(setq buffer-read-only nil)
(erase-buffer)
+ ;; Use the originating buffer's working directory instead of
+ ;; that of the pipe buffer.
+ (cd cwd)
(let ((exit-code (call-process-shell-command shell-command nil buf)))
(goto-char (point-max))
(set-buffer-modified-p nil)
(require 'crm)
(require 'notmuch-lib)
-(defcustom notmuch-tag-formats
- '(("unread" (propertize tag 'face '(:foreground "red")))
- ("flagged" (propertize tag 'face '(:foreground "blue"))
- (notmuch-tag-format-image-data tag (notmuch-tag-star-icon))))
- "Custom formats for individual tags.
-
-This gives a list that maps from tag names to lists of formatting
-expressions. The car of each element gives a tag name and the
-cdr gives a list of Elisp expressions that modify the tag. If
-the list is empty, the tag will simply be hidden. Otherwise,
-each expression will be evaluated in order: for the first
-expression, the variable `tag' will be bound to the tag name; for
-each later expression, the variable `tag' will be bound to the
-result of the previous expression. In this way, each expression
-can build on the formatting performed by the previous expression.
-The result of the last expression will displayed in 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
- (propertize tag 'face '(:foreground \"red\"))
-
-See also `notmuch-tag-format-image', which can help replace tags
-with images."
-
- :group 'notmuch-search
- :group 'notmuch-show
- :type '(alist :key-type (string :tag "Tag")
+(define-widget 'notmuch-tag-format-type 'lazy
+ "Customize widget for notmuch-tag-format and friends"
+ :type '(alist :key-type (regexp :tag "Tag")
:extra-offset -3
:value-type
(radio :format "%v"
(string :tag "Display as")
(list :tag "Face" :extra-offset -4
(const :format "" :inline t
- (propertize tag 'face))
+ (notmuch-apply-face tag))
(list :format "%v"
(const :format "" quote)
custom-face-edit))
(string :tag "Custom")))
(sexp :tag "Custom")))))
+(defcustom notmuch-tag-formats
+ '(("unread" (propertize tag 'face '(:foreground "red")))
+ ("flagged" (propertize tag 'face '(:foreground "blue"))
+ (notmuch-tag-format-image-data tag (notmuch-tag-star-icon))))
+ "Custom formats for individual tags.
+
+This is an association list that maps from tag name regexps to
+lists of formatting expressions. The first entry whose car
+regexp-matches a tag will be used to format that tag. The regexp
+is implicitly anchored, so to match a literal tag name, just use
+that tag name (if it contains special regexp characters like
+\".\" or \"*\", these have to be escaped). The cdr of the
+matching entry gives a list of Elisp expressions that modify the
+tag. If the list is empty, the tag will simply be hidden.
+Otherwise, each expression will be evaluated in order: for the
+first expression, the variable `tag' will be bound to the tag
+name; for each later expression, the variable `tag' will be bound
+to the result of the previous expression. In this way, each
+expression can build on the formatting performed by the previous
+expression. The result of the last expression will displayed in
+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
+ (propertize tag 'face '(:foreground \"red\"))
+
+See also `notmuch-tag-format-image', which can help replace tags
+with images."
+ :group 'notmuch-search
+ :group 'notmuch-show
+ :group 'notmuch-faces
+ :type 'notmuch-tag-format-type)
+
+(defcustom notmuch-tag-deleted-formats
+ '(("unread" (notmuch-apply-face bare-tag
+ (if (display-supports-face-attributes-p '(:strike-through "red"))
+ '(:strike-through "red")
+ '(:inverse-video t))))
+ (".*" (notmuch-apply-face tag
+ (if (display-supports-face-attributes-p '(:strike-through "red"))
+ '(:strike-through "red")
+ '(:inverse-video t)))))
+ "Custom formats for tags when deleted.
+
+For deleted tags the formats in `notmuch-tag-formats` are applied
+first and then these formats are applied on top; that is `tag'
+passed to the function is the tag with all these previous
+formattings applied. The formatted can access the original
+unformatted tag as `bare-tag'.
+
+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
+ '((\".*\" nil))
+
+See `notmuch-tag-formats' for full documentation."
+ :group 'notmuch-show
+ :group 'notmuch-faces
+ :type 'notmuch-tag-format-type)
+
+(defcustom notmuch-tag-added-formats
+ '((".*" (notmuch-apply-face tag '(:underline "green"))))
+ "Custom formats for tags when added.
+
+For added tags the formats in `notmuch-tag-formats` are applied
+first and then these formats are applied on top.
+
+To disable special formatting of added tags, set this variable to
+nil.
+
+See `notmuch-tag-formats' for full documentation."
+ :group 'notmuch-show
+ :group 'notmuch-faces
+ :type 'notmuch-tag-format-type)
+
(defun notmuch-tag-format-image-data (tag data)
"Replace TAG with image DATA, if available.
</g>
</svg>")
-(defun notmuch-tag-format-tag (tag)
- "Format TAG by looking into `notmuch-tag-formats'."
- (let ((formats (assoc tag notmuch-tag-formats)))
- (cond
- ((null formats) ;; - Tag not in `notmuch-tag-formats',
- tag) ;; the format is the tag itself.
- ((null (cdr formats)) ;; - Tag was deliberately hidden,
- nil) ;; no format must be returned
- (t ;; - Tag was found and has formats,
- (let ((tag tag)) ;; we must apply all the formats.
- (dolist (format (cdr formats) tag)
- (setq tag (eval format))))))))
-
-(defun notmuch-tag-format-tags (tags)
+(defvar notmuch-tag--format-cache (make-hash-table :test 'equal)
+ "Cache of tag format lookup. Internal to `notmuch-tag-format-tag'.")
+
+(defun notmuch-tag-clear-cache ()
+ "Clear the internal cache of tag formats."
+ (clrhash notmuch-tag--format-cache))
+
+(defun notmuch-tag--get-formats (tag format-alist)
+ "Find the first item whose car regexp-matches TAG."
+ (save-match-data
+ ;; Don't use assoc-default since there's no way to distinguish a
+ ;; missing key from a present key with a null cdr.
+ (assoc* tag format-alist
+ :test (lambda (tag key)
+ (and (eq (string-match key tag) 0)
+ (= (match-end 0) (length tag)))))))
+
+(defun notmuch-tag--do-format (tag formatted-tag formats)
+ "Apply a tag-formats entry to TAG."
+ (cond ((null formats) ;; - Tag not in `formats',
+ formatted-tag) ;; the format is the tag itself.
+ ((null (cdr formats)) ;; - Tag was deliberately hidden,
+ nil) ;; no format must be returned
+ (t
+ ;; Tag was found and has formats, we must apply all the
+ ;; formats. TAG may be null so treat that as a special case.
+ (let ((bare-tag tag)
+ (tag (copy-sequence (or formatted-tag ""))))
+ (dolist (format (cdr formats))
+ (setq tag (eval format)))
+ (if (and (null formatted-tag) (equal tag ""))
+ nil
+ tag)))))
+
+(defun notmuch-tag-format-tag (tags orig-tags tag)
+ "Format TAG according to `notmuch-tag-formats'.
+
+TAGS and ORIG-TAGS are lists of the current tags and the original
+tags; tags which have been deleted (i.e., are in ORIG-TAGS but
+are not in TAGS) are shown using formats from
+`notmuch-tag-deleted-formats'; tags which have been added (i.e.,
+are in TAGS but are not in ORIG-TAGS) are shown using formats
+from `notmuch-tag-added-formats' and tags which have not been
+changed (the normal case) are shown using formats from
+`notmuch-tag-formats'"
+ (let* ((tag-state (cond ((not (member tag tags)) 'deleted)
+ ((not (member tag orig-tags)) 'added)))
+ (formatted-tag (gethash (cons tag tag-state) notmuch-tag--format-cache 'missing)))
+ (when (eq formatted-tag 'missing)
+ (let ((base (notmuch-tag--get-formats tag notmuch-tag-formats))
+ (over (case tag-state
+ (deleted (notmuch-tag--get-formats
+ tag notmuch-tag-deleted-formats))
+ (added (notmuch-tag--get-formats
+ tag notmuch-tag-added-formats))
+ (otherwise nil))))
+ (setq formatted-tag (notmuch-tag--do-format tag tag base))
+ (setq formatted-tag (notmuch-tag--do-format tag formatted-tag over))
+
+ (puthash (cons tag tag-state) formatted-tag notmuch-tag--format-cache)))
+ formatted-tag))
+
+(defun notmuch-tag-format-tags (tags orig-tags &optional face)
"Return a string representing formatted TAGS."
- (notmuch-combine-face-text-property-string
- (mapconcat #'identity
- ;; nil indicated that the tag was deliberately hidden
- (delq nil (mapcar #'notmuch-tag-format-tag tags))
- " ")
- 'notmuch-tag-face
- t))
+ (let ((face (or face 'notmuch-tag-face))
+ (all-tags (sort (delete-dups (append tags orig-tags nil)) #'string<)))
+ (notmuch-apply-face
+ (mapconcat #'identity
+ ;; nil indicated that the tag was deliberately hidden
+ (delq nil (mapcar
+ (apply-partially #'notmuch-tag-format-tag tags orig-tags)
+ all-tags))
+ " ")
+ face
+ t)))
(defcustom notmuch-before-tag-hook nil
"Hooks that are run before tags of a message are modified.
(unless (string-match-p "^[-+]\\S-+$" tag-change)
(error "Tag must be of the form `+this_tag' or `-that_tag'")))
tag-changes)
+ (unless query
+ (error "Nothing to tag!"))
(unless (null tag-changes)
(run-hooks 'notmuch-before-tag-hook)
(if (<= (length query) notmuch-tag-argument-limit)
:group 'notmuch-tree)
;; Faces for messages that match the query.
-(defface notmuch-tree-match-date-face
+(defface notmuch-tree-match-face
'((t :inherit default))
+ "Default face used in tree mode face for matching messages"
+ :group 'notmuch-tree
+ :group 'notmuch-faces)
+
+(defface notmuch-tree-match-date-face
+ nil
"Face used in tree mode for the date in messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
:group 'notmuch-faces)
(defface notmuch-tree-match-subject-face
- '((t :inherit default))
+ nil
"Face used in tree mode for the subject in messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-match-tree-face
- '((t :inherit default))
+ nil
"Face used in tree mode for the thread tree block graphics in messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
:group 'notmuch-faces)
;; Faces for messages that do not match the query.
-(defface notmuch-tree-no-match-date-face
+(defface notmuch-tree-no-match-face
'((t (:foreground "gray")))
+ "Default face used in tree mode face for non-matching messages"
+ :group 'notmuch-tree
+ :group 'notmuch-faces)
+
+(defface notmuch-tree-no-match-date-face
+ nil
"Face used in tree mode for non-matching dates."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-no-match-subject-face
- '((t (:foreground "gray")))
+ nil
"Face used in tree mode for non-matching subjects."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-no-match-tree-face
- '((t (:foreground "gray")))
+ nil
"Face used in tree mode for the thread tree block graphics in messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-no-match-author-face
- '((t (:foreground "gray")))
+ nil
"Face used in tree mode for the date in messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-no-match-tag-face
- '((t (:foreground "gray")))
+ nil
"Face used in tree mode face for non-matching tags."
:group 'notmuch-tree
:group 'notmuch-faces)
"Return the tags of the current message."
(notmuch-tree-get-prop :tags))
-(defun notmuch-tree-get-message-id ()
+(defun notmuch-tree-get-message-id (&optional bare)
"Return the message id of the current message."
(let ((id (notmuch-tree-get-prop :id)))
(if id
- (notmuch-id-to-query id)
+ (if bare
+ id
+ (notmuch-id-to-query id))
nil)))
(defun notmuch-tree-get-match ()
((string-equal field "tags")
(let ((tags (plist-get msg :tags))
+ (orig-tags (plist-get msg :orig-tags))
(face (if match
'notmuch-tree-match-tag-face
'notmuch-tree-no-match-tag-face)))
- (propertize (format format-string
- (mapconcat #'identity tags ", "))
- 'face face))))))
-
+ (format format-string (notmuch-tag-format-tags tags orig-tags face)))))))
(defun notmuch-tree-format-field-list (field-list msg)
"Format fields of MSG according to FIELD-LIST and return string"
- (let (result-string)
+ (let ((face (if (plist-get msg :match)
+ 'notmuch-tree-match-face
+ 'notmuch-tree-no-match-face))
+ (result-string))
(dolist (spec field-list result-string)
(let ((field-string (notmuch-tree-format-field (car spec) (cdr spec) msg)))
- (setq result-string (concat result-string field-string))))))
+ (setq result-string (concat result-string field-string))))
+ (notmuch-apply-face result-string face t)))
(defun notmuch-tree-insert-msg (msg)
"Insert the message MSG according to notmuch-tree-result-format"
(push "├" tree-status)))
(push (concat (if replies "┬" "─") "►") tree-status)
- (plist-put msg :first (and first (eq 0 depth)))
- (notmuch-tree-goto-and-insert-msg (plist-put msg :tree-status tree-status))
+ (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)))
+ (notmuch-tree-goto-and-insert-msg msg)
(pop tree-status)
(pop tree-status)
(message-arg "--entire-thread"))
(if (equal (car (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"
--- /dev/null
+;; -*- emacs-lisp -*-
+;;
+;; %AG%
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch 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.
+;;
+;; Notmuch 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 Notmuch. If not, see <http://www.gnu.org/licenses/>.
+
+(defconst notmuch-emacs-version %VERSION%
+ "Version of Notmuch Emacs MUA.")
+
+(provide 'notmuch-version)
;;
;; Then, to actually run it, add:
;;
-;; (require 'notmuch)
+;; (autoload 'notmuch "notmuch" "Notmuch mail" t)
;;
;; to your ~/.emacs file, and then run "M-x notmuch" from within emacs,
;; or run:
(require 'notmuch-message)
(require 'notmuch-parser)
+(unless (require 'notmuch-version nil t)
+ (defconst notmuch-emacs-version "unknown"
+ "Placeholder variable when notmuch-version.el[c] is not available."))
+
(defcustom notmuch-search-result-format
`(("date" . "%12s ")
("count" . "%-7s ")
:type '(alist :key-type (string) :value-type (string))
:group 'notmuch-search)
+;; The name of this variable `notmuch-init-file' is consistent with the
+;; convention used in e.g. emacs and gnus. The value, `notmuch-config[.el[c]]'
+;; is consistent with notmuch cli configuration file `~/.notmuch-config'.
+(defcustom notmuch-init-file (locate-user-emacs-file "notmuch-config")
+ "Your Notmuch Emacs-Lisp configuration file name.
+If a file with one of the suffixes defined by `get-load-suffixes' exists,
+it will be read instead.
+This file is read once when notmuch is loaded; the notmuch hooks added
+there will be called at other points of notmuch execution."
+ :type 'file
+ :group 'notmuch)
+
(defvar notmuch-query-history nil
"Variable to store minibuffer history for notmuch queries")
(defvar notmuch-search-stash-map
(let ((map (make-sparse-keymap)))
(define-key map "i" 'notmuch-search-stash-thread-id)
+ (define-key map "?" 'notmuch-subkeymap-help)
map)
"Submap for stash commands")
(fset 'notmuch-search-stash-map notmuch-search-stash-map)
"Return the stable query for the current region.
If ONLY-MATCHED is non-nil, include only matched messages. If it
-is nil, include both matched and unmatched messages."
+is nil, include both matched and unmatched messages. If there are
+no messages in the region then return nil."
(let ((query-list nil) (all (not only-matched)))
(dolist (queries (notmuch-search-properties-in-region :query beg end))
(when (first queries)
(push (first queries) query-list))
(when (and all (second queries))
(push (second queries) query-list)))
- (concat "(" (mapconcat 'identity query-list ") or (") ")")))
+ (when query-list
+ (concat "(" (mapconcat 'identity query-list ") or (") ")"))))
(defun notmuch-search-find-authors ()
"Return the authors for the current thread"
(let ((tag (car elem))
(attributes (cdr elem)))
(when (member tag line-tag-list)
- (notmuch-combine-face-text-property start end attributes))))
+ (notmuch-apply-face nil attributes nil start end))))
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))
format-string (notmuch-sanitize (plist-get result :authors))))
((string-equal field "tags")
- (let ((tags (plist-get result :tags)))
- (insert (format format-string (notmuch-tag-format-tags tags)))))))
+ (let ((tags (plist-get result :tags))
+ (orig-tags (plist-get result :orig-tags)))
+ (insert (format format-string (notmuch-tag-format-tags tags orig-tags)))))))
-(defun notmuch-search-show-result (result &optional pos)
- "Insert RESULT at POS or the end of the buffer if POS is null."
+(defun notmuch-search-show-result (result pos)
+ "Insert RESULT at POS."
;; Ignore excluded matches
(unless (= (plist-get result :matched) 0)
- (let ((beg (or pos (point-max))))
- (save-excursion
- (goto-char beg)
- (dolist (spec notmuch-search-result-format)
- (notmuch-search-insert-field (car spec) (cdr spec) result))
- (insert "\n")
- (notmuch-search-color-line beg (point) (plist-get result :tags))
- (put-text-property beg (point) 'notmuch-search-result result))
- (when (string= (plist-get result :thread) notmuch-search-target-thread)
- (setq notmuch-search-target-thread "found")
- (goto-char beg)))))
+ (save-excursion
+ (goto-char pos)
+ (dolist (spec notmuch-search-result-format)
+ (notmuch-search-insert-field (car spec) (cdr spec) result))
+ (insert "\n")
+ (notmuch-search-color-line pos (point) (plist-get result :tags))
+ (put-text-property pos (point) 'notmuch-search-result result))))
+
+(defun notmuch-search-append-result (result)
+ "Insert RESULT at the end of the buffer.
+
+This is only called when a result is first inserted so it also
+sets the :orig-tag property."
+ (let ((new-result (plist-put result :orig-tags (plist-get result :tags)))
+ (pos (point-max)))
+ (notmuch-search-show-result new-result pos)
+ (when (string= (plist-get result :thread) notmuch-search-target-thread)
+ (setq notmuch-search-target-thread "found")
+ (goto-char pos))))
(defun notmuch-search-process-filter (proc string)
"Process and filter the output of \"notmuch search\""
(save-excursion
(goto-char (point-max))
(insert string))
- (notmuch-sexp-parse-partial-list 'notmuch-search-show-result
+ (notmuch-sexp-parse-partial-list 'notmuch-search-append-result
results-buf)))))
(defun notmuch-search-tag-all (tag-changes)
(let (longest
(longest-length 0))
(loop for tuple in notmuch-saved-searches
- if (let ((quoted-query (regexp-quote (cdr tuple))))
+ if (let ((quoted-query (regexp-quote (notmuch-saved-search-get tuple :query))))
(and (string-match (concat "^" quoted-query) query)
(> (length (match-string 0 query))
longest-length)))
do (setq longest tuple))
longest))
- (saved-search-name (car saved-search))
- (saved-search-query (cdr saved-search)))
+ (saved-search-name (notmuch-saved-search-get saved-search :name))
+ (saved-search-query (notmuch-saved-search-get saved-search :query)))
(cond ((and saved-search (equal saved-search-query query))
;; Query is the same as saved search (ignoring case)
(concat "*notmuch-saved-search-" saved-search-name "*"))
PROMPT is the string to prompt with."
(lexical-let
((completions
- (append (list "folder:" "thread:" "id:" "date:" "from:" "to:"
+ (append (list "folder:" "path:" "thread:" "id:" "date:" "from:" "to:"
"subject:" "attachment:")
(mapcar (lambda (tag)
(concat "tag:" (notmuch-escape-boolean-term tag)))
(set 'notmuch-search-oldest-first oldest-first)
(set 'notmuch-search-target-thread target-thread)
(set 'notmuch-search-target-line target-line)
+ (notmuch-tag-clear-cache)
(let ((proc (get-buffer-process (current-buffer)))
(inhibit-read-only t))
(if proc
(setq mail-user-agent 'notmuch-user-agent)
(provide 'notmuch)
+
+;; After provide to avoid loops if notmuch was require'd via notmuch-init-file.
+(if init-file-user ; don't load init file if the -q option was used.
+ (let ((init-file (locate-file notmuch-init-file '("/")
+ (get-load-suffixes))))
+ (if init-file (load init-file nil t t))))
goto DONE;
}
+ /* Flush any buffered output before forking. */
+ fflush (stdout);
+
pid = fork();
if (pid == -1) {
fprintf (stderr, "Error: %s hook fork failed: %s\n", hook,
const char *prefix;
} prefix_t;
-#define NOTMUCH_DATABASE_VERSION 1
+#define NOTMUCH_DATABASE_VERSION 2
#define STRINGIFY(s) _SUB_STRINGIFY(s)
#define _SUB_STRINGIFY(s) #s
* In addition, terms from the content of the message are added with
* "from", "to", "attachment", and "subject" prefixes for use by the
* user in searching. Similarly, terms from the path of the mail
- * message are added with a "folder" prefix. But the database doesn't
- * really care itself about any of these.
+ * message are added with "folder" and "path" prefixes. But the
+ * database doesn't really care itself about any of these.
*
* The data portion of a mail document is empty.
*
{ "thread", "G" },
{ "tag", "K" },
{ "is", "K" },
- { "id", "Q" }
+ { "id", "Q" },
+ { "path", "P" },
+ /*
+ * Without the ":", since this is a multi-letter prefix, Xapian
+ * will add a colon itself if the first letter of the path is
+ * upper-case ASCII. Including the ":" forces there to always be a
+ * colon, which keeps our own logic simpler.
+ */
+ { "folder", "XFOLDER:" },
};
static prefix_t PROBABILISTIC_PREFIX[]= {
{ "to", "XTO" },
{ "attachment", "XATTACHMENT" },
{ "subject", "XSUBJECT"},
- { "folder", "XFOLDER"}
};
const char *
}
}
+ /*
+ * Prior to version 2, the "folder:" prefix was probabilistic and
+ * stemmed. Change it to the current boolean prefix. Add "path:"
+ * prefixes while at it.
+ */
+ if (version < 2) {
+ notmuch_query_t *query = notmuch_query_create (notmuch, "");
+ notmuch_messages_t *messages;
+ notmuch_message_t *message;
+
+ count = 0;
+ total = notmuch_query_count_messages (query);
+
+ for (messages = notmuch_query_search_messages (query);
+ notmuch_messages_valid (messages);
+ notmuch_messages_move_to_next (messages)) {
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
+
+ message = notmuch_messages_get (messages);
+
+ _notmuch_message_upgrade_folder (message);
+ _notmuch_message_sync (message);
+
+ notmuch_message_destroy (message);
+
+ count++;
+ }
+
+ notmuch_query_destroy (query);
+ }
+
db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION));
db->flush ();
if (ret)
goto DONE;
- notmuch_message_file_restrict_headers (message_file,
- "date",
- "from",
- "in-reply-to",
- "message-id",
- "references",
- "subject",
- "to",
- (char *) NULL);
+ /* Parse message up front to get better error status. */
+ ret = _notmuch_message_file_parse (message_file);
+ if (ret)
+ goto DONE;
try {
/* Before we do any real work, (especially before doing a
date = notmuch_message_file_get_header (message_file, "date");
_notmuch_message_set_header_values (message, date, from, subject);
- ret = _notmuch_message_index_file (message, filename);
+ ret = _notmuch_message_index_file (message, message_file);
if (ret)
goto DONE;
} else {
;;
esac
done
-nm $* | awk '$1 ~ "^[0-9a-fA-F][0-9a-fA-F]*$" && $2 == "T" && $3 ~ "^get(line|delim)$" {print $3 ";"}'
+nm $* | awk '$1 ~ "^[0-9a-fA-F][0-9a-fA-F]*$" && $2 == "T" && $3 ~ "^(getline|getdelim|canonicalize_file_name)$" {print $3 ";"}'
sed -n 's/^[[:space:]]*\(notmuch_[a-z_]*\)[[:space:]]*(.*/ \1;/p' $HEADER
printf "local: *;\n};\n"
InternetAddress *address)
{
InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX (address);
- const char *name, *addr;
+ const char *name, *addr, *combined;
void *local = talloc_new (message);
name = internet_address_get_name (address);
addr = internet_address_mailbox_get_addr (mailbox);
- /* In the absence of a name, we'll strip the part before the @
- * from the address. */
- if (! name) {
- const char *at;
+ /* Combine the name and address and index them as a phrase. */
+ if (name && addr)
+ combined = talloc_asprintf (local, "%s %s", name, addr);
+ else if (name)
+ combined = name;
+ else
+ combined = addr;
- at = strchr (addr, '@');
- if (at)
- name = talloc_strndup (local, addr, at - addr);
- }
-
- if (name)
- _notmuch_message_gen_terms (message, prefix_name, name);
- if (addr)
- _notmuch_message_gen_terms (message, prefix_name, addr);
+ if (combined)
+ _notmuch_message_gen_terms (message, prefix_name, combined);
talloc_free (local);
}
notmuch_status_t
_notmuch_message_index_file (notmuch_message_t *message,
- const char *filename)
+ notmuch_message_file_t *message_file)
{
- GMimeStream *stream = NULL;
- GMimeParser *parser = NULL;
- GMimeMessage *mime_message = NULL;
+ GMimeMessage *mime_message;
InternetAddressList *addresses;
- FILE *file = NULL;
const char *from, *subject;
- notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
- static int initialized = 0;
- char from_buf[5];
- bool is_mbox = false;
- static bool mbox_warning = false;
-
- if (! initialized) {
- g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS);
- initialized = 1;
- }
-
- file = fopen (filename, "r");
- if (! file) {
- fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
- ret = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
- /* Is this mbox? */
- if (fread (from_buf, sizeof (from_buf), 1, file) == 1 &&
- strncmp (from_buf, "From ", 5) == 0)
- is_mbox = true;
- rewind (file);
-
- /* Evil GMime steals my FILE* here so I won't fclose it. */
- stream = g_mime_stream_file_new (file);
-
- parser = g_mime_parser_new_with_stream (stream);
- g_mime_parser_set_scan_from (parser, is_mbox);
+ notmuch_status_t status;
- mime_message = g_mime_parser_construct_message (parser);
-
- if (is_mbox) {
- if (!g_mime_parser_eos (parser)) {
- /* This is a multi-message mbox. */
- ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
- goto DONE;
- }
- /* For historical reasons, we support single-message mboxes,
- * but this behavior is likely to change in the future, so
- * warn. */
- if (!mbox_warning) {
- mbox_warning = true;
- fprintf (stderr, "\
-Warning: %s is an mbox containing a single message,\n\
-likely caused by misconfigured mail delivery. Support for single-message\n\
-mboxes is deprecated and may be removed in the future.\n", filename);
- }
- }
+ status = _notmuch_message_file_get_mime_message (message_file,
+ &mime_message);
+ if (status)
+ return status;
from = g_mime_message_get_sender (mime_message);
_index_mime_part (message, g_mime_message_get_mime_part (mime_message));
- DONE:
- if (mime_message)
- g_object_unref (mime_message);
-
- if (parser)
- g_object_unref (parser);
-
- if (stream)
- g_object_unref (stream);
-
- return ret;
+ return NOTMUCH_STATUS_SUCCESS;
}
#include <glib.h> /* GHashTable */
-typedef struct {
- char *str;
- size_t size;
- size_t len;
-} header_value_closure_t;
-
struct _notmuch_message_file {
/* File object */
FILE *file;
+ char *filename;
- /* Header storage */
- int restrict_headers;
+ /* Cache for decoded headers */
GHashTable *headers;
- int broken_headers;
- int good_headers;
- size_t header_size; /* Length of full message header in bytes. */
-
- /* Parsing state */
- char *line;
- size_t line_size;
- header_value_closure_t value;
- int parsing_started;
- int parsing_finished;
+ GMimeMessage *message;
};
static int
static int
_notmuch_message_file_destructor (notmuch_message_file_t *message)
{
- if (message->line)
- free (message->line);
-
- if (message->value.size)
- free (message->value.str);
-
if (message->headers)
g_hash_table_destroy (message->headers);
+ if (message->message)
+ g_object_unref (message->message);
+
if (message->file)
fclose (message->file);
if (unlikely (message == NULL))
return NULL;
+ /* Only needed for error messages during parsing. */
+ message->filename = talloc_strdup (message, filename);
+ if (message->filename == NULL)
+ goto FAIL;
+
talloc_set_destructor (message, _notmuch_message_file_destructor);
message->file = fopen (filename, "r");
if (message->file == NULL)
goto FAIL;
- message->headers = g_hash_table_new_full (strcase_hash,
- strcase_equal,
- free,
- g_free);
-
- message->parsing_started = 0;
- message->parsing_finished = 0;
-
return message;
FAIL:
talloc_free (message);
}
-void
-notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,
- va_list va_headers)
+static notmuch_bool_t
+_is_mbox (FILE *file)
{
- char *header;
+ char from_buf[5];
+ notmuch_bool_t ret = FALSE;
- if (message->parsing_started)
- INTERNAL_ERROR ("notmuch_message_file_restrict_headers called after parsing has started");
+ /* Is this mbox? */
+ if (fread (from_buf, sizeof (from_buf), 1, file) == 1 &&
+ strncmp (from_buf, "From ", 5) == 0)
+ ret = TRUE;
- while (1) {
- header = va_arg (va_headers, char*);
- if (header == NULL)
- break;
- g_hash_table_insert (message->headers,
- xstrdup (header), NULL);
- }
+ rewind (file);
- message->restrict_headers = 1;
+ return ret;
}
-void
-notmuch_message_file_restrict_headers (notmuch_message_file_t *message, ...)
+notmuch_status_t
+_notmuch_message_file_parse (notmuch_message_file_t *message)
{
- va_list va_headers;
+ GMimeStream *stream;
+ GMimeParser *parser;
+ notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+ static int initialized = 0;
+ notmuch_bool_t is_mbox;
- va_start (va_headers, message);
+ if (message->message)
+ return NOTMUCH_STATUS_SUCCESS;
- notmuch_message_file_restrict_headersv (message, va_headers);
-}
+ is_mbox = _is_mbox (message->file);
-static void
-copy_header_unfolding (header_value_closure_t *value,
- const char *chunk)
-{
- char *last;
+ if (! initialized) {
+ g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS);
+ initialized = 1;
+ }
- if (chunk == NULL)
- return;
+ message->headers = g_hash_table_new_full (strcase_hash, strcase_equal,
+ free, g_free);
+ if (! message->headers)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
- while (*chunk == ' ' || *chunk == '\t')
- chunk++;
+ stream = g_mime_stream_file_new (message->file);
- if (value->len + 1 + strlen (chunk) + 1 > value->size) {
- unsigned int new_size = value->size;
- if (value->size == 0)
- new_size = strlen (chunk) + 1;
- else
- while (value->len + 1 + strlen (chunk) + 1 > new_size)
- new_size *= 2;
- value->str = xrealloc (value->str, new_size);
- value->size = new_size;
+ /* We'll own and fclose the FILE* ourselves. */
+ g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
+
+ parser = g_mime_parser_new_with_stream (stream);
+ g_mime_parser_set_scan_from (parser, is_mbox);
+
+ message->message = g_mime_parser_construct_message (parser);
+ if (! message->message) {
+ status = NOTMUCH_STATUS_FILE_NOT_EMAIL;
+ goto DONE;
}
- last = value->str + value->len;
- if (value->len) {
- *last = ' ';
- last++;
- value->len++;
+ if (is_mbox) {
+ if (! g_mime_parser_eos (parser)) {
+ /* This is a multi-message mbox. */
+ status = NOTMUCH_STATUS_FILE_NOT_EMAIL;
+ goto DONE;
+ }
+ /*
+ * For historical reasons, we support single-message mboxes,
+ * but this behavior is likely to change in the future, so
+ * warn.
+ */
+ static notmuch_bool_t mbox_warning = FALSE;
+ if (! mbox_warning) {
+ mbox_warning = TRUE;
+ fprintf (stderr, "\
+Warning: %s is an mbox containing a single message,\n\
+likely caused by misconfigured mail delivery. Support for single-message\n\
+mboxes is deprecated and may be removed in the future.\n", message->filename);
+ }
}
- strcpy (last, chunk);
- value->len += strlen (chunk);
+ DONE:
+ g_object_unref (stream);
+ g_object_unref (parser);
+
+ if (status) {
+ g_hash_table_destroy (message->headers);
+ message->headers = NULL;
- last = value->str + value->len - 1;
- if (*last == '\n') {
- *last = '\0';
- value->len--;
+ if (message->message) {
+ g_object_unref (message->message);
+ message->message = NULL;
+ }
+
+ rewind (message->file);
}
+
+ return status;
}
-/* As a special-case, a value of NULL for header_desired will force
- * the entire header to be parsed if it is not parsed already. This is
- * used by the _notmuch_message_file_get_headers_end function.
- * Another special case is the Received: header. For this header we
- * want to concatenate all instances of the header instead of just
- * hashing the first instance as we use this when analyzing the path
- * the mail has taken from sender to recipient.
- */
-const char *
-notmuch_message_file_get_header (notmuch_message_file_t *message,
- const char *header_desired)
+notmuch_status_t
+_notmuch_message_file_get_mime_message (notmuch_message_file_t *message,
+ GMimeMessage **mime_message)
{
- int contains;
- char *header, *decoded_value, *header_sofar, *combined_header;
- const char *s, *colon;
- int match, newhdr, hdrsofar, is_received;
- static int initialized = 0;
+ notmuch_status_t status;
- is_received = (strcmp(header_desired,"received") == 0);
+ status = _notmuch_message_file_parse (message);
+ if (status)
+ return status;
- if (! initialized) {
- g_mime_init (GMIME_ENABLE_RFC2047_WORKAROUNDS);
- initialized = 1;
- }
+ *mime_message = message->message;
- message->parsing_started = 1;
-
- if (header_desired == NULL)
- contains = 0;
- else
- contains = g_hash_table_lookup_extended (message->headers,
- header_desired, NULL,
- (gpointer *) &decoded_value);
-
- if (contains && decoded_value)
- return decoded_value;
-
- if (message->parsing_finished)
- return "";
-
-#define NEXT_HEADER_LINE(closure) \
- while (1) { \
- ssize_t bytes_read = getline (&message->line, \
- &message->line_size, \
- message->file); \
- if (bytes_read == -1) { \
- message->parsing_finished = 1; \
- break; \
- } \
- if (*message->line == '\n') { \
- message->parsing_finished = 1; \
- break; \
- } \
- if (closure && \
- (*message->line == ' ' || *message->line == '\t')) \
- { \
- copy_header_unfolding ((closure), message->line); \
- } \
- if (*message->line == ' ' || *message->line == '\t') \
- message->header_size += strlen (message->line); \
- else \
- break; \
- }
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+/*
+ * Get all instances of a header decoded and concatenated.
+ *
+ * The result must be freed using g_free().
+ *
+ * Return NULL on errors, empty string for non-existing headers.
+ */
+static char *
+_notmuch_message_file_get_combined_header (notmuch_message_file_t *message,
+ const char *header)
+{
+ GMimeHeaderList *headers;
+ GMimeHeaderIter *iter;
+ char *combined = NULL;
- if (message->line == NULL)
- NEXT_HEADER_LINE (NULL);
+ headers = g_mime_object_get_header_list (GMIME_OBJECT (message->message));
+ if (! headers)
+ return NULL;
- while (1) {
+ iter = g_mime_header_iter_new ();
+ if (! iter)
+ return NULL;
- if (message->parsing_finished)
- break;
+ if (! g_mime_header_list_get_iter (headers, iter))
+ goto DONE;
- colon = strchr (message->line, ':');
+ do {
+ const char *value;
+ char *decoded;
- if (colon == NULL) {
- message->broken_headers++;
- /* A simple heuristic for giving up on things that just
- * don't look like mail messages. */
- if (message->broken_headers >= 10 &&
- message->good_headers < 5)
- {
- message->parsing_finished = 1;
- break;
- }
- NEXT_HEADER_LINE (NULL);
+ if (strcasecmp (g_mime_header_iter_get_name (iter), header) != 0)
continue;
- }
- message->header_size += strlen (message->line);
+ /* Note that GMime retains ownership of value... */
+ value = g_mime_header_iter_get_value (iter);
- message->good_headers++;
+ /* ... while decoded needs to be freed with g_free(). */
+ decoded = g_mime_utils_header_decode_text (value);
+ if (! decoded) {
+ if (combined) {
+ g_free (combined);
+ combined = NULL;
+ }
+ goto DONE;
+ }
- header = xstrndup (message->line, colon - message->line);
+ if (combined) {
+ char *tmp = g_strdup_printf ("%s %s", combined, decoded);
+ g_free (decoded);
+ g_free (combined);
+ if (! tmp) {
+ combined = NULL;
+ goto DONE;
+ }
- if (message->restrict_headers &&
- ! g_hash_table_lookup_extended (message->headers,
- header, NULL, NULL))
- {
- free (header);
- NEXT_HEADER_LINE (NULL);
- continue;
+ combined = tmp;
+ } else {
+ combined = decoded;
}
+ } while (g_mime_header_iter_next (iter));
- s = colon + 1;
- while (*s == ' ' || *s == '\t')
- s++;
+ /* Return empty string for non-existing headers. */
+ if (! combined)
+ combined = g_strdup ("");
- message->value.len = 0;
- copy_header_unfolding (&message->value, s);
+ DONE:
+ g_mime_header_iter_free (iter);
- NEXT_HEADER_LINE (&message->value);
-
- if (header_desired == NULL)
- match = 0;
- else
- match = (strcasecmp (header, header_desired) == 0);
-
- decoded_value = g_mime_utils_header_decode_text (message->value.str);
- header_sofar = (char *)g_hash_table_lookup (message->headers, header);
- /* we treat the Received: header special - we want to concat ALL of
- * the Received: headers we encounter.
- * for everything else we return the first instance of a header */
- if (strcasecmp(header, "received") == 0) {
- if (header_sofar == NULL) {
- /* first Received: header we encountered; just add it */
- g_hash_table_insert (message->headers, header, decoded_value);
- } else {
- /* we need to add the header to those we already collected */
- newhdr = strlen(decoded_value);
- hdrsofar = strlen(header_sofar);
- combined_header = g_malloc(hdrsofar + newhdr + 2);
- strncpy(combined_header,header_sofar,hdrsofar);
- *(combined_header+hdrsofar) = ' ';
- strncpy(combined_header+hdrsofar+1,decoded_value,newhdr+1);
- g_free (decoded_value);
- g_hash_table_insert (message->headers, header, combined_header);
- }
- } else {
- if (header_sofar == NULL) {
- /* Only insert if we don't have a value for this header, yet. */
- g_hash_table_insert (message->headers, header, decoded_value);
- } else {
- free (header);
- g_free (decoded_value);
- decoded_value = header_sofar;
- }
- }
- /* if we found a match we can bail - unless of course we are
- * collecting all the Received: headers */
- if (match && !is_received)
- return decoded_value;
- }
+ return combined;
+}
- if (message->parsing_finished) {
- fclose (message->file);
- message->file = NULL;
- }
+const char *
+notmuch_message_file_get_header (notmuch_message_file_t *message,
+ const char *header)
+{
+ const char *value;
+ char *decoded;
- if (message->line)
- free (message->line);
- message->line = NULL;
+ if (_notmuch_message_file_parse (message))
+ return NULL;
- if (message->value.size) {
- free (message->value.str);
- message->value.str = NULL;
- message->value.size = 0;
- message->value.len = 0;
+ /* If we have a cached decoded value, use it. */
+ value = g_hash_table_lookup (message->headers, header);
+ if (value)
+ return value;
+
+ if (strcasecmp (header, "received") == 0) {
+ /*
+ * The Received: header is special. We concatenate all
+ * instances of the header as we use this when analyzing the
+ * path the mail has taken from sender to recipient.
+ */
+ decoded = _notmuch_message_file_get_combined_header (message, header);
+ } else {
+ value = g_mime_object_get_header (GMIME_OBJECT (message->message),
+ header);
+ if (value)
+ decoded = g_mime_utils_header_decode_text (value);
+ else
+ decoded = g_strdup ("");
}
- /* For the Received: header we actually might end up here even
- * though we found the header (as we force continued parsing
- * in that case). So let's check if that's the header we were
- * looking for and return the value that we found (if any)
- */
- if (is_received)
- return (char *)g_hash_table_lookup (message->headers, "received");
-
- /* We've parsed all headers and never found the one we're looking
- * for. It's probably just not there, but let's check that we
- * didn't make a mistake preventing us from seeing it. */
- if (message->restrict_headers && header_desired &&
- ! g_hash_table_lookup_extended (message->headers,
- header_desired, NULL, NULL))
- {
- INTERNAL_ERROR ("Attempt to get header \"%s\" which was not\n"
- "included in call to notmuch_message_file_restrict_headers\n",
- header_desired);
- }
+ if (! decoded)
+ return NULL;
+
+ /* Cache the decoded value. We also own the strings. */
+ g_hash_table_insert (message->headers, xstrdup (header), decoded);
- return "";
+ return decoded;
}
const char *
notmuch_message_get_header (notmuch_message_t *message, const char *header)
{
- std::string value;
+ try {
+ std::string value;
+
+ /* Fetch header from the appropriate xapian value field if
+ * available */
+ if (strcasecmp (header, "from") == 0)
+ value = message->doc.get_value (NOTMUCH_VALUE_FROM);
+ else if (strcasecmp (header, "subject") == 0)
+ value = message->doc.get_value (NOTMUCH_VALUE_SUBJECT);
+ else if (strcasecmp (header, "message-id") == 0)
+ value = message->doc.get_value (NOTMUCH_VALUE_MESSAGE_ID);
- /* Fetch header from the appropriate xapian value field if
- * available */
- if (strcasecmp (header, "from") == 0)
- value = message->doc.get_value (NOTMUCH_VALUE_FROM);
- else if (strcasecmp (header, "subject") == 0)
- value = message->doc.get_value (NOTMUCH_VALUE_SUBJECT);
- else if (strcasecmp (header, "message-id") == 0)
- value = message->doc.get_value (NOTMUCH_VALUE_MESSAGE_ID);
+ if (!value.empty())
+ return talloc_strdup (message, value.c_str ());
- if (!value.empty())
- return talloc_strdup (message, value.c_str ());
+ } catch (Xapian::Error &error) {
+ fprintf (stderr, "A Xapian exception occurred when reading header: %s\n",
+ error.get_msg().c_str());
+ message->notmuch->exception_reported = TRUE;
+ return NULL;
+ }
/* Otherwise fall back to parsing the file */
_notmuch_message_ensure_message_file (message);
return _notmuch_messages_create (message->replies);
}
+static void
+_notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
+{
+ Xapian::TermIterator i;
+ size_t prefix_len = strlen (prefix);
+
+ while (1) {
+ i = message->doc.termlist_begin ();
+ i.skip_to (prefix);
+
+ /* Terminate loop when no terms remain with desired prefix. */
+ if (i == message->doc.termlist_end () ||
+ strncmp ((*i).c_str (), prefix, prefix_len))
+ break;
+
+ try {
+ message->doc.remove_term ((*i));
+ } catch (const Xapian::InvalidArgumentError) {
+ /* Ignore failure to remove non-existent term. */
+ }
+ }
+}
+
+/* Return true if p points at "new" or "cur". */
+static bool is_maildir (const char *p)
+{
+ return strcmp (p, "cur") == 0 || strcmp (p, "new") == 0;
+}
+
+/* Add "folder:" term for directory. */
+static notmuch_status_t
+_notmuch_message_add_folder_terms (notmuch_message_t *message,
+ const char *directory)
+{
+ char *folder, *last;
+
+ folder = talloc_strdup (NULL, directory);
+ if (! folder)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ /*
+ * If the message file is in a leaf directory named "new" or
+ * "cur", presume maildir and index the parent directory. Thus a
+ * "folder:" prefix search matches messages in the specified
+ * maildir folder, i.e. in the specified directory and its "new"
+ * and "cur" subdirectories.
+ *
+ * Note that this means the "folder:" prefix can't be used for
+ * distinguishing between message files in "new" or "cur". The
+ * "path:" prefix needs to be used for that.
+ *
+ * Note the deliberate difference to _filename_is_in_maildir(). We
+ * don't want to index different things depending on the existence
+ * or non-existence of all maildir sibling directories "new",
+ * "cur", and "tmp". Doing so would be surprising, and difficult
+ * for the user to fix in case all subdirectories were not in
+ * place during indexing.
+ */
+ last = strrchr (folder, '/');
+ if (last) {
+ if (is_maildir (last + 1))
+ *last = '\0';
+ } else if (is_maildir (folder)) {
+ *folder = '\0';
+ }
+
+ _notmuch_message_add_term (message, "folder", folder);
+
+ talloc_free (folder);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+#define RECURSIVE_SUFFIX "/**"
+
+/* Add "path:" terms for directory. */
+static notmuch_status_t
+_notmuch_message_add_path_terms (notmuch_message_t *message,
+ const char *directory)
+{
+ /* Add exact "path:" term. */
+ _notmuch_message_add_term (message, "path", directory);
+
+ if (strlen (directory)) {
+ char *path, *p;
+
+ path = talloc_asprintf (NULL, "%s%s", directory, RECURSIVE_SUFFIX);
+ if (! path)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ /* Add recursive "path:" terms for directory and all parents. */
+ for (p = path + strlen (path) - 1; p > path; p--) {
+ if (*p == '/') {
+ strcpy (p, RECURSIVE_SUFFIX);
+ _notmuch_message_add_term (message, "path", path);
+ }
+ }
+
+ talloc_free (path);
+ }
+
+ /* Recursive all-matching path:** for consistency. */
+ _notmuch_message_add_term (message, "path", "**");
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+/* Add directory based terms for all filenames of the message. */
+static notmuch_status_t
+_notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message)
+{
+ const char *direntry_prefix = _find_prefix ("file-direntry");
+ int direntry_prefix_len = strlen (direntry_prefix);
+ Xapian::TermIterator i = message->doc.termlist_begin ();
+ notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
+ for (i.skip_to (direntry_prefix); i != message->doc.termlist_end (); i++) {
+ unsigned int directory_id;
+ const char *direntry, *directory;
+ char *colon;
+
+ /* Terminate loop at first term without desired prefix. */
+ if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len))
+ break;
+
+ /* Indicate that there are filenames remaining. */
+ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
+
+ direntry = (*i).c_str ();
+ direntry += direntry_prefix_len;
+
+ directory_id = strtol (direntry, &colon, 10);
+
+ if (colon == NULL || *colon != ':')
+ INTERNAL_ERROR ("malformed direntry");
+
+ directory = _notmuch_database_get_directory_path (ctx,
+ message->notmuch,
+ directory_id);
+
+ _notmuch_message_add_folder_terms (message, directory);
+ _notmuch_message_add_path_terms (message, directory);
+ }
+
+ return status;
+}
+
/* Add an additional 'filename' for 'message'.
*
* This change will not be reflected in the database until the next
* notmuch_directory_get_child_files() . */
_notmuch_message_add_term (message, "file-direntry", direntry);
- /* New terms allow user to search with folder: specification. */
- _notmuch_message_gen_terms (message, "folder", directory);
+ _notmuch_message_add_folder_terms (message, directory);
+ _notmuch_message_add_path_terms (message, directory);
talloc_free (local);
_notmuch_message_remove_filename (notmuch_message_t *message,
const char *filename)
{
- const char *direntry_prefix = _find_prefix ("file-direntry");
- int direntry_prefix_len = strlen (direntry_prefix);
- const char *folder_prefix = _find_prefix ("folder");
- int folder_prefix_len = strlen (folder_prefix);
void *local = talloc_new (message);
- char *zfolder_prefix = talloc_asprintf(local, "Z%s", folder_prefix);
- int zfolder_prefix_len = strlen (zfolder_prefix);
char *direntry;
notmuch_private_status_t private_status;
notmuch_status_t status;
- Xapian::TermIterator i, last;
status = _notmuch_database_filename_to_direntry (
local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry);
if (status)
return status;
- /* Re-synchronize "folder:" terms for this message. This requires:
- * 1. removing all "folder:" terms
- * 2. removing all "folder:" stemmed terms
- * 3. adding back terms for all remaining filenames of the message. */
+ /* Re-synchronize "folder:" and "path:" terms for this message. */
- /* 1. removing all "folder:" terms */
- while (1) {
- i = message->doc.termlist_begin ();
- i.skip_to (folder_prefix);
+ /* Remove all "folder:" terms. */
+ _notmuch_message_remove_terms (message, _find_prefix ("folder"));
- /* Terminate loop when no terms remain with desired prefix. */
- if (i == message->doc.termlist_end () ||
- strncmp ((*i).c_str (), folder_prefix, folder_prefix_len))
- {
- break;
- }
+ /* Remove all "path:" terms. */
+ _notmuch_message_remove_terms (message, _find_prefix ("path"));
- try {
- message->doc.remove_term ((*i));
- } catch (const Xapian::InvalidArgumentError) {
- /* Ignore failure to remove non-existent term. */
- }
- }
-
- /* 2. removing all "folder:" stemmed terms */
- while (1) {
- i = message->doc.termlist_begin ();
- i.skip_to (zfolder_prefix);
-
- /* Terminate loop when no terms remain with desired prefix. */
- if (i == message->doc.termlist_end () ||
- strncmp ((*i).c_str (), zfolder_prefix, zfolder_prefix_len))
- {
- break;
- }
+ /* Add back terms for all remaining filenames of the message. */
+ status = _notmuch_message_add_directory_terms (local, message);
- try {
- message->doc.remove_term ((*i));
- } catch (const Xapian::InvalidArgumentError) {
- /* Ignore failure to remove non-existent term. */
- }
- }
-
- /* 3. adding back terms for all remaining filenames of the message. */
- i = message->doc.termlist_begin ();
- i.skip_to (direntry_prefix);
-
- for (; i != message->doc.termlist_end (); i++) {
- unsigned int directory_id;
- const char *direntry, *directory;
- char *colon;
-
- /* Terminate loop at first term without desired prefix. */
- if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len))
- break;
-
- /* Indicate that there are filenames remaining. */
- status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
-
- direntry = (*i).c_str ();
- direntry += direntry_prefix_len;
-
- directory_id = strtol (direntry, &colon, 10);
+ talloc_free (local);
- if (colon == NULL || *colon != ':')
- INTERNAL_ERROR ("malformed direntry");
+ return status;
+}
- directory = _notmuch_database_get_directory_path (local,
- message->notmuch,
- directory_id);
- if (strlen (directory))
- _notmuch_message_gen_terms (message, "folder", directory);
- }
+/* Upgrade the "folder:" prefix from V1 to V2. */
+#define FOLDER_PREFIX_V1 "XFOLDER"
+#define ZFOLDER_PREFIX_V1 "Z" FOLDER_PREFIX_V1
+void
+_notmuch_message_upgrade_folder (notmuch_message_t *message)
+{
+ /* Remove all old "folder:" terms. */
+ _notmuch_message_remove_terms (message, FOLDER_PREFIX_V1);
- talloc_free (local);
+ /* Remove all old "folder:" stemmed terms. */
+ _notmuch_message_remove_terms (message, ZFOLDER_PREFIX_V1);
- return status;
+ /* Add new boolean "folder:" and "path:" terms. */
+ _notmuch_message_add_directory_terms (message, message);
}
char *
try {
value = message->doc.get_value (NOTMUCH_VALUE_TIMESTAMP);
} catch (Xapian::Error &error) {
- INTERNAL_ERROR ("Failed to read timestamp value from document.");
+ fprintf (stderr, "A Xapian exception occurred when reading date: %s\n",
+ error.get_msg().c_str());
+ message->notmuch->exception_reported = TRUE;
return 0;
}
return NOTMUCH_PRIVATE_STATUS_NULL_POINTER;
term_gen->set_document (message->doc);
- term_gen->set_termpos (message->termpos);
if (prefix_name) {
const char *prefix = _find_prefix (prefix_name);
+ term_gen->set_termpos (message->termpos);
term_gen->index_text (text, 1, prefix);
- message->termpos = term_gen->get_termpos ();
+ /* Create a gap between this an the next terms so they don't
+ * appear to be a phrase. */
+ message->termpos = term_gen->get_termpos () + 100;
}
+ term_gen->set_termpos (message->termpos);
term_gen->index_text (text);
+ /* Create a term gap, as above. */
+ message->termpos = term_gen->get_termpos () + 100;
return NOTMUCH_PRIVATE_STATUS_SUCCESS;
}
#include <talloc.h>
+#include <gmime/gmime.h>
+
#include "xutil.h"
#include "error_util.h"
void
_notmuch_message_upgrade_filename_storage (notmuch_message_t *message);
+void
+_notmuch_message_upgrade_folder (notmuch_message_t *message);
+
notmuch_status_t
_notmuch_message_add_filename (notmuch_message_t *message,
const char *filename);
const char *
notmuch_message_get_author (notmuch_message_t *message);
-
-/* index.cc */
-
-notmuch_status_t
-_notmuch_message_index_file (notmuch_message_t *message,
- const char *filename);
-
/* message-file.c */
/* XXX: I haven't decided yet whether these will actually get exported
void
notmuch_message_file_close (notmuch_message_file_t *message);
-/* Restrict 'message' to only save the named headers.
+/* Parse the message.
*
- * When the caller is only interested in a short list of headers,
- * known in advance, calling this function can avoid wasted time and
- * memory parsing/saving header values that will never be needed.
+ * This will be done automatically as necessary on other calls
+ * depending on it, but an explicit call allows for better error
+ * status reporting.
+ */
+notmuch_status_t
+_notmuch_message_file_parse (notmuch_message_file_t *message);
+
+/* Get the gmime message of a message file.
*
- * The variable arguments should be a list of const char * with a
- * final '(const char *) NULL' to terminate the list.
+ * The message file is parsed as necessary.
*
- * If this function is called, it must be called before any calls to
- * notmuch_message_get_header for this message.
+ * The GMimeMessage* is set to *mime_message on success (which the
+ * caller must not unref).
*
- * After calling this function, if notmuch_message_get_header is
- * called with a header name not in this list, then NULL will be
- * returned even if that header exists in the actual message.
+ * XXX: Would be nice to not have to expose GMimeMessage here.
*/
-void
-notmuch_message_file_restrict_headers (notmuch_message_file_t *message, ...);
-
-/* Identical to notmuch_message_restrict_headers but accepting a va_list. */
-void
-notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,
- va_list va_headers);
+notmuch_status_t
+_notmuch_message_file_get_mime_message (notmuch_message_file_t *message,
+ GMimeMessage **mime_message);
/* Get the value of the specified header from the message as a UTF-8 string.
+ *
+ * The message file is parsed as necessary.
*
* The header name is case insensitive.
*
* only until the message is closed. The caller should copy it if
* needing to modify the value or to hold onto it for longer.
*
- * Returns NULL if the message does not contain a header line matching
- * 'header'.
+ * Returns NULL on errors, empty string if the message does not
+ * contain a header line matching 'header'.
*/
const char *
notmuch_message_file_get_header (notmuch_message_file_t *message,
const char *header);
+/* index.cc */
+
+notmuch_status_t
+_notmuch_message_index_file (notmuch_message_t *message,
+ notmuch_message_file_t *message_file);
+
/* messages.c */
typedef struct _notmuch_message_node {
* Author: Carl Worth <cworth@cworth.org>
*/
+/**
+ * @defgroup notmuch The notmuch API
+ *
+ * Not much of an email library, (just index and search)
+ *
+ * @{
+ */
+
#ifndef NOTMUCH_H
#define NOTMUCH_H
+#ifndef __DOXYGEN__
+
#ifdef __cplusplus
# define NOTMUCH_BEGIN_DECLS extern "C" {
# define NOTMUCH_END_DECLS }
#define LIBNOTMUCH_MINOR_VERSION 1
#define LIBNOTMUCH_MICRO_VERSION 0
-/*
+#endif /* __DOXYGEN__ */
+
+/**
* Check the version of the notmuch library being compiled against.
*
* Return true if the library being compiled against is of the
* specified version or above. For example:
*
+ * @code
* #if LIBNOTMUCH_CHECK_VERSION(3, 1, 0)
* (code requiring libnotmuch 3.1.0 or above)
* #endif
+ * @endcode
*
- * LIBNOTMUCH_CHECK_VERSION has been defined since version 3.1.0; you
- * can use #if !defined(NOTMUCH_CHECK_VERSION) to check for versions
- * prior to that.
+ * LIBNOTMUCH_CHECK_VERSION has been defined since version 3.1.0; to
+ * check for versions prior to that, use:
+ *
+ * @code
+ * #if !defined(NOTMUCH_CHECK_VERSION)
+ * (code requiring libnotmuch prior to 3.1.0)
+ * #endif
+ * @endcode
*/
#define LIBNOTMUCH_CHECK_VERSION (major, minor, micro) \
(LIBNOTMUCH_MAJOR_VERSION > (major) || \
(LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION == (minor) && \
LIBNOTMUCH_MICRO_VERSION >= (micro)))
+/**
+ * Notmuch boolean type.
+ */
typedef int notmuch_bool_t;
-/* Status codes used for the return values of most functions.
+/**
+ * Status codes used for the return values of most functions.
*
* A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
- * completed without error. Any other value indicates an error as
- * follows:
- *
- * NOTMUCH_STATUS_SUCCESS: No error occurred.
- *
- * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory
- *
- * XXX: We don't really want to expose this lame XAPIAN_EXCEPTION
- * value. Instead we should map to things like DATABASE_LOCKED or
- * whatever.
- *
- * NOTMUCH_STATUS_READ_ONLY_DATABASE: An attempt was made to write to
- * a database opened in read-only mode.
- *
- * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
- *
- * NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to read or
- * write to a file (this could be file not found, permission
- * denied, etc.)
- *
- * NOTMUCH_STATUS_FILE_NOT_EMAIL: A file was presented that doesn't
- * appear to be an email message.
- *
- * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: A file contains a message ID
- * that is identical to a message already in the database.
- *
- * NOTMUCH_STATUS_NULL_POINTER: The user erroneously passed a NULL
- * pointer to a notmuch function.
- *
- * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds
- * NOTMUCH_TAG_MAX)
- *
- * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw
- * function has been called more times than notmuch_message_freeze.
- *
- * NOTMUCH_STATUS_UNBALANCED_ATOMIC: notmuch_database_end_atomic has
- * been called more times than notmuch_database_begin_atomic.
- *
- * And finally:
- *
- * NOTMUCH_STATUS_LAST_STATUS: Not an actual status value. Just a way
- * to find out how many valid status values there are.
+ * completed without error. Any other value indicates an error.
*/
typedef enum _notmuch_status {
+ /**
+ * No error occurred.
+ */
NOTMUCH_STATUS_SUCCESS = 0,
+ /**
+ * Out of memory.
+ */
NOTMUCH_STATUS_OUT_OF_MEMORY,
+ /**
+ * An attempt was made to write to a database opened in read-only
+ * mode.
+ */
NOTMUCH_STATUS_READ_ONLY_DATABASE,
+ /**
+ * A Xapian exception occurred.
+ */
NOTMUCH_STATUS_XAPIAN_EXCEPTION,
+ /**
+ * An error occurred trying to read or write to a file (this could
+ * be file not found, permission denied, etc.)
+ *
+ * @todo We don't really want to expose this lame XAPIAN_EXCEPTION
+ * value. Instead we should map to things like DATABASE_LOCKED or
+ * whatever.
+ */
NOTMUCH_STATUS_FILE_ERROR,
+ /**
+ * A file was presented that doesn't appear to be an email
+ * message.
+ */
NOTMUCH_STATUS_FILE_NOT_EMAIL,
+ /**
+ * A file contains a message ID that is identical to a message
+ * already in the database.
+ */
NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,
+ /**
+ * The user erroneously passed a NULL pointer to a notmuch
+ * function.
+ */
NOTMUCH_STATUS_NULL_POINTER,
+ /**
+ * A tag value is too long (exceeds NOTMUCH_TAG_MAX).
+ */
NOTMUCH_STATUS_TAG_TOO_LONG,
+ /**
+ * The notmuch_message_thaw function has been called more times
+ * than notmuch_message_freeze.
+ */
NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW,
+ /**
+ * notmuch_database_end_atomic has been called more times than
+ * notmuch_database_begin_atomic.
+ */
NOTMUCH_STATUS_UNBALANCED_ATOMIC,
+ /**
+ * The operation is not supported.
+ */
NOTMUCH_STATUS_UNSUPPORTED_OPERATION,
-
+ /**
+ * Not an actual status value. Just a way to find out how many
+ * valid status values there are.
+ */
NOTMUCH_STATUS_LAST_STATUS
} notmuch_status_t;
-/* Get a string representation of a notmuch_status_t value.
+/**
+ * Get a string representation of a notmuch_status_t value.
*
* The result is read-only.
*/
/* Various opaque data types. For each notmuch_<foo>_t see the various
* notmuch_<foo> functions below. */
+#ifndef __DOXYGEN__
typedef struct _notmuch_database notmuch_database_t;
typedef struct _notmuch_query notmuch_query_t;
typedef struct _notmuch_threads notmuch_threads_t;
typedef struct _notmuch_tags notmuch_tags_t;
typedef struct _notmuch_directory notmuch_directory_t;
typedef struct _notmuch_filenames notmuch_filenames_t;
+#endif /* __DOXYGEN__ */
-/* Create a new, empty notmuch database located at 'path'.
+/**
+ * Create a new, empty notmuch database located at 'path'.
*
* The path should be a top-level directory to a collection of
* plain-text email messages (one message per file). This call will
notmuch_status_t
notmuch_database_create (const char *path, notmuch_database_t **database);
+/**
+ * Database open mode for notmuch_database_open.
+ */
typedef enum {
+ /**
+ * Open database for reading only.
+ */
NOTMUCH_DATABASE_MODE_READ_ONLY = 0,
+ /**
+ * Open database for reading and writing.
+ */
NOTMUCH_DATABASE_MODE_READ_WRITE
} notmuch_database_mode_t;
-/* Open an existing notmuch database located at 'path'.
+/**
+ * Open an existing notmuch database located at 'path'.
*
* The database should have been created at some time in the past,
* (not necessarily by this process), by calling
notmuch_database_mode_t mode,
notmuch_database_t **database);
-/* Close the given notmuch database.
+/**
+ * Close the given notmuch database.
*
* After notmuch_database_close has been called, calls to other
* functions on objects derived from this database may either behave
void
notmuch_database_close (notmuch_database_t *database);
-/* A callback invoked by notmuch_database_compact to notify the user
+/**
+ * A callback invoked by notmuch_database_compact to notify the user
* of the progress of the compaction process.
*/
typedef void (*notmuch_compact_status_cb_t)(const char *message, void *closure);
-/* Compact a notmuch database, backing up the original database to the
+/**
+ * Compact a notmuch database, backing up the original database to the
* given path.
*
* The database will be opened with NOTMUCH_DATABASE_MODE_READ_WRITE
notmuch_compact_status_cb_t status_cb,
void *closure);
-/* Destroy the notmuch database, closing it if necessary and freeing
+/**
+ * Destroy the notmuch database, closing it if necessary and freeing
* all associated resources.
*/
void
notmuch_database_destroy (notmuch_database_t *database);
-/* Return the database path of the given database.
+/**
+ * Return the database path of the given database.
*
* The return value is a string owned by notmuch so should not be
- * modified nor freed by the caller. */
+ * modified nor freed by the caller.
+ */
const char *
notmuch_database_get_path (notmuch_database_t *database);
-/* Return the database format version of the given database. */
+/**
+ * Return the database format version of the given database.
+ */
unsigned int
notmuch_database_get_version (notmuch_database_t *database);
-/* Does this database need to be upgraded before writing to it?
+/**
+ * Does this database need to be upgraded before writing to it?
*
* If this function returns TRUE then no functions that modify the
* database (notmuch_database_add_message, notmuch_message_add_tag,
* notmuch_directory_set_mtime, etc.) will work unless the function
- * notmuch_database_upgrade is called successfully first. */
+ * notmuch_database_upgrade is called successfully first.
+ */
notmuch_bool_t
notmuch_database_needs_upgrade (notmuch_database_t *database);
-/* Upgrade the current database.
+/**
+ * Upgrade the current database.
*
* After opening a database in read-write mode, the client should
* check if an upgrade is needed (notmuch_database_needs_upgrade) and
double progress),
void *closure);
-/* Begin an atomic database operation.
+/**
+ * Begin an atomic database operation.
*
* Any modifications performed between a successful begin and a
* notmuch_database_end_atomic will be applied to the database
notmuch_status_t
notmuch_database_begin_atomic (notmuch_database_t *notmuch);
-/* Indicate the end of an atomic database operation.
+/**
+ * Indicate the end of an atomic database operation.
*
* Return value:
*
notmuch_status_t
notmuch_database_end_atomic (notmuch_database_t *notmuch);
-/* Retrieve a directory object from the database for 'path'.
+/**
+ * Retrieve a directory object from the database for 'path'.
*
* Here, 'path' should be a path relative to the path of 'database'
* (see notmuch_database_get_path), or else should be an absolute path
* If this directory object does not exist in the database, this
* returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL.
*
+ * Otherwise the returned directory object is owned by the database
+ * and as such, will only be valid until notmuch_database_destroy is
+ * called.
+ *
* Return value:
*
* NOTMUCH_STATUS_SUCCESS: Successfully retrieved directory.
const char *path,
notmuch_directory_t **directory);
-/* Add a new message to the given notmuch database or associate an
+/**
+ * Add a new message to the given notmuch database or associate an
* additional filename with an existing message.
*
* Here, 'filename' should be a path relative to the path of
const char *filename,
notmuch_message_t **message);
-/* Remove a message filename from the given notmuch database. If the
+/**
+ * Remove a message filename from the given notmuch database. If the
* message has no more filenames, remove the message.
*
* If the same message (as determined by the message ID) is still
notmuch_database_remove_message (notmuch_database_t *database,
const char *filename);
-/* Find a message with the given message_id.
+/**
+ * Find a message with the given message_id.
*
* If a message with the given message_id is found then, on successful return
* (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message
const char *message_id,
notmuch_message_t **message);
-/* Find a message with the given filename.
+/**
+ * Find a message with the given filename.
*
* If the database contains a message with the given filename then, on
* successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
const char *filename,
notmuch_message_t **message);
-/* Return a list of all tags found in the database.
+/**
+ * Return a list of all tags found in the database.
*
* This function creates a list of all tags found in the database. The
* resulting list contains all tags from all messages found in the database.
notmuch_tags_t *
notmuch_database_get_all_tags (notmuch_database_t *db);
-/* Create a new query for 'database'.
+/**
+ * Create a new query for 'database'.
*
* Here, 'database' should be an open database, (see
* notmuch_database_open and notmuch_database_create).
notmuch_query_create (notmuch_database_t *database,
const char *query_string);
-/* Sort values for notmuch_query_set_sort */
+/**
+ * Sort values for notmuch_query_set_sort.
+ */
typedef enum {
+ /**
+ * Oldest first.
+ */
NOTMUCH_SORT_OLDEST_FIRST,
+ /**
+ * Newest first.
+ */
NOTMUCH_SORT_NEWEST_FIRST,
+ /**
+ * Sort by message-id.
+ */
NOTMUCH_SORT_MESSAGE_ID,
+ /**
+ * Do not sort.
+ */
NOTMUCH_SORT_UNSORTED
} notmuch_sort_t;
-/* Return the query_string of this query. See notmuch_query_create. */
+/**
+ * Return the query_string of this query. See notmuch_query_create.
+ */
const char *
notmuch_query_get_query_string (notmuch_query_t *query);
-/* Exclude values for notmuch_query_set_omit_excluded. The strange
+/**
+ * Exclude values for notmuch_query_set_omit_excluded. The strange
* order is to maintain backward compatibility: the old FALSE/TRUE
* options correspond to the new
* NOTMUCH_EXCLUDE_FLAG/NOTMUCH_EXCLUDE_TRUE options.
NOTMUCH_EXCLUDE_ALL
} notmuch_exclude_t;
-/* Specify whether to omit excluded results or simply flag them. By
+/**
+ * Specify whether to omit excluded results or simply flag them. By
* default, this is set to TRUE.
*
* If set to TRUE or ALL, notmuch_query_search_messages will omit excluded
notmuch_query_set_omit_excluded (notmuch_query_t *query,
notmuch_exclude_t omit_excluded);
-/* Specify the sorting desired for this query. */
+/**
+ * Specify the sorting desired for this query.
+ */
void
notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort);
-/* Return the sort specified for this query. See notmuch_query_set_sort. */
+/**
+ * Return the sort specified for this query. See
+ * notmuch_query_set_sort.
+ */
notmuch_sort_t
notmuch_query_get_sort (notmuch_query_t *query);
-/* Add a tag that will be excluded from the query results by default.
+/**
+ * Add a tag that will be excluded from the query results by default.
* This exclusion will be overridden if this tag appears explicitly in
- * the query. */
+ * the query.
+ */
void
notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag);
-/* Execute a query for threads, returning a notmuch_threads_t object
+/**
+ * Execute a query for threads, returning a notmuch_threads_t object
* which can be used to iterate over the results. The returned threads
* object is owned by the query and as such, will only be valid until
* notmuch_query_destroy.
notmuch_threads_t *
notmuch_query_search_threads (notmuch_query_t *query);
-/* Execute a query for messages, returning a notmuch_messages_t object
+/**
+ * Execute a query for messages, returning a notmuch_messages_t object
* which can be used to iterate over the results. The returned
* messages object is owned by the query and as such, will only be
* valid until notmuch_query_destroy.
notmuch_messages_t *
notmuch_query_search_messages (notmuch_query_t *query);
-/* Destroy a notmuch_query_t along with any associated resources.
+/**
+ * Destroy a notmuch_query_t along with any associated resources.
*
* This will in turn destroy any notmuch_threads_t and
* notmuch_messages_t objects generated by this query, (and in
void
notmuch_query_destroy (notmuch_query_t *query);
-/* Is the given 'threads' iterator pointing at a valid thread.
+/**
+ * Is the given 'threads' iterator pointing at a valid thread.
*
* When this function returns TRUE, notmuch_threads_get will return a
* valid object. Whereas when this function returns FALSE,
* notmuch_threads_get will return NULL.
*
+ * If passed a NULL pointer, this function returns FALSE
+ *
* See the documentation of notmuch_query_search_threads for example
* code showing how to iterate over a notmuch_threads_t object.
*/
notmuch_bool_t
notmuch_threads_valid (notmuch_threads_t *threads);
-/* Get the current thread from 'threads' as a notmuch_thread_t.
+/**
+ * Get the current thread from 'threads' as a notmuch_thread_t.
*
* Note: The returned thread belongs to 'threads' and has a lifetime
* identical to it (and the query to which it belongs).
notmuch_thread_t *
notmuch_threads_get (notmuch_threads_t *threads);
-/* Move the 'threads' iterator to the next thread.
+/**
+ * Move the 'threads' iterator to the next thread.
*
* If 'threads' is already pointing at the last thread then the
* iterator will be moved to a point just beyond that last thread,
void
notmuch_threads_move_to_next (notmuch_threads_t *threads);
-/* Destroy a notmuch_threads_t object.
+/**
+ * Destroy a notmuch_threads_t object.
*
* It's not strictly necessary to call this function. All memory from
* the notmuch_threads_t object will be reclaimed when the
void
notmuch_threads_destroy (notmuch_threads_t *threads);
-/* Return an estimate of the number of messages matching a search
+/**
+ * Return an estimate of the number of messages matching a search.
*
* This function performs a search and returns Xapian's best
* guess as to number of matching messages.
*/
unsigned
notmuch_query_count_messages (notmuch_query_t *query);
-
-/* Return the number of threads matching a search.
+
+/**
+ * Return the number of threads matching a search.
*
* This function performs a search and returns the number of unique thread IDs
* in the matching messages. This is the same as number of threads matching a
unsigned
notmuch_query_count_threads (notmuch_query_t *query);
-/* Get the thread ID of 'thread'.
+/**
+ * Get the thread ID of 'thread'.
*
* The returned string belongs to 'thread' and as such, should not be
* modified by the caller and will only be valid for as long as the
const char *
notmuch_thread_get_thread_id (notmuch_thread_t *thread);
-/* Get the total number of messages in 'thread'.
+/**
+ * Get the total number of messages in 'thread'.
*
* This count consists of all messages in the database belonging to
* this thread. Contrast with notmuch_thread_get_matched_messages() .
int
notmuch_thread_get_total_messages (notmuch_thread_t *thread);
-/* Get a notmuch_messages_t iterator for the top-level messages in
+/**
+ * Get a notmuch_messages_t iterator for the top-level messages in
* 'thread' in oldest-first order.
*
* This iterator will not necessarily iterate over all of the messages
notmuch_messages_t *
notmuch_thread_get_toplevel_messages (notmuch_thread_t *thread);
-/* Get a notmuch_thread_t iterator for all messages in 'thread' in
+/**
+ * Get a notmuch_thread_t iterator for all messages in 'thread' in
* oldest-first order.
*
* The returned list will be destroyed when the thread is destroyed.
notmuch_messages_t *
notmuch_thread_get_messages (notmuch_thread_t *thread);
-/* Get the number of messages in 'thread' that matched the search.
+/**
+ * Get the number of messages in 'thread' that matched the search.
*
* This count includes only the messages in this thread that were
* matched by the search from which the thread was created and were
int
notmuch_thread_get_matched_messages (notmuch_thread_t *thread);
-/* Get the authors of 'thread' as a UTF-8 string.
+/**
+ * Get the authors of 'thread' as a UTF-8 string.
*
* The returned string is a comma-separated list of the names of the
* authors of mail messages in the query results that belong to this
const char *
notmuch_thread_get_authors (notmuch_thread_t *thread);
-/* Get the subject of 'thread' as a UTF-8 string.
+/**
+ * Get the subject of 'thread' as a UTF-8 string.
*
* The subject is taken from the first message (according to the query
* order---see notmuch_query_set_sort) in the query results that
const char *
notmuch_thread_get_subject (notmuch_thread_t *thread);
-/* Get the date of the oldest message in 'thread' as a time_t value.
+/**
+ * Get the date of the oldest message in 'thread' as a time_t value.
*/
time_t
notmuch_thread_get_oldest_date (notmuch_thread_t *thread);
-/* Get the date of the newest message in 'thread' as a time_t value.
+/**
+ * Get the date of the newest message in 'thread' as a time_t value.
*/
time_t
notmuch_thread_get_newest_date (notmuch_thread_t *thread);
-/* Get the tags for 'thread', returning a notmuch_tags_t object which
+/**
+ * Get the tags for 'thread', returning a notmuch_tags_t object which
* can be used to iterate over all tags.
*
* Note: In the Notmuch database, tags are stored on individual
*
* for (tags = notmuch_thread_get_tags (thread);
* notmuch_tags_valid (tags);
- * notmuch_result_move_to_next (tags))
+ * notmuch_tags_move_to_next (tags))
* {
* tag = notmuch_tags_get (tags);
* ....
notmuch_tags_t *
notmuch_thread_get_tags (notmuch_thread_t *thread);
-/* Destroy a notmuch_thread_t object. */
+/**
+ * Destroy a notmuch_thread_t object.
+ */
void
notmuch_thread_destroy (notmuch_thread_t *thread);
-/* Is the given 'messages' iterator pointing at a valid message.
+/**
+ * Is the given 'messages' iterator pointing at a valid message.
*
* When this function returns TRUE, notmuch_messages_get will return a
* valid object. Whereas when this function returns FALSE,
notmuch_bool_t
notmuch_messages_valid (notmuch_messages_t *messages);
-/* Get the current message from 'messages' as a notmuch_message_t.
+/**
+ * Get the current message from 'messages' as a notmuch_message_t.
*
* Note: The returned message belongs to 'messages' and has a lifetime
* identical to it (and the query to which it belongs).
notmuch_message_t *
notmuch_messages_get (notmuch_messages_t *messages);
-/* Move the 'messages' iterator to the next message.
+/**
+ * Move the 'messages' iterator to the next message.
*
* If 'messages' is already pointing at the last message then the
* iterator will be moved to a point just beyond that last message,
void
notmuch_messages_move_to_next (notmuch_messages_t *messages);
-/* Destroy a notmuch_messages_t object.
+/**
+ * Destroy a notmuch_messages_t object.
*
* It's not strictly necessary to call this function. All memory from
* the notmuch_messages_t object will be reclaimed when the containing
void
notmuch_messages_destroy (notmuch_messages_t *messages);
-/* Return a list of tags from all messages.
+/**
+ * Return a list of tags from all messages.
*
* The resulting list is guaranteed not to contain duplicated tags.
*
notmuch_tags_t *
notmuch_messages_collect_tags (notmuch_messages_t *messages);
-/* Get the message ID of 'message'.
+/**
+ * Get the message ID of 'message'.
*
* The returned string belongs to 'message' and as such, should not be
* modified by the caller and will only be valid for as long as the
const char *
notmuch_message_get_message_id (notmuch_message_t *message);
-/* Get the thread ID of 'message'.
+/**
+ * Get the thread ID of 'message'.
*
* The returned string belongs to 'message' and as such, should not be
* modified by the caller and will only be valid for as long as the
const char *
notmuch_message_get_thread_id (notmuch_message_t *message);
-/* Get a notmuch_messages_t iterator for all of the replies to
+/**
+ * Get a notmuch_messages_t iterator for all of the replies to
* 'message'.
*
* Note: This call only makes sense if 'message' was ultimately
notmuch_messages_t *
notmuch_message_get_replies (notmuch_message_t *message);
-/* Get a filename for the email corresponding to 'message'.
+/**
+ * Get a filename for the email corresponding to 'message'.
*
* The returned filename is an absolute filename, (the initial
* component will match notmuch_database_get_path() ).
const char *
notmuch_message_get_filename (notmuch_message_t *message);
-/* Get all filenames for the email corresponding to 'message'.
+/**
+ * Get all filenames for the email corresponding to 'message'.
*
* Returns a notmuch_filenames_t iterator listing all the filenames
* associated with 'message'. These files may not have identical
notmuch_filenames_t *
notmuch_message_get_filenames (notmuch_message_t *message);
-/* Message flags */
+/**
+ * Message flags.
+ */
typedef enum _notmuch_message_flag {
NOTMUCH_MESSAGE_FLAG_MATCH,
NOTMUCH_MESSAGE_FLAG_EXCLUDED
} notmuch_message_flag_t;
-/* Get a value of a flag for the email corresponding to 'message'. */
+/**
+ * Get a value of a flag for the email corresponding to 'message'.
+ */
notmuch_bool_t
notmuch_message_get_flag (notmuch_message_t *message,
notmuch_message_flag_t flag);
-/* Set a value of a flag for the email corresponding to 'message'. */
+/**
+ * Set a value of a flag for the email corresponding to 'message'.
+ */
void
notmuch_message_set_flag (notmuch_message_t *message,
notmuch_message_flag_t flag, notmuch_bool_t value);
-/* Get the date of 'message' as a time_t value.
+/**
+ * Get the date of 'message' as a time_t value.
*
* For the original textual representation of the Date header from the
* message call notmuch_message_get_header() with a header value of
- * "date". */
+ * "date".
+ */
time_t
notmuch_message_get_date (notmuch_message_t *message);
-/* Get the value of the specified header from 'message' as a UTF-8 string.
+/**
+ * Get the value of the specified header from 'message' as a UTF-8 string.
*
* Common headers are stored in the database when the message is
* indexed and will be returned from the database. Other headers will
const char *
notmuch_message_get_header (notmuch_message_t *message, const char *header);
-/* Get the tags for 'message', returning a notmuch_tags_t object which
+/**
+ * Get the tags for 'message', returning a notmuch_tags_t object which
* can be used to iterate over all tags.
*
* The tags object is owned by the message and as such, will only be
*
* for (tags = notmuch_message_get_tags (message);
* notmuch_tags_valid (tags);
- * notmuch_result_move_to_next (tags))
+ * notmuch_tags_move_to_next (tags))
* {
* tag = notmuch_tags_get (tags);
* ....
notmuch_tags_t *
notmuch_message_get_tags (notmuch_message_t *message);
-/* The longest possible tag value. */
+/**
+ * The longest possible tag value.
+ */
#define NOTMUCH_TAG_MAX 200
-/* Add a tag to the given message.
+/**
+ * Add a tag to the given message.
*
* Return value:
*
notmuch_status_t
notmuch_message_add_tag (notmuch_message_t *message, const char *tag);
-/* Remove a tag from the given message.
+/**
+ * Remove a tag from the given message.
*
* Return value:
*
notmuch_status_t
notmuch_message_remove_tag (notmuch_message_t *message, const char *tag);
-/* Remove all tags from the given message.
+/**
+ * Remove all tags from the given message.
*
* See notmuch_message_freeze for an example showing how to safely
* replace tag values.
notmuch_status_t
notmuch_message_remove_all_tags (notmuch_message_t *message);
-/* Add/remove tags according to maildir flags in the message filename(s)
+/**
+ * Add/remove tags according to maildir flags in the message filename(s).
*
* This function examines the filenames of 'message' for maildir
* flags, and adds or removes tags on 'message' as follows when these
notmuch_status_t
notmuch_message_maildir_flags_to_tags (notmuch_message_t *message);
-/* Rename message filename(s) to encode tags as maildir flags
+/**
+ * Rename message filename(s) to encode tags as maildir flags.
*
* Specifically, for each filename corresponding to this message:
*
notmuch_status_t
notmuch_message_tags_to_maildir_flags (notmuch_message_t *message);
-/* Freeze the current state of 'message' within the database.
+/**
+ * Freeze the current state of 'message' within the database.
*
* This means that changes to the message state, (via
* notmuch_message_add_tag, notmuch_message_remove_tag, and
notmuch_status_t
notmuch_message_freeze (notmuch_message_t *message);
-/* Thaw the current 'message', synchronizing any changes that may have
+/**
+ * Thaw the current 'message', synchronizing any changes that may have
* occurred while 'message' was frozen into the notmuch database.
*
* See notmuch_message_freeze for an example of how to use this
notmuch_status_t
notmuch_message_thaw (notmuch_message_t *message);
-/* Destroy a notmuch_message_t object.
+/**
+ * Destroy a notmuch_message_t object.
*
* It can be useful to call this function in the case of a single
* query object with many messages in the result, (such as iterating
void
notmuch_message_destroy (notmuch_message_t *message);
-/* Is the given 'tags' iterator pointing at a valid tag.
+/**
+ * Is the given 'tags' iterator pointing at a valid tag.
*
* When this function returns TRUE, notmuch_tags_get will return a
* valid string. Whereas when this function returns FALSE,
notmuch_bool_t
notmuch_tags_valid (notmuch_tags_t *tags);
-/* Get the current tag from 'tags' as a string.
+/**
+ * Get the current tag from 'tags' as a string.
*
* Note: The returned string belongs to 'tags' and has a lifetime
* identical to it (and the query to which it ultimately belongs).
const char *
notmuch_tags_get (notmuch_tags_t *tags);
-/* Move the 'tags' iterator to the next tag.
+/**
+ * Move the 'tags' iterator to the next tag.
*
* If 'tags' is already pointing at the last tag then the iterator
* will be moved to a point just beyond that last tag, (where
void
notmuch_tags_move_to_next (notmuch_tags_t *tags);
-/* Destroy a notmuch_tags_t object.
+/**
+ * Destroy a notmuch_tags_t object.
*
* It's not strictly necessary to call this function. All memory from
* the notmuch_tags_t object will be reclaimed when the containing
void
notmuch_tags_destroy (notmuch_tags_t *tags);
-/* Store an mtime within the database for 'directory'.
+/**
+ * Store an mtime within the database for 'directory'.
*
* The 'directory' should be an object retrieved from the database
* with notmuch_database_get_directory for a particular path.
notmuch_directory_set_mtime (notmuch_directory_t *directory,
time_t mtime);
-/* Get the mtime of a directory, (as previously stored with
+/**
+ * Get the mtime of a directory, (as previously stored with
* notmuch_directory_set_mtime).
*
* Returns 0 if no mtime has previously been stored for this
- * directory.*/
+ * directory.
+ */
time_t
notmuch_directory_get_mtime (notmuch_directory_t *directory);
-/* Get a notmuch_filenames_t iterator listing all the filenames of
+/**
+ * Get a notmuch_filenames_t iterator listing all the filenames of
* messages in the database within the given directory.
*
* The returned filenames will be the basename-entries only (not
- * complete paths). */
+ * complete paths).
+ */
notmuch_filenames_t *
notmuch_directory_get_child_files (notmuch_directory_t *directory);
-/* Get a notmuch_filenams_t iterator listing all the filenames of
+/**
+ * Get a notmuch_filenams_t iterator listing all the filenames of
* sub-directories in the database within the given directory.
*
* The returned filenames will be the basename-entries only (not
- * complete paths). */
+ * complete paths).
+ */
notmuch_filenames_t *
notmuch_directory_get_child_directories (notmuch_directory_t *directory);
-/* Destroy a notmuch_directory_t object. */
+/**
+ * Destroy a notmuch_directory_t object.
+ */
void
notmuch_directory_destroy (notmuch_directory_t *directory);
-/* Is the given 'filenames' iterator pointing at a valid filename.
+/**
+ * Is the given 'filenames' iterator pointing at a valid filename.
*
* When this function returns TRUE, notmuch_filenames_get will return
* a valid string. Whereas when this function returns FALSE,
notmuch_bool_t
notmuch_filenames_valid (notmuch_filenames_t *filenames);
-/* Get the current filename from 'filenames' as a string.
+/**
+ * Get the current filename from 'filenames' as a string.
*
* Note: The returned string belongs to 'filenames' and has a lifetime
* identical to it (and the directory to which it ultimately belongs).
const char *
notmuch_filenames_get (notmuch_filenames_t *filenames);
-/* Move the 'filenames' iterator to the next filename.
+/**
+ * Move the 'filenames' iterator to the next filename.
*
* If 'filenames' is already pointing at the last filename then the
* iterator will be moved to a point just beyond that last filename,
void
notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);
-/* Destroy a notmuch_filenames_t object.
+/**
+ * Destroy a notmuch_filenames_t object.
*
* It's not strictly necessary to call this function. All memory from
* the notmuch_filenames_t object will be reclaimed when the
void
notmuch_filenames_destroy (notmuch_filenames_t *filenames);
+/* @} */
+
NOTMUCH_END_DECLS
#endif
{
unsigned int doc_id;
+ if (! threads)
+ return FALSE;
+
while (threads->doc_id_pos < threads->doc_ids->len) {
doc_id = g_array_index (threads->doc_ids, unsigned int,
threads->doc_id_pos);
_resolve_thread_relationships (thread);
/* Commit to returning thread. */
- talloc_steal (ctx, thread);
+ (void) talloc_steal (ctx, thread);
DONE:
talloc_free (local);
+++ /dev/null
-# ignore gzipped man pages
-*.[0-9].gz
+++ /dev/null
-all:
- $(MAKE) -C .. all
-
-.DEFAULT:
- $(MAKE) -C .. $@
+++ /dev/null
-# -*- Makefile -*-
-
-dir := man
-
-# this variable seems to be needed to prevent lazy evaluation causing
-# problems with $(dir) changing values.
-MAIN_PAGE := $(dir)/man1/notmuch.1
-
-MAN1 := \
- $(MAIN_PAGE) \
- $(dir)/man1/notmuch-compact.1 \
- $(dir)/man1/notmuch-config.1 \
- $(dir)/man1/notmuch-count.1 \
- $(dir)/man1/notmuch-dump.1 \
- $(dir)/man1/notmuch-restore.1 \
- $(dir)/man1/notmuch-insert.1 \
- $(dir)/man1/notmuch-new.1 \
- $(dir)/man1/notmuch-reply.1 \
- $(dir)/man1/notmuch-search.1 \
- $(dir)/man1/notmuch-show.1 \
- $(dir)/man1/notmuch-tag.1
-
-MAN5 := $(dir)/man5/notmuch-hooks.5
-MAN7 := $(dir)/man7/notmuch-search-terms.7
-
-MAN1_GZ := $(addsuffix .gz,$(MAN1))
-MAN5_GZ := $(addsuffix .gz,$(MAN5))
-MAN7_GZ := $(addsuffix .gz,$(MAN7))
-
-MAN_SOURCE := $(MAN1) $(MAN5) $(MAN7)
-MAN_BACKUP := $(addsuffix .bak,$(MAN_SOURCE))
-COMPRESSED_MAN := $(MAN1_GZ) $(MAN5_GZ) $(MAN7_GZ)
-
-%.gz: %
- gzip --stdout $^ > $@
-
-.PHONY: install-man update-man-versions
-
-install-man: $(COMPRESSED_MAN)
- mkdir -p "$(DESTDIR)$(mandir)/man1"
- mkdir -p "$(DESTDIR)$(mandir)/man5"
- mkdir -p "$(DESTDIR)$(mandir)/man7"
- install -m0644 $(MAN1_GZ) $(DESTDIR)/$(mandir)/man1
- install -m0644 $(MAN5_GZ) $(DESTDIR)/$(mandir)/man5
- install -m0644 $(MAN7_GZ) $(DESTDIR)/$(mandir)/man7
- cd $(DESTDIR)/$(mandir)/man1 && ln -sf notmuch.1.gz notmuch-setup.1.gz
-
-update-man-versions: $(MAN_SOURCE)
- for file in $(MAN_SOURCE); do \
- cp $$file $$file.bak ; \
- sed "s/^.TH NOTMUCH\([^[:blank:]]*\) \([1-9]\) .*$$/.TH NOTMUCH\1 \2 ${DATE} \"Notmuch ${VERSION}\"/" \
- < $$file.bak > $$file; \
- done
-
-CLEAN := $(CLEAN) $(COMPRESSED_MAN) $(MAN_BACKUP)
+++ /dev/null
-.TH NOTMUCH-COMPACT 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-compact \- compact the notmuch database
-.SH SYNOPSIS
-
-.B notmuch compact
-.RI "[ --quiet ]"
-.RI "[ --backup=<" directory "> ]"
-
-.SH DESCRIPTION
-
-The
-.B compact
-command can be used to compact the notmuch database. This can both reduce
-the space required by the database and improve lookup performance.
-
-The compacted database is built in a temporary directory and is later
-moved into the place of the origin database. The original uncompacted
-database is discarded, unless the
-.BR "\-\-backup=" <directory>
-option is used.
-
-Note that the database write lock will be held during the compaction
-process (which may be quite long) to protect data integrity.
-
-Supported options for
-.B compact
-include
-
-.RS 4
-.TP 4
-.BR "\-\-backup=" <directory>
-
-Save the current database to the given directory before replacing it
-with the compacted database. The backup directory must not exist and
-it must reside on the same mounted filesystem as the current database.
-
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-quiet
-
-Do not report database compaction progress to stdout.
-
-.RE
-
-.RE
-.SH ENVIRONMENT
-The following environment variables can be used to control the
-behavior of notmuch.
-.TP
-.B NOTMUCH_CONFIG
-Specifies the location of the notmuch configuration file. Notmuch will
-use ${HOME}/.notmuch\-config if this variable is not set.
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-count\fR(1), \fBnotmuch-dump\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-CONFIG 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-config \- access notmuch configuration file
-.SH SYNOPSIS
-
-.B notmuch config get
-.RI "<" section ">.<" item ">"
-
-.B notmuch config set
-.RI "<" section ">.<" item "> [" value " ...]"
-
-.B notmuch config list
-
-.SH DESCRIPTION
-
-The
-.B config
-command can be used to get or set settings in the notmuch
-configuration file.
-
-.RS 4
-.TP 4
-.B get
-The value of the specified configuration item is printed to stdout. If
-the item has multiple values (it is a list), each value is separated
-by a newline character.
-.RE
-
-.RS 4
-.TP 4
-.B set
-The specified configuration item is set to the given value. To specify
-a multiple-value item (a list), provide each value as a separate
-command-line argument.
-
-If no values are provided, the specified configuration item will be
-removed from the configuration file.
-.RE
-
-.RS 4
-.TP 4
-.B list
-Every configuration item is printed to stdout, each on a separate line
-of the form:
-
-.RI "" section "." item "=" value
-
-No additional whitespace surrounds the dot or equals sign characters. In a
-multiple-value item (a list), the values are separated by semicolon characters.
-.RE
-
-The available configuration items are described below.
-
-.RS 4
-.TP 4
-.B database.path
-The top-level directory where your mail currently exists and to where
-mail will be delivered in the future. Files should be individual email
-messages. Notmuch will store its database within a sub-directory of
-the path configured here named
-.BR ".notmuch".
-.RE
-
-.RS 4
-.TP 4
-.B user.name
-Your full name.
-.RE
-
-.RS 4
-.TP 4
-.B user.primary_email
-Your primary email address.
-.RE
-
-.RS 4
-.TP 4
-.B user.other_email
-A list of other email addresses at which you receive email.
-.RE
-
-.RS 4
-.TP 4
-.B new.tags
-A list of tags that will be added to all messages incorporated by
-.BR "notmuch new".
-.RE
-
-.RS 4
-.TP 4
-.B new.ignore
-A list of file and directory names, without path, that will not be
-searched for messages by
-.BR "notmuch new".
-All the files and directories matching any of the names specified here
-will be ignored, regardless of the location in the mail store
-directory hierarchy.
-.RE
-
-.RS 4
-.TP 4
-.B search.exclude_tags
-A list of tags that will be excluded from search results by
-default. Using an excluded tag in a query will override that
-exclusion.
-.RE
-
-.RS 4
-.TP 4
-.B maildir.synchronize_flags
-If true, then the following maildir flags (in message filenames) will
-be synchronized with the corresponding notmuch tags:
-
- Flag Tag
- ---- -------
- D draft
- F flagged
- P passed
- R replied
- S unread (added when 'S' flag is not present)
-
-The
-.B notmuch new
-command will notice flag changes in filenames and update tags, while
-the
-.B notmuch tag
-and
-.B notmuch restore
-commands will notice tag changes and update flags in filenames.
-
-If there have been any changes in the maildir (new messages added, old
-ones removed or renamed, maildir flags changed, etc.), it is advisable
-to run
-.B notmuch new
-before
-.B notmuch tag
-or
-.B notmuch restore
-commands to ensure the tag changes are properly synchronized to the
-maildir flags, as the commands expect the database and maildir to be
-in sync.
-.RE
-
-.RE
-.SH ENVIRONMENT
-The following environment variables can be used to control the
-behavior of notmuch.
-.TP
-.B NOTMUCH_CONFIG
-Specifies the location of the notmuch configuration file. Notmuch will
-use ${HOME}/.notmuch\-config if this variable is not set.
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-count\fR(1), \fBnotmuch-dump\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-COUNT 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-count \- count messages matching the given search terms
-.SH SYNOPSIS
-
-.B notmuch count
-.RI [ options "... ] <" search-term ">..."
-
-.SH DESCRIPTION
-
-Count messages matching the search terms.
-
-The number of matching messages (or threads) is output to stdout.
-
-With no search terms, a count of all messages (or threads) in the database will
-be displayed.
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for <search-terms>.
-
-Supported options for
-.B count
-include
-.RS 4
-.TP 4
-.B \-\-output=(messages|threads|files)
-
-.RS 4
-.TP 4
-.B messages
-
-Output the number of matching messages. This is the default.
-.RE
-.RS 4
-.TP 4
-.B threads
-
-Output the number of matching threads.
-.RE
-.RS 4
-.TP 4
-.B files
-
-Output the number of files associated with matching messages. This may
-be bigger than the number of matching messages due to duplicates
-(i.e. multiple files having the same message-id).
-.RE
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-exclude=(true|false)
-
-Specify whether to omit messages matching search.tag_exclude from the
-count (the default) or not.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-batch
-
-Read queries from a file (stdin by default), one per line, and output
-the number of matching messages (or threads) to stdout, one per
-line. On an empty input line the count of all messages (or threads) in
-the database will be output. This option is not compatible with
-specifying search terms on the command line.
-.RE
-
-.RS 4
-.TP 4
-.BR "\-\-input=" <filename>
-
-Read input from given file, instead of from stdin. Implies
-.BR --batch .
-.RE
-
-.RE
-.RE
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-dump\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-DUMP 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-dump \- creates a plain-text dump of the tags of each message
-
-.SH SYNOPSIS
-
-.B "notmuch dump"
-.RB [ "\-\-format=(sup|batch-tag)" "] [--]"
-.RI "[ --output=<" filename "> ] [--]"
-.RI "[ <" search-term ">...]"
-
-.SH DESCRIPTION
-
-Dump tags for messages matching the given search terms.
-
-Output is to the given filename, if any, or to stdout.
-
-These tags are the only data in the notmuch database that can't be
-recreated from the messages themselves. The output of notmuch dump is
-therefore the only critical thing to backup (and much more friendly to
-incremental backup than the native database files.)
-
-.TP 4
-.B \-\-format=(sup|batch-tag)
-
-Notmuch restore supports two plain text dump formats, both with one message-id
-per line, followed by a list of tags.
-
-.RS 4
-.TP 4
-.B sup
-
-The
-.B sup
-dump file format is specifically chosen to be
-compatible with the format of files produced by sup-dump.
-So if you've previously been using sup for mail, then the
-.B "notmuch restore"
-command provides you a way to import all of your tags (or labels as
-sup calls them).
-Each line has the following form
-
-.RS 4
-.RI < message-id >
-.B (
-.RI < tag "> ..."
-.B )
-
-with zero or more tags are separated by spaces. Note that (malformed)
-message-ids may contain arbitrary non-null characters. Note also
-that tags with spaces will not be correctly restored with this format.
-
-.RE
-
-.RE
-.RS 4
-.TP 4
-.B batch-tag
-
-The
-.B batch-tag
-dump format is intended to more robust against malformed message-ids
-and tags containing whitespace or non-\fBascii\fR(7) characters.
-Each line has the form
-
-.RS 4
-.RI "+<" "encoded-tag" "> " "" "+<" "encoded-tag" "> ... -- " "" " id:<" quoted-message-id >
-
-Tags are hex-encoded by replacing every byte not matching the regex
-.B [A-Za-z0-9@=.,_+-]
-with
-.B %nn
-where nn is the two digit hex encoding. The message ID is a valid Xapian
-query, quoted using Xapian boolean term quoting rules: if the ID contains
-whitespace or a close paren or starts with a double quote, it must be
-enclosed in double quotes and double quotes inside the ID must be doubled.
-The astute reader will notice this is a special case of the batch input
-format for \fBnotmuch-tag\fR(1); note that the single message-id query is
-mandatory for \fBnotmuch-restore\fR(1).
-
-.RE
-
-
-With no search terms, a dump of all messages in the database will be
-generated. A "--" argument instructs notmuch that the
-remaining arguments are search terms.
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for <search-terms>.
-
-.RE
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-INSERT 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-insert \- add a message to the maildir and notmuch database
-.SH SYNOPSIS
-
-.B notmuch insert
-.RI "[" options "]"
-.RI "[ +<" tag> "|\-<" tag "> ... ]"
-
-.SH DESCRIPTION
-
-.B notmuch insert
-reads a message from standard input
-and delivers it into the maildir directory given by configuration option
-.BR database.path ,
-then incorporates the message into the notmuch database.
-It is an alternative to using a separate tool to deliver
-the message then running
-.B notmuch new
-afterwards.
-
-The new message will be tagged with the tags specified by the
-.B new.tags
-configuration option, then by operations specified on the command-line:
-tags prefixed by '+' are added while
-those prefixed by '\-' are removed.
-
-If the new message is a duplicate of an existing message in the database
-(it has same Message-ID), it will be added to the maildir folder and
-notmuch database, but the tags will not be changed.
-
-Option arguments must appear before any tag operation arguments.
-Supported options for
-.B insert
-include
-.RS 4
-.TP 4
-.BI "--folder=<" folder ">"
-
-Deliver the message to the specified folder,
-relative to the top-level directory given by the value of
-\fBdatabase.path\fR.
-The default is to deliver to the top-level directory.
-
-.RE
-
-.RS 4
-.TP 4
-.B "--create-folder"
-
-Try to create the folder named by the
-.B "--folder"
-option, if it does not exist.
-Otherwise the folder must already exist for mail
-delivery to succeed.
-
-.RE
-.SH EXIT STATUS
-
-This command returns exit status 0 if the message was successfully
-added to the mail directory, even if the message could not be indexed
-and added to the notmuch database. In the latter case, a warning will
-be printed to standard error but the message file will be left on disk.
-
-If the message could not be written to disk then a non-zero exit
-status is returned.
-
-.RE
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-reply\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-NEW 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-new \- incorporate new mail into the notmuch database
-.SH SYNOPSIS
-
-.B notmuch new
-.RB "[" --no-hooks "]"
-
-.SH DESCRIPTION
-
-Find and import any new messages to the database.
-
-The
-.B new
-command scans all sub-directories of the database, performing
-full-text indexing on new messages that are found. Each new message
-will automatically be tagged with both the
-.BR inbox " and " unread
-tags.
-
-You should run
-.B "notmuch new"
-once after first running
-.B "notmuch setup"
-to create the initial database. The first run may take a long time if
-you have a significant amount of mail (several hundred thousand
-messages or more). Subsequently, you should run
-.B "notmuch new"
-whenever new mail is delivered and you wish to incorporate it into the
-database. These subsequent runs will be much quicker than the initial
-run.
-
-Invoking
-.B notmuch
-with no command argument will run
-.B new
-if
-.B "notmuch setup"
-has previously been completed, but
-.B "notmuch new"
-has not previously been run.
-
-.B "notmuch new"
-updates tags according to maildir flag changes if the
-.B "maildir.synchronize_flags"
-configuration option is enabled. See \fBnotmuch-config\fR(1) for
-details.
-
-The
-.B new
-command supports hooks. See \fBnotmuch-hooks(5)\fR
-for more details on hooks.
-
-Supported options for
-.B new
-include
-.RS 4
-.TP 4
-.BR \-\-no\-hooks
-
-Prevents hooks from being run.
-.RE
-.RE
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-REPLY 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-reply \- constructs a reply template for a set of messages
-
-.SH SYNOPSIS
-
-.B notmuch reply
-.RI "[" options "...] <" search-term ">..."
-
-.SH DESCRIPTION
-
-Constructs a reply template for a set of messages.
-
-To make replying to email easier,
-.B notmuch reply
-takes an existing set of messages and constructs a suitable mail
-template. The Reply-to: header (if any, otherwise From:) is used for
-the To: address. Unless
-.BR \-\-reply-to=sender
-is specified, values from the To: and Cc: headers are copied, but not
-including any of the current user's email addresses (as configured in
-primary_mail or other_email in the .notmuch\-config file) in the
-recipient list.
-
-It also builds a suitable new subject, including Re: at the front (if
-not already present), and adding the message IDs of the messages being
-replied to to the References list and setting the In\-Reply\-To: field
-correctly.
-
-Finally, the original contents of the emails are quoted by prefixing
-each line with '> ' and included in the body.
-
-The resulting message template is output to stdout.
-
-Supported options for
-.B reply
-include
-.RS
-.TP 4
-.BR \-\-format= ( default | json | sexp | headers\-only )
-.RS
-.TP 4
-.BR default
-Includes subject and quoted message body as an RFC 2822 message.
-.TP
-.BR json
-Produces JSON output containing headers for a reply message and the
-contents of the original message. This output can be used by a client
-to create a reply message intelligently.
-.TP
-.BR sexp
-Produces S-Expression output containing headers for a reply message and
-the contents of the original message. This output can be used by a client
-to create a reply message intelligently.
-.TP
-.BR headers\-only
-Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
-.RE
-.RE
-
-.RS
-.TP 4
-.BR \-\-format-version=N
-
-Use the specified structured output format version. This is intended
-for programs that invoke \fBnotmuch\fR(1) internally. If omitted, the
-latest supported version will be used.
-.RE
-
-.RS
-.TP 4
-.BR \-\-reply\-to= ( all | sender )
-.RS
-.TP 4
-.BR all " (default)"
-Replies to all addresses.
-.TP 4
-.BR sender
-Replies only to the sender. If replying to user's own message
-(Reply-to: or From: header is one of the user's configured email
-addresses), try To:, Cc:, and Bcc: headers in this order, and copy
-values from the first that contains something other than only the
-user's addresses.
-.RE
-.RE
-.RS
-.TP 4
-.B \-\-decrypt
-
-Decrypt any MIME encrypted parts found in the selected content
-(ie. "multipart/encrypted" parts). Status of the decryption will be
-reported (currently only supported with --format=json and
---format=sexp) and on successful decryption the multipart/encrypted
-part will be replaced by the decrypted content.
-
-Decryption expects a functioning \fBgpg-agent\fR(1) to provide any
-needed credentials. Without one, the decryption will fail.
-.RE
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for <search-terms>.
-
-Note: It is most common to use
-.B "notmuch reply"
-with a search string matching a single message, (such as
-id:<message-id>), but it can be useful to reply to several messages at
-once. For example, when a series of patches are sent in a single
-thread, replying to the entire thread allows for the reply to comment
-on issues found in multiple patches. The default format supports
-replying to multiple messages at once, but the JSON and S-Expression
-formats do not.
-.RE
-.RE
-
-.SH EXIT STATUS
-
-This command supports the following special exit status codes
-
-.TP
-.B 20
-The requested format version is too old.
-.TP
-.B 21
-The requested format version is too new.
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-RESTORE 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-restore \- restores the tags from the given file (see notmuch dump)
-
-.SH SYNOPSIS
-
-.B "notmuch restore"
-.RB [ "--accumulate" ]
-.RB [ "--format=(auto|batch-tag|sup)" ]
-.RI "[ --input=<" filename "> ]"
-
-.SH DESCRIPTION
-
-Restores the tags from the given file (see
-.BR "notmuch dump" ")."
-
-The input is read from the given filename, if any, or from stdin.
-
-
-Supported options for
-.B restore
-include
-.RS 4
-.TP 4
-.B \-\-accumulate
-
-The union of the existing and new tags is applied, instead of
-replacing each message's tags as they are read in from the dump file.
-
-.RE
-.RS 4
-.TP 4
-.B \-\-format=(sup|batch-tag|auto)
-
-Notmuch restore supports two plain text dump formats, with each line
-specifying a message-id and a set of tags.
-For details of the actual formats, see \fBnotmuch-dump\fR(1).
-
-.RS 4
-.TP 4
-.B sup
-
-The
-.B sup
-dump file format is specifically chosen to be
-compatible with the format of files produced by sup-dump.
-So if you've previously been using sup for mail, then the
-.B "notmuch restore"
-command provides you a way to import all of your tags (or labels as
-sup calls them).
-
-.RE
-.RS 4
-.TP 4
-.B batch-tag
-
-The
-.B batch-tag
-dump format is intended to more robust against malformed message-ids
-and tags containing whitespace or non-\fBascii\fR(7) characters. See
-\fBnotmuch-dump\fR(1) for details on this format.
-
-.B "notmuch restore"
-updates the maildir flags according to tag changes if the
-.B "maildir.synchronize_flags"
-configuration option is enabled. See \fBnotmuch-config\fR(1) for
-details.
-
-.RE
-
-.RS 4
-.TP 4
-.B auto
-
-This option (the default) tries to guess the format from the
-input. For correctly formed input in either supported format, this
-heuristic, based the fact that batch-tag format contains no parentheses,
-should be accurate.
-
-.RE
-
-.RE
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-SEARCH 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-search \- search for messages matching the given search terms
-.SH SYNOPSIS
-
-.B notmuch search
-.RI [ options "...] <" search-term ">..."
-
-.SH DESCRIPTION
-
-Search for messages matching the given search terms, and display as
-results the threads containing the matched messages.
-
-The output consists of one line per thread, giving a thread ID, the
-date of the newest (or oldest, depending on the sort option) matched
-message in the thread, the number of matched messages and total
-messages in the thread, the names of all participants in the thread,
-and the subject of the newest (or oldest) message.
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for <search-terms>.
-
-Supported options for
-.B search
-include
-.RS 4
-.TP 4
-.BR \-\-format= ( json | sexp | text | text0 )
-
-Presents the results in either JSON, S-Expressions, newline character
-separated plain-text (default), or null character separated plain-text
-(compatible with \fBxargs\fR(1) -0 option where available).
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-format-version=N
-
-Use the specified structured output format version. This is intended
-for programs that invoke \fBnotmuch\fR(1) internally. If omitted, the
-latest supported version will be used.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-output=(summary|threads|messages|files|tags)
-
-.RS 4
-.TP 4
-.B summary
-
-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 the total number),
-the authors of the thread and the subject.
-.RE
-.RS 4
-.TP 4
-.B threads
-
-Output the thread IDs of all threads with any message matching the
-search terms, either one per line (\-\-format=text), separated by null
-characters (\-\-format=text0), as a JSON array (\-\-format=json), or
-an S-Expression list (\-\-format=sexp).
-.RE
-.RS 4
-.TP 4
-.B messages
-
-Output the message IDs of all messages matching the search terms,
-either one per line (\-\-format=text), separated by null characters
-(\-\-format=text0), as a JSON array (\-\-format=json), or as an
-S-Expression list (\-\-format=sexp).
-.RE
-.RS 4
-.TP 4
-.B files
-
-Output the filenames of all messages matching the search terms, either
-one per line (\-\-format=text), separated by null characters
-(\-\-format=text0), as a JSON array (\-\-format=json), or as an
-S-Expression list (\-\-format=sexp).
-
-Note that each message may have multiple filenames associated with it.
-All of them are included in the output, unless limited with the
-\-\-duplicate=N option.
-.RE
-.RS 4
-.TP 4
-.B tags
-
-Output all tags that appear on any message matching the search terms,
-either one per line (\-\-format=text), separated by null characters
-(\-\-format=text0), as a JSON array (\-\-format=json), or as an
-S-Expression list (\-\-format=sexp).
-.RE
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-sort= ( newest\-first | oldest\-first )
-
-This option can be used to present results in either chronological order
-.RB ( oldest\-first )
-or reverse chronological order
-.RB ( newest\-first ).
-
-Note: The thread order will be distinct between these two options
-(beyond being simply reversed). When sorting by
-.B oldest\-first
-the threads will be sorted by the oldest message in each thread, but
-when sorting by
-.B newest\-first
-the threads will be sorted by the newest message in each thread.
-
-By default, results will be displayed in reverse chronological order,
-(that is, the newest results will be displayed first).
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-offset=[\-]N
-
-Skip displaying the first N results. With the leading '\-', start at the Nth
-result from the end.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-limit=N
-
-Limit the number of displayed results to N.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-exclude=(true|false|all|flag)
-
-A message is called "excluded" if it matches at least one tag in
-search.tag_exclude that does not appear explicitly in the search terms.
-This option specifies whether to omit excluded messages in the search
-process.
-
-The default value,
-.BR true ,
-prevents excluded messages from matching the search terms.
-
-.B all
-additionally prevents excluded messages from appearing in displayed
-results, in effect behaving as though the excluded messages do not exist.
-
-.B false
-allows excluded messages to match search terms and appear in displayed
-results. Excluded messages are still marked in the relevant outputs.
-
-.B flag
-only has an effect when
-.BR --output=summary .
-The output is almost identical to
-.BR false ,
-but the "match count" is the number of matching non-excluded messages in the
-thread, rather than the number of matching messages.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-duplicate=N
-
-Effective with
-.BR --output=files ,
-output the Nth filename associated with each message matching the
-query (N is 1-based). If N is greater than the number of files
-associated with the message, don't print anything.
-
-Note that this option is orthogonal with the
-.BR folder:
-search prefix. The prefix matches messages based on filenames. This
-option filters filenames of the matching messages.
-.RE
-
-.SH EXIT STATUS
-
-This command supports the following special exit status codes
-
-.TP
-.B 20
-The requested format version is too old.
-.TP
-.B 21
-The requested format version is too new.
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-notmuch.1
\ No newline at end of file
+++ /dev/null
-.TH NOTMUCH-SHOW 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-show \- show messages matching the given search terms
-.SH SYNOPSIS
-
-.B notmuch show
-.RI "[" options "...] <" search-term ">..."
-
-.SH DESCRIPTION
-
-Shows all messages matching the search terms.
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for <search-terms>.
-
-The messages will be grouped and sorted based on the threading (all
-replies to a particular message will appear immediately after that
-message in date order). The output is not indented by default, but
-depth tags are printed so that proper indentation can be performed by
-a post-processor (such as the emacs interface to notmuch).
-
-Supported options for
-.B show
-include
-.RS 4
-.TP 4
-.B \-\-entire\-thread=(true|false)
-
-If true,
-.B notmuch show
-outputs all messages in the thread of any message matching the search
-terms; if false, it outputs only the matching messages. For
-.B --format=json
-and
-.B --format=sexp
-this defaults to true. For other formats, this defaults to false.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-format=(text|json|sexp|mbox|raw)
-
-.RS 4
-.TP 4
-.BR text " (default for messages)"
-
-The default plain-text format has all text-content MIME parts
-decoded. Various components in the output,
-.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
-will be delimited by easily-parsed markers. Each marker consists of a
-Control-L character (ASCII decimal 12), the name of the marker, and
-then either an opening or closing brace, ('{' or '}'), to either open
-or close the component. For a multipart MIME message, these parts will
-be nested.
-.RE
-.RS 4
-.TP 4
-.B json
-
-The output is formatted with Javascript Object Notation (JSON). This
-format is more robust than the text format for automated
-processing. The nested structure of multipart MIME messages is
-reflected in nested JSON output. By default JSON output includes all
-messages in a matching thread; that is, by default,
-
-.B \-\-format=json
-sets
-.B "\-\-entire\-thread"
-The caller can disable this behaviour by setting
-.B \-\-entire\-thread=false
-.RE
-.RS 4
-.TP 4
-.B sexp
-
-The output is formatted as an S-Expression (sexp). This
-format is more robust than the text format for automated
-processing. The nested structure of multipart MIME messages is
-reflected in nested S-Expression output. By default,
-S-Expression output includes all messages in a matching thread;
-that is, by default,
-
-.B \-\-format=sexp
-sets
-.B "\-\-entire\-thread"
-The caller can disable this behaviour by setting
-.B \-\-entire\-thread=false
-
-.RE
-.RS 4
-.TP 4
-.B mbox
-
-All matching messages are output in the traditional, Unix mbox format
-with each message being prefixed by a line beginning with "From " and
-a blank line separating each message. Lines in the message content
-beginning with "From " (preceded by zero or more '>' characters) have
-an additional '>' character added. This reversible escaping
-is termed "mboxrd" format and described in detail here:
-
-.nf
-.nh
-http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
-.hy
-.fi
-.
-.RE
-.RS 4
-.TP 4
-.BR raw " (default for a single part, see \-\-part)"
-
-For a message or an attached message part, the original, raw content
-of the email message is output. Consumers of this format should expect
-to implement MIME decoding and similar functions.
-
-For a single part (\-\-part) the raw part content is output after
-performing any necessary MIME decoding. Note that messages with a
-simple body still have two parts: part 0 is the whole message and part
-1 is the body.
-
-For a multipart part, the part headers and body (including all child
-parts) is output.
-
-The raw format must only be used with search terms matching single
-message.
-.RE
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-format-version=N
-
-Use the specified structured output format version. This is intended
-for programs that invoke \fBnotmuch\fR(1) internally. If omitted, the
-latest supported version will be used.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-part=N
-
-Output the single decoded MIME part N of a single message. The search
-terms must match only a single message. Message parts are numbered in
-a depth-first walk of the message MIME structure, and are identified
-in the 'json', 'sexp' or 'text' output formats.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-verify
-
-Compute and report the validity of any MIME cryptographic signatures
-found in the selected content (ie. "multipart/signed" parts). Status
-of the signature will be reported (currently only supported with
---format=json and --format=sexp), and the multipart/signed part
-will be replaced by the signed data.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-decrypt
-
-Decrypt any MIME encrypted parts found in the selected content
-(ie. "multipart/encrypted" parts). Status of the decryption will be
-reported (currently only supported with --format=json and
---format=sexp) and on successful decryption the multipart/encrypted
-part will be replaced by the decrypted content.
-
-Decryption expects a functioning \fBgpg-agent\fR(1) to provide any
-needed credentials. Without one, the decryption will fail.
-
-Implies --verify.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-exclude=(true|false)
-
-Specify whether to omit threads only matching search.tag_exclude from
-the search results (the default) or not. In either case the excluded
-message will be marked with the exclude flag (except when output=mbox
-when there is nowhere to put the flag).
-
-If --entire-thread is specified then complete threads are returned
-regardless (with the excluded flag being set when appropriate) but
-threads that only match in an excluded message are not returned when
-.B --exclude=true.
-
-The default is
-.B --exclude=true.
-
-.RE
-
-.RS 4
-.TP 4
-.B \-\-body=(true|false)
-
-If true (the default)
-.B notmuch show
-includes the bodies of the messages in the output; if false,
-bodies are omitted.
-.B --body=false
-is only implemented for the json and sexp formats and it is incompatible with
-.B --part > 0.
-
-This is useful if the caller only needs the headers as body-less
-output is much faster and substantially smaller.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-include-html
-
-Include "text/html" parts as part of the output (currently only supported with
---format=json and --format=sexp).
-By default, unless
-.B --part=N
-is used to select a specific part or
-.B --include-html
-is used to include all "text/html" parts, no part with content type "text/html"
-is included in the output.
-.RE
-
-A common use of
-.B notmuch show
-is to display a single thread of email messages. For this, use a
-search term of "thread:<thread-id>" as can be seen in the first
-column of output from the
-.B notmuch search
-command.
-
-.SH EXIT STATUS
-
-This command supports the following special exit status codes
-
-.TP
-.B 20
-The requested format version is too old.
-.TP
-.B 21
-The requested format version is too new.
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
-\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-TAG 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch-tag \- add/remove tags for all messages matching the search terms
-
-.SH SYNOPSIS
-.B notmuch tag
-.RI [ options "...] +<" tag ">|\-<" tag "> [...] [\-\-] <" search-term "> [...]"
-
-.B notmuch tag
-.RI "--batch"
-.RI "[ --input=<" filename "> ]"
-
-
-.SH DESCRIPTION
-
-Add/remove tags for all messages matching the search terms.
-
-See \fBnotmuch-search-terms\fR(7)
-for details of the supported syntax for
-.RI < search-term >.
-
-Tags prefixed by '+' are added while those prefixed by '\-' are
-removed. For each message, tag changes are applied in the order they
-appear on the command line.
-
-The beginning of the search terms is recognized by the first
-argument that begins with neither '+' nor '\-'. Support for
-an initial search term beginning with '+' or '\-' is provided
-by allowing the user to specify a "\-\-" argument to separate
-the tags from the search terms.
-
-.B "notmuch tag"
-updates the maildir flags according to tag changes if the
-.B "maildir.synchronize_flags"
-configuration option is enabled. See \fBnotmuch-config\fR(1) for
-details.
-
-Supported options for
-.B tag
-include
-.RS 4
-.TP 4
-.BR \-\-remove\-all
-
-Remove all tags from each message matching the search terms before
-applying the tag changes appearing on the command line. This means
-setting the tags of each message to the tags to be added. If there are
-no tags to be added, the messages will have no tags.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-batch
-
-Read batch tagging operations from a file (stdin by default). This is more
-efficient than repeated
-.B notmuch tag
-invocations. See
-.B TAG FILE FORMAT
-below for the input format. This option is not compatible with
-specifying tagging on the command line.
-.RE
-
-.RS 4
-.TP 4
-.BR "\-\-input=" <filename>
-
-Read input from given file, instead of from stdin. Implies
-.BR --batch .
-
-.SH TAG FILE FORMAT
-
-The input must consist of lines of the format:
-
-.RI "+<" tag ">|\-<" tag "> [...] [\-\-] <" query ">"
-
-Each line is interpreted similarly to
-.B notmuch tag
-command line arguments. The delimiter is one or more spaces ' '. Any
-characters in
-.RI < tag >
-.B may
-be hex-encoded with %NN where NN is the hexadecimal value of the
-character. To hex-encode a character with a multi-byte UTF-8 encoding,
-hex-encode each byte.
-Any spaces in <tag>
-.B must
-be hex-encoded as %20. Any characters that are not
-part of
-.RI < tag >
-.B must not
-be hex-encoded.
-
-In the future tag:"tag with spaces" style quoting may be supported for
-.RI < tag >
-as well;
-for this reason all double quote characters in
-.RI < tag >
-.B should
-be hex-encoded.
-
-The
-.RI < query >
-should be quoted using Xapian boolean term quoting rules: if a term
-contains whitespace or a close paren or starts with a double quote, it
-must be enclosed in double quotes (not including any prefix) and
-double quotes inside the term must be doubled (see below for
-examples).
-
-Leading and trailing space ' ' is ignored. Empty lines and lines
-beginning with '#' are ignored.
-
-.SS EXAMPLE
-
-The following shows a valid input to batch tagging. Note that only the
-isolated '*' acts as a wildcard. Also note the two different quotings
-of the tag
-.B space in tags
-.
-.RS
-.nf
-+winner *
-+foo::bar%25 -- (One and Two) or (One and tag:winner)
-+found::it -- tag:foo::bar%
-# ignore this line and the next
-
-+space%20in%20tags -- Two
-# add tag '(tags)', among other stunts.
-+crazy{ +(tags) +&are +#possible\ -- tag:"space in tags"
-+match*crazy -- tag:crazy{
-+some_tag -- id:"this is ""nauty)"""
-.fi
-.RE
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
-\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
-\fBnotmuch-show\fR(1),
+++ /dev/null
-.\" notmuch - Not much of an email program, (just index, search and tagging)
-.\"
-.\" Copyright © 2009 Carl Worth
-.\"
-.\" Notmuch 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.
-.\"
-.\" Notmuch is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public License
-.\" along with this program. If not, see http://www.gnu.org/licenses/ .
-.\"
-.\" Author: Carl Worth <cworth@cworth.org>
-.TH NOTMUCH 1 2013-12-30 "Notmuch 0.17"
-.SH NAME
-notmuch \- thread-based email index, search, and tagging
-.SH SYNOPSIS
-.B notmuch
-.RI "[" option " ...] " command " [" arg " ...]"
-.SH DESCRIPTION
-Notmuch is a command-line based program for indexing, searching,
-reading, and tagging large collections of email messages.
-
-This page describes how to get started using notmuch from the command
-line, and gives a brief overview of the commands available. For more
-information on e.g.
-.B notmuch show
-consult the \fBnotmuch-show\fR(1) man page, also accessible via
-.B notmuch help show
-
-The quickest way to get started with Notmuch is to simply invoke the
-.B notmuch
-command with no arguments, which will interactively guide you through
-the process of indexing your mail.
-.SH NOTE
-While the command-line program
-.B notmuch
-provides powerful functionality, it does not provide the most
-convenient interface for that functionality. More sophisticated
-interfaces are expected to be built on top of either the command-line
-interface, or more likely, on top of the notmuch library
-interface. See http://notmuchmail.org for more about alternate
-interfaces to notmuch. The emacs-based interface to notmuch (available under
-.B emacs/
-in the Notmuch source distribution) is probably the most widely used at
-this time.
-
-.SH OPTIONS
-
-Supported global options for
-.B notmuch
-include
-
-.RS 4
-.TP 4
-.B \-\-help
-
-Print a synopsis of available commands and exit.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-version
-
-Print the installed version of notmuch, and exit.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-config=FILE
-
-Specify the configuration file to use. This overrides any
-configuration file specified by ${NOTMUCH_CONFIG}.
-
-.RE
-
-.SH COMMANDS
-
-
-.SS SETUP
-
-The
-.B notmuch setup
-command is used to configure Notmuch for first use, (or to reconfigure
-it later).
-
-The setup command will prompt for your full name, your primary email
-address, any alternate email addresses you use, and the directory
-containing your email archives. Your answers will be written to a
-configuration file in ${NOTMUCH_CONFIG} (if set) or
-${HOME}/.notmuch-config . This configuration file will be created with
-descriptive comments, making it easy to edit by hand later to change the
-configuration. Or you can run
-.B "notmuch setup"
-again to change the configuration.
-
-The mail directory you specify can contain any number of
-sub-directories and should primarily contain only files with individual
-email messages (eg. maildir or mh archives are perfect). If there are
-other, non-email files (such as indexes maintained by other email
-programs) then notmuch will do its best to detect those and ignore
-them.
-
-Mail storage that uses mbox format, (where one mbox file contains many
-messages), will not work with notmuch. If that's how your mail is
-currently stored, it is recommended you first convert it to maildir
-format with a utility such as mb2md before running
-.B "notmuch setup" .
-
-Invoking
-.B notmuch
-with no command argument will run
-.B setup
-if the setup command has not previously been completed.
-.RE
-
-.SS OTHER COMMANDS
-
-Several of the notmuch commands accept search terms with a common
-syntax. See \fNnotmuch-search-terms\fR(7)
-for more details on the supported syntax.
-
-The
-.BR search ", " show " and " count
-commands are used to query the email database.
-
-The
-.B reply
-command is useful for preparing a template for an email reply.
-
-The
-.B tag
-command is the only command available for manipulating database
-contents.
-
-
-The
-.BR dump " and " restore
-commands can be used to create a textual dump of email tags for backup
-purposes, and to restore from that dump.
-
-The
-.B config
-command can be used to get or set settings int the notmuch
-configuration file.
-
-.SH ENVIRONMENT
-The following environment variables can be used to control the
-behavior of notmuch.
-.TP
-.B NOTMUCH_CONFIG
-Specifies the location of the notmuch configuration file. Notmuch will
-use ${HOME}/.notmuch\-config if this variable is not set.
-
-.TP
-.B NOTMUCH_TALLOC_REPORT
-Location to write a talloc memory usage report. See
-.B talloc_enable_leak_report_full
-in \fBtalloc\fR(3)
-for more information.
-
-.TP
-.B NOTMUCH_DEBUG_QUERY
-If set to a non-empty value, the notmuch library will print (to stderr) Xapian
-queries it constructs.
-
-.SH SEE ALSO
-
-\fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
-\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
-\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
-
-
-The notmuch website:
-.B http://notmuchmail.org
-.SH CONTACT
-Feel free to send questions, comments, or kudos to the notmuch mailing
-list <notmuch@notmuchmail.org> . Subscription is not required before
-posting, but is available from the notmuchmail.org website.
-
-Real-time interaction with the Notmuch community is available via IRC
-(server: irc.freenode.net, channel: #notmuch).
+++ /dev/null
-.TH NOTMUCH-HOOKS 5 2013-12-30 "Notmuch 0.17"
-
-.SH NAME
-notmuch-hooks \- hooks for notmuch
-
-.SH SYNOPSIS
- $DATABASEDIR/.notmuch/hooks/*
-
-.SH DESCRIPTION
-Hooks are scripts (or arbitrary executables or symlinks to such) that notmuch
-invokes before and after certain actions. These scripts reside in
-the .notmuch/hooks directory within the database directory and must have
-executable permissions.
-
-The currently available hooks are described below.
-.RS 4
-.TP 4
-.B pre\-new
-This hook is invoked by the
-.B new
-command before scanning or importing new messages into the database. If this
-hook exits with a non-zero status, notmuch will abort further processing of the
-.B new
-command.
-
-Typically this hook is used for fetching or delivering new mail to be imported
-into the database.
-.RE
-.RS 4
-.TP 4
-.B post\-new
-This hook is invoked by the
-.B new
-command after new messages have been imported into the database and initial tags
-have been applied. The hook will not be run if there have been any errors during
-the scan or import.
-
-Typically this hook is used to perform additional query\-based tagging on the
-imported messages.
-.RE
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
-\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
-\fBnotmuch-tag\fR(1)
+++ /dev/null
-.TH NOTMUCH-SEARCH-TERMS 7 2013-12-30 "Notmuch 0.17"
-
-.SH NAME
-notmuch-search-terms \- syntax for notmuch queries
-
-.SH SYNOPSIS
-
-.B notmuch count
-.RI [ options... ]
-.RI < search-term ">..."
-
-.B "notmuch dump"
-.RI "[ <" filename "> ] [--]"
-.RI "[ <" search-term ">...]"
-
-.B notmuch search
-.RI [ options "...] <" search-term ">..."
-
-.B notmuch show
-.RI "[" options "...] <" search-term ">..."
-
-.B notmuch tag
-.RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..."
-
-
-.SH DESCRIPTION
-Several notmuch commands accept a common syntax for search terms.
-
-The search terms can consist of free-form text (and quoted phrases)
-which will match all messages that contain all of the given
-terms/phrases in the body, the subject, or any of the sender or
-recipient headers.
-
-As a special case, a search string consisting of exactly a single
-asterisk ("*") will match all messages.
-
-In addition to free text, the following prefixes can be used to force
-terms to match against specific portions of an email, (where
-<brackets> indicate user-supplied values):
-
- from:<name-or-address>
-
- to:<name-or-address>
-
- subject:<word-or-quoted-phrase>
-
- attachment:<word>
-
- tag:<tag> (or is:<tag>)
-
- id:<message-id>
-
- thread:<thread-id>
-
- folder:<directory-path>
-
- date:<since>..<until>
-
-The
-.B from:
-prefix is used to match the name or address of the sender of an email
-message.
-
-The
-.B to:
-prefix is used to match the names or addresses of any recipient of an
-email message, (whether To, Cc, or Bcc).
-
-Any term prefixed with
-.B subject:
-will match only text from the subject of an email. Searching for a
-phrase in the subject is supported by including quotation marks around
-the phrase, immediately following
-.BR subject: .
-
-The
-.B attachment:
-prefix can be used to search for specific filenames (or extensions) of
-attachments to email messages.
-
-For
-.BR tag: " and " is:
-valid tag values include
-.BR inbox " and " unread
-by default for new messages added by
-.B notmuch new
-as well as any other tag values added manually with
-.BR "notmuch tag" .
-
-For
-.BR id: ,
-message ID values are the literal contents of the Message\-ID: header
-of email messages, but without the '<', '>' delimiters.
-
-The
-.B thread:
-prefix can be used with the thread ID values that are generated
-internally by notmuch (and do not appear in email messages). These
-thread ID values can be seen in the first column of output from
-.B "notmuch search"
-
-The
-.B folder:
-prefix can be used to search for email message files that are
-contained within particular directories within the mail store. If the
-same email message has multiple message files associated with it, it's
-sufficient for a match that at least one of the files is contained
-within a matching directory. Only the directory components below the
-top-level mail database path are available to be searched.
-
-The
-.B date:
-prefix can be used to restrict the results to only messages within a
-particular time range (based on the Date: header) with a range syntax
-of:
-
- date:<since>..<until>
-
-See \fBDATE AND TIME SEARCH\fR below for details on the range
-expression, and supported syntax for <since> and <until> date and time
-expressions.
-
-The time range can also be specified using timestamps with a syntax
-of:
-
- <initial-timestamp>..<final-timestamp>
-
-Each timestamp is a number representing the number of seconds since
-1970\-01\-01 00:00:00 UTC.
-
-In addition to individual terms, multiple terms can be
-combined with Boolean operators (
-.BR and ", " or ", " not
-, etc.). Each term in the query will be implicitly connected by a
-logical AND if no explicit operator is provided, (except that terms
-with a common prefix will be implicitly combined with OR until we get
-Xapian defect #402 fixed).
-
-Parentheses can also be used to control the combination of the Boolean
-operators, but will have to be protected from interpretation by the
-shell, (such as by putting quotation marks around any parenthesized
-expression).
-
-.SH DATE AND TIME SEARCH
-
-notmuch understands a variety of standard and natural ways of
-expressing dates and times, both in absolute terms ("2012-10-24") and
-in relative terms ("yesterday"). Any number of relative terms can be
-combined ("1 hour 25 minutes") and an absolute date/time can be
-combined with relative terms to further adjust it. A non-exhaustive
-description of the syntax supported for absolute and relative terms is
-given below.
-
-.RS 4
-.TP 4
-.B The range expression
-
-date:<since>..<until>
-
-The above expression restricts the results to only messages from
-<since> to <until>, based on the Date: header.
-
-<since> and <until> can describe imprecise times, such as "yesterday".
-In this case, <since> is taken as the earliest time it could describe
-(the beginning of yesterday) and <until> is taken as the latest time
-it could describe (the end of yesterday). Similarly,
-date:january..february matches from the beginning of January to the
-end of February.
-
-Currently, we do not support spaces in range expressions. You can
-replace the spaces with '_', or (in most cases) '-', or (in some
-cases) leave the spaces out altogether. Examples in this man page use
-spaces for clarity.
-
-Open-ended ranges are supported (since Xapian 1.2.1), i.e. it's
-possible to specify date:..<until> or date:<since>.. to not limit the
-start or end time, respectively. Pre-1.2.1 Xapian does not report an
-error on open ended ranges, but it does not work as expected either.
-
-Entering date:expr without ".." (for example date:yesterday) won't
-work, as it's not interpreted as a range expression at all. You can
-achieve the expected result by duplicating the expr both sides of ".."
-(for example date:yesterday..yesterday).
-.RE
-
-.RS 4
-.TP 4
-.B Relative date and time
-[N|number] (years|months|weeks|days|hours|hrs|minutes|mins|seconds|secs) [...]
-
-All refer to past, can be repeated and will be accumulated.
-
-Units can be abbreviated to any length, with the otherwise ambiguous
-single m being m for minutes and M for months.
-
-Number can also be written out one, two, ..., ten, dozen,
-hundred. Additionally, the unit may be preceded by "last" or "this"
-(e.g., "last week" or "this month").
-
-When combined with absolute date and time, the relative date and time
-specification will be relative from the specified absolute date and
-time.
-
-Examples: 5M2d, two weeks
-.RE
-
-.RS 4
-.TP 4
-.B Supported absolute time formats
-H[H]:MM[:SS] [(am|a.m.|pm|p.m.)]
-
-H[H] (am|a.m.|pm|p.m.)
-
-HHMMSS
-
-now
-
-noon
-
-midnight
-
-Examples: 17:05, 5pm
-.RE
-
-.RS 4
-.TP 4
-.B Supported absolute date formats
-YYYY-MM[-DD]
-
-DD-MM[-[YY]YY]
-
-MM-YYYY
-
-M[M]/D[D][/[YY]YY]
-
-M[M]/YYYY
-
-D[D].M[M][.[YY]YY]
-
-D[D][(st|nd|rd|th)] Mon[thname] [YYYY]
-
-Mon[thname] D[D][(st|nd|rd|th)] [YYYY]
-
-Wee[kday]
-
-Month names can be abbreviated at three or more characters.
-
-Weekday names can be abbreviated at three or more characters.
-
-Examples: 2012-07-31, 31-07-2012, 7/31/2012, August 3
-.RE
-
-.RS 4
-.TP 4
-.B Time zones
-(+|-)HH:MM
-
-(+|-)HH[MM]
-
-Some time zone codes, e.g. UTC, EET.
-.RE
-
-.SH SEE ALSO
-
-\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
-\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
-\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
-\fBnotmuch-search\fR(1), \fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
mime_node_t *
mime_node_seek_dfs (mime_node_t *node, int n);
+typedef enum dump_formats {
+ DUMP_FORMAT_AUTO,
+ DUMP_FORMAT_BATCH_TAG,
+ DUMP_FORMAT_SUP
+} dump_format_t;
+
+int
+notmuch_database_dump (notmuch_database_t *notmuch,
+ const char *output_file_name,
+ const char *query_str,
+ dump_format_t output_format,
+ notmuch_bool_t gzip_output);
+
#include "command-line-arguments.h"
#endif
const char *path = notmuch_config_get_database_path (config);
const char *backup_path = NULL;
notmuch_status_t ret;
- notmuch_bool_t quiet;
+ notmuch_bool_t quiet = FALSE;
int opt_index;
notmuch_opt_desc_t options[] = {
opt_index = parse_arguments (argc, argv, options, 1);
if (opt_index < 0)
- return 1;
+ return EXIT_FAILURE;
if (! quiet)
printf ("Compacting database...\n");
quiet ? NULL : status_update_cb, NULL);
if (ret) {
fprintf (stderr, "Compaction failed: %s\n", notmuch_status_to_string (ret));
- return 1;
+ return EXIT_FAILURE;
}
if (! quiet) {
printf ("Done.\n");
}
- return 0;
+ return EXIT_SUCCESS;
}
}
/* Try not to overwrite symlinks. */
- filename = realpath (config->filename, NULL);
+ filename = canonicalize_file_name (config->filename);
if (! filename) {
if (errno == ENOENT) {
filename = strdup (config->filename);
return config->is_new;
}
+static const char *
+_config_get (notmuch_config_t *config, char **field,
+ const char *group, const char *key)
+{
+ /* read from config file and cache value, if not cached already */
+ if (*field == NULL) {
+ char *value;
+ value = g_key_file_get_string (config->key_file, group, key, NULL);
+ if (value) {
+ *field = talloc_strdup (config, value);
+ free (value);
+ }
+ }
+ return *field;
+}
+
+static void
+_config_set (notmuch_config_t *config, char **field,
+ const char *group, const char *key, const char *value)
+{
+ g_key_file_set_string (config->key_file, group, key, value);
+
+ /* drop the cached value */
+ talloc_free (*field);
+ *field = NULL;
+}
static const char **
_config_get_list (notmuch_config_t *config,
{
assert(outlist);
+ /* read from config file and cache value, if not cached already */
if (*outlist == NULL) {
char **inlist = g_key_file_get_string_list (config->key_file,
size_t length, const char ***config_var )
{
g_key_file_set_string_list (config->key_file, group, name, list, length);
+
+ /* drop the cached value */
talloc_free (*config_var);
*config_var = NULL;
}
const char *
notmuch_config_get_database_path (notmuch_config_t *config)
{
- char *path;
-
- if (config->database_path == NULL) {
- path = g_key_file_get_string (config->key_file,
- "database", "path", NULL);
- if (path) {
- config->database_path = talloc_strdup (config, path);
- free (path);
- }
- }
-
- return config->database_path;
+ return _config_get (config, &config->database_path, "database", "path");
}
void
notmuch_config_set_database_path (notmuch_config_t *config,
const char *database_path)
{
- g_key_file_set_string (config->key_file,
- "database", "path", database_path);
-
- talloc_free (config->database_path);
- config->database_path = NULL;
+ _config_set (config, &config->database_path, "database", "path", database_path);
}
const char *
notmuch_config_get_user_name (notmuch_config_t *config)
{
- char *name;
-
- if (config->user_name == NULL) {
- name = g_key_file_get_string (config->key_file,
- "user", "name", NULL);
- if (name) {
- config->user_name = talloc_strdup (config, name);
- free (name);
- }
- }
-
- return config->user_name;
+ return _config_get (config, &config->user_name, "user", "name");
}
void
notmuch_config_set_user_name (notmuch_config_t *config,
const char *user_name)
{
- g_key_file_set_string (config->key_file,
- "user", "name", user_name);
-
- talloc_free (config->user_name);
- config->user_name = NULL;
+ _config_set (config, &config->user_name, "user", "name", user_name);
}
const char *
notmuch_config_get_user_primary_email (notmuch_config_t *config)
{
- char *email;
-
- if (config->user_primary_email == NULL) {
- email = g_key_file_get_string (config->key_file,
- "user", "primary_email", NULL);
- if (email) {
- config->user_primary_email = talloc_strdup (config, email);
- free (email);
- }
- }
-
- return config->user_primary_email;
+ return _config_get (config, &config->user_primary_email, "user", "primary_email");
}
void
notmuch_config_set_user_primary_email (notmuch_config_t *config,
const char *primary_email)
{
- g_key_file_set_string (config->key_file,
- "user", "primary_email", primary_email);
-
- talloc_free (config->user_primary_email);
- config->user_primary_email = NULL;
+ _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
}
const char **
int
notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
{
+ int ret;
+
argc--; argv++; /* skip subcommand argument */
if (argc < 1) {
fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (strcmp (argv[0], "get") == 0) {
if (argc != 2) {
fprintf (stderr, "Error: notmuch config get requires exactly "
"one argument.\n");
- return 1;
+ return EXIT_FAILURE;
}
- return notmuch_config_command_get (config, argv[1]);
+ ret = notmuch_config_command_get (config, argv[1]);
} else if (strcmp (argv[0], "set") == 0) {
if (argc < 2) {
fprintf (stderr, "Error: notmuch config set requires at least "
"one argument.\n");
- return 1;
+ return EXIT_FAILURE;
}
- return notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
+ ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
} else if (strcmp (argv[0], "list") == 0) {
- return notmuch_config_command_list (config);
+ ret = notmuch_config_command_list (config);
+ } else {
+ fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
+ argv[0]);
+ return EXIT_FAILURE;
}
- fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
- argv[0]);
- return 1;
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
+
}
notmuch_bool_t
};
opt_index = parse_arguments (argc, argv, options, 1);
-
- if (opt_index < 0) {
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
if (input_file_name) {
batch = TRUE;
if (input == NULL) {
fprintf (stderr, "Error opening %s for reading: %s\n",
input_file_name, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
}
if (batch && opt_index != argc) {
fprintf (stderr, "--batch and query string are not compatible\n");
- return 1;
+ return EXIT_FAILURE;
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
- return 1;
+ return EXIT_FAILURE;
query_str = query_string_from_args (config, argc-opt_index, argv+opt_index);
if (query_str == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (exclude == EXCLUDE_TRUE) {
if (input != stdin)
fclose (input);
- return ret;
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}
*/
#include "notmuch-client.h"
-#include "dump-restore-private.h"
+#include "hex-escape.h"
#include "string-util.h"
+#include <zlib.h>
-int
-notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
+
+static int
+database_dump_file (notmuch_database_t *notmuch, gzFile output,
+ const char *query_str, int output_format)
{
- notmuch_database_t *notmuch;
notmuch_query_t *query;
- FILE *output = stdout;
notmuch_messages_t *messages;
notmuch_message_t *message;
notmuch_tags_t *tags;
- const char *query_str = "";
-
- if (notmuch_database_open (notmuch_config_get_database_path (config),
- NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
- return 1;
-
- char *output_file_name = NULL;
- int opt_index;
-
- int output_format = DUMP_FORMAT_SUP;
-
- notmuch_opt_desc_t options[] = {
- { NOTMUCH_OPT_KEYWORD, &output_format, "format", 'f',
- (notmuch_keyword_t []){ { "sup", DUMP_FORMAT_SUP },
- { "batch-tag", DUMP_FORMAT_BATCH_TAG },
- { 0, 0 } } },
- { NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0 },
- { 0, 0, 0, 0, 0 }
- };
- opt_index = parse_arguments (argc, argv, options, 1);
-
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
-
- if (output_file_name) {
- output = fopen (output_file_name, "w");
- if (output == NULL) {
- fprintf (stderr, "Error opening %s for writing: %s\n",
- output_file_name, strerror (errno));
- return 1;
- }
- }
-
-
- if (opt_index < argc) {
- query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index);
- if (query_str == NULL) {
- fprintf (stderr, "Out of memory.\n");
- return 1;
- }
- }
+ if (! query_str)
+ query_str = "";
query = notmuch_query_create (notmuch, query_str);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Don't ask xapian to sort by Message-ID. Xapian optimizes returning the
* first results quickly at the expense of total time.
}
if (output_format == DUMP_FORMAT_SUP) {
- fprintf (output, "%s (", message_id);
+ gzprintf (output, "%s (", message_id);
}
for (tags = notmuch_message_get_tags (message);
const char *tag_str = notmuch_tags_get (tags);
if (! first)
- fputs (" ", output);
+ gzputs (output, " ");
first = 0;
if (output_format == DUMP_FORMAT_SUP) {
- fputs (tag_str, output);
+ gzputs (output, tag_str);
} else {
if (hex_encode (notmuch, tag_str,
&buffer, &buffer_size) != HEX_SUCCESS) {
fprintf (stderr, "Error: failed to hex-encode tag %s\n",
tag_str);
- return 1;
+ return EXIT_FAILURE;
}
- fprintf (output, "+%s", buffer);
+ gzprintf (output, "+%s", buffer);
}
}
if (output_format == DUMP_FORMAT_SUP) {
- fputs (")\n", output);
+ gzputs (output, ")\n");
} else {
if (make_boolean_term (notmuch, "id", message_id,
&buffer, &buffer_size)) {
fprintf (stderr, "Error quoting message id %s: %s\n",
message_id, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
- fprintf (output, " -- %s\n", buffer);
+ gzprintf (output, " -- %s\n", buffer);
}
notmuch_message_destroy (message);
}
- if (output != stdout)
- fclose (output);
-
notmuch_query_destroy (query);
+
+ return EXIT_SUCCESS;
+}
+
+/* Dump database into output_file_name if it's non-NULL, stdout
+ * otherwise.
+ */
+int
+notmuch_database_dump (notmuch_database_t *notmuch,
+ const char *output_file_name,
+ const char *query_str,
+ dump_format_t output_format,
+ notmuch_bool_t gzip_output)
+{
+ gzFile output = NULL;
+ const char *mode = gzip_output ? "w9" : "wT";
+ const char *name_for_error = output_file_name ? output_file_name : "stdout";
+
+ char *tempname = NULL;
+ int outfd = -1;
+
+ int ret = -1;
+
+ if (output_file_name) {
+ tempname = talloc_asprintf (notmuch, "%s.XXXXXX", output_file_name);
+ outfd = mkstemp (tempname);
+ } else {
+ outfd = dup (STDOUT_FILENO);
+ }
+
+ if (outfd < 0) {
+ fprintf (stderr, "Bad output file %s\n", name_for_error);
+ goto DONE;
+ }
+
+ output = gzdopen (outfd, mode);
+
+ if (output == NULL) {
+ fprintf (stderr, "Error opening %s for (gzip) writing: %s\n",
+ name_for_error, strerror (errno));
+ if (close (outfd))
+ fprintf (stderr, "Error closing %s during shutdown: %s\n",
+ name_for_error, strerror (errno));
+ goto DONE;
+ }
+
+ ret = database_dump_file (notmuch, output, query_str, output_format);
+ if (ret) goto DONE;
+
+ ret = gzflush (output, Z_FINISH);
+ if (ret) {
+ fprintf (stderr, "Error flushing output: %s\n", gzerror (output, NULL));
+ goto DONE;
+ }
+
+ if (output_file_name) {
+ ret = fsync (outfd);
+ if (ret) {
+ fprintf (stderr, "Error syncing %s to disk: %s\n",
+ name_for_error, strerror (errno));
+ goto DONE;
+ }
+ }
+
+ if (gzclose_w (output) != Z_OK) {
+ fprintf (stderr, "Error closing %s: %s\n", name_for_error,
+ gzerror (output, NULL));
+ ret = EXIT_FAILURE;
+ output = NULL;
+ goto DONE;
+ }
+
+ if (output_file_name) {
+ ret = rename (tempname, output_file_name);
+ if (ret) {
+ fprintf (stderr, "Error renaming %s to %s: %s\n",
+ tempname, output_file_name, strerror (errno));
+ goto DONE;
+ }
+
+ }
+ DONE:
+ if (ret != EXIT_SUCCESS && output)
+ (void) gzclose_w (output);
+
+ if (ret != EXIT_SUCCESS && output_file_name)
+ (void) unlink (tempname);
+
+ return ret;
+}
+
+int
+notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
+{
+ notmuch_database_t *notmuch;
+ const char *query_str = NULL;
+ int ret;
+
+ if (notmuch_database_open (notmuch_config_get_database_path (config),
+ NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
+ return EXIT_FAILURE;
+
+ char *output_file_name = NULL;
+ int opt_index;
+
+ int output_format = DUMP_FORMAT_BATCH_TAG;
+ notmuch_bool_t gzip_output = 0;
+
+ notmuch_opt_desc_t options[] = {
+ { NOTMUCH_OPT_KEYWORD, &output_format, "format", 'f',
+ (notmuch_keyword_t []){ { "sup", DUMP_FORMAT_SUP },
+ { "batch-tag", DUMP_FORMAT_BATCH_TAG },
+ { 0, 0 } } },
+ { NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0 },
+ { NOTMUCH_OPT_BOOLEAN, &gzip_output, "gzip", 'z', 0 },
+ { 0, 0, 0, 0, 0 }
+ };
+
+ opt_index = parse_arguments (argc, argv, options, 1);
+ if (opt_index < 0)
+ return EXIT_FAILURE;
+
+ if (opt_index < argc) {
+ query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index);
+ if (query_str == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ ret = notmuch_database_dump (notmuch, output_file_name, query_str,
+ output_format, gzip_output);
+
notmuch_database_destroy (notmuch);
- return 0;
+ return ret;
}
* The file is renamed to encode notmuch tags as maildir flags. */
static void
add_file_to_database (notmuch_database_t *notmuch, const char *path,
- tag_op_list_t *tag_ops)
+ tag_op_list_t *tag_ops, notmuch_bool_t synchronize_flags)
{
notmuch_message_t *message;
notmuch_status_t status;
if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
/* Don't change tags of an existing message. */
- status = notmuch_message_tags_to_maildir_flags (message);
- if (status != NOTMUCH_STATUS_SUCCESS)
- fprintf (stderr, "Error: failed to sync tags to maildir flags\n");
+ if (synchronize_flags) {
+ status = notmuch_message_tags_to_maildir_flags (message);
+ if (status != NOTMUCH_STATUS_SUCCESS)
+ fprintf (stderr, "Error: failed to sync tags to maildir flags\n");
+ }
} else {
- tag_op_list_apply (message, tag_ops, TAG_FLAG_MAILDIR_SYNC);
+ tag_op_flag_t flags = synchronize_flags ? TAG_FLAG_MAILDIR_SYNC : 0;
+
+ tag_op_list_apply (message, tag_ops, flags);
}
notmuch_message_destroy (message);
static notmuch_bool_t
insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
- const char *dir, tag_op_list_t *tag_ops)
+ const char *dir, tag_op_list_t *tag_ops,
+ notmuch_bool_t synchronize_flags)
{
char *tmppath;
char *newpath;
/* Even if adding the message to the notmuch database fails,
* the message is on disk and we consider the delivery completed. */
- add_file_to_database (notmuch, newpath, tag_ops);
+ add_file_to_database (notmuch, newpath, tag_ops, synchronize_flags);
return TRUE;
char *query_string = NULL;
const char *folder = NULL;
notmuch_bool_t create_folder = FALSE;
+ notmuch_bool_t synchronize_flags;
const char *maildir;
int opt_index;
unsigned int i;
};
opt_index = parse_arguments (argc, argv, options, 1);
-
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
db_path = notmuch_config_get_database_path (config);
new_tags = notmuch_config_get_new_tags (config, &new_tags_length);
+ synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ return EXIT_FAILURE;
}
for (i = 0; i < new_tags_length; i++) {
+ const char *error_msg;
+
+ error_msg = illegal_tag (new_tags[i], FALSE);
+ if (error_msg) {
+ fprintf (stderr, "Error: tag '%s' in new.tags: %s\n",
+ new_tags[i], error_msg);
+ return EXIT_FAILURE;
+ }
+
if (tag_op_list_append (tag_ops, new_tags[i], FALSE))
- return 1;
+ return EXIT_FAILURE;
}
if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
&query_string, tag_ops))
- return 1;
+ return EXIT_FAILURE;
if (*query_string != '\0') {
fprintf (stderr, "Error: unexpected query string: %s\n", query_string);
- return 1;
+ return EXIT_FAILURE;
}
if (folder == NULL) {
} else {
if (! check_folder_name (folder)) {
fprintf (stderr, "Error: bad folder name: %s\n", folder);
- return 1;
+ return EXIT_FAILURE;
}
maildir = talloc_asprintf (config, "%s/%s", db_path, folder);
if (! maildir) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
if (create_folder && ! maildir_create_folder (config, maildir)) {
fprintf (stderr, "Error: creating maildir %s: %s\n",
maildir, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
- return 1;
+ return EXIT_FAILURE;
- ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops);
+ ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops,
+ synchronize_flags);
notmuch_database_destroy (notmuch);
- return (ret) ? 0 : 1;
+ return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}
*/
#include "notmuch-client.h"
+#include "tag-util.h"
#include <unistd.h>
_filename_node_t **tail;
} _filename_list_t;
+enum verbosity {
+ VERBOSITY_QUIET,
+ VERBOSITY_NORMAL,
+ VERBOSITY_VERBOSE,
+};
+
typedef struct {
int output_is_a_tty;
- notmuch_bool_t verbose;
+ enum verbosity verbosity;
notmuch_bool_t debug;
const char **new_tags;
size_t new_tags_length;
char *abspath;
int err, saved_errno;
-#ifdef _DIRENT_HAVE_D_TYPE
+#if HAVE_D_TYPE
/* Mapping from d_type to stat mode_t. We omit DT_LNK so that
* we'll fall through to stat and get the real file type. */
static const mode_t modes[] = {
return FALSE;
}
+/* Add a single file to the database. */
+static notmuch_status_t
+add_file (notmuch_database_t *notmuch, const char *filename,
+ add_files_state_t *state)
+{
+ notmuch_message_t *message = NULL;
+ const char **tag;
+ notmuch_status_t status;
+
+ status = notmuch_database_begin_atomic (notmuch);
+ if (status)
+ goto DONE;
+
+ status = notmuch_database_add_message (notmuch, filename, &message);
+ switch (status) {
+ /* Success. */
+ case NOTMUCH_STATUS_SUCCESS:
+ state->added_messages++;
+ notmuch_message_freeze (message);
+ for (tag = state->new_tags; *tag != NULL; tag++)
+ notmuch_message_add_tag (message, *tag);
+ if (state->synchronize_flags)
+ notmuch_message_maildir_flags_to_tags (message);
+ notmuch_message_thaw (message);
+ break;
+ /* Non-fatal issues (go on to next file). */
+ case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
+ if (state->synchronize_flags)
+ notmuch_message_maildir_flags_to_tags (message);
+ break;
+ case NOTMUCH_STATUS_FILE_NOT_EMAIL:
+ fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
+ break;
+ /* Fatal issues. Don't process anymore. */
+ case NOTMUCH_STATUS_READ_ONLY_DATABASE:
+ case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
+ case NOTMUCH_STATUS_OUT_OF_MEMORY:
+ fprintf (stderr, "Error: %s. Halting processing.\n",
+ notmuch_status_to_string (status));
+ goto DONE;
+ default:
+ INTERNAL_ERROR ("add_message returned unexpected value: %d", status);
+ goto DONE;
+ }
+
+ status = notmuch_database_end_atomic (notmuch);
+
+ DONE:
+ if (message)
+ notmuch_message_destroy (message);
+
+ return status;
+}
+
/* Examine 'path' recursively as follows:
*
* o Ask the filesystem for the mtime of 'path' (fs_mtime)
char *next = NULL;
time_t fs_mtime, db_mtime;
notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
- notmuch_message_t *message = NULL;
struct dirent **fs_entries = NULL;
int i, num_fs_entries = 0, entry_type;
notmuch_directory_t *directory;
time_t stat_time;
struct stat st;
notmuch_bool_t is_maildir;
- const char **tag;
if (stat (path, &st)) {
fprintf (stderr, "Error reading directory %s: %s\n",
state->processed_files++;
- if (state->verbose) {
+ if (state->verbosity >= VERBOSITY_VERBOSE) {
if (state->output_is_a_tty)
printf("\r\033[K");
- printf ("%i/%i: %s",
- state->processed_files,
- state->total_files,
+ printf ("%i/%i: %s", state->processed_files, state->total_files,
next);
putchar((state->output_is_a_tty) ? '\r' : '\n');
fflush (stdout);
}
- status = notmuch_database_begin_atomic (notmuch);
+ status = add_file (notmuch, next, state);
if (status) {
ret = status;
goto DONE;
}
- status = notmuch_database_add_message (notmuch, next, &message);
- switch (status) {
- /* success */
- case NOTMUCH_STATUS_SUCCESS:
- state->added_messages++;
- notmuch_message_freeze (message);
- for (tag=state->new_tags; *tag != NULL; tag++)
- notmuch_message_add_tag (message, *tag);
- if (state->synchronize_flags == TRUE)
- notmuch_message_maildir_flags_to_tags (message);
- notmuch_message_thaw (message);
- break;
- /* Non-fatal issues (go on to next file) */
- case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
- if (state->synchronize_flags == TRUE)
- notmuch_message_maildir_flags_to_tags (message);
- break;
- case NOTMUCH_STATUS_FILE_NOT_EMAIL:
- fprintf (stderr, "Note: Ignoring non-mail file: %s\n",
- next);
- break;
- /* Fatal issues. Don't process anymore. */
- case NOTMUCH_STATUS_READ_ONLY_DATABASE:
- case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
- case NOTMUCH_STATUS_OUT_OF_MEMORY:
- fprintf (stderr, "Error: %s. Halting processing.\n",
- notmuch_status_to_string (status));
- ret = status;
- goto DONE;
- default:
- case NOTMUCH_STATUS_FILE_ERROR:
- case NOTMUCH_STATUS_NULL_POINTER:
- case NOTMUCH_STATUS_TAG_TOO_LONG:
- case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
- case NOTMUCH_STATUS_UNBALANCED_ATOMIC:
- case NOTMUCH_STATUS_LAST_STATUS:
- INTERNAL_ERROR ("add_message returned unexpected value: %d", status);
- goto DONE;
- }
-
- status = notmuch_database_end_atomic (notmuch);
- if (status) {
- ret = status;
- goto DONE;
- }
-
- if (message) {
- notmuch_message_destroy (message);
- message = NULL;
- }
-
if (do_print_progress) {
do_print_progress = 0;
generic_print_progress ("Processed", "files", state->tv_start,
{
struct dirent *entry = NULL;
char *next;
- struct stat st;
struct dirent **fs_entries = NULL;
int num_fs_entries = scandir (path, &fs_entries, 0, dirent_sort_inode);
- int i = 0;
+ int entry_type, i;
if (num_fs_entries == -1) {
fprintf (stderr, "Warning: failed to open directory %s: %s\n",
goto DONE;
}
- while (!interrupted) {
- if (i == num_fs_entries)
- break;
-
- entry = fs_entries[i++];
+ for (i = 0; i < num_fs_entries && ! interrupted; i++) {
+ entry = fs_entries[i];
/* Ignore special directories to avoid infinite recursion.
* Also ignore the .notmuch directory and files/directories
strcmp (entry->d_name, ".notmuch") == 0 ||
_entry_in_ignore_list (entry->d_name, state))
{
- if (_entry_in_ignore_list (entry->d_name, state) && state->debug)
+ if (state->debug && _entry_in_ignore_list (entry->d_name, state))
printf ("(D) count_files: explicitly ignoring %s/%s\n",
path,
entry->d_name);
continue;
}
- stat (next, &st);
-
- if (S_ISREG (st.st_mode)) {
+ entry_type = dirent_type (path, entry);
+ if (entry_type == S_IFREG) {
*count = *count + 1;
- if (*count % 1000 == 0) {
+ if (*count % 1000 == 0 && state->verbosity >= VERBOSITY_NORMAL) {
printf ("Found %d files so far.\r", *count);
fflush (stdout);
}
- } else if (S_ISDIR (st.st_mode)) {
+ } else if (entry_type == S_IFDIR) {
count_files (next, count, state);
}
return status;
}
+static void
+print_results (const add_files_state_t *state)
+{
+ double elapsed;
+ struct timeval tv_now;
+
+ gettimeofday (&tv_now, NULL);
+ elapsed = notmuch_time_elapsed (state->tv_start, tv_now);
+
+ if (state->processed_files) {
+ printf ("Processed %d %s in ", state->processed_files,
+ state->processed_files == 1 ? "file" : "total files");
+ notmuch_time_print_formatted_seconds (elapsed);
+ if (elapsed > 1)
+ printf (" (%d files/sec.).\033[K\n",
+ (int) (state->processed_files / elapsed));
+ else
+ printf (".\033[K\n");
+ }
+
+ if (state->added_messages)
+ printf ("Added %d new %s to the database.", state->added_messages,
+ state->added_messages == 1 ? "message" : "messages");
+ else
+ printf ("No new mail.");
+
+ if (state->removed_messages)
+ printf (" Removed %d %s.", state->removed_messages,
+ state->removed_messages == 1 ? "message" : "messages");
+
+ if (state->renamed_messages)
+ printf (" Detected %d file %s.", state->renamed_messages,
+ state->renamed_messages == 1 ? "rename" : "renames");
+
+ printf ("\n");
+}
+
int
notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
{
notmuch_database_t *notmuch;
add_files_state_t add_files_state;
- double elapsed;
- struct timeval tv_now, tv_start;
+ struct timeval tv_start;
int ret = 0;
struct stat st;
const char *db_path;
struct sigaction action;
_filename_node_t *f;
int opt_index;
- int i;
+ unsigned int i;
notmuch_bool_t timer_is_active = FALSE;
notmuch_bool_t no_hooks = FALSE;
+ notmuch_bool_t quiet = FALSE, verbose = FALSE;
- add_files_state.verbose = FALSE;
+ add_files_state.verbosity = VERBOSITY_NORMAL;
add_files_state.debug = FALSE;
add_files_state.output_is_a_tty = isatty (fileno (stdout));
notmuch_opt_desc_t options[] = {
- { NOTMUCH_OPT_BOOLEAN, &add_files_state.verbose, "verbose", 'v', 0 },
+ { NOTMUCH_OPT_BOOLEAN, &quiet, "quiet", 'q', 0 },
+ { NOTMUCH_OPT_BOOLEAN, &verbose, "verbose", 'v', 0 },
{ NOTMUCH_OPT_BOOLEAN, &add_files_state.debug, "debug", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &no_hooks, "no-hooks", 'n', 0 },
{ 0, 0, 0, 0, 0 }
};
opt_index = parse_arguments (argc, argv, options, 1);
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
+
+ /* quiet trumps verbose */
+ if (quiet)
+ add_files_state.verbosity = VERBOSITY_QUIET;
+ else if (verbose)
+ add_files_state.verbosity = VERBOSITY_VERBOSE;
add_files_state.new_tags = notmuch_config_get_new_tags (config, &add_files_state.new_tags_length);
add_files_state.new_ignore = notmuch_config_get_new_ignore (config, &add_files_state.new_ignore_length);
add_files_state.synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
db_path = notmuch_config_get_database_path (config);
+ for (i = 0; i < add_files_state.new_tags_length; i++) {
+ const char *error_msg;
+
+ error_msg = illegal_tag (add_files_state.new_tags[i], FALSE);
+ if (error_msg) {
+ fprintf (stderr, "Error: tag '%s' in new.tags: %s\n",
+ add_files_state.new_tags[i], error_msg);
+ return EXIT_FAILURE;
+ }
+ }
+
if (!no_hooks) {
ret = notmuch_run_hook (db_path, "pre-new");
if (ret)
- return ret;
+ return EXIT_FAILURE;
}
dot_notmuch_path = talloc_asprintf (config, "%s/%s", db_path, ".notmuch");
count = 0;
count_files (db_path, &count, &add_files_state);
if (interrupted)
- return 1;
+ return EXIT_FAILURE;
- printf ("Found %d total files (that's not much mail).\n", count);
+ if (add_files_state.verbosity >= VERBOSITY_NORMAL)
+ printf ("Found %d total files (that's not much mail).\n", count);
if (notmuch_database_create (db_path, ¬much))
- return 1;
+ return EXIT_FAILURE;
add_files_state.total_files = count;
} else {
if (notmuch_database_open (db_path, NOTMUCH_DATABASE_MODE_READ_WRITE,
¬much))
- return 1;
+ return EXIT_FAILURE;
if (notmuch_database_needs_upgrade (notmuch)) {
- printf ("Welcome to a new version of notmuch! Your database will now be upgraded.\n");
+ time_t now = time (NULL);
+ struct tm *gm_time = gmtime (&now);
+
+ /* since dump files are written atomically, the amount of
+ * harm from overwriting one within a second seems
+ * relatively small. */
+
+ const char *backup_name =
+ talloc_asprintf (notmuch, "%s/dump-%04d%02d%02dT%02d%02d%02d.gz",
+ dot_notmuch_path,
+ gm_time->tm_year + 1900,
+ gm_time->tm_mon + 1,
+ gm_time->tm_mday,
+ gm_time->tm_hour,
+ gm_time->tm_min,
+ gm_time->tm_sec);
+
+ if (add_files_state.verbosity >= VERBOSITY_NORMAL) {
+ printf ("Welcome to a new version of notmuch! Your database will now be upgraded.\n");
+ printf ("This process is safe to interrupt.\n");
+ printf ("Backing up tags to %s...\n", backup_name);
+ }
+
+ if (notmuch_database_dump (notmuch, backup_name, "",
+ DUMP_FORMAT_BATCH_TAG, TRUE)) {
+ fprintf (stderr, "Backup failed. Aborting upgrade.");
+ return EXIT_FAILURE;
+ }
+
gettimeofday (&add_files_state.tv_start, NULL);
- notmuch_database_upgrade (notmuch, upgrade_print_progress,
+ notmuch_database_upgrade (notmuch,
+ add_files_state.verbosity >= VERBOSITY_NORMAL ? upgrade_print_progress : NULL,
&add_files_state);
- printf ("Your notmuch database has now been upgraded to database format version %u.\n",
+ if (add_files_state.verbosity >= VERBOSITY_NORMAL)
+ printf ("Your notmuch database has now been upgraded to database format version %u.\n",
notmuch_database_get_version (notmuch));
}
}
if (notmuch == NULL)
- return 1;
+ return EXIT_FAILURE;
/* Setup our handler for SIGINT. We do this after having
* potentially done a database upgrade we this interrupt handler
add_files_state.removed_directories = _filename_list_create (config);
add_files_state.directory_mtimes = _filename_list_create (config);
- if (! debugger_is_active () && add_files_state.output_is_a_tty
- && ! add_files_state.verbose) {
+ if (add_files_state.verbosity == VERBOSITY_NORMAL &&
+ add_files_state.output_is_a_tty && ! debugger_is_active ()) {
setup_progress_printing_timer ();
timer_is_active = TRUE;
}
if (timer_is_active)
stop_progress_printing_timer ();
- gettimeofday (&tv_now, NULL);
- elapsed = notmuch_time_elapsed (add_files_state.tv_start,
- tv_now);
-
- if (add_files_state.processed_files) {
- printf ("Processed %d %s in ", add_files_state.processed_files,
- add_files_state.processed_files == 1 ?
- "file" : "total files");
- notmuch_time_print_formatted_seconds (elapsed);
- if (elapsed > 1) {
- printf (" (%d files/sec.).\033[K\n",
- (int) (add_files_state.processed_files / elapsed));
- } else {
- printf (".\033[K\n");
- }
- }
-
- if (add_files_state.added_messages) {
- printf ("Added %d new %s to the database.",
- add_files_state.added_messages,
- add_files_state.added_messages == 1 ?
- "message" : "messages");
- } else {
- printf ("No new mail.");
- }
-
- if (add_files_state.removed_messages) {
- printf (" Removed %d %s.",
- add_files_state.removed_messages,
- add_files_state.removed_messages == 1 ? "message" : "messages");
- }
-
- if (add_files_state.renamed_messages) {
- printf (" Detected %d file %s.",
- add_files_state.renamed_messages,
- add_files_state.renamed_messages == 1 ? "rename" : "renames");
- }
-
- printf ("\n");
+ if (add_files_state.verbosity >= VERBOSITY_NORMAL)
+ print_results (&add_files_state);
if (ret)
fprintf (stderr, "Note: A fatal error was encountered: %s\n",
if (!no_hooks && !ret && !interrupted)
ret = notmuch_run_hook (db_path, "post-new");
- return ret || interrupted;
+ return ret || interrupted ? EXIT_FAILURE : EXIT_SUCCESS;
}
*/
#include "notmuch-client.h"
+#include "string-util.h"
#include "sprinter.h"
static void
return from_addr;
}
+/*
+ * Look for the user's address in " for <email@add.res>" in the
+ * received headers.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
static const char *
-guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)
+guess_from_in_received_for (notmuch_config_t *config, const char *received)
{
- const char *addr, *received, *by;
- char *mta,*ptr,*token;
- char *domain=NULL;
- char *tld=NULL;
- const char *delim=". \t";
- size_t i;
+ const char *ptr;
- const char *to_headers[] = {
- "Envelope-to",
- "X-Original-To",
- "Delivered-To",
- };
-
- /* sadly, there is no standard way to find out to which email
- * address a mail was delivered - what is in the headers depends
- * on the MTAs used along the way. So we are trying a number of
- * heuristics which hopefully will answer this question.
-
- * We only got here if none of the users email addresses are in
- * the To: or Cc: header. From here we try the following in order:
- * 1) check for an Envelope-to: header
- * 2) check for an X-Original-To: header
- * 3) check for a Delivered-To: header
- * 4) check for a (for <email@add.res>) clause in Received: headers
- * 5) check for the domain part of known email addresses in the
- * 'by' part of Received headers
- * If none of these work, we give up and return NULL
- */
- for (i = 0; i < ARRAY_SIZE (to_headers); i++) {
- const char *tohdr = notmuch_message_get_header (message, to_headers[i]);
-
- /* Note: tohdr potentially contains a list of email addresses. */
- addr = user_address_in_string (tohdr, config);
- if (addr)
- return addr;
- }
-
- /* We get the concatenated Received: headers and search from the
- * front (last Received: header added) and try to extract from
- * them indications to which email address this message was
- * delivered.
- * The Received: header is special in our get_header function
- * and is always concatenated.
- */
- received = notmuch_message_get_header (message, "received");
- if (received == NULL)
+ ptr = strstr (received, " for ");
+ if (! ptr)
return NULL;
- /* First we look for a " for <email@add.res>" in the received
- * header
- */
- ptr = strstr (received, " for ");
+ return user_address_in_string (ptr, config);
+}
- /* Note: ptr potentially contains a list of email addresses. */
- addr = user_address_in_string (ptr, config);
- if (addr)
- return addr;
-
- /* Finally, we parse all the " by MTA ..." headers to guess the
- * email address that this was originally delivered to.
- * We extract just the MTA here by removing leading whitespace and
- * assuming that the MTA name ends at the next whitespace.
- * We test for *(by+4) to be non-'\0' to make sure there's
- * something there at all - and then assume that the first
- * whitespace delimited token that follows is the receiving
- * system in this step of the receive chain
- */
- by = received;
- while((by = strstr (by, " by ")) != NULL) {
+/*
+ * Parse all the " by MTA ..." parts in received headers to guess the
+ * email address that this was originally delivered to.
+ *
+ * Extract just the MTA here by removing leading whitespace and
+ * assuming that the MTA name ends at the next whitespace. Test for
+ * *(by+4) to be non-'\0' to make sure there's something there at all
+ * - and then assume that the first whitespace delimited token that
+ * follows is the receiving system in this step of the receive chain.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+guess_from_in_received_by (notmuch_config_t *config, const char *received)
+{
+ const char *addr;
+ const char *by = received;
+ char *domain, *tld, *mta, *ptr, *token;
+
+ while ((by = strstr (by, " by ")) != NULL) {
by += 4;
if (*by == '\0')
break;
free (mta);
break;
}
- /* Now extract the last two components of the MTA host name
- * as domain and tld.
+ /*
+ * Now extract the last two components of the MTA host name as
+ * domain and tld.
*/
domain = tld = NULL;
- while ((ptr = strsep (&token, delim)) != NULL) {
+ while ((ptr = strsep (&token, ". \t")) != NULL) {
if (*ptr == '\0')
continue;
domain = tld;
}
if (domain) {
- /* Recombine domain and tld and look for it among the configured
- * email addresses.
- * This time we have a known domain name and nothing else - so
- * the test is the other way around: we check if this is a
- * substring of one of the email addresses.
+ /*
+ * Recombine domain and tld and look for it among the
+ * configured email addresses. This time we have a known
+ * domain name and nothing else - so the test is the other
+ * way around: we check if this is a substring of one of
+ * the email addresses.
*/
- *(tld-1) = '.';
+ *(tld - 1) = '.';
addr = string_in_user_address (domain, config);
if (addr) {
return NULL;
}
+/*
+ * Get the concatenated Received: headers and search from the front
+ * (last Received: header added) and try to extract from them
+ * indications to which email address this message was delivered.
+ *
+ * The Received: header is special in our get_header function and is
+ * always concatenated.
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+guess_from_in_received_headers (notmuch_config_t *config,
+ notmuch_message_t *message)
+{
+ const char *received, *addr;
+ char *sanitized;
+
+ received = notmuch_message_get_header (message, "received");
+ if (! received)
+ return NULL;
+
+ sanitized = sanitize_string (NULL, received);
+ if (! sanitized)
+ return NULL;
+
+ addr = guess_from_in_received_for (config, sanitized);
+ if (! addr)
+ addr = guess_from_in_received_by (config, sanitized);
+
+ talloc_free (sanitized);
+
+ return addr;
+}
+
+/*
+ * Try to find user's email address in one of the extra To-like
+ * headers: Envelope-To, X-Original-To, and Delivered-To (searched in
+ * that order).
+ *
+ * Return the address that was found, if any, and NULL otherwise.
+ */
+static const char *
+get_from_in_to_headers (notmuch_config_t *config, notmuch_message_t *message)
+{
+ size_t i;
+ const char *tohdr, *addr;
+ const char *to_headers[] = {
+ "Envelope-to",
+ "X-Original-To",
+ "Delivered-To",
+ };
+
+ for (i = 0; i < ARRAY_SIZE (to_headers); i++) {
+ tohdr = notmuch_message_get_header (message, to_headers[i]);
+
+ /* Note: tohdr potentially contains a list of email addresses. */
+ addr = user_address_in_string (tohdr, config);
+ if (addr)
+ return addr;
+ }
+
+ return NULL;
+}
+
static GMimeMessage *
create_reply_message(void *ctx,
notmuch_config_t *config,
from_addr = add_recipients_from_message (reply, config,
message, reply_all);
+ /*
+ * Sadly, there is no standard way to find out to which email
+ * address a mail was delivered - what is in the headers depends
+ * on the MTAs used along the way.
+ *
+ * If none of the user's email addresses are in the To: or Cc:
+ * headers, we try a number of heuristics which hopefully will
+ * answer this question.
+ *
+ * First, check for Envelope-To:, X-Original-To:, and
+ * Delivered-To: headers.
+ */
+ if (from_addr == NULL)
+ from_addr = get_from_in_to_headers (config, message);
+
+ /*
+ * Check for a (for <email@add.res>) clause in Received: headers,
+ * and the domain part of known email addresses in the 'by' part
+ * of Received: headers
+ */
if (from_addr == NULL)
- from_addr = guess_from_received_header (config, message);
+ from_addr = guess_from_in_received_headers (config, message);
+ /* Default to user's primary address. */
if (from_addr == NULL)
from_addr = notmuch_config_get_user_primary_email (config);
notmuch_database_t *notmuch;
notmuch_query_t *query;
char *query_string;
- int opt_index, ret = 0;
+ int opt_index;
int (*reply_format_func) (void *ctx,
notmuch_config_t *config,
notmuch_query_t *query,
};
opt_index = parse_arguments (argc, argv, options, 1);
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
if (format == FORMAT_HEADERS_ONLY) {
reply_format_func = notmuch_reply_format_headers_only;
query_string = query_string_from_args (config, argc-opt_index, argv+opt_index);
if (query_string == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
if (*query_string == '\0') {
fprintf (stderr, "Error: notmuch reply requires at least one search term.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
- return 1;
+ return EXIT_FAILURE;
query = notmuch_query_create (notmuch, query_string);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
if (reply_format_func (config, config, query, ¶ms, reply_all, sp) != 0)
- return 1;
+ return EXIT_FAILURE;
notmuch_crypto_cleanup (¶ms.crypto);
notmuch_query_destroy (query);
notmuch_database_destroy (notmuch);
- return ret;
+ return EXIT_SUCCESS;
}
*/
#include "notmuch-client.h"
-#include "dump-restore-private.h"
+#include "hex-escape.h"
#include "tag-util.h"
#include "string-util.h"
+#include "zlib-extra.h"
static regex_t regex;
tag_op_list_t *tag_ops;
char *input_file_name = NULL;
- FILE *input = stdin;
+ const char *name_for_error = NULL;
+ gzFile input = NULL;
char *line = NULL;
void *line_ctx = NULL;
- size_t line_size;
ssize_t line_len;
int ret = 0;
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
- return 1;
+ return EXIT_FAILURE;
if (notmuch_config_get_maildir_synchronize_flags (config))
flags |= TAG_FLAG_MAILDIR_SYNC;
};
opt_index = parse_arguments (argc, argv, options, 1);
-
if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
+ ret = EXIT_FAILURE;
+ goto DONE;
}
+ name_for_error = input_file_name ? input_file_name : "stdin";
+
if (! accumulate)
flags |= TAG_FLAG_REMOVE_ALL;
- if (input_file_name) {
- input = fopen (input_file_name, "r");
- if (input == NULL) {
- fprintf (stderr, "Error opening %s for reading: %s\n",
- input_file_name, strerror (errno));
- return 1;
+ errno = 0;
+ if (input_file_name)
+ input = gzopen (input_file_name, "r");
+ else {
+ int infd = dup (STDIN_FILENO);
+ if (infd < 0) {
+ fprintf (stderr, "Error duping stdin: %s\n",
+ strerror (errno));
+ ret = EXIT_FAILURE;
+ goto DONE;
}
+ input = gzdopen (infd, "r");
+ if (! input)
+ close (infd);
+ }
+
+ if (input == NULL) {
+ fprintf (stderr, "Error opening %s for (gzip) reading: %s\n",
+ name_for_error, strerror (errno));
+ ret = EXIT_FAILURE;
+ goto DONE;
}
if (opt_index < argc) {
- fprintf (stderr,
- "Unused positional parameter: %s\n",
- argv[opt_index]);
- return 1;
+ fprintf (stderr, "Unused positional parameter: %s\n", argv[opt_index]);
+ ret = EXIT_FAILURE;
+ goto DONE;
}
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ ret = EXIT_FAILURE;
+ goto DONE;
}
do {
- line_len = getline (&line, &line_size, input);
+ util_status_t status;
+
+ status = gz_getline (line_ctx, &line, &line_len, input);
/* empty input file not considered an error */
- if (line_len < 0)
- return 0;
+ if (status == UTIL_EOF) {
+ ret = EXIT_SUCCESS;
+ goto DONE;
+ }
+ if (status) {
+ fprintf (stderr, "Error reading (gzipped) input: %s\n",
+ gz_error_string(status, input));
+ ret = EXIT_FAILURE;
+ goto DONE;
+ }
} while ((line_len == 0) ||
(line[0] == '#') ||
/* the cast is safe because we checked about for line_len < 0 */
if (ret)
break;
- } while ((line_len = getline (&line, &line_size, input)) != -1);
+ } while (! (ret = gz_getline (line_ctx, &line, &line_len, input)));
+
+
+ /* EOF is normal loop termination condition, UTIL_SUCCESS is
+ * impossible here */
+ if (ret == UTIL_EOF) {
+ ret = EXIT_SUCCESS;
+ } else {
+ fprintf (stderr, "Error reading (gzipped) input: %s\n",
+ gz_error_string (ret, input));
+ ret = EXIT_FAILURE;
+ }
- if (line_ctx != NULL)
- talloc_free (line_ctx);
+ /* currently this should not be after DONE: since we don't
+ * know if the xregcomp was reached
+ */
if (input_format == DUMP_FORMAT_SUP)
regfree (®ex);
- if (line)
- free (line);
+ DONE:
+ if (line_ctx != NULL)
+ talloc_free (line_ctx);
- notmuch_database_destroy (notmuch);
+ if (notmuch)
+ notmuch_database_destroy (notmuch);
- if (input != stdin)
- fclose (input);
+ if (input && gzclose_r (input)) {
+ fprintf (stderr, "Error closing %s: %s\n",
+ name_for_error, gzerror (input, NULL));
+ ret = EXIT_FAILURE;
+ }
- return ret;
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}
OUTPUT_TAGS
} output_t;
-static char *
-sanitize_string (const void *ctx, const char *str)
-{
- char *out, *loop;
-
- if (NULL == str)
- return NULL;
-
- loop = out = talloc_strdup (ctx, str);
-
- for (; *loop; loop++) {
- if ((unsigned char)(*loop) < 32)
- *loop = '?';
- }
- return out;
-}
-
/* Return two stable query strings that identify exactly the matched
* and unmatched messages currently in thread. If there are no
* matched or unmatched messages, the returned buffers will be
};
opt_index = parse_arguments (argc, argv, options, 1);
-
- if (opt_index < 0) {
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
switch (format_sel) {
case NOTMUCH_FORMAT_TEXT:
case NOTMUCH_FORMAT_TEXT0:
if (output == OUTPUT_SUMMARY) {
fprintf (stderr, "Error: --format=text0 is not compatible with --output=summary.\n");
- return 1;
+ return EXIT_FAILURE;
}
format = sprinter_text0_create (config, stdout);
break;
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
- return 1;
+ return EXIT_FAILURE;
query_str = query_string_from_args (notmuch, argc-opt_index, argv+opt_index);
if (query_str == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (*query_str == '\0') {
fprintf (stderr, "Error: notmuch search requires at least one search term.\n");
- return 1;
+ return EXIT_FAILURE;
}
query = notmuch_query_create (notmuch, query_str);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
notmuch_query_set_sort (query, sort);
talloc_free (format);
- return ret;
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}
fflush (stdout); \
if (getline (&response, &response_size, stdin) < 0) { \
printf ("Exiting.\n"); \
- exit (1); \
+ exit (EXIT_FAILURE); \
} \
chomp_newline (response); \
} while (0)
g_ptr_array_free (tags, TRUE);
}
+ if (notmuch_config_save (config))
+ return EXIT_FAILURE;
- if (! notmuch_config_save (config)) {
- if (notmuch_config_is_new (config))
- welcome_message_post_setup ();
- return 0;
- } else {
- return 1;
- }
+ if (notmuch_config_is_new (config))
+ welcome_message_post_setup ();
+
+ return EXIT_SUCCESS;
}
notmuch_messages_t *messages;
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
+ threads = notmuch_query_search_threads (query);
+ if (! threads)
+ return 1;
+
sp->begin_list (sp);
- for (threads = notmuch_query_search_threads (query);
+ for ( ;
notmuch_threads_valid (threads);
notmuch_threads_move_to_next (threads))
{
};
opt_index = parse_arguments (argc, argv, options, 1);
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
/* decryption implies verification */
if (params.crypto.decrypt)
case NOTMUCH_FORMAT_MBOX:
if (params.part > 0) {
fprintf (stderr, "Error: specifying parts is incompatible with mbox output format.\n");
- return 1;
+ return EXIT_FAILURE;
}
format = &format_mbox;
query_string = query_string_from_args (config, argc-opt_index, argv+opt_index);
if (query_string == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
if (*query_string == '\0') {
fprintf (stderr, "Error: notmuch show requires at least one search term.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
- return 1;
+ return EXIT_FAILURE;
query = notmuch_query_create (notmuch, query_string);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Create structure printer. */
notmuch_query_destroy (query);
notmuch_database_destroy (notmuch);
- return ret;
+ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}
FILE *input = stdin;
char *input_file_name = NULL;
int opt_index;
- int ret = 0;
+ int ret;
/* Setup our handler for SIGINT */
memset (&action, 0, sizeof (struct sigaction));
opt_index = parse_arguments (argc, argv, options, 1);
if (opt_index < 0)
- return 1;
+ return EXIT_FAILURE;
if (input_file_name) {
batch = TRUE;
if (input == NULL) {
fprintf (stderr, "Error opening %s for reading: %s\n",
input_file_name, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
}
if (batch) {
if (opt_index != argc) {
fprintf (stderr, "Can't specify both cmdline and stdin!\n");
- return 1;
+ return EXIT_FAILURE;
}
if (remove_all) {
fprintf (stderr, "Can't specify both --remove-all and --batch\n");
- return 1;
+ return EXIT_FAILURE;
}
} else {
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
&query_string, tag_ops))
- return 1;
+ return EXIT_FAILURE;
if (tag_op_list_size (tag_ops) == 0 && ! remove_all) {
fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");
- return 1;
+ return EXIT_FAILURE;
}
if (*query_string == '\0') {
fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");
- return 1;
+ return EXIT_FAILURE;
}
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
- return 1;
+ return EXIT_FAILURE;
if (notmuch_config_get_maildir_synchronize_flags (config))
tag_flags |= TAG_FLAG_MAILDIR_SYNC;
if (input != stdin)
fclose (input);
- return ret || interrupted;
+ return ret || interrupted ? EXIT_FAILURE : EXIT_SUCCESS;
}
#include "notmuch-client.h"
+/*
+ * Notmuch subcommand hook.
+ *
+ * The return value will be used as notmuch exit status code,
+ * preferrably EXIT_SUCCESS or EXIT_FAILURE.
+ */
typedef int (*command_function_t) (notmuch_config_t *config, int argc, char *argv[]);
typedef struct command {
"This message, or more detailed help for the named command." }
};
+typedef struct help_topic {
+ const char *name;
+ const char *summary;
+} help_topic_t;
+
+static help_topic_t help_topics[] = {
+ { "search-terms",
+ "Common search term syntax." },
+ { "hooks",
+ "Hooks that will be run before or after certain commands." },
+};
+
static command_t *
find_command (const char *name)
{
usage (FILE *out)
{
command_t *command;
+ help_topic_t *topic;
unsigned int i;
fprintf (out,
command = &commands[i];
if (command->name)
- fprintf (out, " %-11s %s\n", command->name, command->summary);
+ fprintf (out, " %-12s %s\n", command->name, command->summary);
+ }
+
+ fprintf (out, "\n");
+ fprintf (out, "Additional help topics are as follows:\n");
+ fprintf (out, "\n");
+
+ for (i = 0; i < ARRAY_SIZE (help_topics); i++) {
+ topic = &help_topics[i];
+ fprintf (out, " %-12s %s\n", topic->name, topic->summary);
}
fprintf (out, "\n");
fprintf (out,
- "Use \"notmuch help <command>\" for more details on each command\n"
- "and \"notmuch help search-terms\" for the common search-terms syntax.\n\n");
+ "Use \"notmuch help <command or topic>\" for more details "
+ "on each command or topic.\n\n");
}
void
notmuch_help_command (notmuch_config_t *config, int argc, char *argv[])
{
command_t *command;
+ help_topic_t *topic;
+ unsigned int i;
argc--; argv++; /* Ignore "help" */
if (argc == 0) {
printf ("The notmuch mail system.\n\n");
usage (stdout);
- return 0;
+ return EXIT_SUCCESS;
}
if (strcmp (argv[0], "help") == 0) {
"\tof difficulties check that MANPATH includes the pages\n"
"\tinstalled by notmuch.\n\n"
"\tTry \"notmuch help\" for a list of topics.\n");
- return 0;
+ return EXIT_SUCCESS;
}
command = find_command (argv[0]);
exec_man (page);
}
- if (strcmp (argv[0], "search-terms") == 0) {
- exec_man ("notmuch-search-terms");
- } else if (strcmp (argv[0], "hooks") == 0) {
- exec_man ("notmuch-hooks");
+ for (i = 0; i < ARRAY_SIZE (help_topics); i++) {
+ topic = &help_topics[i];
+ if (strcmp (argv[0], topic->name) == 0) {
+ char *page = talloc_asprintf (config, "notmuch-%s", topic->name);
+ exec_man (page);
+ }
}
fprintf (stderr,
"\nSorry, %s is not a known command. There's not much I can do to help.\n\n",
argv[0]);
- return 1;
+ return EXIT_FAILURE;
}
/* Handle the case of "notmuch" being invoked with no command
if (errno != ENOENT) {
fprintf (stderr, "Error looking for notmuch database at %s: %s\n",
db_path, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
printf ("Notmuch is configured, but there's not yet a database at\n\n\t%s\n\n",
db_path);
"Note that the first run of \"notmuch new\" can take a very long time\n"
"and that the resulting database will use roughly the same amount of\n"
"storage space as the email being indexed.\n\n");
- return 0;
+ return EXIT_SUCCESS;
}
printf ("Notmuch is configured and appears to have a database. Excellent!\n\n"
notmuch_config_get_user_name (config),
notmuch_config_get_user_primary_email (config));
- return 0;
+ return EXIT_SUCCESS;
}
int
const char *command_name = NULL;
command_t *command;
char *config_file_name = NULL;
- notmuch_config_t *config;
+ notmuch_config_t *config = NULL;
notmuch_bool_t print_help=FALSE, print_version=FALSE;
int opt_index;
- int ret = 0;
+ int ret;
notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_BOOLEAN, &print_help, "help", 'h', 0 },
opt_index = parse_arguments (argc, argv, options, 1);
if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
+ ret = EXIT_FAILURE;
+ goto DONE;
}
- if (print_help)
- return notmuch_help_command (NULL, argc - 1, &argv[1]);
+ if (print_help) {
+ ret = notmuch_help_command (NULL, argc - 1, &argv[1]);
+ goto DONE;
+ }
if (print_version) {
printf ("notmuch " STRINGIFY(NOTMUCH_VERSION) "\n");
- return 0;
+ ret = EXIT_SUCCESS;
+ goto DONE;
}
if (opt_index < argc)
if (!command) {
fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n",
command_name);
- return 1;
+ ret = EXIT_FAILURE;
+ goto DONE;
}
config = notmuch_config_open (local, config_file_name, command->create_config);
- if (!config)
- return 1;
+ if (!config) {
+ ret = EXIT_FAILURE;
+ goto DONE;
+ }
ret = (command->function)(config, argc - opt_index, argv + opt_index);
- notmuch_config_close (config);
+ DONE:
+ if (config)
+ notmuch_config_close (config);
talloc_report = getenv ("NOTMUCH_TALLOC_REPORT");
if (talloc_report && strcmp (talloc_report, "") != 0) {
--- /dev/null
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.15 (GNU/Linux)
+
+iQGcBAABCAAGBQJSdaDkAAoJEPIClx2kp54sQ54L/ikkvF1fy88hjLitN59v6g2J
+vw85YNRifNHyp/UXI6nt2eXFzyWJiRHuvHFoBgmEsJVxauOKw61Gs2zd53x9Ear4
+MGcQWyiM1cnwX/nD7GvxRQNh33f+FEamTjg+QhG47K0A2YdLWcDC7r9GMatGT11x
+5KE24WQGOqtgQn/9qNtJvkiKIehpRiDTaW/QJ7mTCYeJFjIHJUY8dxyfiTtkJ0z7
+cJ6omehvWSw4STbEg65XJgqykxMdltNEavfvSbAT73FgmkkyXxul0s5hDZ/esd0n
+re3dyDxGt085POiAgPti05a4tJI5EQC2wLBUFri0s2JdMtazcD6yVuHNbVzZ4Do3
+nL/sgwKGUq5wRrPqPWp6HXtZ9zG+/V7hFNrr/l42qGrLqsSh0bqvEnUiwczZLBGy
+NEs4G8VjmfS2cMKePsWaekBAvFUtb47PSB6JIPwpCNvKXDrcCb28eOQVB2atgj1h
+9SktOtWYJhWIQp2YW9iae30Z6lhCcdPRRHTFMQq2nQ==
+=eSMY
+-----END PGP SIGNATURE-----
{
rm -rf ${MAIL_DIR}
- case "$corpus_size" in
- small)
- mail_subdir="mail/enron/bailey-s"
- check_for="${TEST_DIRECTORY}/corpus/$mail_subdir"
- ;;
- medium)
- mail_subdir="mail/notmuch-archive"
- check_for="${TEST_DIRECTORY}/corpus/$mail_subdir"
- ;;
- *)
- mail_subdir=mail
- check_for="${TEST_DIRECTORY}/corpus/$mail_subdir/enron/wolfe-j"
- esac
+ CORPUS_DIR=${TEST_DIRECTORY}/corpus
+ mkdir -p "${CORPUS_DIR}"
- MAIL_CORPUS="${TEST_DIRECTORY}/corpus/$mail_subdir"
- TAG_CORPUS="${TEST_DIRECTORY}/corpus/tags"
+ MAIL_CORPUS="${CORPUS_DIR}/mail.${corpus_size}"
+ TAG_CORPUS="${CORPUS_DIR}/tags"
- args=()
- if [ ! -d "$TAG_CORPUS" ] ; then
- args+=("notmuch-email-corpus/tags")
+ if command -v pixz > /dev/null; then
+ XZ=pixz
+ else
+ XZ=xz
fi
- if [ ! -d "$check_for" ] ; then
- args+=("notmuch-email-corpus/$mail_subdir")
+ if [ ! -d "${CORPUS_DIR}/manifest" ]; then
+
+ printf "Unpacking manifests\n"
+ tar --extract --use-compress-program ${XZ} --strip-components=1 \
+ --directory ${TEST_DIRECTORY}/corpus \
+ --wildcards --file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
+ 'notmuch-email-corpus/manifest/*'
fi
- if [[ ${#args[@]} > 0 ]]; then
- if command -v pixz > /dev/null; then
- XZ=pixz
+ file_list=$(mktemp file_listXXXXXX)
+ declare -a extract_dirs
+ if [ ! -d "$TAG_CORPUS" ] ; then
+ extract_dirs=("${extract_dirs[@]}" notmuch-email-corpus/tags)
+ fi
+
+ if [ ! -d "$MAIL_CORPUS" ] ; then
+ if [[ "$corpus_size" != "large" ]]; then
+ sed s,^,notmuch-email-corpus/, < \
+ ${TEST_DIRECTORY}/corpus/manifest/MANIFEST.${corpus_size} >> $file_list
else
- XZ=xz
+ extract_dirs=("${extract_dirs[@]}" notmuch-email-corpus/mail)
fi
+ fi
- printf "Unpacking corpus\n"
- mkdir -p "${TEST_DIRECTORY}/corpus"
+ if [[ -s $file_list || -n "${extract_dirs[*]}" ]]; then
+ printf "Unpacking corpus\n"
tar --checkpoint=.5000 --extract --strip-components=1 \
--directory ${TEST_DIRECTORY}/corpus \
--use-compress-program ${XZ} \
--file ../download/notmuch-email-corpus-${PERFTEST_VERSION}.tar.xz \
- "${args[@]}"
+ --anchored --recursion \
+ --files-from $file_list "${extract_dirs[@]}"
printf "\n"
+ if [[ ! -d ${MAIL_CORPUS} ]]; then
+ printf "creating link farm\n"
+
+ if [[ "$corpus_size" = large ]]; then
+ cp -rl ${TEST_DIRECTORY}/corpus/mail ${MAIL_CORPUS}
+ else
+ while read -r file; do
+ tdir=${MAIL_CORPUS}/$(dirname $file)
+ mkdir -p $tdir
+ ln ${TEST_DIRECTORY}/corpus/$file $tdir
+ done <${TEST_DIRECTORY}/corpus/manifest/MANIFEST.${corpus_size}
+ fi
+ fi
+
fi
+ rm $file_list
cp -lr $TAG_CORPUS $TMP_DIRECTORY/corpus.tags
cp -lr $MAIL_CORPUS $MAIL_DIR
}
# this should be both a valid Makefile fragment and valid POSIX(ish) shell.
-PERFTEST_VERSION=0.3
+PERFTEST_VERSION=0.4
return status;
}
-/*
- * Test tags for some forbidden cases.
- *
- * return: NULL if OK,
- * explanatory message otherwise.
- */
-
-static const char *
+const char *
illegal_tag (const char *tag, notmuch_bool_t remove)
{
msg = illegal_tag (argv[i] + 1, is_remove);
if (msg) {
- fprintf (stderr, "Error: %s", msg);
+ fprintf (stderr, "Error: %s\n", msg);
return TAG_PARSE_INVALID;
}
parse_tag_command_line (void *ctx, int argc, char **argv,
char **query_str, tag_op_list_t *ops);
+/*
+ * Test tags for some forbidden cases.
+ *
+ * Relax the checks if 'remove' is true to allow removal of previously
+ * added forbidden tags.
+ *
+ * return: NULL if OK,
+ * explanatory message otherwise.
+ */
+const char *
+illegal_tag (const char *tag, notmuch_bool_t remove);
+
/*
* Create an empty list of tag operations
*
dir := test
-extra_cflags += -I.
+# save against changes in $(dir)
+test_src_dir := $(dir)
+extra_cflags += -I$(srcdir)
smtp_dummy_srcs = \
$(notmuch_compat_srcs) \
smtp_dummy_modules = $(smtp_dummy_srcs:.c=.o)
$(dir)/arg-test: $(dir)/arg-test.o command-line-arguments.o util/libutil.a
- $(call quiet,CC) -I. $^ -o $@
+ $(call quiet,CC) $^ -o $@
$(dir)/hex-xcode: $(dir)/hex-xcode.o command-line-arguments.o util/libutil.a
- $(call quiet,CC) -I. $^ -o $@ -ltalloc
+ $(call quiet,CC) $^ $(TALLOC_LDFLAGS) -o $@
random_corpus_deps = $(dir)/random-corpus.o $(dir)/database-test.o \
notmuch-config.o command-line-arguments.o \
$(dir)/parse-time: $(dir)/parse-time.o parse-time-string/parse-time-string.o
$(call quiet,CC) $^ -o $@
+$(dir)/have-compact: Makefile.config
+ifeq ($(HAVE_XAPIAN_COMPACT),1)
+ ln -sf /bin/true $@
+else
+ ln -sf /bin/false $@
+endif
+
+$(dir)/have-man: Makefile.config
+ifeq ($(HAVE_SPHINX)$(HAVE_RST2MAN),00)
+ ln -sf /bin/false $@
+else
+ ln -sf /bin/true $@
+endif
+
.PHONY: test check
TEST_BINARIES=$(dir)/arg-test \
+ $(dir)/have-compact \
+ $(dir)/have-man \
$(dir)/hex-xcode \
$(dir)/random-corpus \
$(dir)/parse-time \
test-binaries: $(TEST_BINARIES)
test: all test-binaries
- @${dir}/notmuch-test $(OPTIONS)
+ @${test_src_dir}/notmuch-test $(OPTIONS)
check: test
SRCS := $(SRCS) $(smtp_dummy_srcs)
-CLEAN := $(CLEAN) $(dir)/smtp-dummy $(dir)/smtp-dummy.o \
- $(dir)/symbol-test $(dir)/symbol-test.o \
- $(dir)/arg-test $(dir)/arg-test.o \
- $(dir)/hex-xcode $(dir)/hex-xcode.o \
+CLEAN += $(TEST_BINARIES) $(addsuffix .o,$(TEST_BINARIES)) \
$(dir)/database-test.o \
- $(dir)/random-corpus $(dir)/random-corpus.o \
- $(dir)/parse-time $(dir)/parse-time.o \
$(dir)/corpus.mail $(dir)/test-results $(dir)/tmp.*
Pointing this argument at a tmpfs filesystem can improve the
speed of the test suite for some users.
+Certain tests require precomputed databases to complete. You can fetch these
+databases with
+
+ make download-test-databases
+
+If you do not download the test databases, the relevant tests will be
+skipped.
+
When invoking the test suite via "make test" any of the above options
can be specified as follows:
TEST_EMACS=my-special-emacs TEST_EMACSCLIENT=my-emacsclient ./emacs
make test TEST_EMACS=my-special-emacs TEST_EMACSCLIENT=my-emacsclient
+Quiet Execution
+---------------
+
+Normally, when new script starts and when test PASSes you get a message
+printed on screen. This printing can be disabled by setting the
+NOTMUCH_TEST_QUIET variable to a non-null value. Message on test
+failures and skips are still printed.
+
Skipping Tests
--------------
If, for any reason, you need to skip one or more tests, you can do so
--- /dev/null
+#!/usr/bin/env bash
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='the test framework itself.'
+
+################################################################
+# It appears that people try to run tests without building...
+
+if ! test -x ../notmuch
+then
+ echo >&2 'You do not seem to have built notmuch yet.'
+ exit 1
+fi
+
+. ./test-lib.sh
+
+################################################################
+# Test harness
+test_expect_success 'success is reported like this' '
+ :
+'
+test_set_prereq HAVEIT
+haveit=no
+test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
+ test_have_prereq HAVEIT &&
+ haveit=yes
+'
+
+clean=no
+test_expect_success 'tests clean up after themselves' '
+ test_when_finished clean=yes
+'
+
+cleaner=no
+test_expect_code 1 'tests clean up even after a failure' '
+ test_when_finished cleaner=yes &&
+ (exit 1)
+'
+
+if test $clean$cleaner != yesyes
+then
+ say "bug in test framework: cleanup commands do not work reliably"
+ exit 1
+fi
+
+test_expect_code 2 'failure to clean up causes the test to fail' '
+ test_when_finished "(exit 2)"
+'
+
+EXPECTED=$TEST_DIRECTORY/test.expected-output
+suppress_diff_date() {
+ sed -e 's/\(.*\-\-\- test-verbose\.4\.\expected\).*/\1/' \
+ -e 's/\(.*\+\+\+ test-verbose\.4\.\output\).*/\1/'
+}
+
+test_begin_subtest "Ensure that test output is suppressed unless the test fails"
+output=$(cd $TEST_DIRECTORY; NOTMUCH_TEST_QUIET= ./test-verbose 2>&1 | suppress_diff_date)
+expected=$(cat $EXPECTED/test-verbose-no | suppress_diff_date)
+test_expect_equal "$output" "$expected"
+
+test_begin_subtest "Ensure that -v does not suppress test output"
+output=$(cd $TEST_DIRECTORY; NOTMUCH_TEST_QUIET= ./test-verbose -v 2>&1 | suppress_diff_date)
+expected=$(cat $EXPECTED/test-verbose-yes | suppress_diff_date)
+# Do not include the results of test-verbose in totals
+rm $TEST_DIRECTORY/test-results/test-verbose
+rm -r $TEST_DIRECTORY/tmp.test-verbose
+test_expect_equal "$output" "$expected"
+
+
+################################################################
+# Test mail store prepared in test-lib.sh
+
+test_expect_success \
+ 'test that mail store was created' \
+ 'test -d "${MAIL_DIR}"'
+
+
+find "${MAIL_DIR}" -type f -print >should-be-empty
+test_expect_success \
+ 'mail store should be empty' \
+ 'cmp -s /dev/null should-be-empty'
+
+test_expect_success \
+ 'NOTMUCH_CONFIG is set and points to an existing file' \
+ 'test -f "${NOTMUCH_CONFIG}"'
+
+test_begin_subtest 'PATH is set to build directory'
+test_expect_equal \
+ "$(dirname ${TEST_DIRECTORY})" \
+ "$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="online help"
+. ./test-lib.sh
+
+test_expect_success 'notmuch --help' 'notmuch --help'
+test_expect_success 'notmuch help' 'notmuch help'
+test_expect_success 'notmuch --version' 'notmuch --version'
+
+if ${TEST_DIRECTORY}/have-man; then
+ test_expect_success 'notmuch --help tag' 'notmuch --help tag'
+ test_expect_success 'notmuch help tag' 'notmuch help tag'
+else
+ test_expect_success 'notmuch --help tag (man pages not available)' \
+ 'test_must_fail notmuch --help tag'
+ test_expect_success 'notmuch help tag (man pages not available)' \
+ 'test_must_fail notmuch help tag'
+fi
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch compact"'
+. ./test-lib.sh
+
+add_message '[subject]=One'
+add_message '[subject]=Two'
+add_message '[subject]=Three'
+
+notmuch tag +tag1 \*
+notmuch tag +tag2 subject:Two
+notmuch tag -tag1 +tag3 subject:Three
+
+if ! ${TEST_DIRECTORY}/have-compact; then
+ test_begin_subtest "Compact unsupported: error message"
+ output=$(notmuch compact --quiet 2>&1)
+ test_expect_equal "$output" "notmuch was compiled against a xapian version lacking compaction support.
+Compaction failed: Unsupported operation"
+
+ test_expect_code 1 "Compact unsupported: status code" "notmuch compact"
+
+ test_done
+fi
+
+test_expect_success "Running compact" "notmuch compact --backup=${TEST_DIRECTORY}/xapian.old"
+
+test_begin_subtest "Compact preserves database"
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)"
+
+test_expect_success 'Restoring Backup' \
+ 'rm -Rf ${MAIL_DIR}/.notmuch/xapian &&
+ mv ${TEST_DIRECTORY}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
+
+test_begin_subtest "Checking restored backup"
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description='"notmuch config"'
+. ./test-lib.sh
+
+test_begin_subtest "Get string value"
+test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
+
+test_begin_subtest "Get list value"
+test_expect_equal "$(notmuch config get new.tags)" "\
+unread
+inbox"
+
+test_begin_subtest "Set string value"
+notmuch config set foo.string "this is a string value"
+test_expect_equal "$(notmuch config get foo.string)" "this is a string value"
+
+test_begin_subtest "Set string value again"
+notmuch config set foo.string "this is another string value"
+test_expect_equal "$(notmuch config get foo.string)" "this is another string value"
+
+test_begin_subtest "Set list value"
+notmuch config set foo.list this "is a" "list value"
+test_expect_equal "$(notmuch config get foo.list)" "\
+this
+is a
+list value"
+
+test_begin_subtest "Set list value again"
+notmuch config set foo.list this "is another" "list value"
+test_expect_equal "$(notmuch config get foo.list)" "\
+this
+is another
+list value"
+
+test_begin_subtest "Remove key"
+notmuch config set foo.remove baz
+notmuch config set foo.remove
+test_expect_equal "$(notmuch config get foo.remove)" ""
+
+test_begin_subtest "Remove non-existent key"
+notmuch config set foo.nonexistent
+test_expect_equal "$(notmuch config get foo.nonexistent)" ""
+
+test_begin_subtest "List all items"
+notmuch config set database.path "/canonical/path"
+output=$(notmuch config list)
+test_expect_equal "$output" "\
+database.path=/canonical/path
+user.name=Notmuch Test Suite
+user.primary_email=test_suite@notmuchmail.org
+user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org
+new.tags=unread;inbox;
+new.ignore=
+search.exclude_tags=
+maildir.synchronize_flags=true
+foo.string=this is another string value
+foo.list=this;is another;list value;"
+
+test_begin_subtest "Top level --config=FILE option"
+cp "${NOTMUCH_CONFIG}" alt-config
+notmuch --config=alt-config config set user.name "Another Name"
+test_expect_equal "$(notmuch --config=alt-config config get user.name)" \
+ "Another Name"
+
+test_begin_subtest "Top level --config=FILE option changed the right file"
+test_expect_equal "$(notmuch config get user.name)" \
+ "Notmuch Test Suite"
+
+test_begin_subtest "Read config file through a symlink"
+ln -s alt-config alt-config-link
+test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \
+ "Another Name"
+
+test_begin_subtest "Write config file through a symlink"
+notmuch --config=alt-config-link config set user.name "Link Name"
+test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \
+ "Link Name"
+
+test_begin_subtest "Writing config file through symlink follows symlink"
+test_expect_equal "$(readlink alt-config-link)" "alt-config"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description='"notmuch setup"'
+. ./test-lib.sh
+
+test_begin_subtest "Create a new config interactively"
+notmuch --config=new-notmuch-config > /dev/null <<EOF
+Test Suite
+test.suite@example.com
+another.suite@example.com
+
+/path/to/maildir
+foo bar
+baz
+EOF
+output=$(notmuch --config=new-notmuch-config config list)
+test_expect_equal "$output" "\
+database.path=/path/to/maildir
+user.name=Test Suite
+user.primary_email=test.suite@example.com
+user.other_email=another.suite@example.com;
+new.tags=foo;bar;
+new.ignore=
+search.exclude_tags=baz;
+maildir.synchronize_flags=true"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch new" in several variations'
+. ./test-lib.sh
+
+test_begin_subtest "No new messages"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+
+
+test_begin_subtest "Single new message"
+generate_message
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "Multiple new messages"
+generate_message
+generate_message
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 2 new messages to the database."
+
+
+test_begin_subtest "No new messages (non-empty DB)"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+
+
+test_begin_subtest "New directories"
+rm -rf "${MAIL_DIR}"/* "${MAIL_DIR}"/.notmuch
+mkdir "${MAIL_DIR}"/def
+mkdir "${MAIL_DIR}"/ghi
+generate_message [dir]=def
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "Alternate inode order"
+
+rm -rf "${MAIL_DIR}"/.notmuch
+mv "${MAIL_DIR}"/ghi "${MAIL_DIR}"/abc
+rm "${MAIL_DIR}"/def/*
+generate_message [dir]=abc
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "Message moved in"
+rm -rf "${MAIL_DIR}"/* "${MAIL_DIR}"/.notmuch
+generate_message
+tmp_msg_filename=tmp/"$gen_msg_filename"
+mkdir -p "$(dirname "$tmp_msg_filename")"
+mv "$gen_msg_filename" "$tmp_msg_filename"
+notmuch new > /dev/null
+mv "$tmp_msg_filename" "$gen_msg_filename"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "Renamed message"
+
+generate_message
+notmuch new > /dev/null
+mv "$gen_msg_filename" "${gen_msg_filename}"-renamed
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Detected 1 file rename."
+
+
+test_begin_subtest "Deleted message"
+
+rm "${gen_msg_filename}"-renamed
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Removed 1 message."
+
+
+test_begin_subtest "Renamed directory"
+
+generate_message [dir]=dir
+generate_message [dir]=dir
+generate_message [dir]=dir
+
+notmuch new > /dev/null
+
+mv "${MAIL_DIR}"/dir "${MAIL_DIR}"/dir-renamed
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Detected 3 file renames."
+
+
+test_begin_subtest "Deleted directory"
+
+rm -rf "${MAIL_DIR}"/dir-renamed
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Removed 3 messages."
+
+
+test_begin_subtest "New directory (at end of list)"
+
+generate_message [dir]=zzz
+generate_message [dir]=zzz
+generate_message [dir]=zzz
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 3 new messages to the database."
+
+
+test_begin_subtest "Deleted directory (end of list)"
+
+rm -rf "${MAIL_DIR}"/zzz
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Removed 3 messages."
+
+
+test_begin_subtest "New symlink to directory"
+
+rm -rf "${MAIL_DIR}"/.notmuch
+mv "${MAIL_DIR}" "${TMP_DIRECTORY}"/actual_maildir
+
+mkdir "${MAIL_DIR}"
+ln -s "${TMP_DIRECTORY}"/actual_maildir "${MAIL_DIR}"/symlink
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "New symlink to a file"
+generate_message
+external_msg_filename="${TMP_DIRECTORY}"/external/"$(basename "$gen_msg_filename")"
+mkdir -p "$(dirname "$external_msg_filename")"
+mv "$gen_msg_filename" "$external_msg_filename"
+ln -s "$external_msg_filename" "$gen_msg_filename"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+
+test_begin_subtest "Broken symlink aborts"
+ln -s does-not-exist "${MAIL_DIR}/broken"
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" \
+"Error reading file ${MAIL_DIR}/broken: No such file or directory
+Note: A fatal error was encountered: Something went wrong trying to read or write a file
+No new mail."
+rm "${MAIL_DIR}/broken"
+
+
+test_begin_subtest "New two-level directory"
+
+generate_message [dir]=two/levels
+generate_message [dir]=two/levels
+generate_message [dir]=two/levels
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 3 new messages to the database."
+
+
+test_begin_subtest "Deleted two-level directory"
+
+rm -rf "${MAIL_DIR}"/two
+
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Removed 3 messages."
+
+test_begin_subtest "Support single-message mbox (deprecated)"
+cat > "${MAIL_DIR}"/mbox_file1 <<EOF
+From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Test mbox message 1
+
+Body.
+EOF
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" \
+"Warning: ${MAIL_DIR}/mbox_file1 is an mbox containing a single message,
+likely caused by misconfigured mail delivery. Support for single-message
+mboxes is deprecated and may be removed in the future.
+Added 1 new message to the database."
+
+# This test requires that notmuch new has been run at least once.
+test_begin_subtest "Skip and report non-mail files"
+generate_message
+mkdir -p "${MAIL_DIR}"/.git && touch "${MAIL_DIR}"/.git/config
+touch "${MAIL_DIR}"/ignored_file
+touch "${MAIL_DIR}"/.ignored_hidden_file
+cat > "${MAIL_DIR}"/mbox_file <<EOF
+From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Test mbox message 1
+
+Body.
+
+From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Test mbox message 2
+
+Body 2.
+EOF
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" \
+"Note: Ignoring non-mail file: ${MAIL_DIR}/.git/config
+Note: Ignoring non-mail file: ${MAIL_DIR}/.ignored_hidden_file
+Note: Ignoring non-mail file: ${MAIL_DIR}/ignored_file
+Note: Ignoring non-mail file: ${MAIL_DIR}/mbox_file
+Added 1 new message to the database."
+rm "${MAIL_DIR}"/mbox_file
+
+test_begin_subtest "Ignore files and directories specified in new.ignore"
+generate_message
+notmuch config set new.ignore .git ignored_file .ignored_hidden_file
+touch "${MAIL_DIR}"/.git # change .git's mtime for notmuch new to rescan.
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Ignore files and directories specified in new.ignore (multiple occurrences)"
+notmuch config set new.ignore .git ignored_file .ignored_hidden_file
+notmuch new > /dev/null # ensure that files/folders will be printed in ASCII order.
+touch "${MAIL_DIR}"/.git # change .git's mtime for notmuch new to rescan.
+touch "${MAIL_DIR}" # likewise for MAIL_DIR
+mkdir -p "${MAIL_DIR}"/one/two/three/.git
+touch "${MAIL_DIR}"/{one,one/two,one/two/three}/ignored_file
+output=$(NOTMUCH_NEW --debug 2>&1 | sort)
+test_expect_equal "$output" \
+"(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/.git
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/.ignored_hidden_file
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/ignored_file
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/ignored_file
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/ignored_file
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/three/.git
+(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/three/ignored_file
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/.git
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/.ignored_hidden_file
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/ignored_file
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/ignored_file
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/ignored_file
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/three/.git
+(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/three/ignored_file
+No new mail."
+
+
+test_begin_subtest "Don't stop for ignored broken symlinks"
+notmuch config set new.ignore .git ignored_file .ignored_hidden_file broken_link
+ln -s i_do_not_exist "${MAIL_DIR}"/broken_link
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" "No new mail."
+
+test_begin_subtest "Quiet: No new mail."
+output=$(NOTMUCH_NEW --quiet)
+test_expect_equal "$output" ""
+
+test_begin_subtest "Quiet: new, removed and renamed messages."
+# new
+generate_message
+# deleted
+notmuch search --format=text0 --output=files --limit=1 '*' | xargs -0 rm
+# moved
+mkdir "${MAIL_DIR}"/moved_messages
+notmuch search --format=text0 --output=files --offset=1 --limit=1 '*' | xargs -0 -I {} mv {} "${MAIL_DIR}"/moved_messages
+output=$(NOTMUCH_NEW --quiet)
+test_expect_equal "$output" ""
+
+OLDCONFIG=$(notmuch config get new.tags)
+
+test_begin_subtest "Empty tags in new.tags are forbidden"
+notmuch config set new.tags "foo;;bar"
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden"
+
+test_begin_subtest "Tags starting with '-' in new.tags are forbidden"
+notmuch config set new.tags "-foo;bar"
+output=$(NOTMUCH_NEW 2>&1)
+test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden"
+
+test_expect_code 1 "Invalid tags set exit code" \
+ "NOTMUCH_NEW 2>&1"
+
+notmuch config set new.tags $OLDCONFIG
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch count" for messages and threads'
+. ./test-lib.sh
+
+add_email_corpus
+
+# Note: The 'wc -l' results below are wrapped in arithmetic evaluation
+# $((...)) to strip whitespace. This is for portability, as 'wc -l'
+# emits whitespace on some BSD variants.
+
+test_begin_subtest "message count is the default for notmuch count"
+test_expect_equal \
+ "$((`notmuch search --output=messages '*' | wc -l`))" \
+ "`notmuch count '*'`"
+
+test_begin_subtest "message count with --output=messages"
+test_expect_equal \
+ "$((`notmuch search --output=messages '*' | wc -l`))" \
+ "`notmuch count --output=messages '*'`"
+
+test_begin_subtest "thread count with --output=threads"
+test_expect_equal \
+ "$((`notmuch search --output=threads '*' | wc -l`))" \
+ "`notmuch count --output=threads '*'`"
+
+test_begin_subtest "thread count is the default for notmuch search"
+test_expect_equal \
+ "$((`notmuch search '*' | wc -l`))" \
+ "`notmuch count --output=threads '*'`"
+
+test_begin_subtest "files count"
+test_expect_equal \
+ "$((`notmuch search --output=files '*' | wc -l`))" \
+ "`notmuch count --output=files '*'`"
+
+test_begin_subtest "files count for a duplicate message-id"
+test_expect_equal \
+ "2" \
+ "`notmuch count --output=files id:20091117232137.GA7669@griffis1.net`"
+
+test_begin_subtest "count with no matching messages"
+test_expect_equal \
+ "0" \
+ "`notmuch count --output=messages from:cworth and not from:cworth`"
+
+test_begin_subtest "count with no matching threads"
+test_expect_equal \
+ "0" \
+ "`notmuch count --output=threads from:cworth and not from:cworth`"
+
+test_begin_subtest "message count is the default for batch count"
+notmuch count --batch >OUTPUT <<EOF
+
+from:cworth
+EOF
+notmuch count --output=messages >EXPECTED
+notmuch count --output=messages from:cworth >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch message count"
+notmuch count --batch --output=messages >OUTPUT <<EOF
+from:cworth
+
+tag:inbox
+EOF
+notmuch count --output=messages from:cworth >EXPECTED
+notmuch count --output=messages >>EXPECTED
+notmuch count --output=messages tag:inbox >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch thread count"
+notmuch count --batch --output=threads >OUTPUT <<EOF
+
+from:cworth
+from:cworth and not from:cworth
+foo
+EOF
+notmuch count --output=threads >EXPECTED
+notmuch count --output=threads from:cworth >>EXPECTED
+notmuch count --output=threads from:cworth and not from:cworth >>EXPECTED
+notmuch count --output=threads foo >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "batch message count with input file"
+cat >INPUT <<EOF
+from:cworth
+
+tag:inbox
+EOF
+notmuch count --input=INPUT --output=messages >OUTPUT
+notmuch count --output=messages from:cworth >EXPECTED
+notmuch count --output=messages >>EXPECTED
+notmuch count --output=messages tag:inbox >>EXPECTED
+test_expect_equal_file EXPECTED OUTPUT
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch insert"'
+. ./test-lib.sh
+
+# Create directories and database before inserting.
+mkdir -p "$MAIL_DIR"/{cur,new,tmp}
+mkdir -p "$MAIL_DIR"/Drafts/{cur,new,tmp}
+notmuch new > /dev/null
+
+# We use generate_message to create the temporary message files.
+# They happen to be in the mail directory already but that is okay
+# since we do not call notmuch new hereafter.
+
+gen_insert_msg() {
+ generate_message \
+ "[subject]=\"insert-subject\"" \
+ "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" \
+ "[body]=\"insert-message\""
+}
+
+test_expect_code 1 "Insert zero-length file" \
+ "notmuch insert < /dev/null"
+
+# This test is a proxy for other errors that may occur while trying to
+# add a message to the notmuch database, e.g. database locked.
+test_expect_code 0 "Insert non-message" \
+ "echo bad_message | notmuch insert"
+
+test_begin_subtest "Database empty so far"
+test_expect_equal "0" "`notmuch count --output=messages '*'`"
+
+test_begin_subtest "Insert message"
+gen_insert_msg
+notmuch insert < "$gen_msg_filename"
+cur_msg_filename=$(notmuch search --output=files "subject:insert-subject")
+test_expect_equal_file "$cur_msg_filename" "$gen_msg_filename"
+
+test_begin_subtest "Insert message adds default tags"
+output=$(notmuch show --format=json "subject:insert-subject")
+expected='[[[{
+ "id": "'"${gen_msg_id}"'",
+ "match": true,
+ "excluded": false,
+ "filename": "'"${cur_msg_filename}"'",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["inbox","unread"],
+ "headers": {
+ "Subject": "insert-subject",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "content-type": "text/plain",
+ "content": "insert-message\n"}]},
+ []]]]'
+test_expect_equal_json "$output" "$expected"
+
+test_begin_subtest "Insert duplicate message"
+notmuch insert +duptag -unread < "$gen_msg_filename"
+output=$(notmuch search --output=files "subject:insert-subject" | wc -l)
+test_expect_equal "$output" 2
+
+test_begin_subtest "Duplicate message does not change tags"
+output=$(notmuch search --format=json --output=tags "subject:insert-subject")
+test_expect_equal_json "$output" '["inbox", "unread"]'
+
+test_begin_subtest "Insert message, add tag"
+gen_insert_msg
+notmuch insert +custom < "$gen_msg_filename"
+output=$(notmuch search --output=messages tag:custom)
+test_expect_equal "$output" "id:$gen_msg_id"
+
+test_begin_subtest "Insert message, add/remove tags"
+gen_insert_msg
+notmuch insert +custom -unread < "$gen_msg_filename"
+output=$(notmuch search --output=messages tag:custom NOT tag:unread)
+test_expect_equal "$output" "id:$gen_msg_id"
+
+test_begin_subtest "Insert message with default tags stays in new/"
+gen_insert_msg
+notmuch insert < "$gen_msg_filename"
+output=$(notmuch search --output=files id:$gen_msg_id)
+dirname=$(dirname "$output")
+test_expect_equal "$dirname" "$MAIL_DIR/new"
+
+test_begin_subtest "Insert message with non-maildir synced tags stays in new/"
+gen_insert_msg
+notmuch insert +custom -inbox < "$gen_msg_filename"
+output=$(notmuch search --output=files id:$gen_msg_id)
+dirname=$(dirname "$output")
+test_expect_equal "$dirname" "$MAIL_DIR/new"
+
+test_begin_subtest "Insert message with custom new.tags goes to cur/"
+OLDCONFIG=$(notmuch config get new.tags)
+notmuch config set new.tags test
+gen_insert_msg
+notmuch insert < "$gen_msg_filename"
+output=$(notmuch search --output=files id:$gen_msg_id)
+dirname=$(dirname "$output")
+notmuch config set new.tags $OLDCONFIG
+test_expect_equal "$dirname" "$MAIL_DIR/cur"
+
+# additional check on the previous message
+test_begin_subtest "Insert message with custom new.tags actually gets the tags"
+output=$(notmuch search --output=tags id:$gen_msg_id)
+test_expect_equal "$output" "test"
+
+test_begin_subtest "Insert message with maildir synced tags goes to cur/"
+gen_insert_msg
+notmuch insert +flagged < "$gen_msg_filename"
+output=$(notmuch search --output=files id:$gen_msg_id)
+dirname=$(dirname "$output")
+test_expect_equal "$dirname" "$MAIL_DIR/cur"
+
+test_begin_subtest "Insert message with maildir sync off goes to new/"
+OLDCONFIG=$(notmuch config get maildir.synchronize_flags)
+notmuch config set maildir.synchronize_flags false
+gen_insert_msg
+notmuch insert +flagged < "$gen_msg_filename"
+output=$(notmuch search --output=files id:$gen_msg_id)
+dirname=$(dirname "$output")
+notmuch config set maildir.synchronize_flags $OLDCONFIG
+test_expect_equal "$dirname" "$MAIL_DIR/new"
+
+test_begin_subtest "Insert message into folder"
+gen_insert_msg
+notmuch insert --folder=Drafts < "$gen_msg_filename"
+output=$(notmuch search --output=files path:Drafts/new)
+dirname=$(dirname "$output")
+test_expect_equal "$dirname" "$MAIL_DIR/Drafts/new"
+
+test_begin_subtest "Insert message into folder, add/remove tags"
+gen_insert_msg
+notmuch insert --folder=Drafts +draft -unread < "$gen_msg_filename"
+output=$(notmuch search --output=messages path:Drafts/cur tag:draft NOT tag:unread)
+test_expect_equal "$output" "id:$gen_msg_id"
+
+gen_insert_msg
+test_expect_code 1 "Insert message into non-existent folder" \
+ "notmuch insert --folder=nonesuch < $gen_msg_filename"
+
+test_begin_subtest "Insert message, create folder"
+gen_insert_msg
+notmuch insert --folder=F --create-folder +folder < "$gen_msg_filename"
+output=$(notmuch search --output=files path:F/new tag:folder)
+basename=$(basename "$output")
+test_expect_equal_file "$gen_msg_filename" "$MAIL_DIR/F/new/${basename}"
+
+test_begin_subtest "Insert message, create subfolder"
+gen_insert_msg
+notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename"
+output=$(notmuch search --output=files path:F/G/H/I/J/new tag:folder)
+basename=$(basename "$output")
+test_expect_equal_file "$gen_msg_filename" "${MAIL_DIR}/F/G/H/I/J/new/${basename}"
+
+test_begin_subtest "Insert message, create existing subfolder"
+gen_insert_msg
+notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename"
+output=$(notmuch count path:F/G/H/I/J/new tag:folder)
+test_expect_equal "$output" "2"
+
+gen_insert_msg
+test_expect_code 1 "Insert message, create invalid subfolder" \
+ "notmuch insert --folder=../G --create-folder $gen_msg_filename"
+
+OLDCONFIG=$(notmuch config get new.tags)
+
+test_begin_subtest "Empty tags in new.tags are forbidden"
+notmuch config set new.tags "foo;;bar"
+gen_insert_msg
+output=$(notmuch insert $gen_msg_filename 2>&1)
+test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden"
+
+test_begin_subtest "Tags starting with '-' in new.tags are forbidden"
+notmuch config set new.tags "-foo;bar"
+gen_insert_msg
+output=$(notmuch insert $gen_msg_filename 2>&1)
+test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden"
+
+test_expect_code 1 "Invalid tags set exit code" \
+ "notmuch insert $gen_msg_filename 2>&1"
+
+notmuch config set new.tags $OLDCONFIG
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch search" in several variations'
+. ./test-lib.sh
+
+add_email_corpus
+
+test_begin_subtest "Search body"
+add_message '[subject]="body search"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [body]=bodysearchtest
+output=$(notmuch search bodysearchtest | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)"
+
+test_begin_subtest "Search by from:"
+add_message '[subject]="search by from"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom
+output=$(notmuch search from:searchbyfrom | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] searchbyfrom; search by from (inbox unread)"
+
+test_begin_subtest "Search by to:"
+add_message '[subject]="search by to"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto
+output=$(notmuch search to:searchbyto | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)"
+
+test_begin_subtest "Search by subject:"
+add_message [subject]=subjectsearchtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(notmuch search subject:subjectsearchtest | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)"
+
+test_begin_subtest "Search by subject (utf-8):"
+add_message [subject]=utf8-sübjéct '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(notmuch search subject:utf8-sübjéct | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
+
+test_begin_subtest "Search by id:"
+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)"
+
+test_begin_subtest "Search by tag:"
+add_message '[subject]="search by tag"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+notmuch tag +searchbytag id:${gen_msg_id}
+output=$(notmuch search tag:searchbytag | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)"
+
+test_begin_subtest "Search by thread:"
+add_message '[subject]="search by thread"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+thread_id=$(notmuch search id:${gen_msg_id} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")
+output=$(notmuch search thread:${thread_id} | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)"
+
+test_begin_subtest "Search body (phrase)"
+add_message '[subject]="body search (phrase)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="body search (phrase)"'
+add_message '[subject]="negative result"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="This phrase should not match the body search"'
+output=$(notmuch search '"body search (phrase)"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox unread)"
+
+test_begin_subtest "Search by from: (address)"
+add_message '[subject]="search by from (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom@example.com
+output=$(notmuch search from:searchbyfrom@example.com | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] searchbyfrom@example.com; search by from (address) (inbox unread)"
+
+test_begin_subtest "Search by from: (name)"
+add_message '[subject]="search by from (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[from]="Search By From Name <test@example.com>"'
+output=$(notmuch search 'from:"Search By From Name"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
+
+test_begin_subtest "Search by from: (name and address)"
+output=$(notmuch search 'from:"Search By From Name <test@example.com>"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
+
+test_begin_subtest "Search by from: without prefix (name and address)"
+output=$(notmuch search '"Search By From Name <test@example.com>"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
+
+test_begin_subtest "Search by to: (address)"
+add_message '[subject]="search by to (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto@example.com
+output=$(notmuch search to:searchbyto@example.com | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)"
+
+test_begin_subtest "Search by to: (name)"
+add_message '[subject]="search by to (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[to]="Search By To Name <test@example.com>"'
+output=$(notmuch search 'to:"Search By To Name"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
+
+test_begin_subtest "Search by to: (name and adress)"
+output=$(notmuch search 'to:"Search By To Name <test@example.com>"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
+
+test_begin_subtest "Search by to: without prefix (name and adress)"
+output=$(notmuch search '"Search By To Name <test@example.com>"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
+
+test_begin_subtest "Search by subject: (phrase)"
+add_message '[subject]="subject search test (phrase)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+add_message '[subject]="this phrase should not match the subject search test"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(notmuch search 'subject:"subject search test (phrase)"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)"
+
+test_begin_subtest 'Search for all messages ("*")'
+notmuch search '*' | notmuch_search_sanitize > OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX 2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+thread:XXX 2010-12-16 [1/1] Olivier Berger; Essai accentué (inbox unread)
+thread:XXX 2009-11-18 [1/1] Chris Wilson; [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+thread:XXX 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)
+thread:XXX 2009-11-18 [2/2] Ingmar Vanhassel, Carl Worth; [notmuch] [PATCH] Typsos (inbox unread)
+thread:XXX 2009-11-18 [3/3] Adrian Perez de Castro, Keith Packard, Carl Worth; [notmuch] Introducing myself (inbox signed unread)
+thread:XXX 2009-11-18 [3/3] Israel Herraiz, Keith Packard, Carl Worth; [notmuch] New to the list (inbox unread)
+thread:XXX 2009-11-18 [3/3] Jan Janak, Carl Worth; [notmuch] What a great idea! (inbox unread)
+thread:XXX 2009-11-18 [2/2] Jan Janak, Carl Worth; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+thread:XXX 2009-11-18 [3/3] Aron Griffis, Keith Packard, Carl Worth; [notmuch] archive (inbox unread)
+thread:XXX 2009-11-18 [2/2] Keith Packard, Carl Worth; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+thread:XXX 2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
+thread:XXX 2009-11-18 [5/5] Mikhail Gusarov, Carl Worth, Keith Packard; [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+thread:XXX 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)
+thread:XXX 2009-11-18 [1/1] Alexander Botero-Lowry; [notmuch] request for pull (inbox unread)
+thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+thread:XXX 2009-11-18 [1/1] Rolland Santimano; [notmuch] Link to mailing list archives ? (inbox unread)
+thread:XXX 2009-11-18 [1/1] Jan Janak; [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
+thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
+thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
+thread:XXX 2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+thread:XXX 2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
+thread:XXX 2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)
+thread:XXX 2000-01-01 [1/1] searchbyfrom; search by from (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; negative result (inbox unread)
+thread:XXX 2000-01-01 [1/1] searchbyfrom@example.com; search by from (address) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; this phrase should not match the subject search test (inbox unread)
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Search body (utf-8):"
+add_message '[subject]="utf8-message-body-subject"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="message body utf8: bödý"'
+output=$(notmuch search "bödý" | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-message-body-subject (inbox unread)"
+
+
+cat <<EOF > ${MAIL_DIR}/termpos
+From: Source <source@example.com>
+To: Dest <dest@example.com>
+Subject: part overlap test
+Date: Sat, 01 January 2000 00:00:00 +0000
+Message-ID: <termpos>
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="==-=="
+
+--==-==
+Content-Type: text/plain
+
+a b c
+
+--==-==
+Content-Type: text/plain
+
+x y z
+
+--==-==--
+EOF
+notmuch new > /dev/null
+
+test_begin_subtest "headers do not have adjacent term positions"
+# Regression test for a bug where term positions for non-prefixed
+# terms weren't updated
+output=$(notmuch search id:termpos and '"com dest"')
+test_expect_equal "$output" ""
+
+test_begin_subtest "parts have non-overlapping term positions"
+output=$(notmuch search id:termpos and '"a y c"')
+test_expect_equal "$output" ""
+
+test_begin_subtest "parts do not have adjacent term positions"
+output=$(notmuch search id:termpos and '"c x"')
+test_expect_equal "$output" ""
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='various settings for "notmuch search --output="'
+. ./test-lib.sh
+
+add_email_corpus
+
+test_begin_subtest "--output=threads"
+notmuch search --output=threads '*' | sed -e s/thread:.*/thread:THREADID/ >OUTPUT
+cat <<EOF >EXPECTED
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+thread:THREADID
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=threads --format=json"
+notmuch search --format=json --output=threads '*' | sed -e s/\".*\"/\"THREADID\"/ >OUTPUT
+cat <<EOF >EXPECTED
+["THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID",
+"THREADID"]
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--output=messages"
+notmuch search --output=messages '*' >OUTPUT
+cat <<EOF >EXPECTED
+id:4EFC743A.3060609@april.org
+id:877h1wv7mg.fsf@inf-8657.int-evry.fr
+id:1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk
+id:877htoqdbo.fsf@yoom.home.cworth.org
+id:878we4qdqf.fsf@yoom.home.cworth.org
+id:87aaykqe24.fsf@yoom.home.cworth.org
+id:87bpj0qeng.fsf@yoom.home.cworth.org
+id:87fx8cqf8v.fsf@yoom.home.cworth.org
+id:87hbssqfix.fsf@yoom.home.cworth.org
+id:87iqd8qgiz.fsf@yoom.home.cworth.org
+id:87k4xoqgnl.fsf@yoom.home.cworth.org
+id:87ocn0qh6d.fsf@yoom.home.cworth.org
+id:87pr7gqidx.fsf@yoom.home.cworth.org
+id:867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
+id:1258532999-9316-1-git-send-email-keithp@keithp.com
+id:86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
+id:86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
+id:ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com
+id:86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
+id:736613.51770.qm@web113505.mail.gq1.yahoo.com
+id:1258520223-15328-1-git-send-email-jan@ryngle.com
+id:ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com
+id:1258510940-7018-1-git-send-email-stewart@flamingspork.com
+id:yunzl6kd1w0.fsf@aiko.keithp.com
+id:yun1vjwegii.fsf@aiko.keithp.com
+id:yun3a4cegoa.fsf@aiko.keithp.com
+id:1258509400-32511-1-git-send-email-stewart@flamingspork.com
+id:1258506353-20352-1-git-send-email-stewart@flamingspork.com
+id:20091118010116.GC25380@dottiness.seas.harvard.edu
+id:20091118005829.GB25380@dottiness.seas.harvard.edu
+id:20091118005040.GA25380@dottiness.seas.harvard.edu
+id:cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com
+id:1258500222-32066-1-git-send-email-ingmar@exherbo.org
+id:20091117232137.GA7669@griffis1.net
+id:20091118002059.067214ed@hikari
+id:1258498485-sup-142@elly
+id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com
+id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com
+id:1258496327-12086-1-git-send-email-jan@ryngle.com
+id:1258493565-13508-1-git-send-email-keithp@keithp.com
+id:yunaayketfm.fsf@aiko.keithp.com
+id:yunbpj0etua.fsf@aiko.keithp.com
+id:1258491078-29658-1-git-send-email-dottedmag@dottedmag.net
+id:87fx8can9z.fsf@vertex.dottedmag
+id:20091117203301.GV3165@dottiness.seas.harvard.edu
+id:87lji4lx9v.fsf@yoom.home.cworth.org
+id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com
+id:87iqd9rn3l.fsf@vertex.dottedmag
+id:20091117190054.GU3165@dottiness.seas.harvard.edu
+id:87lji5cbwo.fsf@yoom.home.cworth.org
+id:1258471718-6781-2-git-send-email-dottedmag@dottedmag.net
+id:1258471718-6781-1-git-send-email-dottedmag@dottedmag.net
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=messages --format=json"
+notmuch search --format=json --output=messages '*' >OUTPUT
+cat <<EOF >EXPECTED
+["4EFC743A.3060609@april.org",
+"877h1wv7mg.fsf@inf-8657.int-evry.fr",
+"1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk",
+"877htoqdbo.fsf@yoom.home.cworth.org",
+"878we4qdqf.fsf@yoom.home.cworth.org",
+"87aaykqe24.fsf@yoom.home.cworth.org",
+"87bpj0qeng.fsf@yoom.home.cworth.org",
+"87fx8cqf8v.fsf@yoom.home.cworth.org",
+"87hbssqfix.fsf@yoom.home.cworth.org",
+"87iqd8qgiz.fsf@yoom.home.cworth.org",
+"87k4xoqgnl.fsf@yoom.home.cworth.org",
+"87ocn0qh6d.fsf@yoom.home.cworth.org",
+"87pr7gqidx.fsf@yoom.home.cworth.org",
+"867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
+"1258532999-9316-1-git-send-email-keithp@keithp.com",
+"86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
+"86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
+"ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com",
+"86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
+"736613.51770.qm@web113505.mail.gq1.yahoo.com",
+"1258520223-15328-1-git-send-email-jan@ryngle.com",
+"ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com",
+"1258510940-7018-1-git-send-email-stewart@flamingspork.com",
+"yunzl6kd1w0.fsf@aiko.keithp.com",
+"yun1vjwegii.fsf@aiko.keithp.com",
+"yun3a4cegoa.fsf@aiko.keithp.com",
+"1258509400-32511-1-git-send-email-stewart@flamingspork.com",
+"1258506353-20352-1-git-send-email-stewart@flamingspork.com",
+"20091118010116.GC25380@dottiness.seas.harvard.edu",
+"20091118005829.GB25380@dottiness.seas.harvard.edu",
+"20091118005040.GA25380@dottiness.seas.harvard.edu",
+"cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com",
+"1258500222-32066-1-git-send-email-ingmar@exherbo.org",
+"20091117232137.GA7669@griffis1.net",
+"20091118002059.067214ed@hikari",
+"1258498485-sup-142@elly",
+"f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com",
+"f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com",
+"1258496327-12086-1-git-send-email-jan@ryngle.com",
+"1258493565-13508-1-git-send-email-keithp@keithp.com",
+"yunaayketfm.fsf@aiko.keithp.com",
+"yunbpj0etua.fsf@aiko.keithp.com",
+"1258491078-29658-1-git-send-email-dottedmag@dottedmag.net",
+"87fx8can9z.fsf@vertex.dottedmag",
+"20091117203301.GV3165@dottiness.seas.harvard.edu",
+"87lji4lx9v.fsf@yoom.home.cworth.org",
+"cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com",
+"87iqd9rn3l.fsf@vertex.dottedmag",
+"20091117190054.GU3165@dottiness.seas.harvard.edu",
+"87lji5cbwo.fsf@yoom.home.cworth.org",
+"1258471718-6781-2-git-send-email-dottedmag@dottedmag.net",
+"1258471718-6781-1-git-send-email-dottedmag@dottedmag.net"]
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=files"
+notmuch search --output=files '*' | notmuch_search_files_sanitize | sort >OUTPUT
+cat <<EOF >EXPECTED
+MAIL_DIR/01:2,
+MAIL_DIR/02:2,
+MAIL_DIR/bar/17:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/bar/baz/05:2,
+MAIL_DIR/bar/baz/23:2,
+MAIL_DIR/bar/baz/24:2,
+MAIL_DIR/bar/baz/cur/25:2,
+MAIL_DIR/bar/baz/cur/26:2,
+MAIL_DIR/bar/baz/new/27:2,
+MAIL_DIR/bar/baz/new/28:2,
+MAIL_DIR/bar/cur/19:2,
+MAIL_DIR/bar/cur/20:2,
+MAIL_DIR/bar/new/21:2,
+MAIL_DIR/bar/new/22:2,
+MAIL_DIR/cur/29:2,
+MAIL_DIR/cur/30:2,
+MAIL_DIR/cur/31:2,
+MAIL_DIR/cur/32:2,
+MAIL_DIR/cur/33:2,
+MAIL_DIR/cur/34:2,
+MAIL_DIR/cur/35:2,
+MAIL_DIR/cur/36:2,
+MAIL_DIR/cur/37:2,
+MAIL_DIR/cur/38:2,
+MAIL_DIR/cur/39:2,
+MAIL_DIR/cur/40:2,
+MAIL_DIR/cur/41:2,
+MAIL_DIR/cur/42:2,
+MAIL_DIR/cur/43:2,
+MAIL_DIR/cur/44:2,
+MAIL_DIR/cur/45:2,
+MAIL_DIR/cur/46:2,
+MAIL_DIR/cur/47:2,
+MAIL_DIR/cur/48:2,
+MAIL_DIR/cur/49:2,
+MAIL_DIR/cur/50:2,
+MAIL_DIR/cur/51:2,
+MAIL_DIR/cur/52:2,
+MAIL_DIR/cur/53:2,
+MAIL_DIR/foo/06:2,
+MAIL_DIR/foo/baz/11:2,
+MAIL_DIR/foo/baz/12:2,
+MAIL_DIR/foo/baz/cur/13:2,
+MAIL_DIR/foo/baz/cur/14:2,
+MAIL_DIR/foo/baz/new/15:2,
+MAIL_DIR/foo/baz/new/16:2,
+MAIL_DIR/foo/cur/07:2,
+MAIL_DIR/foo/cur/08:2,
+MAIL_DIR/foo/new/03:2,
+MAIL_DIR/foo/new/09:2,
+MAIL_DIR/foo/new/10:2,
+MAIL_DIR/new/04:2,
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+dup1=$(notmuch search --output=files id:20091117232137.GA7669@griffis1.net | head -n 1 | sed -e "s,$MAIL_DIR,MAIL_DIR,")
+dup2=$(notmuch search --output=files id:20091117232137.GA7669@griffis1.net | tail -n 1 | sed -e "s,$MAIL_DIR,MAIL_DIR,")
+
+test_begin_subtest "--output=files --duplicate=1"
+notmuch search --output=files --duplicate=1 '*' | notmuch_search_files_sanitize | sort >OUTPUT
+cat <<EOF | sort >EXPECTED
+$dup1
+MAIL_DIR/cur/52:2,
+MAIL_DIR/cur/53:2,
+MAIL_DIR/cur/50:2,
+MAIL_DIR/cur/49:2,
+MAIL_DIR/cur/48:2,
+MAIL_DIR/cur/47:2,
+MAIL_DIR/cur/46:2,
+MAIL_DIR/cur/45:2,
+MAIL_DIR/cur/44:2,
+MAIL_DIR/cur/43:2,
+MAIL_DIR/cur/42:2,
+MAIL_DIR/cur/41:2,
+MAIL_DIR/cur/40:2,
+MAIL_DIR/cur/39:2,
+MAIL_DIR/cur/38:2,
+MAIL_DIR/cur/37:2,
+MAIL_DIR/cur/36:2,
+MAIL_DIR/cur/35:2,
+MAIL_DIR/cur/34:2,
+MAIL_DIR/cur/33:2,
+MAIL_DIR/cur/32:2,
+MAIL_DIR/cur/31:2,
+MAIL_DIR/cur/30:2,
+MAIL_DIR/cur/29:2,
+MAIL_DIR/bar/baz/new/28:2,
+MAIL_DIR/bar/baz/new/27:2,
+MAIL_DIR/bar/baz/cur/26:2,
+MAIL_DIR/bar/baz/cur/25:2,
+MAIL_DIR/bar/baz/24:2,
+MAIL_DIR/bar/baz/23:2,
+MAIL_DIR/bar/new/22:2,
+MAIL_DIR/bar/new/21:2,
+MAIL_DIR/bar/cur/19:2,
+MAIL_DIR/bar/cur/20:2,
+MAIL_DIR/bar/17:2,
+MAIL_DIR/foo/baz/new/16:2,
+MAIL_DIR/foo/baz/new/15:2,
+MAIL_DIR/foo/baz/cur/14:2,
+MAIL_DIR/foo/baz/cur/13:2,
+MAIL_DIR/foo/baz/12:2,
+MAIL_DIR/foo/baz/11:2,
+MAIL_DIR/foo/new/10:2,
+MAIL_DIR/foo/new/09:2,
+MAIL_DIR/foo/cur/08:2,
+MAIL_DIR/foo/06:2,
+MAIL_DIR/bar/baz/05:2,
+MAIL_DIR/new/04:2,
+MAIL_DIR/foo/new/03:2,
+MAIL_DIR/foo/cur/07:2,
+MAIL_DIR/02:2,
+MAIL_DIR/01:2,
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=files --format=json"
+notmuch search --format=json --output=files '*' | notmuch_search_files_sanitize \
+ | test_sort_json >OUTPUT
+cat <<EOF | test_sort_json >EXPECTED
+["MAIL_DIR/cur/52:2,",
+"MAIL_DIR/cur/53:2,",
+"MAIL_DIR/cur/50:2,",
+"MAIL_DIR/cur/49:2,",
+"MAIL_DIR/cur/48:2,",
+"MAIL_DIR/cur/47:2,",
+"MAIL_DIR/cur/46:2,",
+"MAIL_DIR/cur/45:2,",
+"MAIL_DIR/cur/44:2,",
+"MAIL_DIR/cur/43:2,",
+"MAIL_DIR/cur/42:2,",
+"MAIL_DIR/cur/41:2,",
+"MAIL_DIR/cur/40:2,",
+"MAIL_DIR/cur/39:2,",
+"MAIL_DIR/cur/38:2,",
+"MAIL_DIR/cur/37:2,",
+"MAIL_DIR/cur/36:2,",
+"MAIL_DIR/cur/35:2,",
+"MAIL_DIR/cur/34:2,",
+"MAIL_DIR/cur/33:2,",
+"MAIL_DIR/cur/32:2,",
+"MAIL_DIR/cur/31:2,",
+"MAIL_DIR/cur/30:2,",
+"MAIL_DIR/cur/29:2,",
+"MAIL_DIR/bar/baz/new/28:2,",
+"MAIL_DIR/bar/baz/new/27:2,",
+"MAIL_DIR/bar/baz/cur/26:2,",
+"MAIL_DIR/bar/baz/cur/25:2,",
+"MAIL_DIR/bar/baz/24:2,",
+"MAIL_DIR/bar/baz/23:2,",
+"MAIL_DIR/bar/new/22:2,",
+"MAIL_DIR/bar/new/21:2,",
+"MAIL_DIR/bar/cur/19:2,",
+"MAIL_DIR/bar/18:2,",
+"MAIL_DIR/cur/51:2,",
+"MAIL_DIR/bar/cur/20:2,",
+"MAIL_DIR/bar/17:2,",
+"MAIL_DIR/foo/baz/new/16:2,",
+"MAIL_DIR/foo/baz/new/15:2,",
+"MAIL_DIR/foo/baz/cur/14:2,",
+"MAIL_DIR/foo/baz/cur/13:2,",
+"MAIL_DIR/foo/baz/12:2,",
+"MAIL_DIR/foo/baz/11:2,",
+"MAIL_DIR/foo/new/10:2,",
+"MAIL_DIR/foo/new/09:2,",
+"MAIL_DIR/foo/cur/08:2,",
+"MAIL_DIR/foo/06:2,",
+"MAIL_DIR/bar/baz/05:2,",
+"MAIL_DIR/new/04:2,",
+"MAIL_DIR/foo/new/03:2,",
+"MAIL_DIR/foo/cur/07:2,",
+"MAIL_DIR/02:2,",
+"MAIL_DIR/01:2,"]
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=files --format=json --duplicate=2"
+notmuch search --format=json --output=files --duplicate=2 '*' | notmuch_search_files_sanitize >OUTPUT
+cat <<EOF >EXPECTED
+["$dup2"]
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=tags"
+notmuch search --output=tags '*' >OUTPUT
+cat <<EOF >EXPECTED
+attachment
+inbox
+signed
+unread
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=tags --format=json"
+notmuch search --format=json --output=tags '*' >OUTPUT
+cat <<EOF >EXPECTED
+["attachment",
+"inbox",
+"signed",
+"unread"]
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "sanitize output for quoted-printable line-breaks in author and subject"
+add_message "[subject]='two =?ISO-8859-1?Q?line=0A_subject?=
+ headers'"
+notmuch search id:"$gen_msg_id" | notmuch_search_sanitize >OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; two line subject headers (inbox unread)
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "search for non-existent message prints nothing"
+notmuch search "no-message-matches-this" > OUTPUT
+echo -n >EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "search --format=json for non-existent message prints proper empty json"
+notmuch search --format=json "no-message-matches-this" > OUTPUT
+echo "[]" >EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch search" by folder: and path: (with variations)'
+. ./test-lib.sh
+
+add_message '[dir]=bad' '[subject]="To the bone"'
+add_message '[dir]=.' '[subject]="Top level"'
+add_message '[dir]=bad/news' '[subject]="Bears"'
+mkdir -p "${MAIL_DIR}/duplicate/bad/news"
+cp "$gen_msg_filename" "${MAIL_DIR}/duplicate/bad/news"
+
+add_message '[dir]=things' '[subject]="These are a few"'
+add_message '[dir]=things/favorite' '[subject]="Raindrops, whiskers, kettles"'
+add_message '[dir]=things/bad' '[subject]="Bites, stings, sad feelings"'
+
+test_begin_subtest "Single-world folder: specification (multiple results)"
+output=$(notmuch search folder:bad folder:bad/news folder:things/bad | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
+
+test_begin_subtest "Top level folder"
+output=$(notmuch search folder:'""' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Top level (inbox unread)"
+
+test_begin_subtest "Two-word path to narrow results to one"
+output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
+
+test_begin_subtest "Folder search with --output=files"
+output=$(notmuch search --output=files folder:bad/news | notmuch_search_files_sanitize)
+test_expect_equal "$output" "MAIL_DIR/bad/news/msg-003
+MAIL_DIR/duplicate/bad/news/msg-003"
+
+test_begin_subtest "After removing duplicate instance of matching path"
+rm -r "${MAIL_DIR}/bad/news"
+notmuch new
+output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
+test_expect_equal "$output" ""
+
+test_begin_subtest "Folder search with --output=files part #2"
+output=$(notmuch search --output=files folder:duplicate/bad/news | notmuch_search_files_sanitize)
+test_expect_equal "$output" "MAIL_DIR/duplicate/bad/news/msg-003"
+
+test_begin_subtest "After removing duplicate instance of matching path part #2"
+output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
+
+test_begin_subtest "After rename, old path returns nothing"
+mv "${MAIL_DIR}/duplicate/bad/news" "${MAIL_DIR}/duplicate/bad/olds"
+notmuch new
+output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize)
+test_expect_equal "$output" ""
+
+test_begin_subtest "After rename, new path returns result"
+output=$(notmuch search folder:duplicate/bad/olds | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
+
+# folder: and path: searches with full corpus
+rm -rf $MAIL_DIR
+add_email_corpus
+
+# add some more dupes
+cp $MAIL_DIR/foo/new/03:2, $MAIL_DIR/new
+cp $MAIL_DIR/bar/baz/05:2, $MAIL_DIR/foo
+notmuch new >/dev/null
+
+test_begin_subtest "folder: search"
+output=$(notmuch search --output=files folder:foo | notmuch_search_files_sanitize | sort)
+# bar/baz/05:2, is a duplicate of foo/05:2,
+# new/03:2, is a duplicate of foo/new/03:2,
+test_expect_equal "$output" "MAIL_DIR/bar/baz/05:2,
+MAIL_DIR/foo/05:2,
+MAIL_DIR/foo/06:2,
+MAIL_DIR/foo/cur/07:2,
+MAIL_DIR/foo/cur/08:2,
+MAIL_DIR/foo/new/03:2,
+MAIL_DIR/foo/new/09:2,
+MAIL_DIR/foo/new/10:2,
+MAIL_DIR/new/03:2,"
+
+test_begin_subtest "top level folder: search"
+output=$(notmuch search --output=files folder:'""' | notmuch_search_files_sanitize | sort)
+# bar/18:2, is a duplicate of cur/51:2,
+# foo/new/03:2, is a duplicate of new/03:2,
+test_expect_equal "$output" "MAIL_DIR/01:2,
+MAIL_DIR/02:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/cur/29:2,
+MAIL_DIR/cur/30:2,
+MAIL_DIR/cur/31:2,
+MAIL_DIR/cur/32:2,
+MAIL_DIR/cur/33:2,
+MAIL_DIR/cur/34:2,
+MAIL_DIR/cur/35:2,
+MAIL_DIR/cur/36:2,
+MAIL_DIR/cur/37:2,
+MAIL_DIR/cur/38:2,
+MAIL_DIR/cur/39:2,
+MAIL_DIR/cur/40:2,
+MAIL_DIR/cur/41:2,
+MAIL_DIR/cur/42:2,
+MAIL_DIR/cur/43:2,
+MAIL_DIR/cur/44:2,
+MAIL_DIR/cur/45:2,
+MAIL_DIR/cur/46:2,
+MAIL_DIR/cur/47:2,
+MAIL_DIR/cur/48:2,
+MAIL_DIR/cur/49:2,
+MAIL_DIR/cur/50:2,
+MAIL_DIR/cur/51:2,
+MAIL_DIR/cur/52:2,
+MAIL_DIR/cur/53:2,
+MAIL_DIR/foo/new/03:2,
+MAIL_DIR/new/03:2,
+MAIL_DIR/new/04:2,"
+
+test_begin_subtest "path: search"
+output=$(notmuch search --output=files path:"bar" | notmuch_search_files_sanitize | sort)
+# cur/51:2, is a duplicate of bar/18:2,
+test_expect_equal "$output" "MAIL_DIR/bar/17:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/cur/51:2,"
+
+test_begin_subtest "top level path: search"
+output=$(notmuch search --output=files path:'""' | notmuch_search_files_sanitize | sort)
+test_expect_equal "$output" "MAIL_DIR/01:2,
+MAIL_DIR/02:2,"
+
+test_begin_subtest "recursive path: search"
+output=$(notmuch search --output=files path:"bar/**" | notmuch_search_files_sanitize | sort)
+# cur/51:2, is a duplicate of bar/18:2,
+# foo/05:2, is a duplicate of bar/baz/05:2,
+test_expect_equal "$output" "MAIL_DIR/bar/17:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/bar/baz/05:2,
+MAIL_DIR/bar/baz/23:2,
+MAIL_DIR/bar/baz/24:2,
+MAIL_DIR/bar/baz/cur/25:2,
+MAIL_DIR/bar/baz/cur/26:2,
+MAIL_DIR/bar/baz/new/27:2,
+MAIL_DIR/bar/baz/new/28:2,
+MAIL_DIR/bar/cur/19:2,
+MAIL_DIR/bar/cur/20:2,
+MAIL_DIR/bar/new/21:2,
+MAIL_DIR/bar/new/22:2,
+MAIL_DIR/cur/51:2,
+MAIL_DIR/foo/05:2,"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+# Test to demonstrate a position overlap bug.
+#
+# At one point, notmuch would index terms incorrectly in the case of
+# calling index_terms multiple times for a single field. The term
+# generator was being reset to position 0 each time. This means that
+# with text such as:
+#
+# To: a@b.c, x@y.z
+#
+# one could get a bogus match by searching for:
+#
+# To: a@y.c
+#
+# Thanks to Mark Anderson for reporting the bug, (and providing a nice,
+# minimal test case that inspired what is used here), in
+# id:3wd4o8wa7fx.fsf@testarossa.amd.com
+
+test_description='that notmuch does not overlap term positions'
+. ./test-lib.sh
+
+add_message '[to]="a@b.c, x@y.z"'
+
+test_begin_subtest "Search for a@b.c matches"
+output=$(notmuch search a@b.c | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Test message #1 (inbox unread)"
+
+test_begin_subtest "Search for x@y.z matches"
+output=$(notmuch search x@y.z | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Test message #1 (inbox unread)"
+
+test_begin_subtest "Search for a@y.c must not match"
+output=$(notmuch search a@y.c | notmuch_search_sanitize)
+test_expect_equal "$output" ""
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='messages with unquoted . in name'
+. ./test-lib.sh
+
+add_message \
+ '[from]="Some.Name for Someone <bugs@quoting.com>"' \
+ '[subject]="This message needs more quoting on the From line"'
+
+add_message \
+ '[from]="\"Some.Name for Someone\" <bugs@quoting.com>"' \
+ '[subject]="This message has necessary quoting in place"'
+
+add_message \
+ '[from]="No.match Here <filler@mail.com>"' \
+ '[subject]="This message needs more quoting on the From line"'
+
+add_message \
+ '[from]="\"No.match Here\" <filler@mail.com>"' \
+ '[subject]="This message has necessary quoting in place"'
+
+
+test_begin_subtest "Search by first name"
+output=$(notmuch search from:Some.Name | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
+thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
+
+test_begin_subtest "Search by last name:"
+output=$(notmuch search from:Someone | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
+thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
+
+test_begin_subtest "Search by address:"
+output=$(notmuch search from:bugs@quoting.com | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
+thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
+
+test_begin_subtest "Search for all messages:"
+output=$(notmuch search '*' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
+thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)
+thread:XXX 2001-01-05 [1/1] No.match Here; This message needs more quoting on the From line (inbox unread)
+thread:XXX 2001-01-05 [1/1] No.match Here; This message has necessary quoting in place (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch search" --offset and --limit parameters'
+. ./test-lib.sh
+
+add_email_corpus
+
+for outp in messages threads; do
+ test_begin_subtest "${outp}: limit does the right thing"
+ notmuch search --output=${outp} "*" | head -n 20 >expected
+ notmuch search --output=${outp} --limit=20 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: concatenation of limited searches"
+ notmuch search --output=${outp} "*" | head -n 20 >expected
+ notmuch search --output=${outp} --limit=10 "*" >output
+ notmuch search --output=${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} "*"`
+ notmuch search --output=${outp} "*" >expected
+ notmuch search --output=${outp} --limit=$((1 + ${N})) "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: limit = 0"
+ test_expect_equal "`notmuch search --output=${outp} --limit=0 "*"`" ""
+
+ test_begin_subtest "${outp}: offset does the right thing"
+ # note: tail -n +N is 1-based
+ notmuch search --output=${outp} "*" | tail -n +21 >expected
+ notmuch search --output=${outp} --offset=20 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: offset = 0"
+ notmuch search --output=${outp} "*" >expected
+ notmuch search --output=${outp} --offset=0 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset"
+ notmuch search --output=${outp} "*" | tail -n 20 >expected
+ notmuch search --output=${outp} --offset=-20 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset"
+ notmuch search --output=${outp} "*" | tail -n 1 >expected
+ notmuch search --output=${outp} --offset=-1 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset combined with limit"
+ notmuch search --output=${outp} "*" | tail -n 20 | head -n 10 >expected
+ notmuch search --output=${outp} --offset=-20 --limit=10 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset combined with equal limit"
+ notmuch search --output=${outp} "*" | tail -n 20 >expected
+ notmuch search --output=${outp} --offset=-20 --limit=20 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset combined with large limit"
+ notmuch search --output=${outp} "*" | tail -n 20 >expected
+ notmuch search --output=${outp} --offset=-20 --limit=50 "*" >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "${outp}: negative offset larger then results"
+ N=`notmuch count --output=${outp} "*"`
+ notmuch search --output=${outp} "*" >expected
+ notmuch search --output=${outp} --offset=-$((1 + ${N})) "*" >output
+ test_expect_equal_file expected output
+done
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch search, count and show" with excludes in several variations'
+. ./test-lib.sh
+
+# Generates a thread consisting of a top level message and 'length'
+# replies. The subject of the top message 'subject: top message"
+# and the subject of the nth reply in the thread is "subject: reply n"
+generate_thread ()
+{
+ local subject="$1"
+ local length="$2"
+ generate_message '[subject]="'"${subject}: top message"'"' '[body]="'"body of top message"'"'
+ parent_id=$gen_msg_id
+ gen_thread_msg_id[0]=$gen_msg_id
+ for i in `seq 1 $length`
+ do
+ generate_message '[subject]="'"${subject}: reply $i"'"' \
+ "[in-reply-to]=\<$parent_id\>" \
+ '[body]="'"body of reply $i"'"'
+ gen_thread_msg_id[$i]=$gen_msg_id
+ parent_id=$gen_msg_id
+ done
+ notmuch new > /dev/null
+ # We cannot retrieve the thread_id until after we have run notmuch new.
+ gen_thread_id=`notmuch search --output=threads id:${gen_thread_msg_id[0]}`
+}
+
+#############################################
+# These are the original search exclude tests.
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search"
+notmuch config set search.exclude_tags deleted
+generate_message '[subject]="Not deleted"'
+not_deleted_id=$gen_msg_id
+generate_message '[subject]="Deleted"'
+notmuch new > /dev/null
+notmuch tag +deleted id:$gen_msg_id
+deleted_id=$gen_msg_id
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search"
+output=$(notmuch search --output=messages subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search --exclude=false"
+output=$(notmuch search --exclude=false --output=messages subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id
+id:$deleted_id"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from message search (non-existent exclude-tag)"
+notmuch config set search.exclude_tags deleted non_existent_tag
+output=$(notmuch search --output=messages subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "id:$not_deleted_id"
+notmuch config set search.exclude_tags deleted
+
+test_begin_subtest "Search, exclude \"deleted\" messages from search, overridden"
+output=$(notmuch search subject:deleted and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Deleted (deleted inbox unread)"
+
+test_begin_subtest "Search, exclude \"deleted\" messages from threads"
+add_message '[subject]="Not deleted reply"' '[in-reply-to]="<$gen_msg_id>"'
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
+thread:XXX 2001-01-05 [1/2] Notmuch Test Suite; Not deleted reply (deleted inbox unread)"
+
+test_begin_subtest "Search, don't exclude \"deleted\" messages when --exclude=flag specified"
+output=$(notmuch search --exclude=flag subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
+thread:XXX 2001-01-05 [1/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
+
+test_begin_subtest "Search, don't exclude \"deleted\" messages from search if not configured"
+notmuch config set search.exclude_tags
+output=$(notmuch search subject:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
+thread:XXX 2001-01-05 [2/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
+
+
+########################################################
+# We construct some threads for the tests. We use the tag "test" to
+# indicate which messages we will search for.
+
+# A thread of deleted messages; test matches one of them.
+generate_thread "All messages excluded: single match" 5
+notmuch tag +deleted $gen_thread_id
+notmuch tag +test id:${gen_thread_msg_id[2]}
+
+# A thread of deleted messages; test matches two of them.
+generate_thread "All messages excluded: double match" 5
+notmuch tag +deleted $gen_thread_id
+notmuch tag +test id:${gen_thread_msg_id[2]}
+notmuch tag +test id:${gen_thread_msg_id[4]}
+
+# A thread some messages deleted; test only matches a deleted message.
+generate_thread "Some messages excluded: single excluded match" 5
+notmuch tag +deleted +test id:${gen_thread_msg_id[3]}
+
+# A thread some messages deleted; test only matches a non-deleted message.
+generate_thread "Some messages excluded: single non-excluded match" 5
+notmuch tag +deleted id:${gen_thread_msg_id[2]}
+notmuch tag +test id:${gen_thread_msg_id[4]}
+
+# A thread no messages deleted; test matches a message.
+generate_thread "No messages excluded: single match" 5
+notmuch tag +test id:${gen_thread_msg_id[3]}
+
+# Temporarily remove excludes to get list of matching messages
+notmuch config set search.exclude_tags
+matching_message_ids=( `notmuch search --output=messages tag:test` )
+notmuch config set search.exclude_tags deleted
+
+#########################################
+# Notmuch search tests
+
+test_begin_subtest "Search, default exclusion (thread summary)"
+output=$(notmuch search tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
+
+test_begin_subtest "Search, default exclusion (messages)"
+output=$(notmuch search --output=messages tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[4]}
+${matching_message_ids[5]}"
+
+test_begin_subtest "Search, exclude=true (thread summary)"
+output=$(notmuch search --exclude=true tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
+
+test_begin_subtest "Search, exclude=true (messages)"
+output=$(notmuch search --exclude=true --output=messages tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[4]}
+${matching_message_ids[5]}"
+
+test_begin_subtest "Search, exclude=false (thread summary)"
+output=$(notmuch search --exclude=false tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
+
+test_begin_subtest "Search, exclude=false (messages)"
+output=$(notmuch search --exclude=false --output=messages tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}
+${matching_message_ids[4]}
+${matching_message_ids[5]}"
+
+test_begin_subtest "Search, exclude=flag (thread summary)"
+output=$(notmuch search --exclude=flag tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
+
+test_begin_subtest "Search, exclude=flag (messages)"
+output=$(notmuch search --exclude=flag --output=messages tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}
+${matching_message_ids[4]}
+${matching_message_ids[5]}"
+
+test_begin_subtest "Search, exclude=all (thread summary)"
+output=$(notmuch search --exclude=all tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/5] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
+
+test_begin_subtest "Search, exclude=all (messages)"
+output=$(notmuch search --exclude=all --output=messages tag:test | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[4]}
+${matching_message_ids[5]}"
+
+test_begin_subtest "Search, default exclusion: tag in query (thread summary)"
+output=$(notmuch search tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
+
+test_begin_subtest "Search, default exclusion: tag in query (messages)"
+output=$(notmuch search --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}"
+
+test_begin_subtest "Search, exclude=true: tag in query (thread summary)"
+output=$(notmuch search --exclude=true tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
+
+test_begin_subtest "Search, exclude=true: tag in query (messages)"
+output=$(notmuch search --exclude=true --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}"
+
+test_begin_subtest "Search, exclude=false: tag in query (thread summary)"
+output=$(notmuch search --exclude=false tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
+
+test_begin_subtest "Search, exclude=false: tag in query (messages)"
+output=$(notmuch search --exclude=false --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}"
+
+test_begin_subtest "Search, exclude=flag: tag in query (thread summary)"
+output=$(notmuch search --exclude=flag tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
+
+test_begin_subtest "Search, exclude=flag: tag in query (messages)"
+output=$(notmuch search --exclude=flag --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}"
+
+test_begin_subtest "Search, exclude=all: tag in query (thread summary)"
+output=$(notmuch search --exclude=all tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
+thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
+
+test_begin_subtest "Search, exclude=all: tag in query (messages)"
+output=$(notmuch search --exclude=all --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
+test_expect_equal "$output" "${matching_message_ids[0]}
+${matching_message_ids[1]}
+${matching_message_ids[2]}
+${matching_message_ids[3]}"
+
+#########################################################
+# Notmuch count tests
+
+test_begin_subtest "Count, default exclusion (messages)"
+output=$(notmuch count tag:test)
+test_expect_equal "$output" "2"
+
+test_begin_subtest "Count, default exclusion (threads)"
+output=$(notmuch count --output=threads tag:test)
+test_expect_equal "$output" "2"
+
+test_begin_subtest "Count, exclude=true (messages)"
+output=$(notmuch count --exclude=true tag:test)
+test_expect_equal "$output" "2"
+
+test_begin_subtest "Count, exclude=true (threads)"
+output=$(notmuch count --output=threads --exclude=true tag:test)
+test_expect_equal "$output" "2"
+
+test_begin_subtest "Count, exclude=false (messages)"
+output=$(notmuch count --exclude=false tag:test)
+test_expect_equal "$output" "6"
+
+test_begin_subtest "Count, exclude=false (threads)"
+output=$(notmuch count --output=threads --exclude=false tag:test)
+test_expect_equal "$output" "5"
+
+test_begin_subtest "Count, default exclusion: tag in query (messages)"
+output=$(notmuch count tag:test and tag:deleted)
+test_expect_equal "$output" "4"
+
+test_begin_subtest "Count, default exclusion: tag in query (threads)"
+output=$(notmuch count --output=threads tag:test and tag:deleted)
+test_expect_equal "$output" "3"
+
+test_begin_subtest "Count, exclude=true: tag in query (messages)"
+output=$(notmuch count --exclude=true tag:test and tag:deleted)
+test_expect_equal "$output" "4"
+
+test_begin_subtest "Count, exclude=true: tag in query (threads)"
+output=$(notmuch count --output=threads --exclude=true tag:test and tag:deleted)
+test_expect_equal "$output" "3"
+
+test_begin_subtest "Count, exclude=false: tag in query (messages)"
+output=$(notmuch count --exclude=false tag:test and tag:deleted)
+test_expect_equal "$output" "4"
+
+test_begin_subtest "Count, exclude=false: tag in query (threads)"
+output=$(notmuch count --output=threads --exclude=false tag:test and tag:deleted)
+test_expect_equal "$output" "3"
+
+#############################################################
+# Show tests
+
+test_begin_subtest "Show, default exclusion"
+output=$(notmuch show tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3"
+
+test_begin_subtest "Show, default exclusion (entire-thread)"
+output=$(notmuch show --entire-thread tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 2
+\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 3
+\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 2
+\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3
+\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 5"
+
+test_begin_subtest "Show, exclude=true"
+output=$(notmuch show --exclude=true tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3"
+
+test_begin_subtest "Show, exclude=true (entire-thread)"
+output=$(notmuch show --entire-thread --exclude=true tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 2
+\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 3
+\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 2
+\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3
+\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 5"
+
+test_begin_subtest "Show, exclude=false"
+output=$(notmuch show --exclude=false tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 2
+\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 2
+\fmessage{ id:XXXXX depth:1 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 4
+\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 3
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3"
+
+test_begin_subtest "Show, exclude=false (entire-thread)"
+output=$(notmuch show --entire-thread --exclude=false tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 1
+\fmessage{ id:XXXXX depth:2 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 2
+\fmessage{ id:XXXXX depth:3 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 3
+\fmessage{ id:XXXXX depth:4 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: single match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 1
+\fmessage{ id:XXXXX depth:2 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 2
+\fmessage{ id:XXXXX depth:3 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 3
+\fmessage{ id:XXXXX depth:4 match:1 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:1 filename:XXXXX
+Subject: All messages excluded: double match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single excluded match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 2
+\fmessage{ id:XXXXX depth:3 match:1 excluded:1 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 3
+\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single excluded match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 2
+\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 3
+\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: Some messages excluded: single non-excluded match: reply 5
+\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: top message
+\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 1
+\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 2
+\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 3
+\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 4
+\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
+Subject: No messages excluded: single match: reply 5"
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch tag"'
+. ./test-lib.sh
+
+add_message '[subject]=One'
+add_message '[subject]=Two'
+
+test_begin_subtest "Adding tags"
+notmuch tag +tag1 +tag2 +tag3 \*
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 tag2 tag3 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 tag3 unread)"
+
+test_begin_subtest "Removing tags"
+notmuch tag -tag1 -tag2 \*
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag3 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag3 unread)"
+
+test_expect_code 1 "No tag operations" 'notmuch tag One'
+test_expect_code 1 "No query" 'notmuch tag +tag2'
+
+test_begin_subtest "Redundant tagging"
+notmuch tag +tag1 -tag3 One
+notmuch tag +tag1 -tag3 \*
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
+
+test_begin_subtest "Remove all"
+notmuch tag --remove-all One
+notmuch tag --remove-all +tag5 +tag6 +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One ()
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (tag5 tag6 unread)"
+
+test_begin_subtest "Remove all with a no-op"
+notmuch tag +inbox +tag1 +unread One
+notmuch tag --remove-all +foo +inbox +tag1 -foo +unread Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
+
+test_begin_subtest "Special characters in tags"
+notmuch tag +':" ' \*
+notmuch tag -':" ' Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
+
+test_begin_subtest "Tagging order"
+notmuch tag +tag4 -tag4 One
+notmuch tag -tag4 +tag4 Two
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag4 unread)"
+
+test_begin_subtest "--batch"
+notmuch tag --batch <<EOF
+# %20 is a space in tag
+-:"%20 -tag1 +tag5 +tag6 -- One
++tag1 -tag1 -tag4 +tag4 -- Two
+-tag6 One
++tag5 Two
+EOF
+output=$(notmuch search \* | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag5 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag4 tag5 unread)"
+
+# generate a common input file for the next several tests.
+cat > batch.in <<EOF
+# %40 is an @ in tag
++%40 -tag5 +tag6 -- One
++tag1 -tag1 -tag4 +tag4 -- Two
+-tag5 +tag6 Two
+EOF
+
+cat > batch.expected <<EOF
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (@ inbox tag6 unread)
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag4 tag6 unread)
+EOF
+
+test_begin_subtest "--input"
+notmuch dump --format=batch-tag > backup.tags
+notmuch tag --input=batch.in
+notmuch search \* | notmuch_search_sanitize > OUTPUT
+notmuch restore --format=batch-tag < backup.tags
+test_expect_equal_file batch.expected OUTPUT
+
+test_begin_subtest "--batch --input"
+notmuch dump --format=batch-tag > backup.tags
+notmuch tag --batch --input=batch.in
+notmuch search \* | notmuch_search_sanitize > OUTPUT
+notmuch restore --format=batch-tag < backup.tags
+test_expect_equal_file batch.expected OUTPUT
+
+test_begin_subtest "--batch, blank lines and comments"
+notmuch dump | sort > EXPECTED
+notmuch tag --batch <<EOF
+# this line is a comment; the next has only white space
+
+
+# the previous line is empty
+EOF
+notmuch dump | sort > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest '--batch: checking error messages'
+notmuch dump --format=batch-tag > BACKUP
+notmuch tag --batch <<EOF 2>OUTPUT
+# the next line has a space
+
+# this line has no tag operations, but this is permitted in batch format.
+a
++0
++a +b
+# trailing whitespace
++a +b
++c +d --
+# this is a harmless comment, do not yell about it.
+
+# the previous line was blank; also no yelling please
++%zz -- id:whatever
+# the next non-comment line should report an an empty tag error for
+# batch tagging, but not for restore
++ +e -- id:foo
++- -- id:foo
+EOF
+
+cat <<EOF > EXPECTED
+Warning: no query string [+0]
+Warning: no query string [+a +b]
+Warning: missing query string [+a +b ]
+Warning: no query string after -- [+c +d --]
+Warning: hex decoding of tag %zz failed [+%zz -- id:whatever]
+Warning: empty tag forbidden [+ +e -- id:foo]
+Warning: tag starting with '-' forbidden [+- -- id:foo]
+EOF
+
+notmuch restore --format=batch-tag < BACKUP
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest '--batch: tags with quotes'
+notmuch dump --format=batch-tag > BACKUP
+
+notmuch tag --batch <<EOF
++%22%27%22%27%22%22%27%27 -- One
+-%22%27%22%27%22%22%27%27 -- One
++%22%27%22%22%22%27 -- One
++%22%27%22%27%22%22%27%27 -- Two
+EOF
+
+cat <<EOF > EXPECTED
++%22%27%22%22%22%27 +inbox +tag5 +unread -- id:msg-001@notmuch-test-suite
++%22%27%22%27%22%22%27%27 +inbox +tag4 +tag5 +unread -- id:msg-002@notmuch-test-suite
+EOF
+
+notmuch dump --format=batch-tag | sort > OUTPUT
+notmuch restore --format=batch-tag < BACKUP
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest '--batch: tags with punctuation and space'
+notmuch dump --format=batch-tag > BACKUP
+
+notmuch tag --batch <<EOF
++%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
+-%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
++%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%20%60%7e -- Two
+-%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%20%60%7e -- Two
++%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
++%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- Two
+EOF
+
+cat <<EOF > EXPECTED
++%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e +inbox +tag4 +tag5 +unread -- id:msg-002@notmuch-test-suite
++%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e +inbox +tag5 +unread -- id:msg-001@notmuch-test-suite
+EOF
+
+notmuch dump --format=batch-tag | sort > OUTPUT
+notmuch restore --format=batch-tag < BACKUP
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest '--batch: unicode tags'
+notmuch dump --format=batch-tag > BACKUP
+
+notmuch tag --batch <<EOF
++%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 -- One
++=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d -- One
++A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 -- One
++R -- One
++%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 -- One
++%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- One
++L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 -- One
++P%c4%98%2f -- One
++%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d -- One
++%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b -- One
++%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +R +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b -- Two
+EOF
+
+cat <<EOF > EXPECTED
++%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +R +inbox +tag4 +tag5 +unread +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- id:msg-002@notmuch-test-suite
++%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +R +inbox +tag5 +unread +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- id:msg-001@notmuch-test-suite
+EOF
+
+notmuch dump --format=batch-tag | sort > OUTPUT
+notmuch restore --format=batch-tag < BACKUP
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "--batch: only space and % needs to be encoded."
+notmuch dump --format=batch-tag > BACKUP
+
+notmuch tag --batch <<EOF
++winner *
++foo::bar%25 -- (One and Two) or (One and tag:winner)
++found::it -- tag:foo::bar%
+# ignore this line and the next
+
++space%20in%20tags -- Two
+# add tag '(tags)', among other stunts.
++crazy{ +(tags) +&are +#possible\ -- tag:"space in tags"
++match*crazy -- tag:crazy{
++some_tag -- id:"this is ""nauty)"""
+EOF
+
+cat <<EOF > EXPECTED
++%23possible%5c +%26are +%28tags%29 +crazy%7b +inbox +match%2acrazy +space%20in%20tags +tag4 +tag5 +unread +winner -- id:msg-002@notmuch-test-suite
++foo%3a%3abar%25 +found%3a%3ait +inbox +tag5 +unread +winner -- id:msg-001@notmuch-test-suite
+EOF
+
+notmuch dump --format=batch-tag | sort > OUTPUT
+notmuch restore --format=batch-tag < BACKUP
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest '--batch: unicode message-ids'
+
+${TEST_DIRECTORY}/random-corpus --config-path=${NOTMUCH_CONFIG} \
+ --num-messages=100
+
+notmuch dump --format=batch-tag | sed 's/^.* -- /+common_tag -- /' | \
+ sort > EXPECTED
+
+notmuch dump --format=batch-tag | sed 's/^.* -- / -- /' | \
+ notmuch restore --format=batch-tag
+
+notmuch tag --batch < EXPECTED
+
+notmuch dump --format=batch-tag| \
+ sort > OUTPUT
+
+test_expect_equal_file EXPECTED OUTPUT
+
+test_expect_code 1 "Empty tag names" 'notmuch tag + One'
+
+test_expect_code 1 "Tag name beginning with -" 'notmuch tag +- One'
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="--format=json output"
+. ./test-lib.sh
+
+test_begin_subtest "Show message: json"
+add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"json-show-message\""
+output=$(notmuch show --format=json "json-show-message")
+test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"json-show-message\n\"}]}, []]]]"
+
+# This should be the same output as above.
+test_begin_subtest "Show message: json --body=true"
+output=$(notmuch show --format=json --body=true "json-show-message")
+test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"json-show-message\n\"}]}, []]]]"
+
+test_begin_subtest "Show message: json --body=false"
+output=$(notmuch show --format=json --body=false "json-show-message")
+test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}}, []]]]"
+
+test_begin_subtest "Search message: json"
+add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
+output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
+test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
+ \"timestamp\": 946728000,
+ \"date_relative\": \"2000-01-01\",
+ \"matched\": 1,
+ \"total\": 1,
+ \"authors\": \"Notmuch Test Suite\",
+ \"subject\": \"json-search-subject\",
+ \"query\": [\"id:$gen_msg_id\", null],
+ \"tags\": [\"inbox\",
+ \"unread\"]}]"
+
+test_begin_subtest "Show message: json, utf-8"
+add_message "[subject]=\"json-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
+output=$(notmuch show --format=json "jsön-show-méssage")
+test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-utf8-body-sübjéct\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"jsön-show-méssage\n\"}]}, []]]]"
+
+test_begin_subtest "Show message: json, inline attachment filename"
+subject='json-show-inline-attachment-filename'
+id="json-show-inline-attachment-filename@notmuchmail.org"
+emacs_fcc_message \
+ "$subject" \
+ 'This is a test message with inline attachment with a filename' \
+ "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
+ (message-goto-eoh)
+ (insert \"Message-ID: <$id>\n\")"
+output=$(notmuch show --format=json "id:$id")
+filename=$(notmuch search --output=files "id:$id")
+# Get length of README after base64-encoding, minus additional newline.
+attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
+test_expect_equal_json "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\": false, \"filename\": \"$filename\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": {\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"test_suite@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"multipart/mixed\", \"content\": [{\"id\": 2, \"content-type\": \"text/plain\", \"content\": \"This is a test message with inline attachment with a filename\"}, {\"id\": 3, \"content-type\": \"application/octet-stream\", \"content-length\": $attachment_length, \"content-transfer-encoding\": \"base64\", \"filename\": \"README\"}]}]}, []]]]"
+
+test_begin_subtest "Search message: json, utf-8"
+add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
+output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
+test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
+ \"timestamp\": 946728000,
+ \"date_relative\": \"2000-01-01\",
+ \"matched\": 1,
+ \"total\": 1,
+ \"authors\": \"Notmuch Test Suite\",
+ \"subject\": \"json-search-utf8-body-sübjéct\",
+ \"query\": [\"id:$gen_msg_id\", null],
+ \"tags\": [\"inbox\",
+ \"unread\"]}]"
+
+test_expect_code 20 "Format version: too low" \
+ "notmuch search --format-version=0 \\*"
+
+test_expect_code 21 "Format version: too high" \
+ "notmuch search --format-version=999 \\*"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="--format=sexp output"
+. ./test-lib.sh
+
+test_begin_subtest "Show message: sexp"
+add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"sexp-show-message\""
+output=$(notmuch show --format=sexp "sexp-show-message")
+test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"sexp-show-message\n\"))) ())))"
+
+# This should be the same output as above.
+test_begin_subtest "Show message: sexp --body=true"
+output=$(notmuch show --format=sexp --body=true "sexp-show-message")
+test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"sexp-show-message\n\"))) ())))"
+
+test_begin_subtest "Show message: sexp --body=false"
+output=$(notmuch show --format=sexp --body=false "sexp-show-message")
+test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\")) ())))"
+
+test_begin_subtest "Search message: sexp"
+add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"sexp-search-message\""
+output=$(notmuch search --format=sexp "sexp-search-message" | notmuch_search_sanitize)
+test_expect_equal "$output" "((:thread \"0000000000000002\" :timestamp 946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch Test Suite\" :subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
+
+test_begin_subtest "Show message: sexp, utf-8"
+add_message "[subject]=\"sexp-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
+output=$(notmuch show --format=sexp "jsön-show-méssage")
+test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-utf8-body-sübjéct\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"jsön-show-méssage\n\"))) ())))"
+
+test_begin_subtest "Show message: sexp, inline attachment filename"
+subject='sexp-show-inline-attachment-filename'
+id="sexp-show-inline-attachment-filename@notmuchmail.org"
+emacs_fcc_message \
+ "$subject" \
+ 'This is a test message with inline attachment with a filename' \
+ "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
+ (message-goto-eoh)
+ (insert \"Message-ID: <$id>\n\")"
+output=$(notmuch show --format=sexp "id:$id")
+filename=$(notmuch search --output=files "id:$id")
+# Get length of README after base64-encoding, minus additional newline.
+attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
+test_expect_equal "$output" "((((:id \"$id\" :match t :excluded nil :filename \"$filename\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\") :headers (:Subject \"sexp-show-inline-attachment-filename\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"test_suite@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"multipart/mixed\" :content ((:id 2 :content-type \"text/plain\" :content \"This is a test message with inline attachment with a filename\") (:id 3 :content-type \"application/octet-stream\" :filename \"README\" :content-transfer-encoding \"base64\" :content-length $attachment_length))))) ())))"
+
+test_begin_subtest "Search message: sexp, utf-8"
+add_message "[subject]=\"sexp-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
+output=$(notmuch search --format=sexp "jsön-search-méssage" | notmuch_search_sanitize)
+test_expect_equal "$output" "((:thread \"0000000000000005\" :timestamp 946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch Test Suite\" :subject \"sexp-search-utf8-body-sübjéct\" :query (\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="--format=text output"
+. ./test-lib.sh
+
+test_begin_subtest "Show message: text"
+add_message "[subject]=\"text-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"text-show-message\""
+output=$(notmuch show --format=text "text-show-message" | notmuch_show_sanitize_all)
+test_expect_equal "$output" "\
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (inbox unread)
+Subject: text-show-subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+text-show-message
+\fpart}
+\fbody}
+\fmessage}"
+
+test_begin_subtest "Search message: text"
+add_message "[subject]=\"text-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"text-search-message\""
+output=$(notmuch search --format=text "text-search-message" | notmuch_search_sanitize)
+test_expect_equal "$output" \
+"thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; text-search-subject (inbox unread)"
+
+test_begin_subtest "Show message: text, utf-8"
+add_message "[subject]=\"text-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"tëxt-show-méssage\""
+output=$(notmuch show --format=text "tëxt-show-méssage" | notmuch_show_sanitize_all)
+test_expect_equal "$output" "\
+\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (inbox unread)
+Subject: text-show-utf8-body-sübjéct
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+tëxt-show-méssage
+\fpart}
+\fbody}
+\fmessage}"
+
+test_begin_subtest "Search message: text, utf-8"
+add_message "[subject]=\"text-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"tëxt-search-méssage\""
+output=$(notmuch search --format=text "tëxt-search-méssage" | notmuch_search_sanitize)
+test_expect_equal "$output" \
+"thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; text-search-utf8-body-sübjéct (inbox unread)"
+
+add_email_corpus
+
+test_begin_subtest "Search message tags: text0"
+cat <<EOF > EXPECTED
+attachment inbox signed unread
+EOF
+notmuch search --format=text0 --output=tags '*' | xargs -0 | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+# Use tr(1) to convert --output=text0 to --output=text for
+# comparison. Also translate newlines to spaces to fail with more
+# noise if they are present as delimiters instead of null
+# characters. This assumes there are no newlines in the data.
+test_begin_subtest "Compare text vs. text0 for threads"
+notmuch search --format=text --output=threads '*' | notmuch_search_sanitize > EXPECTED
+notmuch search --format=text0 --output=threads '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "Compare text vs. text0 for messages"
+notmuch search --format=text --output=messages '*' | notmuch_search_sanitize > EXPECTED
+notmuch search --format=text0 --output=messages '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "Compare text vs. text0 for files"
+notmuch search --format=text --output=files '*' | notmuch_search_sanitize > EXPECTED
+notmuch search --format=text0 --output=files '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "Compare text vs. text0 for tags"
+notmuch search --format=text --output=tags '*' | notmuch_search_sanitize > EXPECTED
+notmuch search --format=text0 --output=tags '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="output of multipart message"
+. ./test-lib.sh
+
+cat <<EOF > embedded_message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Subject: html message
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="==-=-=="
+
+--==-=-==
+Content-Type: text/html
+
+<p>This is an embedded message, with a multipart/alternative part.</p>
+
+--==-=-==
+Content-Type: text/plain
+
+This is an embedded message, with a multipart/alternative part.
+
+--==-=-==--
+EOF
+
+cat <<EOF > ${MAIL_DIR}/multipart
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Subject: Multipart message
+Date: Fri, 05 Jan 2001 15:43:57 +0000
+User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+Message-ID: <87liy5ap00.fsf@yoom.home.cworth.org>
+MIME-Version: 1.0
+Content-Type: multipart/signed; boundary="==-=-=";
+ micalg=pgp-sha1; protocol="application/pgp-signature"
+
+--==-=-=
+Content-Type: multipart/mixed; boundary="=-=-="
+
+--=-=-=
+Content-Type: message/rfc822
+Content-Disposition: inline
+
+EOF
+cat embedded_message >> ${MAIL_DIR}/multipart
+cat <<EOF >> ${MAIL_DIR}/multipart
+
+--=-=-=
+Content-Disposition: attachment; filename=attachment
+
+This is a text attachment.
+
+--=-=-=
+
+And this message is signed.
+
+-Carl
+
+--=-=-=--
+
+--==-=-=
+Content-Type: application/pgp-signature
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.11 (GNU/Linux)
+
+iEYEARECAAYFAk3SA/gACgkQ6JDdNq8qSWj0sACghqVJEQJUs3yV8zbTzhgnSIcD
+W6cAmQE4dcYrx/LPLtYLZm1jsGauE5hE
+=zkga
+-----END PGP SIGNATURE-----
+--==-=-=--
+EOF
+
+cat <<EOF > ${MAIL_DIR}/base64-part-with-crlf
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Subject: Test message with a BASE64 encoded binary containing CRLF pair
+Date: Fri, 05 Jan 2001 15:43:57 +0000
+User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+Message-ID: <base64-part-with-crlf>
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="==-=-=";
+
+--==-=-=
+
+The attached BASE64-encoded part expands to a binary containing a CRLF
+pair (that is one bye of 0x0D followed by one byte of 0x0A). This is
+designed to ensure that notmuch is not corrupting the output of this
+part by converting the CRLF pair to an LF only (as would be appropriate
+for display of a text part on a Linux system, for example).
+
+The part should be a 3-byte file with the following sequence of 3
+hexadecimal bytes:
+
+ EF 0D 0A
+
+--==-=-=
+Content-Type: application/octet-stream
+Content-Disposition: attachment; filename=crlf.bin
+Content-Transfer-Encoding: base64
+
+7w0K
+--==-=-=--
+EOF
+notmuch new > /dev/null
+
+test_begin_subtest "--format=text --part=0, full message"
+notmuch show --format=text --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fmessage{ id:87liy5ap00.fsf@yoom.home.cworth.org depth:0 match:1 excluded:0 filename:${MAIL_DIR}/multipart
+\fheader{
+Carl Worth <cworth@cworth.org> (2001-01-05) (attachment inbox signed unread)
+Subject: Multipart message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Date: Fri, 05 Jan 2001 15:43:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: multipart/signed
+\fpart{ ID: 2, Content-type: multipart/mixed
+\fpart{ ID: 3, Content-type: message/rfc822
+\fheader{
+Subject: html message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 4, Content-type: multipart/alternative
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+\fpart}
+\fbody}
+\fpart}
+\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
+This is a text attachment.
+\fattachment}
+\fpart{ ID: 8, Content-type: text/plain
+And this message is signed.
+
+-Carl
+\fpart}
+\fpart}
+\fpart{ ID: 9, Content-type: application/pgp-signature
+Non-text part: application/pgp-signature
+\fpart}
+\fpart}
+\fbody}
+\fmessage}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=1, message body"
+notmuch show --format=text --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 1, Content-type: multipart/signed
+\fpart{ ID: 2, Content-type: multipart/mixed
+\fpart{ ID: 3, Content-type: message/rfc822
+\fheader{
+Subject: html message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 4, Content-type: multipart/alternative
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+\fpart}
+\fbody}
+\fpart}
+\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
+This is a text attachment.
+\fattachment}
+\fpart{ ID: 8, Content-type: text/plain
+And this message is signed.
+
+-Carl
+\fpart}
+\fpart}
+\fpart{ ID: 9, Content-type: application/pgp-signature
+Non-text part: application/pgp-signature
+\fpart}
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=2, multipart/mixed"
+notmuch show --format=text --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 2, Content-type: multipart/mixed
+\fpart{ ID: 3, Content-type: message/rfc822
+\fheader{
+Subject: html message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 4, Content-type: multipart/alternative
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+\fpart}
+\fbody}
+\fpart}
+\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
+This is a text attachment.
+\fattachment}
+\fpart{ ID: 8, Content-type: text/plain
+And this message is signed.
+
+-Carl
+\fpart}
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=3, rfc822 part"
+notmuch show --format=text --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 3, Content-type: message/rfc822
+\fheader{
+Subject: html message
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 4, Content-type: multipart/alternative
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+\fpart}
+\fbody}
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=4, rfc822's multipart"
+notmuch show --format=text --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 4, Content-type: multipart/alternative
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=5, rfc822's html part"
+notmuch show --format=text --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 5, Content-type: text/html
+Non-text part: text/html
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=6, rfc822's text part"
+notmuch show --format=text --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 6, Content-type: text/plain
+This is an embedded message, with a multipart/alternative part.
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=7, inline attachement"
+notmuch show --format=text --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
+This is a text attachment.
+\fattachment}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=8, plain text part"
+notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 8, Content-type: text/plain
+And this message is signed.
+
+-Carl
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=text --part=9, pgp signature (unverified)"
+notmuch show --format=text --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+\fpart{ ID: 9, Content-type: application/pgp-signature
+Non-text part: application/pgp-signature
+\fpart}
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_expect_success \
+ "--format=text --part=8, no part, expect error" \
+ "notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
+
+test_begin_subtest "--format=json --part=0, full message"
+notmuch show --format=json --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": "87liy5ap00.fsf@yoom.home.cworth.org", "match": true, "excluded": false, "filename": "${MAIL_DIR}/multipart", "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["attachment","inbox","signed","unread"], "headers": {"Subject": "Multipart message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [
+{"id": 1, "content-type": "multipart/signed", "content": [
+{"id": 2, "content-type": "multipart/mixed", "content": [
+{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
+{"id": 4, "content-type": "multipart/alternative", "content": [
+{"id": 5, "content-type": "text/html", "content-length": 71},
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
+{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
+{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
+{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}]}]}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=1, message body"
+notmuch show --format=json --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 1, "content-type": "multipart/signed", "content": [
+{"id": 2, "content-type": "multipart/mixed", "content": [
+{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
+{"id": 4, "content-type": "multipart/alternative", "content": [
+{"id": 5, "content-type": "text/html", "content-length": 71},
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
+{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
+{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
+{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}]}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=2, multipart/mixed"
+notmuch show --format=json --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 2, "content-type": "multipart/mixed", "content": [
+{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
+{"id": 4, "content-type": "multipart/alternative", "content": [
+{"id": 5, "content-type": "text/html", "content-length": 71},
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
+{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
+{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=3, rfc822 part"
+notmuch show --format=json --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
+{"id": 4, "content-type": "multipart/alternative", "content": [
+{"id": 5, "content-type": "text/html", "content-length": 71},
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=4, rfc822's multipart/alternative"
+notmuch show --format=json --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 4, "content-type": "multipart/alternative", "content": [
+{"id": 5, "content-type": "text/html", "content-length": 71},
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=5, rfc822's html part"
+notmuch show --format=json --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 5, "content-type": "text/html", "content-length": 71}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=6, rfc822's text part"
+notmuch show --format=json --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=7, inline attachment"
+notmuch show --format=json --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=8, plain text part"
+notmuch show --format=json --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "--format=json --part=9, pgp signature (unverified)"
+notmuch show --format=json --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_expect_success \
+ "--format=json --part=10, no part, expect error" \
+ "notmuch show --format=json --part=10 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
+
+test_begin_subtest "--format=raw"
+notmuch show --format=raw 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
+
+test_begin_subtest "--format=raw --part=0, full message"
+notmuch show --format=raw --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
+
+test_begin_subtest "--format=raw --part=1, message body"
+notmuch show --format=raw --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
+
+test_begin_subtest "--format=raw --part=2, multipart/mixed"
+notmuch show --format=raw --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+Content-Type: multipart/mixed; boundary="=-=-="
+
+--=-=-=
+Content-Type: message/rfc822
+Content-Disposition: inline
+
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Subject: html message
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="==-=-=="
+
+--==-=-==
+Content-Type: text/html
+
+<p>This is an embedded message, with a multipart/alternative part.</p>
+
+--==-=-==
+Content-Type: text/plain
+
+This is an embedded message, with a multipart/alternative part.
+
+--==-=-==--
+
+--=-=-=
+Content-Disposition: attachment; filename=attachment
+
+This is a text attachment.
+
+--=-=-=
+
+And this message is signed.
+
+-Carl
+
+--=-=-=--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=3, rfc822 part"
+notmuch show --format=raw --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+test_expect_equal_file OUTPUT embedded_message
+
+test_begin_subtest "--format=raw --part=4, rfc822's multipart"
+notmuch show --format=raw --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+From: Carl Worth <cworth@cworth.org>
+To: cworth@cworth.org
+Subject: html message
+Date: Fri, 05 Jan 2001 15:42:57 +0000
+User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="==-=-=="
+
+--==-=-==
+Content-Type: text/html
+
+<p>This is an embedded message, with a multipart/alternative part.</p>
+
+--==-=-==
+Content-Type: text/plain
+
+This is an embedded message, with a multipart/alternative part.
+
+--==-=-==--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=5, rfc822's html part"
+notmuch show --format=raw --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+<p>This is an embedded message, with a multipart/alternative part.</p>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=6, rfc822's text part"
+notmuch show --format=raw --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+This is an embedded message, with a multipart/alternative part.
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=7, inline attachment"
+notmuch show --format=raw --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+This is a text attachment.
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=8, plain text part"
+notmuch show --format=raw --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+And this message is signed.
+
+-Carl
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--format=raw --part=9, pgp signature (unverified)"
+notmuch show --format=raw --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+# output should *not* include newline
+echo >>OUTPUT
+cat <<EOF >EXPECTED
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.11 (GNU/Linux)
+
+iEYEARECAAYFAk3SA/gACgkQ6JDdNq8qSWj0sACghqVJEQJUs3yV8zbTzhgnSIcD
+W6cAmQE4dcYrx/LPLtYLZm1jsGauE5hE
+=zkga
+-----END PGP SIGNATURE-----
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_expect_success \
+ "--format=raw --part=10, no part, expect error" \
+ "notmuch show --format=raw --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
+
+test_begin_subtest "--format=mbox"
+notmuch show --format=mbox 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+printf "From cworth@cworth.org Fri Jan 5 15:43:57 2001\n" >EXPECTED
+cat "${MAIL_DIR}"/multipart >>EXPECTED
+# mbox output is expected to include a blank line
+echo >>EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_expect_success \
+ "--format=mbox --part=1, incompatible, expect error" \
+ "! notmuch show --format=mbox --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
+
+test_begin_subtest "'notmuch reply' to a multipart message"
+notmuch reply 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: Multipart message
+To: Carl Worth <cworth@cworth.org>, cworth@cworth.org
+In-Reply-To: <87liy5ap00.fsf@yoom.home.cworth.org>
+References: <87liy5ap00.fsf@yoom.home.cworth.org>
+
+On Fri, 05 Jan 2001 15:43:57 +0000, Carl Worth <cworth@cworth.org> wrote:
+> From: Carl Worth <cworth@cworth.org>
+> To: cworth@cworth.org
+> Subject: html message
+> Date: Fri, 05 Jan 2001 15:42:57 +0000
+>
+Non-text part: text/html
+> This is an embedded message, with a multipart/alternative part.
+> This is a text attachment.
+> And this message is signed.
+>
+> -Carl
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "'notmuch reply' to a multipart message with json format"
+notmuch reply --format=json 'id:87liy5ap00.fsf@yoom.home.cworth.org' | notmuch_json_show_sanitize >OUTPUT
+notmuch_json_show_sanitize <<EOF >EXPECTED
+{"reply-headers": {"Subject": "Re: Multipart message",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Carl Worth <cworth@cworth.org>, cworth@cworth.org",
+ "In-reply-to": "<87liy5ap00.fsf@yoom.home.cworth.org>",
+ "References": "<87liy5ap00.fsf@yoom.home.cworth.org>"},
+ "original": {"id": "XXXXX",
+ "match": false,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437,
+ "date_relative": "2001-01-05",
+ "tags": ["attachment","inbox","signed","unread"],
+ "headers": {"Subject": "Multipart message",
+ "From": "Carl Worth <cworth@cworth.org>",
+ "To": "cworth@cworth.org",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
+ "body": [{"id": 1,
+ "content-type": "multipart/signed",
+ "content": [{"id": 2,
+ "content-type": "multipart/mixed",
+ "content": [{"id": 3,
+ "content-type": "message/rfc822",
+ "content": [{"headers": {"Subject": "html message",
+ "From": "Carl Worth <cworth@cworth.org>",
+ "To": "cworth@cworth.org",
+ "Date": "Fri, 05 Jan 2001 15:42:57 +0000"},
+ "body": [{"id": 4,
+ "content-type": "multipart/alternative",
+ "content": [{"id": 5,
+ "content-type": "text/html",
+ "content-length": 71},
+ {"id": 6,
+ "content-type": "text/plain",
+ "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
+ {"id": 7,
+ "content-type": "text/plain",
+ "filename": "attachment",
+ "content": "This is a text attachment.\n"},
+ {"id": 8,
+ "content-type": "text/plain",
+ "content": "And this message is signed.\n\n-Carl\n"}]},
+ {"id": 9,
+ "content-type": "application/pgp-signature",
+ "content-length": 197}]}]}}
+EOF
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
+
+test_begin_subtest "'notmuch show --part' does not corrupt a part with CRLF pair"
+notmuch show --format=raw --part=3 id:base64-part-with-crlf > crlf.out
+echo -n -e "\xEF\x0D\x0A" > crlf.expected
+test_expect_equal_file crlf.out crlf.expected
+
+
+# The ISO-8859-1 encoding of U+00BD is a single byte: octal 275
+# (Portability note: Dollar-Single ($'...', ANSI C-style escape sequences)
+# quoting works on bash, ksh, zsh, *BSD sh but not on dash, ash nor busybox sh)
+readonly u_00bd_latin1=$'\275'
+
+# The Unicode fraction symbol 1/2 is U+00BD and is encoded
+# in UTF-8 as two bytes: octal 302 275
+readonly u_00bd_utf8=$'\302\275'
+
+cat <<EOF > ${MAIL_DIR}/include-html
+From: A <a@example.com>
+To: B <b@example.com>
+Subject: html message
+Date: Sat, 01 January 2000 00:00:00 +0000
+Message-ID: <htmlmessage>
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="==-=="
+
+--==-==
+Content-Type: text/html; charset=UTF-8
+
+<p>0.5 equals ${u_00bd_utf8}</p>
+
+--==-==
+Content-Type: text/html; charset=ISO-8859-1
+
+<p>0.5 equals ${u_00bd_latin1}</p>
+
+--==-==
+Content-Type: text/plain; charset=UTF-8
+
+0.5 equals ${u_00bd_utf8}
+
+--==-==--
+EOF
+
+notmuch new > /dev/null
+
+cat_expected_head ()
+{
+ cat <<EOF
+[[[{"id": "htmlmessage", "match":true, "excluded": false, "date_relative":"2000-01-01",
+ "timestamp": 946684800,
+ "filename": "${MAIL_DIR}/include-html",
+ "tags": ["inbox", "unread"],
+ "headers": { "Date": "Sat, 01 Jan 2000 00:00:00 +0000", "From": "A <a@example.com>",
+ "Subject": "html message", "To": "B <b@example.com>"},
+ "body": [{
+ "content-type": "multipart/alternative", "id": 1,
+EOF
+}
+
+cat_expected_head > EXPECTED.nohtml
+cat <<EOF >> EXPECTED.nohtml
+"content": [
+ { "id": 2, "content-charset": "UTF-8", "content-length": 21, "content-type": "text/html"},
+ { "id": 3, "content-charset": "ISO-8859-1", "content-length": 20, "content-type": "text/html"},
+ { "id": 4, "content-type": "text/plain", "content": "0.5 equals \\u00bd\\n"}
+]}]},[]]]]
+EOF
+
+# Both the UTF-8 and ISO-8859-1 part should have U+00BD
+cat_expected_head > EXPECTED.withhtml
+cat <<EOF >> EXPECTED.withhtml
+"content": [
+ { "id": 2, "content-type": "text/html", "content": "<p>0.5 equals \\u00bd</p>\\n"},
+ { "id": 3, "content-type": "text/html", "content": "<p>0.5 equals \\u00bd</p>\\n"},
+ { "id": 4, "content-type": "text/plain", "content": "0.5 equals \\u00bd\\n"}
+]}]},[]]]]
+EOF
+
+test_begin_subtest "html parts excluded by default"
+notmuch show --format=json id:htmlmessage > OUTPUT
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED.nohtml)"
+
+test_begin_subtest "html parts included"
+notmuch show --format=json --include-html id:htmlmessage > OUTPUT
+test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED.withhtml)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="naming of threads with changing subject"
+. ./test-lib.sh
+
+test_begin_subtest "Initial thread name (oldest-first search)"
+add_message '[subject]="thread-naming: Initial thread subject"' \
+ '[date]="Fri, 05 Jan 2001 15:43:56 -0000"'
+first=${gen_msg_cnt}
+parent=${gen_msg_id}
+add_message '[subject]="thread-naming: Older changed subject"' \
+ '[date]="Sat, 06 Jan 2001 15:43:56 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+add_message '[subject]="thread-naming: Newer changed subject"' \
+ '[date]="Sun, 07 Jan 2001 15:43:56 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+add_message '[subject]="thread-naming: Final thread subject"' \
+ '[date]="Mon, 08 Jan 2001 15:43:56 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+final=${gen_msg_id}
+output=$(notmuch search --sort=oldest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [4/4] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
+
+test_begin_subtest "Initial thread name (newest-first search)"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-08 [4/4] Notmuch Test Suite; thread-naming: Final thread subject (inbox unread)"
+
+# Remove oldest and newest messages from search results
+notmuch tag -inbox id:$parent or id:$final
+
+test_begin_subtest "Changed thread name (oldest-first search)"
+output=$(notmuch search --sort=oldest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-06 [2/4] Notmuch Test Suite; thread-naming: Older changed subject (inbox unread)"
+
+test_begin_subtest "Changed thread name (newest-first search)"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-07 [2/4] Notmuch Test Suite; thread-naming: Newer changed subject (inbox unread)"
+
+test_begin_subtest "Ignore added reply prefix (Re:)"
+add_message '[subject]="Re: thread-naming: Initial thread subject"' \
+ '[date]="Tue, 09 Jan 2001 15:43:45 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-09 [3/5] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
+
+test_begin_subtest "Ignore added reply prefix (Aw:)"
+add_message '[subject]="Aw: thread-naming: Initial thread subject"' \
+ '[date]="Wed, 10 Jan 2001 15:43:45 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-10 [4/6] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
+
+test_begin_subtest "Ignore added reply prefix (Vs:)"
+add_message '[subject]="Vs: thread-naming: Initial thread subject"' \
+ '[date]="Thu, 11 Jan 2001 15:43:45 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-11 [5/7] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
+
+test_begin_subtest "Ignore added reply prefix (Sv:)"
+add_message '[subject]="Sv: thread-naming: Initial thread subject"' \
+ '[date]="Fri, 12 Jan 2001 15:43:45 -0000"' \
+ "[in-reply-to]=\<$parent\>"
+output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-12 [6/8] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
+
+test_begin_subtest 'Test order of messages in "notmuch show"'
+output=$(notmuch show thread-naming | notmuch_show_sanitize)
+test_expect_equal "$output" "\fmessage{ id:msg-$(printf "%03d" $first)@notmuch-test-suite depth:0 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $first)
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (unread)
+Subject: thread-naming: Initial thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Fri, 05 Jan 2001 15:43:56 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$first)
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 1)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 1)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-06) (inbox unread)
+Subject: thread-naming: Older changed subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Sat, 06 Jan 2001 15:43:56 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 1)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 2)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 2)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-07) (inbox unread)
+Subject: thread-naming: Newer changed subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Sun, 07 Jan 2001 15:43:56 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 2)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 3)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 3)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-08) (unread)
+Subject: thread-naming: Final thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Mon, 08 Jan 2001 15:43:56 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 3)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 4)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 4)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-09) (inbox unread)
+Subject: Re: thread-naming: Initial thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Tue, 09 Jan 2001 15:43:45 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 4)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 5)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 5)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-10) (inbox unread)
+Subject: Aw: thread-naming: Initial thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Wed, 10 Jan 2001 15:43:45 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 5)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 6)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 6)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-11) (inbox unread)
+Subject: Vs: thread-naming: Initial thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Thu, 11 Jan 2001 15:43:45 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 6)))
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:msg-$(printf "%03d" $((first + 7)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 7)))
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-12) (inbox unread)
+Subject: Sv: thread-naming: Initial thread subject
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Fri, 12 Jan 2001 15:43:45 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+This is just a test message (#$((first + 7)))
+\fpart}
+\fbody}
+\fmessage}"
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description='notmuch show --format=raw'
+. ./test-lib.sh
+
+add_message
+add_message
+
+test_begin_subtest "Attempt to show multiple raw messages"
+output=$(notmuch show --format=raw "*" 2>&1)
+test_expect_equal "$output" "Error: search term did not match precisely one message."
+
+test_begin_subtest "Show a raw message"
+output=$(notmuch show --format=raw id:msg-001@notmuch-test-suite | notmuch_date_sanitize)
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Message-Id: <msg-001@notmuch-test-suite>
+Subject: Test message #1
+Date: GENERATED_DATE
+
+This is just a test message (#1)"
+
+test_begin_subtest "Show another raw message"
+output=$(notmuch show --format=raw id:msg-002@notmuch-test-suite | notmuch_date_sanitize)
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Message-Id: <msg-002@notmuch-test-suite>
+Subject: Test message #2
+Date: GENERATED_DATE
+
+This is just a test message (#2)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="\"notmuch reply\" in several variations"
+. ./test-lib.sh
+
+test_begin_subtest "Basic reply"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="basic reply test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> basic reply test"
+
+test_begin_subtest "Multiple recipients"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Multiple recipients"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, Someone Else <someone@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> Multiple recipients"
+
+test_begin_subtest "Reply with CC"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ '[cc]="Other Parties <cc@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply with CC"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+Cc: Other Parties <cc@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> reply with CC"
+
+test_begin_subtest "Reply from alternate address"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite_other@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply from alternate address"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> reply from alternate address"
+
+test_begin_subtest "Reply from address in named group list"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]=group:test_suite@notmuchmail.org,someone@example.com\;' \
+ [cc]=test_suite_other@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Reply from address in named group list"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, someone@example.com
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> Reply from address in named group list"
+
+test_begin_subtest "Support for Reply-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="support for reply-to"' \
+ '[reply-to]="Sender <elsewhere@example.com>"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <elsewhere@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> support for reply-to"
+
+test_begin_subtest "Un-munging Reply-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Some List <list@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Un-munging Reply-To"' \
+ '[reply-to]="Evil Munging List <list@example.com>"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, Some List <list@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> Un-munging Reply-To"
+
+test_begin_subtest "Message with header of exactly 200 bytes"
+add_message '[subject]="This subject is exactly 200 bytes in length. Other than its length there is not much of note here. Note that the length of 200 bytes includes the Subject: and Re: prefixes with two spaces"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="200-byte header"'
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: This subject is exactly 200 bytes in length. Other than its
+ length there is not much of note here. Note that the length of 200 bytes
+ includes the Subject: and Re: prefixes with two spaces
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> 200-byte header"
+
+test_begin_subtest "From guessing: Envelope-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ '[subject]="From guessing"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="From guessing"' \
+ '[header]="Envelope-To: test_suite_other@notmuchmail.org"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: From guessing
+To: Sender <sender@example.com>, Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> From guessing"
+
+test_begin_subtest "From guessing: X-Original-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ '[subject]="From guessing"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="From guessing"' \
+ '[header]="X-Original-To: test_suite@otherdomain.org"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@otherdomain.org>
+Subject: Re: From guessing
+To: Sender <sender@example.com>, Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> From guessing"
+
+test_begin_subtest "From guessing: Delivered-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ '[subject]="From guessing"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="From guessing"' \
+ '[header]="Delivered-To: test_suite_other@notmuchmail.org"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: From guessing
+To: Sender <sender@example.com>, Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> From guessing"
+
+test_begin_subtest "Reply with RFC 2047-encoded headers"
+add_message '[subject]="=?iso-8859-1?q?=e0=df=e7?="' \
+ '[from]="=?utf-8?q?=e2=98=83?= <snowman@example.com>"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Encoding"'
+
+# GMime happens to change from Q- to B-encoding. We canonicalize the
+# case of the encoding and charset because different versions of GMime
+# capitalize the encoding differently.
+output=$(notmuch reply id:${gen_msg_id} | perl -pe 's/=\?[^?]+\?[bB]\?/lc($&)/ge')
+test_expect_equal "$output" "\
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: =?iso-8859-1?b?4N/n?=
+To: =?utf-8?b?4piD?= <snowman@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, ☃ <snowman@example.com> wrote:
+> Encoding"
+
+test_begin_subtest "Reply with RFC 2047-encoded headers (JSON)"
+output=$(notmuch reply --format=json id:${gen_msg_id})
+test_expect_equal_json "$output" '
+{
+ "original": {
+ "body": [
+ {
+ "content": "Encoding\n",
+ "content-type": "text/plain",
+ "id": 1
+ }
+ ],
+ "date_relative": "2010-01-05",
+ "excluded": false,
+ "filename": "'${MAIL_DIR}'/msg-012",
+ "headers": {
+ "Date": "Tue, 05 Jan 2010 15:43:56 +0000",
+ "From": "\u2603 <snowman@example.com>",
+ "Subject": "\u00e0\u00df\u00e7",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>"
+ },
+ "id": "'${gen_msg_id}'",
+ "match": false,
+ "tags": [
+ "inbox",
+ "unread"
+ ],
+ "timestamp": 1262706236
+ },
+ "reply-headers": {
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "In-reply-to": "<'${gen_msg_id}'>",
+ "References": "<'${gen_msg_id}'>",
+ "Subject": "Re: \u00e0\u00df\u00e7",
+ "To": "\u2603 <snowman@example.com>"
+ }
+}'
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="\"notmuch reply --reply-to=sender\" in several variations"
+. ./test-lib.sh
+
+test_begin_subtest "Basic reply-to-sender"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="basic reply-to-sender test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> basic reply-to-sender test"
+
+test_begin_subtest "From Us, Basic reply to message"
+add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="basic reply-to-from-us test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> basic reply-to-from-us test"
+
+test_begin_subtest "Multiple recipients"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Multiple recipients"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> Multiple recipients"
+
+test_begin_subtest "From Us, Multiple TO recipients"
+add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
+ '[to]="Recipient <recipient@example.com>, Someone Else <someone@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="From Us, Multiple TO recipients"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Recipient <recipient@example.com>, Someone Else <someone@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> From Us, Multiple TO recipients"
+
+test_begin_subtest "Reply with CC"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ '[cc]="Other Parties <cc@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply with CC"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply with CC"
+add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
+ '[to]="Recipient <recipient@example.com>"' \
+ '[cc]="Other Parties <cc@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply with CC"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Recipient <recipient@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply no TO but with CC"
+add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
+ '[cc]="Other Parties <cc@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply with CC"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+Cc: Other Parties <cc@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> reply with CC"
+
+test_begin_subtest "Reply from alternate address"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite_other@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="reply from alternate address"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> reply from alternate address"
+
+test_begin_subtest "Support for Reply-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="support for reply-to"' \
+ '[reply-to]="Sender <elsewhere@example.com>"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <elsewhere@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> support for reply-to"
+
+test_begin_subtest "Support for Reply-To with multiple recipients"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="support for reply-to with multiple recipients"' \
+ '[reply-to]="Sender <elsewhere@example.com>"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <elsewhere@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> support for reply-to with multiple recipients"
+
+test_begin_subtest "Un-munging Reply-To"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]="Some List <list@example.com>"' \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="Un-munging Reply-To"' \
+ '[reply-to]="Evil Munging List <list@example.com>"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> Un-munging Reply-To"
+
+test_begin_subtest "Message with header of exactly 200 bytes"
+add_message '[subject]="This subject is exactly 200 bytes in length. Other than its length there is not much of note here. Note that the length of 200 bytes includes the Subject: and Re: prefixes with two spaces"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="200-byte header"'
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: This subject is exactly 200 bytes in length. Other than its
+ length there is not much of note here. Note that the length of 200 bytes
+ includes the Subject: and Re: prefixes with two spaces
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> 200-byte header"
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="\"notmuch dump\" and \"notmuch restore\""
+. ./test-lib.sh
+
+add_email_corpus
+
+test_expect_success 'Dumping all tags' \
+ 'generate_message &&
+ notmuch new &&
+ notmuch dump > dump.expected'
+
+# The use of from:cworth is rather arbitrary: it matches some of the
+# email corpus' messages, but not all of them.
+
+test_expect_success 'Dumping all tags II' \
+ 'notmuch tag +ABC +DEF -- from:cworth &&
+ notmuch dump > dump-ABC_DEF.expected &&
+ ! cmp dump.expected dump-ABC_DEF.expected'
+
+test_expect_success 'Clearing all tags' \
+ 'sed -e "s/(\([^(]*\))$/()/" < dump.expected > clear.expected &&
+ notmuch restore --input=clear.expected &&
+ notmuch dump > clear.actual &&
+ test_cmp clear.expected clear.actual'
+
+test_expect_success 'Accumulate original tags' \
+ 'notmuch tag +ABC +DEF -- from:cworth &&
+ notmuch restore --accumulate < dump.expected &&
+ notmuch dump > dump.actual &&
+ test_cmp dump-ABC_DEF.expected dump.actual'
+
+test_expect_success 'Restoring original tags' \
+ 'notmuch restore --input=dump.expected &&
+ notmuch dump > dump.actual &&
+ test_cmp dump.expected dump.actual'
+
+test_expect_success 'Restore with nothing to do' \
+ 'notmuch restore < dump.expected &&
+ notmuch dump > dump.actual &&
+ test_cmp dump.expected dump.actual'
+
+test_expect_success 'Accumulate with existing tags' \
+ 'notmuch restore --accumulate --input=dump.expected &&
+ notmuch dump > dump.actual &&
+ test_cmp dump.expected dump.actual'
+
+test_expect_success 'Accumulate with no tags' \
+ 'notmuch restore --accumulate < clear.expected &&
+ notmuch dump > dump.actual &&
+ test_cmp dump.expected dump.actual'
+
+test_expect_success 'Accumulate with new tags' \
+ 'notmuch restore --input=dump.expected &&
+ notmuch restore --accumulate --input=dump-ABC_DEF.expected &&
+ notmuch dump > OUTPUT.$test_count &&
+ notmuch restore --input=dump.expected &&
+ test_cmp dump-ABC_DEF.expected OUTPUT.$test_count'
+
+# notmuch restore currently only considers the first argument.
+test_expect_success 'Invalid restore invocation' \
+ 'test_must_fail notmuch restore --input=dump.expected another_one'
+
+test_begin_subtest "dump --output=outfile"
+notmuch dump --output=dump-outfile.actual
+test_expect_equal_file dump.expected dump-outfile.actual
+
+test_begin_subtest "dump --output=outfile --"
+notmuch dump --output=dump-1-arg-dash.actual --
+test_expect_equal_file dump.expected dump-1-arg-dash.actual
+
+# gzipped output
+
+test_begin_subtest "dump --gzip"
+notmuch dump --gzip > dump-gzip.gz
+gunzip dump-gzip.gz
+test_expect_equal_file dump.expected dump-gzip
+
+test_begin_subtest "dump --gzip --output=outfile"
+notmuch dump --gzip --output=dump-gzip-outfile.gz
+gunzip dump-gzip-outfile.gz
+test_expect_equal_file dump.expected dump-gzip-outfile
+
+test_begin_subtest "restoring gzipped stdin"
+notmuch dump --gzip --output=backup.gz
+notmuch tag +new_tag '*'
+notmuch restore < backup.gz
+notmuch dump --output=dump.actual
+test_expect_equal_file dump.expected dump.actual
+
+test_begin_subtest "restoring gzipped file"
+notmuch dump --gzip --output=backup.gz
+notmuch tag +new_tag '*'
+notmuch restore --input=backup.gz
+notmuch dump --output=dump.actual
+test_expect_equal_file dump.expected dump.actual
+
+# Note, we assume all messages from cworth have a message-id
+# containing cworth.org
+
+grep 'cworth[.]org' dump.expected > dump-cworth.expected
+
+test_begin_subtest "dump -- from:cworth"
+notmuch dump -- from:cworth > dump-dash-cworth.actual
+test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
+
+test_begin_subtest "dump --output=outfile from:cworth"
+notmuch dump --output=dump-outfile-cworth.actual from:cworth
+test_expect_equal_file dump-cworth.expected dump-outfile-cworth.actual
+
+test_begin_subtest "dump --output=outfile -- from:cworth"
+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"
+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
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "format=batch-tag, dump sanity check."
+notmuch dump --format=sup from:cworth | cut -f1 -d' ' | \
+ sort > EXPECTED.$test_count
+notmuch dump --format=batch-tag from:cworth | sed 's/^.*-- id://' | \
+ sort > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "format=batch-tag, missing newline"
+printf "+a_tag_without_newline -- id:20091117232137.GA7669@griffis1.net" > IN
+notmuch restore --accumulate < IN
+notmuch dump id:20091117232137.GA7669@griffis1.net > OUT
+cat <<EOF > EXPECTED
++a_tag_without_newline +inbox +unread -- id:20091117232137.GA7669@griffis1.net
+EOF
+test_expect_equal_file EXPECTED OUT
+
+test_begin_subtest "format=batch-tag, # round-trip"
+notmuch dump --format=sup | sort > EXPECTED.$test_count
+notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
+notmuch dump --format=sup | sort > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "format=batch-tag, # blank lines and comments"
+notmuch dump --format=batch-tag| sort > EXPECTED.$test_count
+notmuch restore <<EOF
+# this line is a comment; the next has only white space
+
+
+# the previous line is empty
+EOF
+notmuch dump --format=batch-tag | sort > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "format=batch-tag, # reverse-round-trip empty tag"
+cat <<EOF >EXPECTED.$test_count
++ -- id:20091117232137.GA7669@griffis1.net
+EOF
+notmuch restore --format=batch-tag < EXPECTED.$test_count
+notmuch dump --format=batch-tag id:20091117232137.GA7669@griffis1.net > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+tag1='comic_swear=$&^%$^%\\//-+$^%$'
+enc1=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag1")
+
+tag2=$(printf 'this\n tag\t has\n spaces')
+enc2=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag2")
+
+enc3='%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a'
+tag3=$($TEST_DIRECTORY/hex-xcode --direction=decode $enc3)
+
+notmuch dump --format=batch-tag > BACKUP
+
+notmuch tag +"$tag1" +"$tag2" +"$tag3" -inbox -unread "*"
+
+# initial segment of file used for several tests below.
+cat <<EOF > comments-and-blanks
+# this is a comment
+
+# next line has leading whitespace
+
+
+EOF
+
+test_begin_subtest 'restoring empty file is not an error'
+notmuch restore < /dev/null 2>OUTPUT.$test_count
+cp /dev/null EXPECTED
+test_expect_equal_file EXPECTED OUTPUT.$test_count
+
+test_begin_subtest 'file of comments and blank lines is not an error'
+notmuch restore --input=comments-and-blanks
+ret_val=$?
+test_expect_equal "$ret_val" "0"
+
+cp comments-and-blanks leading-comments-blanks-batch-tag
+echo "+some_tag -- id:yun1vjwegii.fsf@aiko.keithp.com" \
+ >> leading-comments-blanks-batch-tag
+
+test_begin_subtest 'detect format=batch-tag with leading comments and blanks'
+notmuch restore --input=leading-comments-blanks-batch-tag
+notmuch search --output=tags id:yun1vjwegii.fsf@aiko.keithp.com > OUTPUT.$test_count
+echo "some_tag" > EXPECTED
+test_expect_equal_file EXPECTED OUTPUT.$test_count
+
+cp comments-and-blanks leading-comments-blanks-sup
+echo "yun1vjwegii.fsf@aiko.keithp.com (another_tag)" \
+ >> leading-comments-blanks-sup
+
+test_begin_subtest 'detect format=sup with leading comments and blanks'
+notmuch restore --input=leading-comments-blanks-sup
+notmuch search --output=tags id:yun1vjwegii.fsf@aiko.keithp.com > OUTPUT.$test_count
+echo "another_tag" > EXPECTED
+test_expect_equal_file EXPECTED OUTPUT.$test_count
+
+test_begin_subtest 'format=batch-tag, round trip with strange tags'
+notmuch dump --format=batch-tag > EXPECTED.$test_count
+notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
+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'
+notmuch dump --format=batch-tag -- from:cworth |\
+ awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
+notmuch dump --format=batch-tag -- from:cworth > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest 'restoring sane tags'
+notmuch restore --format=batch-tag < BACKUP
+notmuch dump --format=batch-tag > OUTPUT.$test_count
+test_expect_equal_file BACKUP OUTPUT.$test_count
+
+test_begin_subtest 'format=batch-tag, restore=auto'
+notmuch dump --format=batch-tag > EXPECTED.$test_count
+notmuch tag -inbox -unread "*"
+notmuch restore --format=auto < EXPECTED.$test_count
+notmuch dump --format=batch-tag > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest 'format=sup, restore=auto'
+notmuch dump --format=sup > EXPECTED.$test_count
+notmuch tag -inbox -unread "*"
+notmuch restore --format=auto < EXPECTED.$test_count
+notmuch dump --format=sup > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest 'format=batch-tag, restore=default'
+notmuch dump --format=batch-tag > EXPECTED.$test_count
+notmuch tag -inbox -unread "*"
+notmuch restore < EXPECTED.$test_count
+notmuch dump --format=batch-tag > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest 'format=sup, restore=default'
+notmuch dump --format=sup > EXPECTED.$test_count
+notmuch tag -inbox -unread "*"
+notmuch restore < EXPECTED.$test_count
+notmuch dump --format=sup > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest 'restore: checking error messages'
+notmuch restore <<EOF 2>OUTPUT
+# the next line has a space
+
+a
++0
++a +b
+# trailing whitespace
++a +b
++c +d --
+# this is a harmless comment, do not yell about it.
+
+# the previous line was blank; also no yelling please
++%zz -- id:whatever
++e +f id:"
++e +f tag:abc
+# the next non-comment line should report an an empty tag error for
+# batch tagging, but not for restore
++ +e -- id:20091117232137.GA7669@griffis1.net
+# valid id, but warning about missing message
++e id:missing_message_id
+# exercise parser
++e -- id:some)stuff
++e -- id:some stuff
++e -- id:some"stuff
++e -- id:"a_message_id_with""_a_quote"
++e -- id:"a message id with spaces"
++e -- id:an_id_with_leading_and_trailing_ws \
+
+EOF
+
+cat <<EOF > EXPECTED
+Warning: cannot parse query: a (skipping)
+Warning: no query string [+0]
+Warning: no query string [+a +b]
+Warning: missing query string [+a +b ]
+Warning: no query string after -- [+c +d --]
+Warning: hex decoding of tag %zz failed [+%zz -- id:whatever]
+Warning: cannot parse query: id:" (skipping)
+Warning: not an id query: tag:abc (skipping)
+Warning: cannot apply tags to missing message: missing_message_id
+Warning: cannot parse query: id:some)stuff (skipping)
+Warning: cannot parse query: id:some stuff (skipping)
+Warning: cannot apply tags to missing message: some"stuff
+Warning: cannot apply tags to missing message: a_message_id_with"_a_quote
+Warning: cannot apply tags to missing message: a message id with spaces
+Warning: cannot apply tags to missing message: an_id_with_leading_and_trailing_ws
+EOF
+
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest 'roundtripping random message-ids and tags'
+
+ ${TEST_DIRECTORY}/random-corpus --config-path=${NOTMUCH_CONFIG} \
+ --num-messages=100
+
+ notmuch dump --format=batch-tag| \
+ sort > EXPECTED.$test_count
+
+ notmuch tag +this_tag_is_very_unlikely_to_be_random '*'
+
+ notmuch restore --format=batch-tag < EXPECTED.$test_count
+
+ notmuch dump --format=batch-tag| \
+ sort > OUTPUT.$test_count
+
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_done
+
+# Note the database is "poisoned" for sup format at this point.
--- /dev/null
+#!/usr/bin/env bash
+test_description="handling of uuencoded data"
+. ./test-lib.sh
+
+add_message [subject]=uuencodetest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' \
+'[body]="This message is used to ensure that notmuch correctly handles a
+message containing a block of uuencoded data. First, we have a marker
+this content beforeuudata . Then we begin the uuencoded data itself:
+
+begin 644 bogus-uuencoded-data
+M0123456789012345678901234567890123456789012345678901234567890
+MOBVIOUSLY, THIS IS NOT ANY SORT OF USEFUL UUENCODED DATA.
+MINSTEAD THIS IS JUST A WAY TO ENSURE THAT THIS BLOCK OF DATA
+MIS CORRECTLY IGNORED WHEN NOTMUCH CREATES ITS INDEX. SO WE
+MINCLUDE A DURINGUUDATA MARKER THAT SHOULD NOT RESULT IN ANY
+MSEARCH RESULT.
+\\\`
+end
+
+Finally, we have our afteruudata marker as well."'
+
+test_begin_subtest "Ensure content before uu data is indexed"
+output=$(notmuch search beforeuudata | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; uuencodetest (inbox unread)"
+
+test_begin_subtest "Ensure uu data is not indexed"
+output=$(notmuch search DURINGUUDATA | notmuch_search_sanitize)
+test_expect_equal "$output" ""
+
+test_begin_subtest "Ensure content after uu data is indexed"
+output=$(notmuch search afteruudata | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; uuencodetest (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="threading when messages received out of order"
+. ./test-lib.sh
+
+test_begin_subtest "Adding initial child message"
+generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching returns the message"
+output=$(notmuch search foo | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; brokenthreadtest (inbox unread)"
+
+test_begin_subtest "Adding second child message"
+generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching returns both messages in one thread"
+output=$(notmuch search foo | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [2/2] Notmuch Test Suite; brokenthreadtest (inbox unread)"
+
+test_begin_subtest "Adding parent message"
+generate_message [body]=foo [id]=parent-id [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching returns all three messages in one thread"
+output=$(notmuch search foo | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [3/3] Notmuch Test Suite; brokenthreadtest (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="author reordering;"
+. ./test-lib.sh
+
+test_begin_subtest "Adding parent message"
+generate_message [body]=findme [id]=new-parent-id [subject]=author-reorder-threadtest '[from]="User <user@example.com>"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Adding initial child message"
+generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User1 <user1@example.com>"' '[date]="Sat, 01 Jan 2000 12:01:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Adding second child message"
+generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User2 <user2@example.com>"' '[date]="Sat, 01 Jan 2000 12:02:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching when all three messages match"
+output=$(notmuch search findme | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [3/3] User, User1, User2; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Searching when two messages match"
+output=$(notmuch search User1 or User2 | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [2/3] User1, User2| User; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Searching when only one message matches"
+output=$(notmuch search User2 | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/3] User2| User, User1; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Searching when only first message matches"
+output=$(notmuch search User | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [1/3] User| User1, User2; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Adding duplicate author"
+generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User1 <user1@example.com>"' '[date]="Sat, 01 Jan 2000 12:03:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching when all four messages match"
+output=$(notmuch search findme | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [4/4] User, User1, User2; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Adding non-monotonic child message"
+generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User0 <user0@example.com>"' '[date]="Sat, 01 Jan 2000 11:00:00 -0000"'
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Searching non-monotonic messages (oldest-first)"
+output=$(notmuch search --sort=oldest-first findme | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [5/5] User0, User, User1, User2; author-reorder-threadtest (inbox unread)"
+
+test_begin_subtest "Searching non-monotonic messages (newest-first)"
+output=$(notmuch search --sort=newest-first findme | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2000-01-01 [5/5] User0, User, User1, User2; author-reorder-threadtest (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="From line heuristics (with multiple configured addresses)"
+. ./test-lib.sh
+
+test_begin_subtest "Magic from guessing (nothing to go on)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Envelope-to:)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[header]="Envelope-To: test_suite_other@notmuchmail.org"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (X-Original-To:)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[header]="X-Original-To: test_suite_other@notmuchmail.org"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Received: .. for ..)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
+ by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
+ for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Received: domain)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
+ by mail.otherdomain.org (some MTA) with ESMTP id 12345678
+ Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@otherdomain.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (multiple Received: headers)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ "[header]=\"Received: from extraneous.example.com (extraneous.example.com [1.1.1.1])
+Received: from mail.example.com (mail.example.com [1.1.1.1])
+ by mail.otherdomain.org (some MTA) with ESMTP id 12345678
+ for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)
+Received: from extraneous.example.com (extraneous.example.com [1.1.1.1])\"" \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output="$(notmuch reply id:${gen_msg_id})"
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Testing From line heuristics (with single configured address)"
+sed -i -e "s/^other_email.*//" "${NOTMUCH_CONFIG}"
+test_expect_equal '' ''
+
+test_begin_subtest "Magic from guessing (nothing to go on)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Envelope-to:)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[header]="Envelope-To: test_suite_other@notmuchmail.org"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (X-Original-To:)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ '[header]="X-Original-To: test_suite_other@notmuchmail.org"' \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Received: .. for ..)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
+ by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
+ for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_begin_subtest "Magic from guessing (Received: domain)"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=mailinglist@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+ "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
+ by mail.otherdomain.org (some MTA) with ESMTP id 12345678
+ Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
+ '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
+ '[body]="from guessing test"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: notmuch-reply-test
+To: Sender <sender@example.com>, mailinglist@notmuchmail.org
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
+> from guessing test"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="messages with ridiculously-long message IDs"
+. ./test-lib.sh
+
+test_begin_subtest "Referencing long ID before adding"
+generate_message '[subject]="Reference of ridiculously-long message ID"' \
+ "[references]=\<abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-\>"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Adding message with long ID"
+generate_message '[subject]="A ridiculously-long message ID"' \
+ "[id]=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Referencing long ID after adding"
+generate_message '[subject]="Reply to ridiculously-long message ID"' \
+ "[in-reply-to]=\<abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-\>"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Ensure all messages were threaded together"
+output=$(notmuch search 'subject:"a ridiculously-long message ID"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/3] Notmuch Test Suite; A ridiculously-long message ID (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="encoding issues"
+. ./test-lib.sh
+
+test_begin_subtest "Message with text of unknown charset"
+add_message '[content-type]="text/plain; charset=unknown-8bit"' \
+ "[body]=irrelevant"
+output=$(notmuch show id:${gen_msg_id} 2>&1 | notmuch_show_sanitize_all)
+test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox unread)
+Subject: Message with text of unknown charset
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+irrelevant
+\fpart}
+\fbody}
+\fmessage}"
+
+test_begin_subtest "Search for ISO-8859-2 encoded message"
+add_message '[content-type]="text/plain; charset=iso-8859-2"' \
+ '[content-transfer-encoding]=8bit' \
+ '[subject]="ISO-8859-2 encoded message"' \
+ "[body]=$'Czech word tu\350\362\341\350\350\355 means pinguin\'s.'" # ISO-8859-2 characters are generated by shell's escape sequences
+output=$(notmuch search tučňáččí 2>&1 | notmuch_show_sanitize_all)
+test_expect_equal "$output" "thread:0000000000000002 2001-01-05 [1/1] Notmuch Test Suite; ISO-8859-2 encoded message (inbox unread)"
+
+test_begin_subtest "RFC 2047 encoded word with spaces"
+add_message '[subject]="=?utf-8?q?encoded word with spaces?="'
+output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
+test_expect_equal "$output" "thread:0000000000000003 2001-01-05 [1/1] Notmuch Test Suite; encoded word with spaces (inbox unread)"
+
+test_begin_subtest "RFC 2047 encoded words back to back"
+add_message '[subject]="=?utf-8?q?encoded-words-back?==?utf-8?q?to-back?="'
+output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
+test_expect_equal "$output" "thread:0000000000000004 2001-01-05 [1/1] Notmuch Test Suite; encoded-words-backto-back (inbox unread)"
+
+test_begin_subtest "RFC 2047 encoded words without space before or after"
+add_message '[subject]="=?utf-8?q?encoded?=word without=?utf-8?q?space?=" '
+output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
+test_expect_equal "$output" "thread:0000000000000005 2001-01-05 [1/1] Notmuch Test Suite; encodedword withoutspace (inbox unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs interface"
+. ./test-lib.sh
+
+EXPECTED=$TEST_DIRECTORY/emacs.expected-output
+
+add_email_corpus
+
+# syntax errors in test-lib.el cause mysterious failures
+test_expect_success 'Syntax of emacs test library' \
+ "${TEST_EMACS} -Q --batch --load $TEST_DIRECTORY/test-lib.el"
+
+test_begin_subtest "Basic notmuch-hello view in emacs"
+test_emacs '(notmuch-hello)
+ (test-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello
+
+test_begin_subtest "Saved search with 0 results"
+test_emacs '(let ((notmuch-show-empty-saved-searches t)
+ (notmuch-saved-searches
+ '\''(("inbox" . "tag:inbox")
+ ("unread" . "tag:unread")
+ ("empty" . "tag:doesnotexist"))))
+ (notmuch-hello)
+ (test-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-with-empty
+
+test_begin_subtest "No saved searches displayed (all with 0 results)"
+test_emacs '(let ((notmuch-saved-searches
+ '\''(("empty" . "tag:doesnotexist"))))
+ (notmuch-hello)
+ (test-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-no-saved-searches
+
+test_begin_subtest "Basic notmuch-search view in emacs"
+test_emacs '(notmuch-search "tag:inbox")
+ (notmuch-test-wait)
+ (test-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-search-tag-inbox
+
+test_begin_subtest "Incremental parsing of search results"
+test_emacs "(ad-enable-advice 'notmuch-search-process-filter 'around 'pessimal)
+ (ad-activate 'notmuch-search-process-filter)
+ (notmuch-search \"tag:inbox\")
+ (notmuch-test-wait)
+ (ad-disable-advice 'notmuch-search-process-filter 'around 'pessimal)
+ (ad-activate 'notmuch-search-process-filter)
+ (test-output)"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-search-tag-inbox
+
+test_begin_subtest "Navigation of notmuch-hello to search results"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (test-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-view-inbox
+
+test_begin_subtest "Basic notmuch-show view in emacs"
+maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
+test_emacs "(notmuch-show \"$maildir_storage_thread\")
+ (test-output)"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
+
+test_begin_subtest "Basic notmuch-show view in emacs default indentation"
+maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
+test_emacs "(let ((notmuch-show-indent-messages-width 1))
+ (notmuch-show \"$maildir_storage_thread\")
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
+
+test_begin_subtest "Basic notmuch-show view in emacs without indentation"
+maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
+test_emacs "(let ((notmuch-show-indent-messages-width 0))
+ (notmuch-show \"$maildir_storage_thread\")
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage-without-indentation
+
+test_begin_subtest "Basic notmuch-show view in emacs with fourfold indentation"
+maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
+test_emacs "(let ((notmuch-show-indent-messages-width 4))
+ (notmuch-show \"$maildir_storage_thread\")
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage-with-fourfold-indentation
+
+test_begin_subtest "notmuch-show for message with invalid From"
+add_message "[subject]=\"message-with-invalid-from\"" \
+ "[from]=\"\\\"Invalid \\\" From\\\" <test_suite@notmuchmail.org>\""
+thread=$(notmuch search --output=threads subject:message-with-invalid-from)
+test_emacs "(notmuch-show \"$thread\")
+ (test-output \"OUTPUT.raw\")"
+cat <<EOF >EXPECTED
+"Invalid " (2001-01-05) (inbox)
+Subject: message-with-invalid-from
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+
+This is just a test message (#1)
+EOF
+notmuch_date_sanitize < OUTPUT.raw > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Navigation of notmuch-search to thread view"
+test_emacs '(notmuch-search "tag:inbox")
+ (notmuch-test-wait)
+ (goto-char (point-min))
+ (re-search-forward "Working with Maildir")
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (test-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
+
+test_begin_subtest "Add tag from search view"
+os_x_darwin_thread=$(notmuch search --output=threads id:ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com)
+test_emacs "(notmuch-search \"$os_x_darwin_thread\")
+ (notmuch-test-wait)
+ (execute-kbd-macro \"+tag-from-search-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-search-view unread)"
+
+test_begin_subtest "Remove tag from search view"
+test_emacs "(notmuch-search \"$os_x_darwin_thread\")
+ (notmuch-test-wait)
+ (execute-kbd-macro \"-tag-from-search-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
+
+test_begin_subtest "Add tag (large query)"
+# We use a long query to force us into batch mode and use a funny tag
+# that requires escaping for batch tagging.
+test_emacs "(notmuch-tag (concat \"$os_x_darwin_thread\" \" or \" (make-string notmuch-tag-argument-limit ?x)) (list \"+tag-from-%-large-query\"))"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-%-large-query unread)"
+notmuch tag -tag-from-%-large-query $os_x_darwin_thread
+
+test_begin_subtest "notmuch-show: add single tag to single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+ (execute-kbd-macro \"+tag-from-show-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-show-view unread)"
+
+test_begin_subtest "notmuch-show: remove single tag from single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+ (execute-kbd-macro \"-tag-from-show-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
+
+test_begin_subtest "notmuch-show: add multiple tags to single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+ (execute-kbd-macro \"+tag1-from-show-view +tag2-from-show-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag1-from-show-view tag2-from-show-view unread)"
+
+test_begin_subtest "notmuch-show: remove multiple tags from single message"
+test_emacs "(notmuch-show \"$os_x_darwin_thread\")
+ (execute-kbd-macro \"-tag1-from-show-view -tag2-from-show-view\")"
+output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
+
+test_begin_subtest "Message with .. in Message-Id:"
+add_message [id]=123..456@example '[subject]="Message with .. in Message-Id"'
+test_emacs '(notmuch-search "id:\"123..456@example\"")
+ (notmuch-test-wait)
+ (execute-kbd-macro "+search-add")
+ (execute-kbd-macro "+search-remove")
+ (execute-kbd-macro "-search-remove")
+ (notmuch-show "id:\"123..456@example\"")
+ (notmuch-test-wait)
+ (execute-kbd-macro "+show-add")
+ (execute-kbd-macro "+show-remove")
+ (execute-kbd-macro "-show-remove")'
+output=$(notmuch search 'id:"123..456@example"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message with .. in Message-Id (inbox search-add show-add)"
+
+test_begin_subtest "Message with quote in Message-Id:"
+add_message '[id]="\"quote\"@example"' '[subject]="Message with quote in Message-Id"'
+test_emacs '(notmuch-search "subject:\"Message with quote\"")
+ (notmuch-test-wait)
+ (execute-kbd-macro "+search-add")
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (execute-kbd-macro "+show-add")'
+output=$(notmuch search 'id:"""quote""@example"' | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message with quote in Message-Id (inbox search-add show-add)"
+
+test_begin_subtest "Sending a message via (fake) SMTP"
+emacs_deliver_message \
+ 'Testing message sent via SMTP' \
+ 'This is a test that messages are sent via SMTP' \
+ '(message-goto-to)
+ (kill-whole-line)
+ (insert "To: user@example.com\n")'
+sed \
+ -e s',^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' \
+ -e s',^Message-ID: <.*>$,Message-ID: <XXX>,' \
+ -e s',^\(Content-Type: text/plain\); charset=us-ascii$,\1,' < sent_message >OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: user@example.com
+Subject: Testing message sent via SMTP
+Date: 01 Jan 2000 12:00:00 -0000
+User-Agent: Notmuch/XXX Emacs/XXX
+Message-ID: <XXX>
+MIME-Version: 1.0
+Content-Type: text/plain
+
+This is a test that messages are sent via SMTP
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
+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)"
+
+test_begin_subtest "notmuch-fcc-dirs set to nil"
+test_emacs "(let ((notmuch-fcc-dirs nil))
+ (notmuch-mua-mail)
+ (test-output))"
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject:
+--text follows this line--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+# Make another FCC maildir specific for the next test
+mkdir -p mail/sent-string/cur
+mkdir -p mail/sent-string/new
+mkdir -p mail/sent-string/tmp
+
+test_begin_subtest "notmuch-fcc-dirs set to a string"
+test_emacs "(let ((notmuch-fcc-dirs \"sent-string\"))
+ (notmuch-mua-mail)
+ (test-output))"
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject:
+Fcc: ${MAIL_DIR}/sent-string
+--text follows this line--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+# Make more FCC maildirs specific for the next test
+mkdir -p mail/sent-list-match/cur
+mkdir -p mail/sent-list-match/new
+mkdir -p mail/sent-list-match/tmp
+mkdir -p mail/failure/cur
+mkdir -p mail/failure/new
+mkdir -p mail/failure/tmp
+
+test_begin_subtest "notmuch-fcc-dirs set to a list (with match)"
+test_emacs "(let ((notmuch-fcc-dirs
+ '((\"notmuchmail.org\" . \"sent-list-match\")
+ (\".*\" . \"failure\"))))
+ (notmuch-mua-mail)
+ (test-output))"
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject:
+Fcc: ${MAIL_DIR}/sent-list-match
+--text follows this line--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+# Make another FCC maildir specific for the next test
+mkdir -p mail/sent-list-catch-all/cur
+mkdir -p mail/sent-list-catch-all/new
+mkdir -p mail/sent-list-catch-all/tmp
+
+test_begin_subtest "notmuch-fcc-dirs set to a list (catch-all)"
+test_emacs "(let ((notmuch-fcc-dirs
+ '((\"example.com\" . \"failure\")
+ (\".*\" . \"sent-list-catch-all\"))))
+ (notmuch-mua-mail)
+ (test-output))"
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject:
+Fcc: ${MAIL_DIR}/sent-list-catch-all
+--text follows this line--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "notmuch-fcc-dirs set to a list (no match)"
+test_emacs "(let ((notmuch-fcc-dirs
+ '((\"example.com\" . \"failure\")
+ (\"nomatchhere.net\" . \"failure\"))))
+ (notmuch-mua-mail)
+ (test-output))"
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject:
+--text follows this line--
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply within emacs"
+test_emacs '(let ((message-hidden-headers ''()))
+ (notmuch-search "subject:\"testing message sent via SMTP\"")
+ (notmuch-test-wait)
+ (notmuch-search-reply-to-thread)
+ (test-output))'
+sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: <XXX>/' OUTPUT
+sed -i -e 's/^References: <.*>$/References: <XXX>/' OUTPUT
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: user@example.com
+Subject: Re: Testing message sent via SMTP
+In-Reply-To: <XXX>
+Fcc: ${MAIL_DIR}/sent
+References: <XXX>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Notmuch Test Suite <test_suite@notmuchmail.org> writes:
+
+> This is a test that messages are sent via SMTP
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply from alternate address within emacs"
+add_message '[from]="Sender <sender@example.com>"' \
+ [to]=test_suite_other@notmuchmail.org
+
+test_emacs "(let ((message-hidden-headers '()))
+ (notmuch-search \"id:\\\"${gen_msg_id}\\\"\")
+ (notmuch-test-wait)
+ (notmuch-search-reply-to-thread)
+ (test-output))"
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
+To: Sender <sender@example.com>
+Subject: Re: ${test_subtest_name}
+In-Reply-To: <${gen_msg_id}>
+Fcc: ${MAIL_DIR}/sent
+References: <${gen_msg_id}>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Sender <sender@example.com> writes:
+
+> This is just a test message (#${gen_msg_cnt})
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply from address in named group list within emacs"
+add_message '[from]="Sender <sender@example.com>"' \
+ '[to]=group:test_suite@notmuchmail.org,someone@example.com\;' \
+ [cc]=test_suite_other@notmuchmail.org
+
+test_emacs "(let ((message-hidden-headers '()))
+ (notmuch-search \"id:\\\"${gen_msg_id}\\\"\")
+ (notmuch-test-wait)
+ (notmuch-search-reply-to-thread)
+ (test-output))"
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Sender <sender@example.com>, someone@example.com
+Subject: Re: ${test_subtest_name}
+In-Reply-To: <${gen_msg_id}>
+Fcc: ${MAIL_DIR}/sent
+References: <${gen_msg_id}>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Sender <sender@example.com> writes:
+
+> This is just a test message (#${gen_msg_cnt})
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply within emacs to a multipart/mixed message"
+test_emacs '(let ((message-hidden-headers ''()))
+ (notmuch-show "id:20091118002059.067214ed@hikari")
+ (notmuch-show-reply)
+ (test-output))'
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Adrian Perez de Castro <aperez@igalia.com>, notmuch@notmuchmail.org
+Subject: Re: [notmuch] Introducing myself
+In-Reply-To: <20091118002059.067214ed@hikari>
+Fcc: ${MAIL_DIR}/sent
+References: <20091118002059.067214ed@hikari>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Adrian Perez de Castro <aperez@igalia.com> writes:
+
+> Hello to all,
+>
+> I have just heard about Not Much today in some random Linux-related news
+> site (LWN?), my name is Adrian Perez and I work as systems administrator
+> (although I can do some code as well :P). I have always thought that the
+> ideas behind Sup were great, but after some time using it, I got tired of
+> the oddities that it has. I also do not like doing things like having to
+> install Ruby just for reading and sorting mails. Some time ago I thought
+> about doing something like Not Much and in fact I played a bit with the
+> Python+Xapian and the Python+Whoosh combinations, because I find relaxing
+> to code things in Python when I am not working and also it is installed
+> by default on most distribution. I got to have some mailboxes indexed and
+> basic searching working a couple of months ago. Lately I have been very
+> busy and had no time for coding, and them... boom! Not Much appears -- and
+> it is almost exactly what I was trying to do, but faster. I have been
+> playing a bit with Not Much today, and I think it has potential.
+>
+> Also, I would like to share one idea I had in mind, that you might find
+> interesting: One thing I have found very annoying is having to re-tag my
+> mail when the indexes get b0rked (it happened a couple of times to me while
+> using Sup), so I was planning to mails as read/unread and adding the tags
+> not just to the index, but to the mail text itself, e.g. by adding a
+> "X-Tags" header field or by reusing the "Keywords" one. This way, the index
+> could be totally recreated by re-reading the mail directories, and this
+> would also allow to a tools like OfflineIMAP [1] to get the mails into a
+> local maildir, tagging and indexing the mails with the e-mail reader and
+> then syncing back the messages with the "X-Tags" header to the IMAP server.
+> This would allow to use the mail reader from a different computer and still
+> have everything tagged finely.
+>
+> Best regards,
+>
+>
+> ---
+> [1] http://software.complete.org/software/projects/show/offlineimap
+>
+> --
+> Adrian Perez de Castro <aperez@igalia.com>
+> Igalia - Free Software Engineering
+> _______________________________________________
+> notmuch mailing list
+> notmuch@notmuchmail.org
+> http://notmuchmail.org/mailman/listinfo/notmuch
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply within emacs to a multipart/alternative message"
+test_emacs '(let ((message-hidden-headers ''()))
+ (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
+ (notmuch-show-reply)
+ (test-output))'
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Alex Botero-Lowry <alex.boterolowry@gmail.com>, notmuch@notmuchmail.org
+Subject: Re: [notmuch] preliminary FreeBSD support
+In-Reply-To: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
+Fcc: ${MAIL_DIR}/sent
+References: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Alex Botero-Lowry <alex.boterolowry@gmail.com> writes:
+
+> I saw the announcement this morning, and was very excited, as I had been
+> hoping sup would be turned into a library,
+> since I like the concept more than the UI (I'd rather an emacs interface).
+>
+> I did a preliminary compile which worked out fine, but
+> sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
+> FreeBSD, so notmuch_config_open segfaulted.
+>
+> Attached is a patch that supplies a default buffer size of 64 in cases where
+> -1 is returned.
+>
+> http://www.opengroup.org/austin/docs/austin_328.txt - seems to indicate this
+> is acceptable behavior,
+> and http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.htmlspecifically
+> uses 64 as the
+> buffer size.
+> _______________________________________________
+> notmuch mailing list
+> notmuch@notmuchmail.org
+> http://notmuchmail.org/mailman/listinfo/notmuch
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Reply within emacs to an html-only message"
+add_message '[content-type]="text/html"' \
+ '[body]="Hi,<br />This is an <b>HTML</b> test message.<br /><br />OK?"'
+test_emacs "(let ((message-hidden-headers '()) (mm-text-html-renderer 'html2text))
+ (notmuch-show \"id:${gen_msg_id}\")
+ (notmuch-show-reply)
+ (test-output))"
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject: Re: Reply within emacs to an html-only message
+In-Reply-To: <${gen_msg_id}>
+Fcc: ${MAIL_DIR}/sent
+References: <${gen_msg_id}>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Notmuch Test Suite <test_suite@notmuchmail.org> writes:
+
+> Hi,This is an HTML test message.OK?
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Quote MML tags in reply"
+message_id='test-emacs-mml-quoting@message.id'
+add_message [id]="$message_id" \
+ "[subject]='$test_subtest_name'" \
+ '[body]="<#part disposition=inline>"'
+test_emacs "(let ((message-hidden-headers '()))
+ (notmuch-show \"id:$message_id\")
+ (notmuch-show-reply)
+ (test-output))"
+sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
+cat <<EOF >EXPECTED
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To:
+Subject: Re: Quote MML tags in reply
+In-Reply-To: <test-emacs-mml-quoting@message.id>
+Fcc: ${MAIL_DIR}/sent
+References: <test-emacs-mml-quoting@message.id>
+User-Agent: Notmuch/XXX Emacs/XXX
+--text follows this line--
+Notmuch Test Suite <test_suite@notmuchmail.org> writes:
+
+> <#!part disposition=inline>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Save attachment from within emacs using notmuch-show-save-attachments"
+# save as archive to test that Emacs does not re-compress .gz
+test_emacs '(let ((standard-input "\"attachment1.gz\""))
+ (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
+ (notmuch-show-save-attachments))'
+test_expect_equal_file attachment1.gz "$EXPECTED/attachment"
+
+test_begin_subtest "Save attachment from within emacs using notmuch-show-save-part"
+# save as archive to test that Emacs does not re-compress .gz
+test_emacs '(let ((standard-input "\"attachment2.gz\""))
+ (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
+ (search-forward "0001-Deal-with")
+ (notmuch-show-save-part))'
+test_expect_equal_file attachment2.gz "$EXPECTED/attachment"
+
+test_begin_subtest "Save 8bit attachment from within emacs using notmuch-show-save-attachments"
+
+add_message '[subject]="Attachment with 8bit chars"' \
+ '[header]="MIME-Version: 1.0"' \
+ '[content-type]="multipart/mixed; boundary=\"abcd\""' \
+ '[body]="--abcd
+Content-Type: text/plain
+
+Attachment follows:
+
+--abcd
+Content-Type: application/octet-stream; name=\"sample\"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: attachment; filename=\"sample\"
+
+“¡ Hey ! It compiles ¡ Ship it !”
+
+--abcd--
+"'
+test_emacs '(notmuch-show "id:'"${gen_msg_id}"'")
+ (delete-file "OUTPUT")
+ (let ((standard-input "\"OUTPUT\""))
+ (notmuch-show-save-attachments))'
+
+test_expect_equal "$(cat OUTPUT)" '“¡ Hey ! It compiles ¡ Ship it !”'
+
+test_begin_subtest "View raw message within emacs"
+test_emacs '(notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
+ (notmuch-show-view-raw-message)
+ (test-output)'
+test_expect_equal_file OUTPUT $EXPECTED/raw-message-cf0c4d-52ad0a
+
+test_begin_subtest "Hiding/showing signature in notmuch-show view"
+maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
+test_emacs "(notmuch-show \"$maildir_storage_thread\")
+ (search-forward \"Click/Enter to show.\")
+ (button-activate (button-at (point)))
+ (search-backward \"Click/Enter to hide.\")
+ (button-activate (button-at (point)))
+ (test-output)"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
+
+test_begin_subtest "Detection and hiding of top-post quoting of message"
+add_message '[subject]="The problem with top-posting"' \
+ [id]=top-post-target \
+ '[body]="A: Because it messes up the order in which people normally read text.
+Q: Why is top-posting such a bad thing?
+A: Top-posting.
+Q: What is the most annoying thing in e-mail?"'
+add_message '[from]="Top Poster <top@poster.com>"' \
+ [in-reply-to]=top-post-target \
+ [references]=top-post-target \
+ '[subject]="Re: The problem with top-posting"' \
+ '[body]="Thanks for the advice! I will be sure to put it to good use.
+
+-Top Poster
+
+----- Original Message -----
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: Notmuch Test Suite <test_suite@notmuchmai.org>
+Sent: Fri, 05 Jan 2001 15:43:57 +0000
+Subject: The problem with top-posting
+
+Q: Why is top-posting such a bad thing?
+A: Top-posting.
+Q: What is the most annoying thing in e-mail?"'
+test_emacs "(notmuch-show \"top-posting\")
+ (test-visible-output \"OUTPUT.raw\")"
+echo "Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
+Subject: The problem with top-posting
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+
+A: Because it messes up the order in which people normally read text.
+Q: Why is top-posting such a bad thing?
+A: Top-posting.
+Q: What is the most annoying thing in e-mail?
+Top Poster <top@poster.com> (2001-01-05) (inbox unread)
+Subject: Re: The problem with top-posting
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+
+Thanks for the advice! I will be sure to put it to good use.
+
+-Top Poster
+
+[ 9-line hidden original message. Click/Enter to show. ]" > EXPECTED
+notmuch_date_sanitize < OUTPUT.raw > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Hiding message in notmuch-show view"
+test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (notmuch-show-toggle-message)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-hidden-messages
+
+test_begin_subtest "Hiding message with visible citation in notmuch-show view"
+test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (search-forward "Click/Enter to show.")
+ (button-activate (button-at (point)))
+ (notmuch-show-toggle-message)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-hidden-messages
+
+test_begin_subtest "notmuch-show: show message headers"
+test_emacs \
+ '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
+ (notmuch-message-headers-visible t))
+ (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-visible
+
+test_begin_subtest "notmuch-show: hide message headers"
+test_emacs \
+ '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
+ (notmuch-message-headers-visible nil))
+ (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-hidden
+
+test_begin_subtest "notmuch-show: hide message headers (w/ notmuch-show-toggle-visibility-headers)"
+test_emacs \
+ '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
+ (notmuch-message-headers-visible t))
+ (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (notmuch-show-toggle-visibility-headers)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-hidden
+
+test_begin_subtest "notmuch-show: collapse all messages in thread"
+test_emacs '(notmuch-show "id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com")
+ (let ((current-prefix-arg t))
+ (notmuch-show-open-or-close-all)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-all-messages-collapsed
+
+test_begin_subtest "notmuch-show: uncollapse all messages in thread"
+test_emacs '(notmuch-show "id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com")
+ (notmuch-show-open-or-close-all)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-all-messages-uncollapsed
+
+test_begin_subtest "Stashing in notmuch-show"
+add_message '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' \
+ '[from]="Some One <someone@somewhere.org>"' \
+ '[to]="Some One Else <notsomeone@somewhere.org>"' \
+ '[cc]="Notmuch <notmuch@notmuchmail.org>"' \
+ '[subject]="Stash my stashables"' \
+ '[id]="bought"' \
+ '[body]="Unable to stash body. Where did you get it in the first place?!?"'
+notmuch tag +stashtest id:${gen_msg_id}
+test_emacs '(notmuch-show "id:\"bought\"")
+ (notmuch-show-stash-date)
+ (notmuch-show-stash-from)
+ (notmuch-show-stash-to)
+ (notmuch-show-stash-cc)
+ (notmuch-show-stash-subject)
+ (notmuch-show-stash-message-id)
+ (notmuch-show-stash-message-id-stripped)
+ (notmuch-show-stash-tags)
+ (notmuch-show-stash-filename)
+ (notmuch-show-stash-mlarchive-link "Gmane")
+ (notmuch-show-stash-mlarchive-link "MARC")
+ (notmuch-show-stash-mlarchive-link "Mail Archive, The")
+ (switch-to-buffer
+ (generate-new-buffer "*test-stashing*"))
+ (dotimes (i 12)
+ (yank)
+ (insert "\n")
+ (rotate-yank-pointer 1))
+ (reverse-region (point-min) (point-max))
+ (test-output)'
+cat <<EOF >EXPECTED
+Sat, 01 Jan 2000 12:00:00 +0000
+Some One <someone@somewhere.org>
+Some One Else <notsomeone@somewhere.org>
+Notmuch <notmuch@notmuchmail.org>
+Stash my stashables
+id:bought
+bought
+inbox,stashtest
+${gen_msg_filename}
+http://mid.gmane.org/bought
+http://marc.info/?i=bought
+http://mid.mail-archive.com/bought
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Stashing in notmuch-search"
+test_emacs '(notmuch-search "id:\"bought\"")
+ (notmuch-test-wait)
+ (notmuch-search-stash-thread-id)
+ (switch-to-buffer
+ (generate-new-buffer "*test-stashing*"))
+ (yank)
+ (test-output)'
+sed -i -e 's/^thread:.*$/thread:XXX/' OUTPUT
+test_expect_equal "$(cat OUTPUT)" "thread:XXX"
+
+test_begin_subtest 'notmuch-show-advance-and-archive with invisible signature'
+message1='id:20091118010116.GC25380@dottiness.seas.harvard.edu'
+message2='id:1258491078-29658-1-git-send-email-dottedmag@dottedmag.net'
+test_emacs "(notmuch-show \"$message2\")
+ (test-output \"EXPECTED\")"
+test_emacs "(notmuch-search \"$message1 or $message2\")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (goto-char (point-max))
+ (redisplay)
+ (notmuch-show-advance-and-archive)
+ (test-output)"
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Refresh show buffer"
+test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (test-visible-output "EXPECTED")
+ (notmuch-show-refresh-view)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Refresh modified show buffer"
+test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
+ (notmuch-show-toggle-message)
+ (notmuch-show-next-message)
+ (notmuch-show-toggle-message)
+ (test-visible-output "EXPECTED")
+ (notmuch-show-refresh-view)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Do not call notmuch for non-inlinable application/mpeg parts"
+id='message-with-application/mpeg-attachment@notmuchmail.org'
+emacs_fcc_message \
+ 'Message with application/mpeg attachment' \
+ '' \
+ "(message-goto-eoh)
+ (insert \"Message-ID: <$id>\n\")
+ (message-goto-body)
+ (mml-insert-part \"application/mpeg\")
+ (insert \"a fake mp3 file\")"
+notmuch_counter_reset
+test_emacs "(let ((notmuch-command \"$notmuch_counter_command\"))
+ (notmuch-show \"id:$id\"))"
+test_expect_equal $(notmuch_counter_value) 1
+
+test_begin_subtest "Do not call notmuch for non-inlinable audio/mpeg parts"
+id='message-with-audio/mpeg-attachment@notmuchmail.org'
+emacs_fcc_message \
+ 'Message with audio/mpeg attachment' \
+ '' \
+ "(message-goto-eoh)
+ (insert \"Message-ID: <$id>\n\")
+ (message-goto-body)
+ (mml-insert-part \"audio/mpeg\")
+ (insert \"a fake mp3 file\")"
+notmuch_counter_reset
+test_emacs "(let ((notmuch-command \"$notmuch_counter_command\"))
+ (notmuch-show \"id:$id\"))"
+test_expect_equal $(notmuch_counter_value) 1
+
+test_begin_subtest "notmuch-hello-mode hook is called"
+counter=$(test_emacs \
+ '(let ((notmuch-hello-mode-hook-counter 0))
+ (kill-buffer "*notmuch-hello*")
+ (notmuch-hello)
+ notmuch-hello-mode-hook-counter)'
+)
+test_expect_equal "$counter" 1
+
+test_begin_subtest "notmuch-hello-mode hook is not called on updates"
+counter=$(test_emacs \
+ '(let ((notmuch-hello-mode-hook-counter 0))
+ (kill-buffer "*notmuch-hello*")
+ (notmuch-hello)
+ (notmuch-hello-update)
+ notmuch-hello-mode-hook-counter)'
+)
+test_expect_equal "$counter" 1
+
+test_begin_subtest "notmuch-hello-refresh hook is called"
+counter=$(test_emacs \
+ '(let ((notmuch-hello-refresh-hook-counter 0))
+ (kill-buffer "*notmuch-hello*")
+ (notmuch-hello)
+ notmuch-hello-refresh-hook-counter)'
+)
+test_expect_equal "$counter" 1
+
+test_begin_subtest "notmuch-hello-refresh hook is called on updates"
+counter=$(test_emacs \
+ '(let ((notmuch-hello-refresh-hook-counter 0))
+ (kill-buffer "*notmuch-hello*")
+ (notmuch-hello)
+ (notmuch-hello-update)
+ notmuch-hello-refresh-hook-counter)'
+)
+test_expect_equal "$counter" 2
+
+
+add_message '[subject]="HTML mail with images"' \
+ '[content-type]="multipart/related; boundary=abcd"' \
+ '[body]="--abcd
+Content-Type: text/html
+
+<img src="cid:330@goomoji.gmail"> smiley
+
+--abcd
+Content-Type: image/gif
+Content-Transfer-Encoding: base64
+Content-ID: <330@goomoji.gmail>
+
+R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMl
+WLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7
+--abcd--"'
+test_emacs "(let ((mm-text-html-renderer
+ (if (assq 'shr mm-text-html-renderer-alist)
+ 'shr 'html2text)))
+ (notmuch-show \"id:${gen_msg_id}\"))
+ (test-output)" > /dev/null
+# Different Emacs versions and renderers give very different results,
+# so just check that something reasonable showed up. We first cat the
+# output so the test framework will print it if the test fails.
+test_expect_success "Rendering HTML mail with images" \
+ 'cat OUTPUT && grep -q smiley OUTPUT'
+
+
+test_begin_subtest "Search handles subprocess error exit codes"
+cat > notmuch_fail <<EOF
+#!/bin/sh
+echo '()'
+exit 1
+EOF
+chmod a+x notmuch_fail
+test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
+ (with-current-buffer \"*Messages*\" (erase-buffer))
+ (with-current-buffer (get-buffer-create \"*Notmuch errors*\")
+ (erase-buffer))
+ (notmuch-search \"tag:inbox\")
+ (notmuch-test-wait)
+ (with-current-buffer \"*Messages*\"
+ (test-output \"MESSAGES\"))
+ (with-current-buffer \"*Notmuch errors*\"
+ (test-output \"ERROR\"))
+ (test-output))"
+
+test_expect_equal "$(notmuch_emacs_error_sanitize notmuch_fail OUTPUT MESSAGES ERROR)" "\
+=== OUTPUT ===
+End of search results.
+=== MESSAGES ===
+YYY/notmuch_fail exited with status 1 (see *Notmuch errors* for more details)
+=== ERROR ===
+[XXX]
+YYY/notmuch_fail exited with status 1
+command: YYY/notmuch_fail search --format\=sexp --format-version\=2 --sort\=newest-first tag\:inbox
+exit status: 1"
+
+test_begin_subtest "Search handles subprocess warnings"
+cat > notmuch_fail <<EOF
+#!/bin/sh
+echo '()'
+echo This is a warning >&2
+echo This is another warning >&2
+exit 0
+EOF
+chmod a+x notmuch_fail
+test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
+ (with-current-buffer \"*Messages*\" (erase-buffer))
+ (with-current-buffer (get-buffer-create \"*Notmuch errors*\")
+ (erase-buffer))
+ (notmuch-search \"tag:inbox\")
+ (notmuch-test-wait)
+ (with-current-buffer \"*Messages*\"
+ (test-output \"MESSAGES\"))
+ (with-current-buffer \"*Notmuch errors*\"
+ (test-output \"ERROR\"))
+ (test-output))"
+sed -i -e 's/^\[.*\]$/[XXX]/' ERROR
+test_expect_equal "$(cat OUTPUT; echo ---; cat MESSAGES; echo ---; cat ERROR)" "\
+End of search results.
+---
+This is a warning (see *Notmuch errors* for more details)
+---
+[XXX]
+This is a warning
+This is another warning"
+
+test_begin_subtest "Search thread tag operations are race-free"
+add_message '[subject]="Search race test"'
+gen_msg_id_1=$gen_msg_id
+generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \
+ '[references]="<'$gen_msg_id_1'>"' \
+ '[subject]="Search race test two"'
+test_emacs '(notmuch-search "subject:\"search race test\"")
+ (notmuch-test-wait)
+ (notmuch-poll)
+ (execute-kbd-macro "+search-thread-race-tag")'
+output=$(notmuch search --output=messages 'tag:search-thread-race-tag')
+test_expect_equal "$output" "id:$gen_msg_id_1"
+
+test_begin_subtest "Search global tag operations are race-free"
+generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \
+ '[references]="<'$gen_msg_id_1'>"' \
+ '[subject]="Re: Search race test"'
+test_emacs '(notmuch-search "subject:\"search race test\" -subject:two")
+ (notmuch-test-wait)
+ (notmuch-poll)
+ (execute-kbd-macro "*+search-global-race-tag")'
+output=$(notmuch search --output=messages 'tag:search-global-race-tag')
+test_expect_equal "$output" "id:$gen_msg_id_1"
+
+test_begin_subtest "Term escaping"
+output=$(test_emacs "(mapcar 'notmuch-escape-boolean-term (list
+ \"\"
+ \"abc\`~\!@#\$%^&*-=_+123\"
+ \"(abc\"
+ \")abc\"
+ \"\\\"abc\"
+ \"\x01xyz\"
+ \"\\x201cxyz\\x201d\"))")
+test_expect_equal "$output" '("\"\"" "abc`~!@#$%^&*-=_+123" "\"(abc\"" "\")abc\"" "\"\"\"abc\"" "\"'$'\x01''xyz\"" "\"“xyz”\"")'
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="Emacs with large search results buffer"
+. ./test-lib.sh
+
+x=xxxxxxxxxx # 10
+x=$x$x$x$x$x$x$x$x$x$x # 100
+x=$x$x$x$x$x$x$x$x$x # 900
+
+# We generate a long subject here (over 900 bytes) so that the emacs
+# search results get large quickly. With 30 such messages we should
+# cross several 4kB page boundaries and see the bug.
+n=30
+for i in $(seq 1 $n); do
+ # Roughly 100B2 KiB per message. That is, we need two messages in order to
+ # exceed the typical size of the pipe buffer (4 KiB on commodity systems).
+ generate_message '[subject]="$x $i of $n"'
+done
+
+notmuch new > /dev/null
+
+test_begin_subtest "Ensure that emacs doesn't drop results"
+notmuch search '*' > EXPECTED
+sed -i -e 's/^thread:[0-9a-f]* //' -e 's/;//' -e 's/xx*/[BLOB]/' EXPECTED
+echo 'End of search results.' >> EXPECTED
+
+test_emacs '(notmuch-search "*")
+ (notmuch-test-wait)
+ (test-output)'
+sed -i -e s', *, ,g' -e 's/xxx*/[BLOB]/g' OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs: mail subject to filename"
+. ./test-lib.sh
+
+# emacs server can't be started in a child process with $(test_emacs ...)
+test_emacs '(ignore)' > /dev/null
+
+# test notmuch-wash-subject-to-patch-sequence-number (subject)
+test_begin_subtest "no patch sequence number"
+output=$(test_emacs '(format "%S" (notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH] A normal patch subject without numbers"))'
+)
+test_expect_equal "$output" '"nil"'
+
+test_begin_subtest "patch sequence number #1"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] A most regular patch subject")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #2"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ " [dummy list prefix] [RFC PATCH v2 13/42] Special prefixes")'
+)
+test_expect_equal "$output" 13
+
+test_begin_subtest "patch sequence number #3"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] [PATCH 032/037] use the last prefix")'
+)
+test_expect_equal "$output" 32
+
+test_begin_subtest "patch sequence number #4"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[dummy list prefix] [PATCH 2/3] PATCH 3/3] do not use a broken prefix")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #5"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[RFC][PATCH 3/5][PATCH 4/5][PATCH 5/5] A made up test")'
+)
+test_expect_equal "$output" 5
+
+test_begin_subtest "patch sequence number #6"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] this -> [PATCH 3/3] is not a prefix anymore [nor this 4/4]")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #7"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[liberally accept crapola right before123/456and after] the numbers")'
+)
+test_expect_equal "$output" 123
+
+# test notmuch-wash-subject-to-filename (subject &optional maxlen)
+test_begin_subtest "filename #1"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "just a subject line")'
+)
+test_expect_equal "$output" '"just-a-subject-line"'
+
+test_begin_subtest "filename #2"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ " [any] [prefixes are ] [removed!] from the subject")'
+)
+test_expect_equal "$output" '"from-the-subject"'
+
+test_begin_subtest "filename #3"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ " leading and trailing space ")'
+)
+test_expect_equal "$output" '"leading-and-trailing-space"'
+
+test_begin_subtest "filename #4"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "!# leading ()// &%, and in between_and_trailing garbage ()(&%%")'
+)
+test_expect_equal "$output" '"-leading-and-in-between_and_trailing-garbage"'
+
+test_begin_subtest "filename #5"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890")'
+)
+test_expect_equal "$output" '"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890"'
+
+test_begin_subtest "filename #6"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "sequences of ... are squashed and trailing are removed ...")'
+)
+test_expect_equal "$output" '"sequences-of-.-are-squashed-and-trailing-are-removed"'
+
+test_begin_subtest "filename #7"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "max length test" 1)'
+)
+test_expect_equal "$output" '"m"'
+
+test_begin_subtest "filename #8"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "max length test /&(/%&/%%&¤%¤" 20)'
+)
+test_expect_equal "$output" '"max-length-test"'
+
+test_begin_subtest "filename #9"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "[a prefix] [is only separated] by [spaces], so \"by\" is not okay!")'
+)
+test_expect_equal "$output" '"by-spaces-so-by-is-not-okay"'
+
+# test notmuch-wash-subject-to-patch-filename (subject)
+test_begin_subtest "patch filename #1"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[RFC][PATCH 099/100] rewrite notmuch")'
+)
+test_expect_equal "$output" '"0099-rewrite-notmuch.patch"'
+
+test_begin_subtest "patch filename #2"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[RFC PATCH v1] has no patch number, default to 1")'
+)
+test_expect_equal "$output" '"0001-has-no-patch-number-default-to-1.patch"'
+
+test_begin_subtest "patch filename #3"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[PATCH 4/5] the maximum length of a patch filename is 52 + patch sequence number + .patch extension")'
+)
+test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patch-s.patch"'
+
+test_begin_subtest "patch filename #4"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[PATCH 4/5] the maximum length of a patch filename is 52 + patchh ! sequence number + .patch extension, *before* trimming trailing - and .")'
+)
+test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patchh.patch"'
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="maildir synchronization"
+
+. ./test-lib.sh
+
+# Create the expected maildir structure
+mkdir $MAIL_DIR/cur
+mkdir $MAIL_DIR/new
+mkdir $MAIL_DIR/tmp
+
+test_begin_subtest "Adding 'S' flag to existing filename removes 'unread' tag"
+add_message [subject]='"Adding S flag"' [filename]='adding-s-flag:2,' [dir]=cur
+output=$(notmuch search subject:"Adding S flag" | notmuch_search_sanitize)
+output+="
+"
+mv "${gen_msg_filename}" "${gen_msg_filename}S"
+output+=$(NOTMUCH_NEW)
+output+="
+"
+output+=$(notmuch search subject:"Adding S flag" | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding S flag (inbox unread)
+No new mail. Detected 1 file rename.
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding S flag (inbox)"
+
+test_begin_subtest "Adding message with 'S' flag prevents 'unread' tag"
+add_message [subject]='"Adding message with S"' [filename]='adding-with-s-flag:2,S' [dir]=cur
+output=$(notmuch search subject:"Adding message with S" | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding message with S (inbox)"
+
+test_begin_subtest "Adding 'replied' tag adds 'R' flag to filename"
+add_message [subject]='"Adding replied tag"' [filename]='adding-replied-tag:2,S' [dir]=cur
+notmuch tag +replied subject:"Adding replied tag"
+output=$(cd ${MAIL_DIR}/cur; ls -1 adding-replied*)
+test_expect_equal "$output" "adding-replied-tag:2,RS"
+
+test_begin_subtest "notmuch show works with renamed file (without notmuch new)"
+output=$(notmuch show --format=json id:${gen_msg_id} | notmuch_json_show_sanitize)
+test_expect_equal_json "$output" '[[[{"id": "XXXXX",
+"match": true,
+"excluded": false,
+"filename": "YYYYY",
+"timestamp": 42,
+"date_relative": "2001-01-05",
+"tags": ["inbox","replied"],
+"headers": {"Subject": "Adding replied tag",
+"From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+"To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+"Date": "GENERATED_DATE"},
+"body": [{"id": 1,
+"content-type": "text/plain",
+"content": "This is just a test message (#3)\n"}]},
+[]]]]'
+
+test_expect_success 'notmuch reply works with renamed file (without notmuch new)' 'notmuch reply id:${gen_msg_id}'
+
+test_begin_subtest "notmuch new detects no file rename after tag->flag synchronization"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+
+test_begin_subtest "When read, message moved from new to cur"
+add_message [subject]='"Message to move to cur"' [date]='"Sat, 01 Jan 2000 12:00:00 -0000"' [filename]='message-to-move-to-cur' [dir]=new
+notmuch tag -unread subject:"Message to move to cur"
+output=$(cd "$MAIL_DIR/cur"; ls message-to-move*)
+test_expect_equal "$output" "message-to-move-to-cur:2,S"
+
+test_begin_subtest "No rename should be detected by notmuch new"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+# (*) If notmuch new was not run we've got "Processed 1 file in almost
+# no time" here. The reason is that removing unread tag in a previous
+# test created directory document in the database but this document
+# was not linked as subdirectory of $MAIL_DIR. Therefore notmuch new
+# could not reach the cur/ directory and its files in it during
+# recursive traversal.
+#
+# XXX: The above sounds like a bug that should be fixed. If notmuch is
+# creating new directories in the mail store, then it should be
+# creating all necessary database state for those directories.
+
+test_begin_subtest "Adding non-maildir tags does not move message from new to cur"
+add_message [subject]='"Message to stay in new"' \
+ [date]='"Sat, 01 Jan 2000 12:00:00 -0000"' \
+ [filename]='message-to-stay-in-new' [dir]=new
+notmuch tag +donotmove subject:"Message to stay in new"
+output=$(cd "$MAIL_DIR"; ls */message-to-stay-in-new*)
+test_expect_equal "$output" "new/message-to-stay-in-new"
+
+test_begin_subtest "Message in cur lacking maildir info gets one on any tag change"
+add_message [filename]='message-to-get-maildir-info' [dir]=cur
+notmuch tag +anytag id:$gen_msg_id
+output=$(cd "$MAIL_DIR"; ls */message-to-get-maildir-info*)
+test_expect_equal "$output" "cur/message-to-get-maildir-info:2,"
+
+test_begin_subtest "Message in new with maildir info is moved to cur on any tag change"
+add_message [filename]='message-with-info-to-be-moved-to-cur:2,' [dir]=new
+notmuch tag +anytag id:$gen_msg_id
+output=$(cd "$MAIL_DIR"; ls */message-with-info-to-be-moved-to-cur*)
+test_expect_equal "$output" "cur/message-with-info-to-be-moved-to-cur:2,"
+
+test_begin_subtest "Removing 'S' flag from existing filename adds 'unread' tag"
+add_message [subject]='"Removing S flag"' [filename]='removing-s-flag:2,S' [dir]=cur
+output=$(notmuch search subject:"Removing S flag" | notmuch_search_sanitize)
+output+="
+"
+mv "${gen_msg_filename}" "${gen_msg_filename%S}"
+output+=$(NOTMUCH_NEW)
+output+="
+"
+output+=$(notmuch search subject:"Removing S flag" | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Removing S flag (inbox)
+No new mail. Detected 1 file rename.
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Removing S flag (inbox unread)"
+
+test_begin_subtest "Removing info from filename leaves tags unchanged"
+add_message [subject]='"Message to lose maildir info"' [filename]='message-to-lose-maildir-info' [dir]=cur
+notmuch tag -unread subject:"Message to lose maildir info"
+mv "$MAIL_DIR/cur/message-to-lose-maildir-info:2,S" "$MAIL_DIR/cur/message-without-maildir-info"
+output=$(NOTMUCH_NEW)
+output+="
+"
+output+=$(notmuch search subject:"Message to lose maildir info" | notmuch_search_sanitize)
+test_expect_equal "$output" "No new mail. Detected 1 file rename.
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message to lose maildir info (inbox)"
+
+add_message [subject]='"Non-maildir message"' [dir]=notmaildir [filename]='non-maildir-message'
+expected=$(notmuch search --output=files subject:"Non-maildir message")
+test_expect_success "Can remove unread tag from message in non-maildir directory" 'notmuch tag -unread subject:"Non-maildir message"'
+
+test_begin_subtest "Message in non-maildir directory does not get renamed"
+output=$(notmuch search --output=files subject:"Non-maildir message")
+test_expect_equal "$output" "$expected"
+
+test_begin_subtest "notmuch dump/restore re-synchronizes maildir tags with flags"
+# Capture current filename state
+expected=$(ls $MAIL_DIR/cur)
+# Add/remove some flags from filenames
+mv $MAIL_DIR/cur/adding-replied-tag:2,RS $MAIL_DIR/cur/adding-replied-tag:2,S
+mv $MAIL_DIR/cur/adding-s-flag:2,S $MAIL_DIR/cur/adding-s-flag:2,
+mv $MAIL_DIR/cur/adding-with-s-flag:2,S $MAIL_DIR/cur/adding-with-s-flag:2,RS
+mv $MAIL_DIR/cur/message-to-move-to-cur:2,S $MAIL_DIR/cur/message-to-move-to-cur:2,DS
+notmuch dump --output=dump.txt
+NOTMUCH_NEW >/dev/null
+notmuch restore --input=dump.txt
+output=$(ls $MAIL_DIR/cur)
+test_expect_equal "$output" "$expected"
+
+test_begin_subtest 'Adding flags to duplicate message tags the mail'
+add_message [subject]='"Duplicated message"' [dir]=cur [filename]='duplicated-message:2,'
+cp "$MAIL_DIR/cur/duplicated-message:2," "$MAIL_DIR/cur/duplicated-message-copy:2,RS"
+NOTMUCH_NEW > output
+notmuch search subject:"Duplicated message" | notmuch_search_sanitize >> output
+test_expect_equal "$(< output)" "No new mail.
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Duplicated message (inbox replied)"
+
+test_begin_subtest "Adding duplicate message without flags does not remove tags"
+cp "$MAIL_DIR/cur/duplicated-message-copy:2,RS" "$MAIL_DIR/cur/duplicated-message-another-copy:2,"
+NOTMUCH_NEW > output
+notmuch search subject:"Duplicated message" | notmuch_search_sanitize >> output
+test_expect_equal "$(< output)" "No new mail.
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Duplicated message (inbox replied)"
+
+test_begin_subtest "Tag changes modify flags of multiple files"
+notmuch tag -replied subject:"Duplicated message"
+(cd $MAIL_DIR/cur/; ls duplicated*) > actual
+test_expect_equal "$(< actual)" "duplicated-message-another-copy:2,S
+duplicated-message-copy:2,S
+duplicated-message:2,S"
+
+test_begin_subtest "Synchronizing tag changes preserves unsupported maildir flags"
+add_message [subject]='"Unsupported maildir flags"' [dir]=cur [filename]='unsupported-maildir-flags:2,FSZxyz'
+notmuch tag +unread +draft -flagged subject:"Unsupported maildir flags"
+test_expect_equal "$(cd $MAIL_DIR/cur/; ls unsupported*)" "unsupported-maildir-flags:2,DZxyz"
+
+test_begin_subtest "A file with non-compliant maildir info will not be renamed"
+add_message [subject]='"Non-compliant maildir info"' [dir]=cur [filename]='non-compliant-maildir-info:2,These-are-not-flags-in-ASCII-order-donottouch'
+notmuch tag +unread +draft -flagged subject:"Non-compliant maildir info"
+test_expect_equal "$(cd $MAIL_DIR/cur/; ls non-compliant*)" "non-compliant-maildir-info:2,These-are-not-flags-in-ASCII-order-donottouch"
+
+test_begin_subtest "Files in new/ get default synchronized tags"
+OLDCONFIG=$(notmuch config get new.tags)
+notmuch config set new.tags test
+add_message [subject]='"File in new/"' [dir]=new [filename]='file-in-new'
+notmuch config set new.tags $OLDCONFIG
+notmuch search 'subject:"File in new"' | notmuch_search_sanitize > output
+test_expect_equal "$(< output)" \
+"thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; File in new/ (test unread)"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+# TODO:
+# - decryption/verification with signer key not available
+# - verification of signatures from expired/revoked keys
+
+test_description='PGP/MIME signature verification and decryption'
+. ./test-lib.sh
+
+add_gnupg_home ()
+{
+ local output
+ [ -d ${GNUPGHOME} ] && return
+ mkdir -m 0700 "$GNUPGHOME"
+ gpg --no-tty --import <$TEST_DIRECTORY/gnupg-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
+ elif (gpg --debug-quick-random --version >/dev/null 2>&1) ; then
+ echo debug-quick-random >> "$GNUPGHOME"/gpg.conf
+ fi
+ echo no-emit-version >> "$GNUPGHOME"/gpg.conf
+}
+
+##################################################
+
+add_gnupg_home
+# get key fingerprint
+FINGERPRINT=$(gpg --no-tty --list-secret-keys --with-colons --fingerprint | grep '^fpr:' | cut -d: -f10)
+
+test_expect_success 'emacs delivery of signed message' \
+'emacs_fcc_message \
+ "test signed message 001" \
+ "This is a test signed message." \
+ "(mml-secure-message-sign)"'
+
+test_begin_subtest "signature verification"
+output=$(notmuch show --format=json --verify subject:"test signed message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["inbox","signed"],
+ "headers": {"Subject": "test signed message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "sigstatus": [{"status": "good",
+ "fingerprint": "'$FINGERPRINT'",
+ "created": 946728000}],
+ "content-type": "multipart/signed",
+ "content": [{"id": 2,
+ "content-type": "text/plain",
+ "content": "This is a test signed message.\n"},
+ {"id": 3,
+ "content-type": "application/pgp-signature",
+ "content-length": 280}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "signature verification with full owner trust"
+# give the key full owner trust
+echo "${FINGERPRINT}:6:" | gpg --no-tty --import-ownertrust >>"$GNUPGHOME"/trust.log 2>&1
+gpg --no-tty --check-trustdb >>"$GNUPGHOME"/trust.log 2>&1
+output=$(notmuch show --format=json --verify subject:"test signed message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["inbox","signed"],
+ "headers": {"Subject": "test signed message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "sigstatus": [{"status": "good",
+ "fingerprint": "'$FINGERPRINT'",
+ "created": 946728000,
+ "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
+ "content-type": "multipart/signed",
+ "content": [{"id": 2,
+ "content-type": "text/plain",
+ "content": "This is a test signed message.\n"},
+ {"id": 3,
+ "content-type": "application/pgp-signature",
+ "content-length": 280}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "signature verification with signer key unavailable"
+# move the gnupghome temporarily out of the way
+mv "${GNUPGHOME}"{,.bak}
+output=$(notmuch show --format=json --verify subject:"test signed message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["inbox","signed"],
+ "headers": {"Subject": "test signed message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "sigstatus": [{"status": "error",
+ "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'",
+ "errors": 2}],
+ "content-type": "multipart/signed",
+ "content": [{"id": 2,
+ "content-type": "text/plain",
+ "content": "This is a test signed message.\n"},
+ {"id": 3,
+ "content-type": "application/pgp-signature",
+ "content-length": 280}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+mv "${GNUPGHOME}"{.bak,}
+
+# create a test encrypted message with attachment
+cat <<EOF >TESTATTACHMENT
+This is a test file.
+EOF
+test_expect_success 'emacs delivery of encrypted message with attachment' \
+'emacs_fcc_message \
+ "test encrypted message 001" \
+ "This is a test encrypted message.\n" \
+ "(mml-attach-file \"TESTATTACHMENT\") (mml-secure-message-encrypt)"'
+
+test_begin_subtest "decryption, --format=text"
+output=$(notmuch show --format=text --decrypt subject:"test encrypted message 001" \
+ | notmuch_show_sanitize_all \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (encrypted inbox)
+Subject: test encrypted message 001
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+To: test_suite@notmuchmail.org
+Date: Sat, 01 Jan 2000 12:00:00 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: multipart/encrypted
+\fpart{ ID: 2, Content-type: application/pgp-encrypted
+Non-text part: application/pgp-encrypted
+\fpart}
+\fpart{ ID: 3, Content-type: multipart/mixed
+\fpart{ ID: 4, Content-type: text/plain
+This is a test encrypted message.
+\fpart}
+\fattachment{ ID: 5, Filename: TESTATTACHMENT, Content-type: application/octet-stream
+Non-text part: application/octet-stream
+\fattachment}
+\fpart}
+\fpart}
+\fbody}
+\fmessage}'
+test_expect_equal \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "decryption, --format=json"
+output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["encrypted","inbox"],
+ "headers": {"Subject": "test encrypted message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "encstatus": [{"status": "good"}],
+ "sigstatus": [],
+ "content-type": "multipart/encrypted",
+ "content": [{"id": 2,
+ "content-type": "application/pgp-encrypted",
+ "content-length": 11},
+ {"id": 3,
+ "content-type": "multipart/mixed",
+ "content": [{"id": 4,
+ "content-type": "text/plain",
+ "content": "This is a test encrypted message.\n"},
+ {"id": 5,
+ "content-type": "application/octet-stream",
+ "content-length": 28,
+ "content-transfer-encoding": "base64",
+ "filename": "TESTATTACHMENT"}]}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "decryption, --format=json, --part=4"
+output=$(notmuch show --format=json --part=4 --decrypt subject:"test encrypted message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='{"id": 4,
+ "content-type": "text/plain",
+ "content": "This is a test encrypted message.\n"}'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "decrypt attachment (--part=5 --format=raw)"
+notmuch show \
+ --format=raw \
+ --part=5 \
+ --decrypt \
+ subject:"test encrypted message 001" >OUTPUT
+test_expect_equal_file OUTPUT TESTATTACHMENT
+
+test_begin_subtest "decryption failure with missing key"
+mv "${GNUPGHOME}"{,.bak}
+# The length of the encrypted attachment varies so must be normalized.
+output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|' \
+ | sed -e 's|"content-length": 6[1234567890]*|"content-length": 652|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["encrypted","inbox"],
+ "headers": {"Subject": "test encrypted message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "encstatus": [{"status": "bad"}],
+ "content-type": "multipart/encrypted",
+ "content": [{"id": 2,
+ "content-type": "application/pgp-encrypted",
+ "content-length": 11},
+ {"id": 3,
+ "content-type": "application/octet-stream",
+ "content-length": 652}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+mv "${GNUPGHOME}"{.bak,}
+
+test_expect_success 'emacs delivery of encrypted + signed message' \
+'emacs_fcc_message \
+ "test encrypted message 002" \
+ "This is another test encrypted message.\n" \
+ "(mml-secure-message-sign-encrypt)"'
+
+test_begin_subtest "decryption + signature verification"
+output=$(notmuch show --format=json --decrypt subject:"test encrypted message 002" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["encrypted","inbox"],
+ "headers": {"Subject": "test encrypted message 002",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "encstatus": [{"status": "good"}],
+ "sigstatus": [{"status": "good",
+ "fingerprint": "'$FINGERPRINT'",
+ "created": 946728000,
+ "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
+ "content-type": "multipart/encrypted",
+ "content": [{"id": 2,
+ "content-type": "application/pgp-encrypted",
+ "content-length": 11},
+ {"id": 3,
+ "content-type": "text/plain",
+ "content": "This is another test encrypted message.\n"}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "reply to encrypted message"
+output=$(notmuch reply --decrypt subject:"test encrypted message 002" \
+ | grep -v -e '^In-Reply-To:' -e '^References:')
+expected='From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Subject: Re: test encrypted message 002
+
+On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
+> This is another test encrypted message.'
+test_expect_equal \
+ "$output" \
+ "$expected"
+
+test_begin_subtest "signature verification with revoked key"
+# generate revocation certificate and load it to revoke key
+echo "y
+1
+Notmuch Test Suite key revocation (automated) $(date '+%F_%T%z')
+
+y
+
+" \
+ | gpg --no-tty --quiet --command-fd 0 --armor --gen-revoke "0x${FINGERPRINT}!" 2>/dev/null \
+ | gpg --no-tty --quiet --import
+output=$(notmuch show --format=json --verify subject:"test signed message 001" \
+ | notmuch_json_show_sanitize \
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+expected='[[[{"id": "XXXXX",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 946728000,
+ "date_relative": "2000-01-01",
+ "tags": ["inbox","signed"],
+ "headers": {"Subject": "test signed message 001",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "test_suite@notmuchmail.org",
+ "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
+ "body": [{"id": 1,
+ "sigstatus": [{"status": "error",
+ "keyid": "6D92612D94E46381",
+ "errors": 8}],
+ "content-type": "multipart/signed",
+ "content": [{"id": 2,
+ "content-type": "text/plain",
+ "content": "This is a test signed message.\n"},
+ {"id": 3,
+ "content-type": "application/pgp-signature",
+ "content-length": 280}]}]},
+ []]]]'
+test_expect_equal_json \
+ "$output" \
+ "$expected"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+#
+# Copyright (c) 2011 David Bremner
+#
+
+# This test tests whether hiding Xapian::Error symbols in libnotmuch
+# also hides them for other users of libxapian. This is motivated by
+# the discussion in http://gcc.gnu.org/wiki/Visibility'
+
+test_description='exception symbol hiding'
+
+. ./test-lib.sh
+
+run_test(){
+ result=$(LD_LIBRARY_PATH="$TEST_DIRECTORY/../lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" $TEST_DIRECTORY/symbol-test 2>&1)
+}
+
+output="A Xapian exception occurred opening database: Couldn't stat 'fakedb/.notmuch/xapian'
+caught No chert database found at path \`./nonexistant'"
+
+mkdir -p fakedb/.notmuch
+
+test_expect_success 'running test' run_test
+
+test_begin_subtest 'checking output'
+test_expect_equal "$result" "$output"
+
+test_begin_subtest 'comparing existing to exported symbols'
+objdump -t $TEST_DIRECTORY/../lib/*.o | awk '$4 == ".text" && $6 ~ "^notmuch" {print $6}' | sort | uniq > ACTUAL
+sed -n 's/[[:blank:]]*\(notmuch_[^;]*\);/\1/p' $TEST_DIRECTORY/../notmuch.sym | sort | uniq > EXPORTED
+test_expect_equal_file EXPORTED ACTUAL
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='folder tags removed and added through file renames remain consistent'
+. ./test-lib.sh
+
+test_begin_subtest "No new messages"
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+
+
+test_begin_subtest "Single new message"
+generate_message
+file_x=$gen_msg_filename
+id_x=$gen_msg_id
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "Add second folder for same message"
+dir=$(dirname $file_x)
+mkdir $dir/spam
+cp $file_x $dir/spam
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail."
+
+
+test_begin_subtest "Multiple files for same message"
+cat <<EOF >EXPECTED
+MAIL_DIR/msg-001
+MAIL_DIR/spam/msg-001
+EOF
+notmuch search --output=files id:$id_x | notmuch_search_files_sanitize >OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Test matches folder:spam"
+output=$(notmuch search folder:spam)
+test_expect_equal "$output" "thread:0000000000000001 2001-01-05 [1/1] Notmuch Test Suite; Single new message (inbox unread)"
+
+test_begin_subtest "Remove folder:spam copy of email"
+rm $dir/spam/$(basename $file_x)
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "No new mail. Detected 1 file rename."
+
+test_begin_subtest "No mails match the folder:spam search"
+output=$(notmuch search folder:spam)
+test_expect_equal "$output" ""
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='atomicity'
+. ./test-lib.sh
+
+# This script tests the effects of killing and restarting "notmuch
+# new" at arbitrary points. If notmuch new is properly atomic, the
+# final database contents should be the same regardless of when (or
+# if) it is killed and restarted.
+
+if test_require_external_prereq gdb; then
+
+# Create a maildir structure to also stress flag synchronization
+ mkdir $MAIL_DIR/cur
+ mkdir $MAIL_DIR/new
+ mkdir $MAIL_DIR/tmp
+ mkdir $MAIL_DIR/.remove-dir
+
+ # Prepare the initial database
+ generate_message [subject]='Duplicate' [filename]='duplicate:2,' [dir]=cur
+ generate_message [subject]='Remove' [filename]='remove:2,' [dir]=cur
+ generate_message [subject]='"Remove duplicate"' [filename]='remove-duplicate:2,' [dir]=cur
+ cp $MAIL_DIR/cur/remove-duplicate:2, $MAIL_DIR/cur/remove-duplicate-copy:2,
+ generate_message [subject]='Rename' [filename]='rename:2,' [dir]=cur
+ generate_message [subject]='"Rename duplicate"' [filename]='rename-duplicate:2,' [dir]=cur
+ generate_message [subject]='"Move 1"' [filename]='move1:2,' [dir]=cur
+ generate_message [subject]='"Move 2"' [filename]='move2:2,' [dir]=new
+ generate_message [subject]='Flag' [filename]='flag:2,' [dir]=cur
+ generate_message [subject]='"Flag duplicate"' [filename]='flag-duplicate:2,' [dir]=cur
+ cp $MAIL_DIR/cur/flag-duplicate:2, $MAIL_DIR/cur/flag-duplicate-copy:2,F
+ generate_message [subject]='"Remove directory"' [filename]='remove-directory:2,' [dir]=.remove-dir
+ generate_message [subject]='"Remove directory duplicate"' [filename]='remove-directory-duplicate:2,' [dir]=.remove-dir
+ cp $MAIL_DIR/.remove-dir/remove-directory-duplicate:2, $MAIL_DIR/cur/
+ notmuch new > /dev/null
+
+ # Make all maildir changes, but *don't* update the database
+ generate_message [subject]='Added' [filename]='added:2,' [dir]=cur
+ cp $MAIL_DIR/cur/duplicate:2, $MAIL_DIR/cur/duplicate-copy:2,
+ generate_message [subject]='"Add duplicate"' [filename]='add-duplicate:2,' [dir]=cur
+ generate_message [subject]='"Add duplicate copy"' [filename]='add-duplicate-copy:2,' [dir]=cur
+ rm $MAIL_DIR/cur/remove:2,
+ rm $MAIL_DIR/cur/remove-duplicate-copy:2,
+ mv $MAIL_DIR/cur/rename:2, $MAIL_DIR/cur/renamed:2,
+ mv $MAIL_DIR/cur/rename-duplicate:2, $MAIL_DIR/cur/renamed-duplicate:2,
+ mv $MAIL_DIR/cur/move1:2, $MAIL_DIR/new/move1:2,
+ mv $MAIL_DIR/new/move2:2, $MAIL_DIR/cur/move2:2,
+ mv $MAIL_DIR/cur/flag:2, $MAIL_DIR/cur/flag:2,F
+ rm $MAIL_DIR/cur/flag-duplicate-copy:2,F
+ rm $MAIL_DIR/.remove-dir/remove-directory:2,
+ rm $MAIL_DIR/.remove-dir/remove-directory-duplicate:2,
+ rmdir $MAIL_DIR/.remove-dir
+
+ # Prepare a snapshot of the updated maildir. The gdb script will
+ # update the database in this snapshot as it goes.
+ cp -a $MAIL_DIR $MAIL_DIR.snap
+ cp ${NOTMUCH_CONFIG} ${NOTMUCH_CONFIG}.snap
+ NOTMUCH_CONFIG=${NOTMUCH_CONFIG}.snap notmuch config set database.path $MAIL_DIR.snap
+
+
+
+ # Execute notmuch new and, at every call to rename, snapshot the
+ # database, run notmuch new again on the snapshot, and capture the
+ # results of search.
+ #
+ # -tty /dev/null works around a conflict between the 'timeout' wrapper
+ # and gdb's attempt to control the TTY.
+ export MAIL_DIR
+ gdb -tty /dev/null -batch -x $TEST_DIRECTORY/atomicity.gdb notmuch >/dev/null 2>/dev/null
+
+ # Get the final, golden output
+ notmuch search '*' > expected
+
+ # Check output against golden output
+ outcount=$(cat outcount)
+ echo -n > searchall
+ echo -n > expectall
+ for ((i = 0; i < $outcount; i++)); do
+ if ! cmp -s search.$i expected; then
+ # Find the range of interruptions that match this output
+ for ((end = $i + 1 ; end < $outcount; end++)); do
+ if ! cmp -s search.$i search.$end; then
+ break
+ fi
+ done
+ echo "When interrupted after $test/backtrace.$(expr $i - 1) (abort points $i-$(expr $end - 1))" >> searchall
+ cat search.$i >> searchall
+ cat expected >> expectall
+ echo >> searchall
+ echo >> expectall
+
+ i=$(expr $end - 1)
+ fi
+ done
+fi
+
+test_begin_subtest '"notmuch new" is idempotent under arbitrary aborts'
+test_expect_equal_file searchall expectall
+
+test_expect_success "detected $outcount>10 abort points" "test $outcount -gt 10"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="python bindings"
+. ./test-lib.sh
+
+add_email_corpus
+
+test_begin_subtest "compare thread ids"
+test_python <<EOF
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
+q_new = notmuch.Query(db, 'tag:inbox')
+q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
+for t in q_new.search_threads():
+ print t.get_thread_id()
+EOF
+notmuch search --sort=oldest-first --output=threads tag:inbox | sed s/^thread:// > EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "compare message ids"
+test_python <<EOF
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
+q_new = notmuch.Query(db, 'tag:inbox')
+q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
+for m in q_new.search_messages():
+ print m.get_message_id()
+EOF
+notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "get non-existent file"
+test_python <<EOF
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
+print db.find_message_by_filename("i-dont-exist")
+EOF
+test_expect_equal "$(cat OUTPUT)" "None"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='hooks'
+. ./test-lib.sh
+
+HOOK_DIR=${MAIL_DIR}/.notmuch/hooks
+
+create_echo_hook () {
+ local TOKEN="${RANDOM}"
+ mkdir -p ${HOOK_DIR}
+ cat <<EOF >"${HOOK_DIR}/${1}"
+#!/bin/sh
+echo "${TOKEN}" > ${3}
+EOF
+ chmod +x "${HOOK_DIR}/${1}"
+ echo "${TOKEN}" > ${2}
+}
+
+create_failing_hook () {
+ mkdir -p ${HOOK_DIR}
+ cat <<EOF >"${HOOK_DIR}/${1}"
+#!/bin/sh
+exit 13
+EOF
+ chmod +x "${HOOK_DIR}/${1}"
+}
+
+rm_hooks () {
+ rm -rf ${HOOK_DIR}
+}
+
+# add a message to generate mail dir and database
+add_message
+
+test_begin_subtest "pre-new is run"
+rm_hooks
+generate_message
+create_echo_hook "pre-new" expected output
+notmuch new > /dev/null
+test_expect_equal_file expected output
+
+test_begin_subtest "post-new is run"
+rm_hooks
+generate_message
+create_echo_hook "post-new" expected output
+notmuch new > /dev/null
+test_expect_equal_file expected output
+
+test_begin_subtest "pre-new is run before post-new"
+rm_hooks
+generate_message
+create_echo_hook "pre-new" pre-new.expected pre-new.output
+create_echo_hook "post-new" post-new.expected post-new.output
+notmuch new > /dev/null
+test_expect_equal_file post-new.expected post-new.output
+
+test_begin_subtest "pre-new non-zero exit status (hook status)"
+rm_hooks
+generate_message
+create_failing_hook "pre-new"
+output=`notmuch new 2>&1`
+test_expect_equal "$output" "Error: pre-new hook failed with status 13"
+
+# depends on the previous subtest leaving broken hook behind
+test_expect_code 1 "pre-new non-zero exit status (notmuch status)" "notmuch new"
+
+# depends on the previous subtests leaving 1 new message behind
+test_begin_subtest "pre-new non-zero exit status aborts new"
+rm_hooks
+output=$(NOTMUCH_NEW)
+test_expect_equal "$output" "Added 1 new message to the database."
+
+test_begin_subtest "post-new non-zero exit status (hook status)"
+rm_hooks
+generate_message
+create_failing_hook "post-new"
+NOTMUCH_NEW 2>output.stderr >output
+cat output.stderr >> output
+echo "Added 1 new message to the database." > expected
+echo "Error: post-new hook failed with status 13" >> expected
+test_expect_equal_file expected output
+
+# depends on the previous subtest leaving broken hook behind
+test_expect_code 1 "post-new non-zero exit status (notmuch status)" "notmuch new"
+
+# test_begin_subtest "hook without executable permissions"
+rm_hooks
+mkdir -p ${HOOK_DIR}
+cat <<EOF >"${HOOK_DIR}/pre-new"
+#!/bin/sh
+echo foo
+EOF
+output=`notmuch new 2>&1`
+test_expect_code 1 "hook without executable permissions" "notmuch new"
+
+# test_begin_subtest "hook execution failure"
+rm_hooks
+mkdir -p ${HOOK_DIR}
+cat <<EOF >"${HOOK_DIR}/pre-new"
+no hashbang, execl fails
+EOF
+chmod +x "${HOOK_DIR}/pre-new"
+test_expect_code 1 "hook execution failure" "notmuch new"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="argument parsing"
+. ./test-lib.sh
+
+test_begin_subtest "sanity check"
+$TEST_DIRECTORY/arg-test pos1 --keyword=one --string=foo pos2 --int=7 > OUTPUT
+cat <<EOF > EXPECTED
+keyword 1
+int 7
+string foo
+positional arg 1 pos1
+positional arg 2 pos2
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs test function sanity"
+. ./test-lib.sh
+
+test_begin_subtest "emacs test function sanity"
+test_emacs_expect_t 't'
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs address cleaning"
+. ./test-lib.sh
+
+test_begin_subtest "notmuch-test-address-clean part 1"
+test_emacs_expect_t '(notmuch-test-address-cleaning-1)'
+
+test_begin_subtest "notmuch-test-address-clean part 2"
+test_emacs_expect_t '(notmuch-test-address-cleaning-2)'
+
+test_begin_subtest "notmuch-test-address-clean part 3"
+test_emacs_expect_t '(notmuch-test-address-cleaning-3)'
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs notmuch-hello view"
+. ./test-lib.sh
+
+EXPECTED=$TEST_DIRECTORY/emacs.expected-output
+
+add_email_corpus
+
+test_begin_subtest "User-defined section with inbox tag"
+test_emacs "(let ((notmuch-hello-sections
+ (list (lambda () (notmuch-hello-insert-searches
+ \"Test\" '((\"inbox\" . \"tag:inbox\")))))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-new-section
+
+test_begin_subtest "User-defined section with empty, hidden entry"
+test_emacs "(let ((notmuch-hello-sections
+ (list (lambda () (notmuch-hello-insert-searches
+ \"Test-with-empty\"
+ '((\"inbox\" . \"tag:inbox\")
+ (\"doesnotexist\" . \"tag:doesnotexist\"))
+ :hide-empty-searches t)))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-with-empty
+
+test_begin_subtest "User-defined section, unread tag filtered out"
+test_emacs "(let ((notmuch-hello-sections
+ (list (lambda () (notmuch-hello-insert-tags-section
+ \"Test-with-filtered\"
+ :hide-tags '(\"unread\"))))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-hidden-tag
+
+test_begin_subtest "User-defined section, different query for counts"
+test_emacs "(let ((notmuch-hello-sections
+ (list (lambda () (notmuch-hello-insert-tags-section
+ \"Test-with-counts\"
+ :filter-count \"tag:signed\")))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-counts
+
+test_begin_subtest "Empty custom tags section"
+test_emacs "(let* ((widget (widget-create 'notmuch-hello-tags-section))
+ (notmuch-hello-sections (list (widget-value widget))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-empty-custom-tags-section
+
+test_begin_subtest "Empty custom queries section"
+test_emacs "(let* ((widget (widget-create 'notmuch-hello-query-section))
+ (notmuch-hello-sections (list (widget-value widget))))
+ (notmuch-hello)
+ (test-output))"
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-empty-custom-queries-section
+
+test_begin_subtest "Column alignment for tag/queries with long names"
+tag=a-very-long-tag # length carefully calculated for 80 characters window width
+notmuch tag +$tag '*'
+test_emacs '(notmuch-hello)
+ (test-output)'
+notmuch tag -$tag '*'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-long-names
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs notmuch-show view"
+. ./test-lib.sh
+
+EXPECTED=$TEST_DIRECTORY/emacs-show.expected-output
+
+add_email_corpus
+
+test_begin_subtest "Hiding Original Message region at beginning of a message"
+message_id='OriginalMessageHiding.1@notmuchmail.org'
+add_message \
+ [id]="$message_id" \
+ '[subject]="Hiding Original Message region at beginning of a message"' \
+ '[body]="-----Original Message-----
+Text here."'
+
+cat <<EOF >EXPECTED
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
+Subject: Hiding Original Message region at beginning of a message
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+
+[ 2-line hidden original message. Click/Enter to show. ]
+EOF
+
+test_emacs "(notmuch-show \"id:$message_id\")
+ (test-visible-output \"OUTPUT.raw\")"
+notmuch_date_sanitize < OUTPUT.raw > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "Bare subject #1"
+output=$(test_emacs '(notmuch-show-strip-re "Re: subject")')
+test_expect_equal "$output" '"subject"'
+
+test_begin_subtest "Bare subject #2"
+output=$(test_emacs '(notmuch-show-strip-re "re:Re: re: Re: re:subject")')
+test_expect_equal "$output" '"subject"'
+
+test_begin_subtest "Bare subject #3"
+output=$(test_emacs '(notmuch-show-strip-re "the cure: fix the regexp")')
+test_expect_equal "$output" '"the cure: fix the regexp"'
+
+test_begin_subtest "don't process cryptographic MIME parts"
+test_emacs '(let ((notmuch-crypto-process-mime nil))
+ (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-off
+
+test_begin_subtest "process cryptographic MIME parts"
+test_emacs '(let ((notmuch-crypto-process-mime t))
+ (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-on
+
+test_begin_subtest "process cryptographic MIME parts (w/ notmuch-show-toggle-process-crypto)"
+test_emacs '(let ((notmuch-crypto-process-mime nil))
+ (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
+ (notmuch-show-toggle-process-crypto)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-on
+
+test_begin_subtest "notmuch-show: don't elide non-matching messages"
+test_emacs '(let ((notmuch-show-only-matching-messages nil))
+ (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-off
+
+test_begin_subtest "notmuch-show: elide non-matching messages"
+test_emacs '(let ((notmuch-show-only-matching-messages t))
+ (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
+
+test_begin_subtest "notmuch-show: elide non-matching messages (w/ notmuch-show-toggle-elide-non-matching)"
+test_emacs '(let ((notmuch-show-only-matching-messages nil))
+ (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (notmuch-show-toggle-elide-non-matching)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
+
+test_begin_subtest "notmuch-show: elide non-matching messages (w/ prefix arg to notmuch-show)"
+test_emacs '(let ((notmuch-show-only-matching-messages nil))
+ (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread t)
+ (notmuch-test-wait)
+ (test-visible-output))'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
+
+test_begin_subtest "notmuch-show: disable indentation of thread content (w/ notmuch-show-toggle-thread-indentation)"
+test_emacs '(notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (notmuch-test-wait)
+ (notmuch-show-toggle-thread-indentation)
+ (test-visible-output)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-indent-thread-content-off
+
+test_begin_subtest "id buttonization"
+add_message '[body]="
+id:abc
+id:abc.def. id:abc,def, id:abc;def; id:abc:def:
+id:foo@bar.?baz? id:foo@bar!.baz!
+(id:foo@bar.baz) [id:foo@bar.baz]
+id:foo@bar.baz...
+id:2+2=5
+id:=_-:/.[]@$%+
+id:abc)def
+id:ab\"c def
+id:\"abc\"def
+id:\"ab\"\"c\"def
+id:\"ab c\"def
+id:\"abc\".def
+id:\"abc
+\"
+id:)
+id:
+cid:xxx
+mid:abc mid:abc/def
+mid:abc%20def
+mid:abc. mid:abc, mid:abc;"'
+test_emacs '(notmuch-show "id:'$gen_msg_id'")
+ (notmuch-test-mark-links)
+ (test-visible-output "OUTPUT.raw")'
+cat <<EOF >EXPECTED
+Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
+Subject: id buttonization
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: GENERATED_DATE
+
+<<id:abc>>
+<<id:abc.def>>. <<id:abc,def>>, <<id:abc;def>>; <<id:abc:def>>:
+<<id:foo@bar.?baz>>? <<id:foo@bar!.baz>>!
+(<<id:foo@bar.baz>>) [<<id:foo@bar.baz>>]
+<<id:foo@bar.baz>>...
+<<id:2+2=5>>
+<<id:=_-:/.[]@$%+>>
+<<id:abc>>)def
+<<id:ab"c>> def
+<<id:"abc">>def
+<<id:"ab""c">>def
+<<id:"ab c">>def
+<<id:"abc">>.def
+id:"abc
+"
+id:)
+id:
+cid:xxx
+<<mid:abc>> <<mid:abc/def>>
+<<mid:abc%20def>>
+<<mid:abc>>. <<mid:abc>>, <<mid:abc>>;
+EOF
+notmuch_date_sanitize < OUTPUT.raw > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+
+test_begin_subtest "Show handles subprocess errors"
+cat > notmuch_fail <<EOF
+#!/bin/sh
+echo This is output
+echo This is an error >&2
+exit 1
+EOF
+chmod a+x notmuch_fail
+test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
+ (with-current-buffer \"*Messages*\" (erase-buffer))
+ (condition-case err
+ (notmuch-show \"*\")
+ (error (message \"%s\" (second err))))
+ (notmuch-test-wait)
+ (with-current-buffer \"*Messages*\"
+ (test-output \"MESSAGES\"))
+ (with-current-buffer \"*Notmuch errors*\"
+ (test-output \"ERROR\"))
+ (test-output))"
+test_expect_equal "$(notmuch_emacs_error_sanitize notmuch_fail OUTPUT MESSAGES ERROR)" "\
+=== OUTPUT ===
+=== MESSAGES ===
+This is an error (see *Notmuch errors* for more details)
+=== ERROR ===
+[XXX]
+This is an error
+command: YYY/notmuch_fail show --format\\=sexp --format-version\\=1 --exclude\\=false \\' \\* \\'
+exit status: 1
+stderr:
+This is an error
+stdout:
+This is output"
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs tree view interface"
+. test-lib.sh
+
+EXPECTED=$TEST_DIRECTORY/tree.expected-output
+
+add_email_corpus
+
+test_begin_subtest "Basic notmuch-tree view in emacs"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
+
+test_begin_subtest "Refreshed notmuch-tree view in emacs"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (notmuch-tree-refresh-view)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
+
+# In the following tag tests we make sure the display is updated
+# correctly and, in a separate test, that the database is updated
+# correctly.
+
+test_begin_subtest "Tag message in notmuch tree view (display)"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (forward-line)
+ (notmuch-tree-tag (list "+test_tag"))
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox-tagged
+
+test_begin_subtest "Tag message in notmuch tree view (database)"
+output=$(notmuch search --output=messages 'tag:test_tag')
+test_expect_equal "$output" "id:877h1wv7mg.fsf@inf-8657.int-evry.fr"
+
+test_begin_subtest "Untag message in notmuch tree view"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (forward-line)
+ (notmuch-tree-tag (list "-test_tag"))
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
+
+test_begin_subtest "Untag message in notmuch tree view (database)"
+output=$(notmuch search --output=messages 'tag:test_tag')
+test_expect_equal "$output" ""
+
+test_begin_subtest "Tag thread in notmuch tree view"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ ;; move to a sizable thread
+ (forward-line 26)
+ (notmuch-tree-tag-thread (list "+test_thread_tag"))
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox-thread-tagged
+
+test_begin_subtest "Tag message in notmuch tree view (database)"
+output=$(notmuch search --output=messages 'tag:test_thread_tag')
+test_expect_equal "$output" \
+"id:87ocn0qh6d.fsf@yoom.home.cworth.org
+id:20091118005040.GA25380@dottiness.seas.harvard.edu
+id:yunaayketfm.fsf@aiko.keithp.com
+id:87fx8can9z.fsf@vertex.dottedmag
+id:20091117203301.GV3165@dottiness.seas.harvard.edu
+id:87iqd9rn3l.fsf@vertex.dottedmag
+id:20091117190054.GU3165@dottiness.seas.harvard.edu"
+
+test_begin_subtest "Untag thread in notmuch tree view"
+test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ ;; move to the same sizable thread as above
+ (forward-line 26)
+ (notmuch-tree-tag-thread (list "-test_thread_tag"))
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
+
+test_begin_subtest "Untag message in notmuch tree view (database)"
+output=$(notmuch search --output=messages 'tag:test_thread_tag')
+test_expect_equal "$output" ""
+
+test_begin_subtest "Navigation of notmuch-hello to search results"
+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 OUTPUT $EXPECTED/notmuch-tree-tag-inbox
+
+test_begin_subtest "Tree view of a single thread (from 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-thread)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-single-thread
+
+test_begin_subtest "Tree view of a single thread (from show)"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-search-show-thread)
+ (notmuch-tree-from-show-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-single-thread
+
+test_begin_subtest "Message window of tree view"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-search-next-thread)
+ (notmuch-tree-from-search-thread)
+ (notmuch-test-wait)
+ (select-window notmuch-tree-message-window)
+ (test-output)
+ (delete-other-windows)'
+cp OUTPUT /tmp/mjwout
+test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-show-window
+
+test_begin_subtest "Stash id"
+output=$(test_emacs '(notmuch-tree "id:1258498485-sup-142@elly")
+ (notmuch-test-wait)
+ (notmuch-show-stash-message-id)')
+test_expect_equal "$output" "\"Stashed: id:1258498485-sup-142@elly\""
+
+test_begin_subtest "Move to next matching message"
+output=$(test_emacs '(notmuch-tree "from:cworth")
+ (notmuch-test-wait)
+ (notmuch-tree-next-matching-message)
+ (notmuch-show-stash-message-id)')
+test_expect_equal "$output" "\"Stashed: id:878we4qdqf.fsf@yoom.home.cworth.org\""
+
+test_begin_subtest "Move to next thread"
+output=$(test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (forward-line 26)
+ (notmuch-tree-next-thread)
+ (notmuch-show-stash-message-id)')
+test_expect_equal "$output" "\"Stashed: id:1258471718-6781-1-git-send-email-dottedmag@dottedmag.net\""
+
+test_begin_subtest "Move to previous thread"
+output=$(test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (forward-line 26)
+ (notmuch-tree-prev-thread)
+ (notmuch-show-stash-message-id)')
+test_expect_equal "$output" "\"Stashed: id:20091117190054.GU3165@dottiness.seas.harvard.edu\""
+
+test_begin_subtest "Move to previous previous thread"
+output=$(test_emacs '(notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (forward-line 26)
+ (notmuch-tree-prev-thread)
+ (notmuch-tree-prev-thread)
+ (notmuch-show-stash-message-id)')
+test_expect_equal "$output" "\"Stashed: id:1258493565-13508-1-git-send-email-keithp@keithp.com\""
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='messages with missing headers'
+. ./test-lib.sh
+
+# Notmuch requires at least one of from, subject, or to or it will
+# ignore the file. Generate two messages so that together they cover
+# all possible missing headers. We also give one of the messages a
+# date to ensure stable result ordering.
+
+cat <<EOF > "${MAIL_DIR}/msg-2"
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Fri, 05 Jan 2001 15:43:57 +0000
+
+Body
+EOF
+
+cat <<EOF > "${MAIL_DIR}/msg-1"
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+
+Body
+EOF
+
+NOTMUCH_NEW
+
+test_begin_subtest "Search: text"
+output=$(notmuch search '*' | notmuch_search_sanitize)
+test_expect_equal "$output" "\
+thread:XXX 2001-01-05 [1/1] (null); (inbox unread)
+thread:XXX 1970-01-01 [1/1] Notmuch Test Suite; (inbox unread)"
+
+test_begin_subtest "Search: json"
+output=$(notmuch search --format=json '*' | notmuch_search_sanitize)
+test_expect_equal_json "$output" '
+[
+ {
+ "authors": "",
+ "date_relative": "2001-01-05",
+ "matched": 1,
+ "subject": "",
+ "tags": [
+ "inbox",
+ "unread"
+ ],
+ "thread": "XXX",
+ "timestamp": 978709437,
+ "total": 1,
+ "query": ["id:notmuch-sha1-7a6e4eac383ef958fcd3ebf2143db71b8ff01161", null]
+ },
+ {
+ "authors": "Notmuch Test Suite",
+ "date_relative": "1970-01-01",
+ "matched": 1,
+ "subject": "",
+ "tags": [
+ "inbox",
+ "unread"
+ ],
+ "thread": "XXX",
+ "timestamp": 0,
+ "total": 1,
+ "query": ["id:notmuch-sha1-ca55943aff7a72baf2ab21fa74fab3d632401334", null]
+ }
+]'
+
+test_begin_subtest "Show: text"
+output=$(notmuch show '*' | notmuch_show_sanitize)
+test_expect_equal "$output" "\
+\fmessage{ id:notmuch-sha1-7a6e4eac383ef958fcd3ebf2143db71b8ff01161 depth:0 match:1 excluded:0 filename:/XXX/mail/msg-2
+\fheader{
+ (2001-01-05) (inbox unread)
+Subject: (null)
+From: (null)
+To: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Fri, 05 Jan 2001 15:43:57 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+Body
+\fpart}
+\fbody}
+\fmessage}
+\fmessage{ id:notmuch-sha1-ca55943aff7a72baf2ab21fa74fab3d632401334 depth:0 match:1 excluded:0 filename:/XXX/mail/msg-1
+\fheader{
+Notmuch Test Suite <test_suite@notmuchmail.org> (1970-01-01) (inbox unread)
+Subject: (null)
+From: Notmuch Test Suite <test_suite@notmuchmail.org>
+Date: Thu, 01 Jan 1970 00:00:00 +0000
+\fheader}
+\fbody{
+\fpart{ ID: 1, Content-type: text/plain
+Body
+\fpart}
+\fbody}
+\fmessage}"
+
+test_begin_subtest "Show: json"
+output=$(notmuch show --format=json '*' | notmuch_json_show_sanitize)
+expected=$(notmuch_json_show_sanitize <<EOF
+[
+ [
+ [
+ {
+ "body": [
+ {
+ "content": "Body\n",
+ "content-type": "text/plain",
+ "id": 1
+ }
+ ],
+ "date_relative": "2001-01-05",
+ "excluded": false,
+ "filename": "YYYYY",
+ "headers": {
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000",
+ "From": "",
+ "Subject": "",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>"
+ },
+ "id": "XXXXX",
+ "match": true,
+ "tags": [
+ "inbox",
+ "unread"
+ ],
+ "timestamp": 978709437
+ },
+ []
+ ]
+ ],
+ [
+ [
+ {
+ "body": [
+ {
+ "content": "Body\n",
+ "content-type": "text/plain",
+ "id": 1
+ }
+ ],
+ "date_relative": "1970-01-01",
+ "excluded": false,
+ "filename": "YYYYY",
+ "headers": {
+ "Date": "Thu, 01 Jan 1970 00:00:00 +0000",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Subject": ""
+ },
+ "id": "XXXXX",
+ "match": true,
+ "tags": [
+ "inbox",
+ "unread"
+ ],
+ "timestamp": 0
+ },
+ []
+ ]
+ ]
+]
+EOF
+)
+test_expect_equal_json "$output" "$expected"
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="hex encoding and decoding"
+. ./test-lib.sh
+
+test_begin_subtest "round trip"
+find $TEST_DIRECTORY/corpus -type f -print | sort | xargs cat > EXPECTED
+$TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "punctuation"
+tag1='comic_swear=$&^%$^%\\//-+$^%$'
+tag_enc1=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag1")
+test_expect_equal "$tag_enc1" "comic_swear=%24%26%5e%25%24%5e%25%5c%5c%2f%2f-+%24%5e%25%24"
+
+test_begin_subtest "round trip newlines"
+printf 'this\n tag\t has\n spaces\n' > EXPECTED.$test_count
+$TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED.$test_count |\
+ $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "round trip 8bit chars"
+echo '%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a' > EXPECTED.$test_count
+$TEST_DIRECTORY/hex-xcode --direction=decode < EXPECTED.$test_count |\
+ $TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "round trip (in-place)"
+find $TEST_DIRECTORY/corpus -type f -print | sort | xargs cat > EXPECTED
+$TEST_DIRECTORY/hex-xcode --in-place --direction=encode < EXPECTED |\
+ $TEST_DIRECTORY/hex-xcode --in-place --direction=decode > OUTPUT
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "punctuation (in-place)"
+tag1='comic_swear=$&^%$^%\\//-+$^%$'
+tag_enc1=$($TEST_DIRECTORY/hex-xcode --in-place --direction=encode "$tag1")
+test_expect_equal "$tag_enc1" "comic_swear=%24%26%5e%25%24%5e%25%5c%5c%2f%2f-+%24%5e%25%24"
+
+test_begin_subtest "round trip newlines (in-place)"
+printf 'this\n tag\t has\n spaces\n' > EXPECTED.$test_count
+$TEST_DIRECTORY/hex-xcode --in-place --direction=encode < EXPECTED.$test_count |\
+ $TEST_DIRECTORY/hex-xcode --in-place --direction=decode > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_begin_subtest "round trip 8bit chars (in-place)"
+echo '%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a' > EXPECTED.$test_count
+$TEST_DIRECTORY/hex-xcode --in-place --direction=decode < EXPECTED.$test_count |\
+ $TEST_DIRECTORY/hex-xcode --in-place --direction=encode > OUTPUT.$test_count
+test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="date/time parser module"
+. ./test-lib.sh
+
+# Sanity/smoke tests for the date/time parser independent of notmuch
+
+_date ()
+{
+ date -d "$*" +%s
+}
+
+_parse_time ()
+{
+ ${TEST_DIRECTORY}/parse-time --format=%s "$*"
+}
+
+test_begin_subtest "date(1) default format without TZ code"
+test_expect_equal "$(_parse_time Fri Aug 3 23:06:06 2012)" "$(_date Fri Aug 3 23:06:06 2012)"
+
+test_begin_subtest "date(1) --rfc-2822 format"
+test_expect_equal "$(_parse_time Fri, 03 Aug 2012 23:07:46 +0100)" "$(_date Fri, 03 Aug 2012 23:07:46 +0100)"
+
+test_begin_subtest "date(1) --rfc=3339=seconds format"
+test_expect_equal "$(_parse_time 2012-08-03 23:09:37+03:00)" "$(_date 2012-08-03 23:09:37+03:00)"
+
+test_begin_subtest "Date parser tests"
+REFERENCE=$(_date Tue Jan 11 11:11:00 +0000 2011)
+cat <<EOF > INPUT
+now ==> Tue Jan 11 11:11:00 +0000 2011
+2010-1-1 ==> ERROR: DATEFORMAT
+Jan 2 ==> Sun Jan 02 11:11:00 +0000 2011
+Mon ==> Mon Jan 10 11:11:00 +0000 2011
+last Friday ==> ERROR: FORMAT
+2 hours ago ==> Tue Jan 11 09:11:00 +0000 2011
+last month ==> Sat Dec 11 11:11:00 +0000 2010
+month ago ==> Sat Dec 11 11:11:00 +0000 2010
+two mo ==> Thu Nov 11 11:11:00 +0000 2010
+3M ==> Mon Oct 11 11:11:00 +0000 2010
+4-mont ==> Sat Sep 11 11:11:00 +0000 2010
+5m ==> Tue Jan 11 11:06:00 +0000 2011
+dozen mi ==> Tue Jan 11 10:59:00 +0000 2011
+8am ==> Tue Jan 11 08:00:00 +0000 2011
+9:15 ==> Tue Jan 11 09:15:00 +0000 2011
+12:34 ==> Tue Jan 11 12:34:00 +0000 2011
+monday ==> Mon Jan 10 11:11:00 +0000 2011
+yesterday ==> Mon Jan 10 11:11:00 +0000 2011
+tomorrow ==> ERROR: KEYWORD
+ ==> Tue Jan 11 11:11:00 +0000 2011 # empty string is reference time
+
+Aug 3 23:06:06 2012 ==> Fri Aug 03 23:06:06 +0000 2012 # date(1) default format without TZ code
+Fri, 03 Aug 2012 23:07:46 +0100 ==> Fri Aug 03 22:07:46 +0000 2012 # rfc-2822
+2012-08-03 23:09:37+03:00 ==> Fri Aug 03 20:09:37 +0000 2012 # rfc-3339 seconds
+
+10s ==> Tue Jan 11 11:10:50 +0000 2011
+19701223s ==> Fri May 28 10:37:17 +0000 2010
+19701223 ==> Wed Dec 23 11:11:00 +0000 1970
+
+19701223 +0100 ==> Wed Dec 23 11:11:00 +0000 1970 # Timezone is ignored without an error
+
+today ==^^> Wed Jan 12 00:00:00 +0000 2011
+today ==^> Tue Jan 11 23:59:59 +0000 2011
+today ==_> Tue Jan 11 00:00:00 +0000 2011
+
+this week ==^^> Sun Jan 16 00:00:00 +0000 2011
+this week ==^> Sat Jan 15 23:59:59 +0000 2011
+this week ==_> Sun Jan 09 00:00:00 +0000 2011
+
+two months ago ==> Thu Nov 11 11:11:00 +0000 2010
+two months ==> Thu Nov 11 11:11:00 +0000 2010
+
+@1348569850 ==> Tue Sep 25 10:44:10 +0000 2012
+@10 ==> Thu Jan 01 00:00:10 +0000 1970
+EOF
+
+${TEST_DIRECTORY}/parse-time --ref=${REFERENCE} < INPUT > OUTPUT
+test_expect_equal_file INPUT OUTPUT
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="date:since..until queries"
+. ./test-lib.sh
+
+add_email_corpus
+
+test_begin_subtest "Absolute date range"
+output=$(notmuch search date:2010-12-16..12/16/2010 | notmuch_search_sanitize)
+test_expect_equal "$output" "thread:XXX 2010-12-16 [1/1] Olivier Berger; Essai accentué (inbox unread)"
+
+test_begin_subtest "Absolute time range with TZ"
+notmuch search date:18-Nov-2009_02:19:26-0800..2009-11-18_04:49:52-06:00 | notmuch_search_sanitize > OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX 2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
+thread:XXX 2009-11-18 [1/2] Carl Worth| Jan Janak; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+thread:XXX 2009-11-18 [1/3] Carl Worth| Aron Griffis, Keith Packard; [notmuch] archive (inbox unread)
+thread:XXX 2009-11-18 [1/2] Carl Worth| Keith Packard; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+#
+# Copyright (c) 2013 Aaron Ecay
+#
+
+test_description='test of proper handling of in-reply-to and references headers'
+
+# This test makes sure that the thread structure in the notmuch
+# database is constructed properly, even in the presence of
+# non-RFC-compliant headers'
+
+. ./test-lib.sh
+
+test_begin_subtest "Use References when In-Reply-To is broken"
+add_message '[id]="foo@one.com"' \
+ '[subject]=one'
+add_message '[in-reply-to]="mumble"' \
+ '[references]="<foo@one.com>"' \
+ '[subject]="Re: one"'
+output=$(notmuch show --format=json 'subject:one' | notmuch_json_show_sanitize)
+expected='[[[{"id": "foo@one.com",
+ "match": true,
+ "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437,
+ "date_relative": "2001-01-05",
+ "tags": ["inbox", "unread"],
+ "headers": {"Subject": "one",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
+ "body": [{"id": 1,
+ "content-type": "text/plain",
+ "content": "This is just a test message (#1)\n"}]},
+ [[{"id": "msg-002@notmuch-test-suite",
+ "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05",
+ "tags": ["inbox", "unread"], "headers": {"Subject": "Re: one",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
+ "body": [{"id": 1, "content-type": "text/plain",
+ "content": "This is just a test message (#2)\n"}]}, []]]]]]'
+expected=`echo "$expected" | notmuch_json_show_sanitize`
+test_expect_equal_json "$output" "$expected"
+
+test_begin_subtest "Prefer References to In-Reply-To"
+add_message '[id]="foo@two.com"' \
+ '[subject]=two'
+add_message '[in-reply-to]="<bar@baz.com>"' \
+ '[references]="<foo@two.com>"' \
+ '[subject]="Re: two"'
+output=$(notmuch show --format=json 'subject:two' | notmuch_json_show_sanitize)
+expected='[[[{"id": "foo@two.com",
+ "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "two",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
+ "body": [{"id": 1, "content-type": "text/plain",
+ "content": "This is just a test message (#3)\n"}]},
+ [[{"id": "msg-004@notmuch-test-suite", "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "Re: two",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
+ "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#4)\n"}]},
+ []]]]]]'
+expected=`echo "$expected" | notmuch_json_show_sanitize`
+test_expect_equal_json "$output" "$expected"
+
+test_begin_subtest "Use In-Reply-To when no References"
+add_message '[id]="foo@three.com"' \
+ '[subject]="three"'
+add_message '[in-reply-to]="<foo@three.com>"' \
+ '[subject]="Re: three"'
+output=$(notmuch show --format=json 'subject:three' | notmuch_json_show_sanitize)
+expected='[[[{"id": "foo@three.com", "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "three",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#5)\n"}]},
+ [[{"id": "msg-006@notmuch-test-suite", "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "Re: three",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#6)\n"}]},
+ []]]]]]'
+expected=`echo "$expected" | notmuch_json_show_sanitize`
+test_expect_equal_json "$output" "$expected"
+
+test_begin_subtest "Use last Reference"
+add_message '[id]="foo@four.com"' \
+ '[subject]="four"'
+add_message '[id]="bar@four.com"' \
+ '[subject]="not-four"'
+add_message '[in-reply-to]="<baz@four.com>"' \
+ '[references]="<baz@four.com> <foo@four.com>"' \
+ '[subject]="neither"'
+output=$(notmuch show --format=json 'subject:four' | notmuch_json_show_sanitize)
+expected='[[[{"id": "foo@four.com", "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "four",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#7)\n"}]},
+ [[{"id": "msg-009@notmuch-test-suite", "match": false, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "neither",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#9)\n"}]},
+ []]]]], [[{"id": "bar@four.com", "match": true, "excluded": false,
+ "filename": "YYYYY",
+ "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
+ "headers": {"Subject": "not-four",
+ "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
+ "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
+ "content-type": "text/plain", "content": "This is just a test message (#8)\n"}]}, []]]]'
+expected=`echo "$expected" | notmuch_json_show_sanitize`
+test_expect_equal_json "$output" "$expected"
+
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch show"'
+
+. ./test-lib.sh
+
+add_email_corpus
+
+test_begin_subtest "exit code for show invalid query"
+notmuch show foo..
+exit_code=$?
+test_expect_equal 1 $exit_code
+
+test_done
--- /dev/null
+#!/usr/bin/env bash
+test_description="database upgrade"
+
+. ./test-lib.sh
+
+dbtarball=database-v1.tar.xz
+
+# XXX: Accomplish the same with test lib helpers
+if [ ! -e ${TEST_DIRECTORY}/test-databases/${dbtarball} ]; then
+ test_subtest_missing_external_prereq_["${dbtarball} - fetch with 'make download-test-databases'"]=t
+fi
+
+test_expect_success \
+ 'database checksum' \
+ '( cd $TEST_DIRECTORY/test-databases &&
+ sha256sum --quiet --check --status ${dbtarball}.sha256 )'
+
+tar xf $TEST_DIRECTORY/test-databases/${dbtarball} -C ${MAIL_DIR} --strip-components=1
+
+test_begin_subtest "folder: search does not work with old database version"
+output=$(notmuch search folder:foo)
+test_expect_equal "$output" ""
+
+test_begin_subtest "path: search does not work with old database version"
+output=$(notmuch search path:foo)
+test_expect_equal "$output" ""
+
+test_expect_success 'pre upgrade dump' 'notmuch dump | sort > pre-upgrade-dump'
+
+test_begin_subtest "database upgrade from format version 1"
+output=$(notmuch new | sed -e 's/^Backing up tags to .*$/Backing up tags to FILENAME/')
+test_expect_equal "$output" "\
+Welcome to a new version of notmuch! Your database will now be upgraded.
+This process is safe to interrupt.
+Backing up tags to FILENAME
+Your notmuch database has now been upgraded to database format version 2.
+No new mail."
+
+test_begin_subtest "tag backup matches pre-upgrade dump"
+gunzip -c ${MAIL_DIR}/.notmuch/dump-*.gz | sort > backup-dump
+test_expect_equal_file pre-upgrade-dump backup-dump
+
+test_begin_subtest "folder: no longer matches in the middle of path"
+output=$(notmuch search folder:baz)
+test_expect_equal "$output" ""
+
+test_begin_subtest "folder: search"
+output=$(notmuch search --output=files folder:foo | notmuch_search_files_sanitize | sort)
+test_expect_equal "$output" "MAIL_DIR/foo/06:2,
+MAIL_DIR/foo/cur/07:2,
+MAIL_DIR/foo/cur/08:2,
+MAIL_DIR/foo/new/03:2,
+MAIL_DIR/foo/new/09:2,
+MAIL_DIR/foo/new/10:2,"
+
+test_begin_subtest "top level folder: search"
+output=$(notmuch search --output=files folder:'""' | notmuch_search_files_sanitize | sort)
+# bar/18:2, is a duplicate of cur/51:2,
+test_expect_equal "$output" "MAIL_DIR/01:2,
+MAIL_DIR/02:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/cur/29:2,
+MAIL_DIR/cur/30:2,
+MAIL_DIR/cur/31:2,
+MAIL_DIR/cur/32:2,
+MAIL_DIR/cur/33:2,
+MAIL_DIR/cur/34:2,
+MAIL_DIR/cur/35:2,
+MAIL_DIR/cur/36:2,
+MAIL_DIR/cur/37:2,
+MAIL_DIR/cur/38:2,
+MAIL_DIR/cur/39:2,
+MAIL_DIR/cur/40:2,
+MAIL_DIR/cur/41:2,
+MAIL_DIR/cur/42:2,
+MAIL_DIR/cur/43:2,
+MAIL_DIR/cur/44:2,
+MAIL_DIR/cur/45:2,
+MAIL_DIR/cur/46:2,
+MAIL_DIR/cur/47:2,
+MAIL_DIR/cur/48:2,
+MAIL_DIR/cur/49:2,
+MAIL_DIR/cur/50:2,
+MAIL_DIR/cur/51:2,
+MAIL_DIR/cur/52:2,
+MAIL_DIR/cur/53:2,
+MAIL_DIR/new/04:2,"
+
+test_begin_subtest "path: search"
+output=$(notmuch search --output=files path:"bar" | notmuch_search_files_sanitize | sort)
+# cur/51:2, is a duplicate of bar/18:2,
+test_expect_equal "$output" "MAIL_DIR/bar/17:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/cur/51:2,"
+
+test_begin_subtest "top level path: search"
+output=$(notmuch search --output=files path:'""' | notmuch_search_files_sanitize | sort)
+test_expect_equal "$output" "MAIL_DIR/01:2,
+MAIL_DIR/02:2,"
+
+test_begin_subtest "recursive path: search"
+output=$(notmuch search --output=files path:"bar/**" | notmuch_search_files_sanitize | sort)
+# cur/51:2, is a duplicate of bar/18:2,
+test_expect_equal "$output" "MAIL_DIR/bar/17:2,
+MAIL_DIR/bar/18:2,
+MAIL_DIR/bar/baz/05:2,
+MAIL_DIR/bar/baz/23:2,
+MAIL_DIR/bar/baz/24:2,
+MAIL_DIR/bar/baz/cur/25:2,
+MAIL_DIR/bar/baz/cur/26:2,
+MAIL_DIR/bar/baz/new/27:2,
+MAIL_DIR/bar/baz/new/28:2,
+MAIL_DIR/bar/cur/19:2,
+MAIL_DIR/bar/cur/20:2,
+MAIL_DIR/bar/new/21:2,
+MAIL_DIR/bar/new/22:2,
+MAIL_DIR/cur/51:2,"
+
+test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="argument parsing"
-. ./test-lib.sh
-
-test_begin_subtest "sanity check"
-$TEST_DIRECTORY/arg-test pos1 --keyword=one --string=foo pos2 --int=7 > OUTPUT
-cat <<EOF > EXPECTED
-keyword 1
-int 7
-string foo
-positional arg 1 pos1
-positional arg 2 pos2
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='atomicity'
-. ./test-lib.sh
-
-# This script tests the effects of killing and restarting "notmuch
-# new" at arbitrary points. If notmuch new is properly atomic, the
-# final database contents should be the same regardless of when (or
-# if) it is killed and restarted.
-
-if test_require_external_prereq gdb; then
-
-# Create a maildir structure to also stress flag synchronization
- mkdir $MAIL_DIR/cur
- mkdir $MAIL_DIR/new
- mkdir $MAIL_DIR/tmp
- mkdir $MAIL_DIR/.remove-dir
-
- # Prepare the initial database
- generate_message [subject]='Duplicate' [filename]='duplicate:2,' [dir]=cur
- generate_message [subject]='Remove' [filename]='remove:2,' [dir]=cur
- generate_message [subject]='"Remove duplicate"' [filename]='remove-duplicate:2,' [dir]=cur
- cp $MAIL_DIR/cur/remove-duplicate:2, $MAIL_DIR/cur/remove-duplicate-copy:2,
- generate_message [subject]='Rename' [filename]='rename:2,' [dir]=cur
- generate_message [subject]='"Rename duplicate"' [filename]='rename-duplicate:2,' [dir]=cur
- generate_message [subject]='"Move 1"' [filename]='move1:2,' [dir]=cur
- generate_message [subject]='"Move 2"' [filename]='move2:2,' [dir]=new
- generate_message [subject]='Flag' [filename]='flag:2,' [dir]=cur
- generate_message [subject]='"Flag duplicate"' [filename]='flag-duplicate:2,' [dir]=cur
- cp $MAIL_DIR/cur/flag-duplicate:2, $MAIL_DIR/cur/flag-duplicate-copy:2,F
- generate_message [subject]='"Remove directory"' [filename]='remove-directory:2,' [dir]=.remove-dir
- generate_message [subject]='"Remove directory duplicate"' [filename]='remove-directory-duplicate:2,' [dir]=.remove-dir
- cp $MAIL_DIR/.remove-dir/remove-directory-duplicate:2, $MAIL_DIR/cur/
- notmuch new > /dev/null
-
- # Make all maildir changes, but *don't* update the database
- generate_message [subject]='Added' [filename]='added:2,' [dir]=cur
- cp $MAIL_DIR/cur/duplicate:2, $MAIL_DIR/cur/duplicate-copy:2,
- generate_message [subject]='"Add duplicate"' [filename]='add-duplicate:2,' [dir]=cur
- generate_message [subject]='"Add duplicate copy"' [filename]='add-duplicate-copy:2,' [dir]=cur
- rm $MAIL_DIR/cur/remove:2,
- rm $MAIL_DIR/cur/remove-duplicate-copy:2,
- mv $MAIL_DIR/cur/rename:2, $MAIL_DIR/cur/renamed:2,
- mv $MAIL_DIR/cur/rename-duplicate:2, $MAIL_DIR/cur/renamed-duplicate:2,
- mv $MAIL_DIR/cur/move1:2, $MAIL_DIR/new/move1:2,
- mv $MAIL_DIR/new/move2:2, $MAIL_DIR/cur/move2:2,
- mv $MAIL_DIR/cur/flag:2, $MAIL_DIR/cur/flag:2,F
- rm $MAIL_DIR/cur/flag-duplicate-copy:2,F
- rm $MAIL_DIR/.remove-dir/remove-directory:2,
- rm $MAIL_DIR/.remove-dir/remove-directory-duplicate:2,
- rmdir $MAIL_DIR/.remove-dir
-
- # Prepare a snapshot of the updated maildir. The gdb script will
- # update the database in this snapshot as it goes.
- cp -a $MAIL_DIR $MAIL_DIR.snap
- cp ${NOTMUCH_CONFIG} ${NOTMUCH_CONFIG}.snap
- NOTMUCH_CONFIG=${NOTMUCH_CONFIG}.snap notmuch config set database.path $MAIL_DIR.snap
-
-
-
- # Execute notmuch new and, at every call to rename, snapshot the
- # database, run notmuch new again on the snapshot, and capture the
- # results of search.
- #
- # -tty /dev/null works around a conflict between the 'timeout' wrapper
- # and gdb's attempt to control the TTY.
- export MAIL_DIR
- gdb -tty /dev/null -batch -x $TEST_DIRECTORY/atomicity.gdb notmuch >/dev/null 2>/dev/null
-
- # Get the final, golden output
- notmuch search '*' > expected
-
- # Check output against golden output
- outcount=$(cat outcount)
- echo -n > searchall
- echo -n > expectall
- for ((i = 0; i < $outcount; i++)); do
- if ! cmp -s search.$i expected; then
- # Find the range of interruptions that match this output
- for ((end = $i + 1 ; end < $outcount; end++)); do
- if ! cmp -s search.$i search.$end; then
- break
- fi
- done
- echo "When interrupted after $test/backtrace.$(expr $i - 1) (abort points $i-$(expr $end - 1))" >> searchall
- cat search.$i >> searchall
- cat expected >> expectall
- echo >> searchall
- echo >> expectall
-
- i=$(expr $end - 1)
- fi
- done
-fi
-
-test_begin_subtest '"notmuch new" is idempotent under arbitrary aborts'
-test_expect_equal_file searchall expectall
-
-test_expect_success "detected $outcount>10 abort points" "test $outcount -gt 10"
-
-test_done
shell touch inodes
+# work around apparent issue with lazy library loading on some
+# platforms
+set breakpoint pending on
+
break rename
commands
# As an optimization, only consider snapshots after a Xapian commit.
+++ /dev/null
-#!/usr/bin/env bash
-test_description="author reordering;"
-. ./test-lib.sh
-
-test_begin_subtest "Adding parent message"
-generate_message [body]=findme [id]=new-parent-id [subject]=author-reorder-threadtest '[from]="User <user@example.com>"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Adding initial child message"
-generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User1 <user1@example.com>"' '[date]="Sat, 01 Jan 2000 12:01:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Adding second child message"
-generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User2 <user2@example.com>"' '[date]="Sat, 01 Jan 2000 12:02:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching when all three messages match"
-output=$(notmuch search findme | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [3/3] User, User1, User2; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Searching when two messages match"
-output=$(notmuch search User1 or User2 | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [2/3] User1, User2| User; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Searching when only one message matches"
-output=$(notmuch search User2 | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/3] User2| User, User1; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Searching when only first message matches"
-output=$(notmuch search User | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/3] User| User1, User2; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Adding duplicate author"
-generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User1 <user1@example.com>"' '[date]="Sat, 01 Jan 2000 12:03:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching when all four messages match"
-output=$(notmuch search findme | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [4/4] User, User1, User2; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Adding non-monotonic child message"
-generate_message [body]=findme "[in-reply-to]=\<new-parent-id\>" [subject]=author-reorder-threadtest '[from]="User0 <user0@example.com>"' '[date]="Sat, 01 Jan 2000 11:00:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching non-monotonic messages (oldest-first)"
-output=$(notmuch search --sort=oldest-first findme | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [5/5] User0, User, User1, User2; author-reorder-threadtest (inbox unread)"
-
-test_begin_subtest "Searching non-monotonic messages (newest-first)"
-output=$(notmuch search --sort=newest-first findme | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [5/5] User0, User, User1, User2; author-reorder-threadtest (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-#
-# Copyright (c) 2005 Junio C Hamano
-#
-
-test_description='the test framework itself.'
-
-################################################################
-# It appears that people try to run tests without building...
-
-if ! test -x ../notmuch
-then
- echo >&2 'You do not seem to have built notmuch yet.'
- exit 1
-fi
-
-. ./test-lib.sh
-
-################################################################
-# Test harness
-test_expect_success 'success is reported like this' '
- :
-'
-test_set_prereq HAVEIT
-haveit=no
-test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
- test_have_prereq HAVEIT &&
- haveit=yes
-'
-
-clean=no
-test_expect_success 'tests clean up after themselves' '
- test_when_finished clean=yes
-'
-
-cleaner=no
-test_expect_code 1 'tests clean up even after a failure' '
- test_when_finished cleaner=yes &&
- (exit 1)
-'
-
-if test $clean$cleaner != yesyes
-then
- say "bug in test framework: cleanup commands do not work reliably"
- exit 1
-fi
-
-test_expect_code 2 'failure to clean up causes the test to fail' '
- test_when_finished "(exit 2)"
-'
-
-# Ensure that all tests are being run
-test_begin_subtest 'Ensure that all available tests will be run by notmuch-test'
-eval $(sed -n -e '/^TESTS="$/,/^"$/p' $TEST_DIRECTORY/notmuch-test)
-tests_in_suite=$(for i in $TESTS; do echo $i; done | sort)
-available=$(find "$TEST_DIRECTORY" -maxdepth 1 -type f \
- '(' -perm -100 -o -perm -10 -o -perm -1 ')' \
- ! -name aggregate-results.sh \
- ! -name arg-test \
- ! -name hex-xcode \
- ! -name notmuch-test \
- ! -name parse-time \
- ! -name random-corpus \
- ! -name smtp-dummy \
- ! -name symbol-test \
- ! -name test-verbose \
- | sed 's,.*/,,' | sort)
-test_expect_equal "$tests_in_suite" "$available"
-
-EXPECTED=$TEST_DIRECTORY/test.expected-output
-suppress_diff_date() {
- sed -e 's/\(.*\-\-\- test-verbose\.4\.\expected\).*/\1/' \
- -e 's/\(.*\+\+\+ test-verbose\.4\.\output\).*/\1/'
-}
-
-test_begin_subtest "Ensure that test output is suppressed unless the test fails"
-output=$(cd $TEST_DIRECTORY; ./test-verbose 2>&1 | suppress_diff_date)
-expected=$(cat $EXPECTED/test-verbose-no | suppress_diff_date)
-test_expect_equal "$output" "$expected"
-
-test_begin_subtest "Ensure that -v does not suppress test output"
-output=$(cd $TEST_DIRECTORY; ./test-verbose -v 2>&1 | suppress_diff_date)
-expected=$(cat $EXPECTED/test-verbose-yes | suppress_diff_date)
-# Do not include the results of test-verbose in totals
-rm $TEST_DIRECTORY/test-results/test-verbose
-rm -r $TEST_DIRECTORY/tmp.test-verbose
-test_expect_equal "$output" "$expected"
-
-
-################################################################
-# Test mail store prepared in test-lib.sh
-
-test_expect_success \
- 'test that mail store was created' \
- 'test -d "${MAIL_DIR}"'
-
-
-find "${MAIL_DIR}" -type f -print >should-be-empty
-test_expect_success \
- 'mail store should be empty' \
- 'cmp -s /dev/null should-be-empty'
-
-test_expect_success \
- 'NOTMUCH_CONFIG is set and points to an existing file' \
- 'test -f "${NOTMUCH_CONFIG}"'
-
-test_expect_success \
- 'PATH is set to this repository' \
- 'test "`echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,'`" = "`dirname ${TEST_DIRECTORY}`"'
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch compact"'
-. ./test-lib.sh
-
-add_message '[subject]=One'
-add_message '[subject]=Two'
-add_message '[subject]=Three'
-
-notmuch tag +tag1 \*
-notmuch tag +tag2 subject:Two
-notmuch tag -tag1 +tag3 subject:Three
-
-test_expect_success "Running compact" "notmuch compact --backup=${TEST_DIRECTORY}/xapian.old"
-
-test_begin_subtest "Compact preserves database"
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)"
-
-test_expect_success 'Restoring Backup' \
- 'rm -Rf ${MAIL_DIR}/.notmuch/xapian &&
- mv ${TEST_DIRECTORY}/xapian.old ${MAIL_DIR}/.notmuch/xapian'
-
-test_begin_subtest "Checking restored backup"
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Three (inbox tag3 unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description='"notmuch config"'
-. ./test-lib.sh
-
-test_begin_subtest "Get string value"
-test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
-
-test_begin_subtest "Get list value"
-test_expect_equal "$(notmuch config get new.tags)" "\
-unread
-inbox"
-
-test_begin_subtest "Set string value"
-notmuch config set foo.string "this is a string value"
-test_expect_equal "$(notmuch config get foo.string)" "this is a string value"
-
-test_begin_subtest "Set string value again"
-notmuch config set foo.string "this is another string value"
-test_expect_equal "$(notmuch config get foo.string)" "this is another string value"
-
-test_begin_subtest "Set list value"
-notmuch config set foo.list this "is a" "list value"
-test_expect_equal "$(notmuch config get foo.list)" "\
-this
-is a
-list value"
-
-test_begin_subtest "Set list value again"
-notmuch config set foo.list this "is another" "list value"
-test_expect_equal "$(notmuch config get foo.list)" "\
-this
-is another
-list value"
-
-test_begin_subtest "Remove key"
-notmuch config set foo.remove baz
-notmuch config set foo.remove
-test_expect_equal "$(notmuch config get foo.remove)" ""
-
-test_begin_subtest "Remove non-existent key"
-notmuch config set foo.nonexistent
-test_expect_equal "$(notmuch config get foo.nonexistent)" ""
-
-test_begin_subtest "List all items"
-notmuch config set database.path "/canonical/path"
-output=$(notmuch config list)
-test_expect_equal "$output" "\
-database.path=/canonical/path
-user.name=Notmuch Test Suite
-user.primary_email=test_suite@notmuchmail.org
-user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org
-new.tags=unread;inbox;
-new.ignore=
-search.exclude_tags=
-maildir.synchronize_flags=true
-foo.string=this is another string value
-foo.list=this;is another;list value;"
-
-test_begin_subtest "Top level --config=FILE option"
-cp "${NOTMUCH_CONFIG}" alt-config
-notmuch --config=alt-config config set user.name "Another Name"
-test_expect_equal "$(notmuch --config=alt-config config get user.name)" \
- "Another Name"
-
-test_begin_subtest "Top level --config=FILE option changed the right file"
-test_expect_equal "$(notmuch config get user.name)" \
- "Notmuch Test Suite"
-
-test_begin_subtest "Read config file through a symlink"
-ln -s alt-config alt-config-link
-test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \
- "Another Name"
-
-test_begin_subtest "Write config file through a symlink"
-notmuch --config=alt-config-link config set user.name "Link Name"
-test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \
- "Link Name"
-
-test_begin_subtest "Writing config file through symlink follows symlink"
-test_expect_equal "$(readlink alt-config-link)" "alt-config"
-
-test_done
--- /dev/null
+From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 21:28:37 +0600
+Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
+ headers
+Message-ID: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+
+Keeping unused files open helps to see "Too many open files" often.
+
+Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
+---
+ lib/message-file.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/lib/message-file.c b/lib/message-file.c
+index 8a3f8ee..197ab01 100644
+--- a/lib/message-file.c
++++ b/lib/message-file.c
+@@ -325,6 +325,11 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
+ return decoded_value;
+ }
+
++ if (message->parsing_finished) {
++ fclose (message->file);
++ message->file = NULL;
++ }
++
+ if (message->line)
+ free (message->line);
+ message->line = NULL;
+--
+1.6.3.3
+
+
--- /dev/null
+From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 21:28:38 +0600
+Subject: [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++
+ file with gcc 4.4
+In-Reply-To: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+Message-ID: <1258471718-6781-2-git-send-email-dottedmag@dottedmag.net>
+
+
+Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
+---
+ lib/message.cc | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/lib/message.cc b/lib/message.cc
+index 72c350f..a4b090b 100644
+--- a/lib/message.cc
++++ b/lib/message.cc
+@@ -21,6 +21,8 @@
+ #include "notmuch-private.h"
+ #include "database-private.h"
+
++#include <stdint.h>
++
+ #include <gmime/gmime.h>
+
+ #include <xapian.h>
+--
+1.6.3.3
+
+
--- /dev/null
+From: "Israel Herraiz" <isra@herraiz.org>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 23:57:18 +0100
+Subject: [notmuch] New to the list
+Message-ID: <1258498485-sup-142@elly>
+
+Hi all,
+
+I have subscribed to the list. As suggested by the welcome message, I
+am introducing myself. My name is Israel Herraiz, and I have done a
+couple of contributions to Sup, the probably well-known here e-mail
+client.
+
+"Not much" sounds interesting, and I wonder whether it could be
+integrated with the views of Sup (inbox, threads, etc). So I have
+subscribed to the list to keep an eye on what's going on here.
+
+I have just heard of "Not much". I have not even tried to download the
+code yet.
+
+Cheers,
+Israel
+
--- /dev/null
+From: "Aron Griffis" <agriffis@n01se.net>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 18:21:38 -0500
+Subject: [notmuch] archive
+Message-ID: <20091117232137.GA7669@griffis1.net>
+
+Just subscribed, I'd like to catch up on the previous postings,
+but the archive link seems to be bogus?
+
+Thanks,
+Aron
+
--- /dev/null
+MIME-Version: 1.0
+Date: Tue, 17 Nov 2009 11:36:14 -0800
+Message-ID: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
+From: Alex Botero-Lowry <alex.boterolowry@gmail.com>
+To: notmuch@notmuchmail.org
+Content-Type: multipart/mixed; boundary=0016e687869333b1570478963d35
+Subject: [notmuch] preliminary FreeBSD support
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+--0016e687869333b1570478963d35
+Content-Type: multipart/alternative; boundary=0016e687869333b14e0478963d33
+
+--0016e687869333b14e0478963d33
+Content-Type: text/plain; charset=ISO-8859-1
+
+I saw the announcement this morning, and was very excited, as I had been
+hoping sup would be turned into a library,
+since I like the concept more than the UI (I'd rather an emacs interface).
+
+I did a preliminary compile which worked out fine, but
+sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
+FreeBSD, so notmuch_config_open segfaulted.
+
+Attached is a patch that supplies a default buffer size of 64 in cases where
+-1 is returned.
+
+http://www.opengroup.org/austin/docs/austin_328.txt - seems to indicate this
+is acceptable behavior,
+and http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.htmlspecifically
+uses 64 as the
+buffer size.
+
+--0016e687869333b14e0478963d33
+Content-Type: text/html; charset=ISO-8859-1
+Content-Transfer-Encoding: quoted-printable
+
+I saw the announcement this morning, and was very excited, as I had been ho=
+ping sup would be turned into a library,<br>since I like the concept more t=
+han the UI (I'd rather an emacs interface).<br><br>I did a preliminary =
+compile which worked out fine, but sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns=
+ -1 on<br>
+FreeBSD, so notmuch_config_open segfaulted.<br><br>Attached is a patch that=
+ supplies a default buffer size of 64 in cases where -1 is returned.<br><br=
+><a href=3D"http://www.opengroup.org/austin/docs/austin_328.txt">http://www=
+.opengroup.org/austin/docs/austin_328.txt</a> - seems to indicate this is a=
+cceptable behavior,<br>
+and <a href=3D"http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg01680=
+8.html">http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.html<=
+/a> specifically uses 64 as the<br>buffer size.<br><br><br>
+
+--0016e687869333b14e0478963d33--
+--0016e687869333b1570478963d35
+Content-Type: application/octet-stream;
+ name="0001-Deal-with-situation-where-sysconf-_SC_GETPW_R_SIZE_M.patch"
+Content-Disposition: attachment;
+ filename="0001-Deal-with-situation-where-sysconf-_SC_GETPW_R_SIZE_M.patch"
+Content-Transfer-Encoding: base64
+X-Attachment-Id: f_g252e6gs0
+
+RnJvbSBlM2JjNGJiZDdiOWQwZDA4NjgxNmFiNWY4ZjJkNmZmZWExZGQzZWE0IE1vbiBTZXAgMTcg
+MDA6MDA6MDAgMjAwMQpGcm9tOiBBbGV4YW5kZXIgQm90ZXJvLUxvd3J5IDxhbGV4LmJvdGVyb2xv
+d3J5QGdtYWlsLmNvbT4KRGF0ZTogVHVlLCAxNyBOb3YgMjAwOSAxMTozMDozOSAtMDgwMApTdWJq
+ZWN0OiBbUEFUQ0hdIERlYWwgd2l0aCBzaXR1YXRpb24gd2hlcmUgc3lzY29uZihfU0NfR0VUUFdf
+Ul9TSVpFX01BWCkgcmV0dXJucyAtMQoKLS0tCiBub3RtdWNoLWNvbmZpZy5jIHwgICAgMiArKwog
+MSBmaWxlcyBjaGFuZ2VkLCAyIGluc2VydGlvbnMoKyksIDAgZGVsZXRpb25zKC0pCgpkaWZmIC0t
+Z2l0IGEvbm90bXVjaC1jb25maWcuYyBiL25vdG11Y2gtY29uZmlnLmMKaW5kZXggMjQ4MTQ5Yy4u
+ZTcyMjBkOCAxMDA2NDQKLS0tIGEvbm90bXVjaC1jb25maWcuYworKysgYi9ub3RtdWNoLWNvbmZp
+Zy5jCkBAIC03Nyw2ICs3Nyw3IEBAIHN0YXRpYyBjaGFyICoKIGdldF9uYW1lX2Zyb21fcGFzc3dk
+X2ZpbGUgKHZvaWQgKmN0eCkKIHsKICAgICBsb25nIHB3X2J1Zl9zaXplID0gc3lzY29uZihfU0Nf
+R0VUUFdfUl9TSVpFX01BWCk7CisgICAgaWYgKHB3X2J1Zl9zaXplID09IC0xKSBwd19idWZfc2l6
+ZSA9IDY0OwogICAgIGNoYXIgKnB3X2J1ZiA9IHRhbGxvY196ZXJvX3NpemUgKGN0eCwgcHdfYnVm
+X3NpemUpOwogICAgIHN0cnVjdCBwYXNzd2QgcGFzc3dkLCAqaWdub3JlZDsKICAgICBjaGFyICpu
+YW1lOwpAQCAtMTAxLDYgKzEwMiw3IEBAIHN0YXRpYyBjaGFyICoKIGdldF91c2VybmFtZV9mcm9t
+X3Bhc3N3ZF9maWxlICh2b2lkICpjdHgpCiB7CiAgICAgbG9uZyBwd19idWZfc2l6ZSA9IHN5c2Nv
+bmYoX1NDX0dFVFBXX1JfU0laRV9NQVgpOworICAgIGlmIChwd19idWZfc2l6ZSA9PSAtMSkgcHdf
+YnVmX3NpemUgPSA2NDsKICAgICBjaGFyICpwd19idWYgPSB0YWxsb2NfemVyb19zaXplIChjdHgs
+IHB3X2J1Zl9zaXplKTsKICAgICBzdHJ1Y3QgcGFzc3dkIHBhc3N3ZCwgKmlnbm9yZWQ7CiAgICAg
+Y2hhciAqbmFtZTsKLS0gCjEuNi41LjIKCg==
+--0016e687869333b1570478963d35
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--0016e687869333b1570478963d35--
+
--- /dev/null
+Date: Tue, 17 Nov 2009 19:58:29 -0500
+From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
+To: notmuch <notmuch@notmuchmail.org>
+Message-ID: <20091118005829.GB25380@dottiness.seas.harvard.edu>
+MIME-Version: 1.0
+User-Agent: Mutt/1.5.19 (2009-01-05)
+Subject: [notmuch] "notmuch help" outputs to stderr?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============1359248349=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+
+--===============1359248349==
+Content-Type: multipart/signed; micalg=pgp-sha256;
+ protocol="application/pgp-signature"; boundary="L6iaP+gRLNZHKoI4"
+Content-Disposition: inline
+
+
+--L6iaP+gRLNZHKoI4
+Content-Type: multipart/mixed; boundary="z6Eq5LdranGa6ru8"
+Content-Disposition: inline
+
+
+--z6Eq5LdranGa6ru8
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+I'm just noticing that 'notmuch help ...' outputs to stderr, which
+isn't terribly intuitive. For example, the obvious invocation:
+
+ notmuch help | less
+
+=2E..isn't terribly helpful.
+
+I've attached a patch that lets usage() take a FILE * argument so that
+you can output to stderr in response to usage errors, and stdout in
+response to an explicit request.
+
+--=20
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Senior Technologist, Computing and Information Technology
+Harvard University School of Engineering and Applied Sciences
+
+
+--z6Eq5LdranGa6ru8
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: attachment; filename="notmuch-help.patch"
+Content-Transfer-Encoding: quoted-printable
+
+diff --git a/notmuch.c b/notmuch.c
+index c47e640..a35cb99 100644
+--- a/notmuch.c
++++ b/notmuch.c
+@@ -157,23 +157,23 @@ command_t commands[] =3D {
+ };
+=20
+ static void
+-usage (void)
++usage (FILE *out)
+ {
+ command_t *command;
+ unsigned int i;
+=20
+- fprintf (stderr, "Usage: notmuch <command> [args...]\n");
+- fprintf (stderr, "\n");
+- fprintf (stderr, "Where <command> and [args...] are as follows:\n");
+- fprintf (stderr, "\n");
++ fprintf (out, "Usage: notmuch <command> [args...]\n");
++ fprintf (out, "\n");
++ fprintf (out, "Where <command> and [args...] are as follows:\n");
++ fprintf (out, "\n");
+=20
+ for (i =3D 0; i < ARRAY_SIZE (commands); i++) {
+ command =3D &commands[i];
+=20
+- fprintf (stderr, "\t%s\t%s\n\n", command->name, command->summary);
++ fprintf (out, "\t%s\t%s\n\n", command->name, command->summary);
+ }
+=20
+- fprintf (stderr, "Use \"notmuch help <command>\" for more details on e=
+ach command.\n\n");
++ fprintf (out, "Use \"notmuch help <command>\" for more details on each=
+ command.\n\n");
+ }
+=20
+ static int
+@@ -183,8 +183,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
+r *argv[])
+ unsigned int i;
+=20
+ if (argc =3D=3D 0) {
+- fprintf (stderr, "The notmuch mail system.\n\n");
+- usage ();
++ fprintf (stdout, "The notmuch mail system.\n\n");
++ usage (stdout);
+ return 0;
+ }
+=20
+
+--z6Eq5LdranGa6ru8--
+
+--L6iaP+gRLNZHKoI4
+Content-Type: application/pgp-signature
+Content-Disposition: inline
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQEcBAEBCAAGBQJLA0a1AAoJENdGlQYxQazYr78IAJtqTWIpBqSdOWqTzt/r4XNn
+KJ5mWAoNfq4H+3kx3xoWOFYS7qAYeJoHQWCDbMdb+zEXvPX6hMFn9+OxRN+N5FdQ
+uxGTugSG9xSsK28oGDCQUtr5uheo+tH0jygPjI+LTD97vjUYS4K2qzhLGFJmpLcj
+1akMJXM0gSdPZT8dJyjxvC15pgboLspE4+b6jexXmd4UoFvXgqvjkYHeV4Wk+s0L
+xu+HkCGXL9WHYc3t171fFAru4Zd1AUxFQl4BZ2Y+OqRZUrD28Mtz3zGQxbJQoifl
+JFrgPAWioLN71SkVq/y+efjvGSl0osPpKU5dftMmyY1zV7k7mMlO08ZSJU+wANA=
+=Iijt
+-----END PGP SIGNATURE-----
+
+--L6iaP+gRLNZHKoI4--
+
+--===============1359248349==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============1359248349==--
+
--- /dev/null
+Return-path: <notmuch-bounces@notmuchmail.org>
+Envelope-to: cworth@localhost
+Delivery-date: Wed, 18 Nov 2009 01:43:47 -0800
+Received: from yoom.home.cworth.org ([127.0.0.1])
+ by yoom.home.cworth.org with esmtp (Exim 4.69)
+ (envelope-from <notmuch-bounces@notmuchmail.org>)
+ id 1NAgpH-0005Ab-20
+ for cworth@localhost; Wed, 18 Nov 2009 01:27:47 -0800
+X-Original-To: cworth@cworth.org
+Delivered-To: cworth@cworth.org
+Received: from olra.theworths.org [82.165.184.25]
+ by yoom.home.cworth.org with IMAP (fetchmail-6.3.9-rc2)
+ for <cworth@localhost> (single-drop); Wed, 18 Nov 2009 01:27:47 -0800 (PST)
+Received: from localhost (localhost [127.0.0.1])
+ by olra.theworths.org (Postfix) with ESMTP id 12248431FC3
+ for <cworth@cworth.org>; Tue, 17 Nov 2009 17:01:22 -0800 (PST)
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
+X-Spam-Flag: NO
+X-Spam-Score: -6.17
+X-Spam-Level:
+X-Spam-Status: No, score=-6.17 tagged_above=-999 required=2 tests=[AWL=0.429,
+ BAYES_00=-2.599, RCVD_IN_DNSWL_MED=-4] autolearn=unavailable
+Received: from olra.theworths.org ([127.0.0.1])
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
+ with ESMTP id TmBdVd1i-Wjb; Tue, 17 Nov 2009 17:01:20 -0800 (PST)
+Received: from olra.theworths.org (localhost [127.0.0.1])
+ by olra.theworths.org (Postfix) with ESMTP id AF876431FBC;
+ Tue, 17 Nov 2009 17:01:20 -0800 (PST)
+X-Original-To: notmuch@notmuchmail.org
+Delivered-To: notmuch@notmuchmail.org
+Received: from localhost (localhost [127.0.0.1])
+ by olra.theworths.org (Postfix) with ESMTP id 75784431FBC
+ for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 17:01:19 -0800 (PST)
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
+Received: from olra.theworths.org ([127.0.0.1])
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
+ with ESMTP id IoYHzHoKBskU for <notmuch@notmuchmail.org>;
+ Tue, 17 Nov 2009 17:01:18 -0800 (PST)
+Received: from smtp-outbound.seas.harvard.edu (smtp-outbound.seas.harvard.edu
+ [140.247.51.171])
+ by olra.theworths.org (Postfix) with ESMTP id 7E033431FAE
+ for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 17:01:18 -0800 (PST)
+Received: from dottiness.seas.harvard.edu (dottiness.seas.harvard.edu
+ [140.247.52.224])
+ by smtp-outbound.seas.harvard.edu (8.13.8/8.13.8) with SMTP id
+ nAI11Gkj008772
+ for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 20:01:16 -0500
+Received: by dottiness.seas.harvard.edu (sSMTP sendmail emulation);
+ Tue, 17 Nov 2009 20:01:16 -0500
+Date: Tue, 17 Nov 2009 20:01:16 -0500
+From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
+To: notmuch <notmuch@notmuchmail.org>
+Message-ID: <20091118010116.GC25380@dottiness.seas.harvard.edu>
+References: <20091118005829.GB25380@dottiness.seas.harvard.edu>
+MIME-Version: 1.0
+In-Reply-To: <20091118005829.GB25380@dottiness.seas.harvard.edu>
+User-Agent: Mutt/1.5.19 (2009-01-05)
+Subject: Re: [notmuch] "notmuch help" outputs to stderr?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============0848253760=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+
+--===============0848253760==
+Content-Type: multipart/signed; micalg=pgp-sha256;
+ protocol="application/pgp-signature"; boundary="ZInfyf7laFu/Kiw7"
+Content-Disposition: inline
+
+
+--ZInfyf7laFu/Kiw7
+Content-Type: multipart/mixed; boundary="KdquIMZPjGJQvRdI"
+Content-Disposition: inline
+
+
+--KdquIMZPjGJQvRdI
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+> I've attached a patch that lets usage() take a FILE * argument so that
+> you can output to stderr in response to usage errors, and stdout in
+> response to an explicit request.
+
+Whoops, missed a couple of stderr's in that last patch. New one
+attached.
+
+--=20
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Senior Technologist, Computing and Information Technology
+Harvard University School of Engineering and Applied Sciences
+
+
+--KdquIMZPjGJQvRdI
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: attachment; filename="notmuch-help.patch"
+Content-Transfer-Encoding: quoted-printable
+
+diff --git a/notmuch.c b/notmuch.c
+index c47e640..446c810 100644
+--- a/notmuch.c
++++ b/notmuch.c
+@@ -157,23 +157,23 @@ command_t commands[] =3D {
+ };
+=20
+ static void
+-usage (void)
++usage (FILE *out)
+ {
+ command_t *command;
+ unsigned int i;
+=20
+- fprintf (stderr, "Usage: notmuch <command> [args...]\n");
+- fprintf (stderr, "\n");
+- fprintf (stderr, "Where <command> and [args...] are as follows:\n");
+- fprintf (stderr, "\n");
++ fprintf (out, "Usage: notmuch <command> [args...]\n");
++ fprintf (out, "\n");
++ fprintf (out, "Where <command> and [args...] are as follows:\n");
++ fprintf (out, "\n");
+=20
+ for (i =3D 0; i < ARRAY_SIZE (commands); i++) {
+ command =3D &commands[i];
+=20
+- fprintf (stderr, "\t%s\t%s\n\n", command->name, command->summary);
++ fprintf (out, "\t%s\t%s\n\n", command->name, command->summary);
+ }
+=20
+- fprintf (stderr, "Use \"notmuch help <command>\" for more details on e=
+ach command.\n\n");
++ fprintf (out, "Use \"notmuch help <command>\" for more details on each=
+ command.\n\n");
+ }
+=20
+ static int
+@@ -183,8 +183,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
+r *argv[])
+ unsigned int i;
+=20
+ if (argc =3D=3D 0) {
+- fprintf (stderr, "The notmuch mail system.\n\n");
+- usage ();
++ fprintf (stdout, "The notmuch mail system.\n\n");
++ usage (stdout);
+ return 0;
+ }
+=20
+@@ -192,8 +192,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
+r *argv[])
+ command =3D &commands[i];
+=20
+ if (strcmp (argv[0], command->name) =3D=3D 0) {
+- fprintf (stderr, "Help for \"notmuch %s\":\n\n", argv[0]);
+- fprintf (stderr, "\t%s\t%s\n\n%s\n\n", command->name,
++ fprintf (stdout, "Help for \"notmuch %s\":\n\n", argv[0]);
++ fprintf (stdout, "\t%s\t%s\n\n%s\n\n", command->name,
+ command->summary, command->documentation);
+ return 0;
+ }
+
+--KdquIMZPjGJQvRdI--
+
+--ZInfyf7laFu/Kiw7
+Content-Type: application/pgp-signature
+Content-Disposition: inline
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQEcBAEBCAAGBQJLA0dcAAoJENdGlQYxQazY4nIIAIBCds86/uTmnouvyoPruUUR
+Bg5mXcnjuopz1Nwotl9s9U5sGeZuZngxyEvDz1Z1aTEjwab8ndNTf1xCwIoqBs+l
+i/sc4nPYubLdy1Ab/84DKVtCSbj+v5rtqhegwUWV7S1BY7t8dKNPNv7YBg7P0Azs
+6s3CUxDV5eJCcxCGxxWHH8JDKRf7rDs6vzDwyPWLxlg1Xb1lEM/sRgPCKiShPdO3
+Ak2hECusjskALhSDYX8/FLMd9HwLBC13sfWuSi/pHUAIOI2jru2p5sXrVSlTnFIJ
+fiMbPhKWiEaJj2kmm4pRwAhbTWp/J8ZvXWp0AyosxXQhQUWqujiyxgfiXS70SdQ=
+=t3Yc
+-----END PGP SIGNATURE-----
+
+--ZInfyf7laFu/Kiw7--
+
+--===============0848253760==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============0848253760==--
+
--- /dev/null
+From: "Stewart Smith" <stewart@flamingspork.com>
+To: notmuch@notmuchmail.org
+Date: Wed, 18 Nov 2009 12:05:53 +1100
+Subject: [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++
+ libs.
+Message-ID: <1258506353-20352-1-git-send-email-stewart@flamingspork.com>
+
+Previously, Ubuntu 9.10, gcc 4.4.1 was getting:
+
+ccache gcc `pkg-config --libs glib-2.0 gmime-2.4 talloc` `xapian-config --libs` notmuch.o notmuch-config.o notmuch-dump.o notmuch-new.o notmuch-reply.o notmuch-restore.o notmuch-search.o notmuch-setup.o notmuch-show.o notmuch-tag.o notmuch-time.o gmime-filter-reply.o query-string.o show-message.o lib/notmuch.a -o notmuch
+/usr/bin/ld: lib/notmuch.a(database.o): in function global constructors keyed to BOOLEAN_PREFIX_INTERNAL:database.cc(.text+0x3a): error: undefined reference to 'std::ios_base::Init::Init()'
+---
+ Makefile.local | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Makefile.local b/Makefile.local
+index f824bed..dbd3e20 100644
+--- a/Makefile.local
++++ b/Makefile.local
+@@ -18,7 +18,7 @@ notmuch_client_srcs = \
+
+ notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
+ notmuch: $(notmuch_client_modules) lib/notmuch.a
+- $(CC) $(LDFLAGS) $^ -o $@
++ $(CXX) $(LDFLAGS) $^ -o $@
+
+ notmuch.1.gz:
+ gzip --stdout notmuch.1 > notmuch.1.gz
+--
+1.6.3.3
+
+
--- /dev/null
+From: "Stewart Smith" <stewart@flamingspork.com>
+To: notmuch@notmuchmail.org
+Date: Wed, 18 Nov 2009 12:56:40 +1100
+Subject: [notmuch] [PATCH 2/2] Read mail directory in inode number order
+Message-ID: <1258509400-32511-1-git-send-email-stewart@flamingspork.com>
+
+This gives a rather decent reduction in number of seeks required when
+reading a Maildir that isn't in pagecache.
+
+Most filesystems give some locality on disk based on inode numbers.
+In ext[234] this is the inode tables, in XFS groups of sequential inode
+numbers are together on disk and the most significant bits indicate
+allocation group (i.e inode 1,000,000 is always after inode 1,000).
+
+With this patch, we read in the whole directory, sort by inode number
+before stat()ing the contents.
+
+Ideally, directory is sequential and then we make one scan through the
+file system stat()ing.
+
+Since the universe is not ideal, we'll probably seek during reading the
+directory and a fair bit while reading the inodes themselves.
+
+However... with readahead, and stat()ing in inode order, we should be
+in the best place possible to hit the cache.
+
+In a (not very good) benchmark of "how long does it take to find the first
+15,000 messages in my Maildir after 'echo 3 > /proc/sys/vm/drop_caches'",
+this patch consistently cut at least 8 seconds off the scan time.
+
+Without patch: 50 seconds
+With patch: 38-42 seconds.
+
+(I did this in a previous maildir reading project and saw large improvements too)
+---
+ notmuch-new.c | 32 +++++++++++++++-----------------
+ 1 files changed, 15 insertions(+), 17 deletions(-)
+
+diff --git a/notmuch-new.c b/notmuch-new.c
+index 83a05ba..11fad8c 100644
+--- a/notmuch-new.c
++++ b/notmuch-new.c
+@@ -73,6 +73,11 @@ add_files_print_progress (add_files_state_t *state)
+ fflush (stdout);
+ }
+
++static int ino_cmp(const struct dirent **a, const struct dirent **b)
++{
++ return ((*a)->d_ino < (*b)->d_ino)? -1: 1;
++}
++
+ /* Examine 'path' recursively as follows:
+ *
+ * o Ask the filesystem for the mtime of 'path' (path_mtime)
+@@ -100,13 +105,12 @@ add_files_recursive (notmuch_database_t *notmuch,
+ add_files_state_t *state)
+ {
+ DIR *dir = NULL;
+- struct dirent *e, *entry = NULL;
+- int entry_length;
+- int err;
++ struct dirent *entry = NULL;
+ char *next = NULL;
+ time_t path_mtime, path_dbtime;
+ notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
+ notmuch_message_t *message = NULL;
++ struct dirent **namelist = NULL;
+
+ /* If we're told to, we bail out on encountering a read-only
+ * directory, (with this being a clear clue from the user to
+@@ -122,31 +126,23 @@ add_files_recursive (notmuch_database_t *notmuch,
+ path_mtime = st->st_mtime;
+
+ path_dbtime = notmuch_database_get_timestamp (notmuch, path);
++ int n_entries= scandir(path, &namelist, 0, ino_cmp);
+
+- dir = opendir (path);
+- if (dir == NULL) {
++ if (n_entries == -1) {
+ fprintf (stderr, "Error opening directory %s: %s\n",
+ path, strerror (errno));
+ ret = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+- entry_length = offsetof (struct dirent, d_name) +
+- pathconf (path, _PC_NAME_MAX) + 1;
+- entry = malloc (entry_length);
++ int i=0;
+
+ while (!interrupted) {
+- err = readdir_r (dir, entry, &e);
+- if (err) {
+- fprintf (stderr, "Error reading directory: %s\n",
+- strerror (errno));
+- ret = NOTMUCH_STATUS_FILE_ERROR;
+- goto DONE;
+- }
+-
+- if (e == NULL)
++ if (i == n_entries)
+ break;
+
++ entry= namelist[i++];
++
+ /* If this directory hasn't been modified since the last
+ * add_files, then we only need to look further for
+ * sub-directories. */
+@@ -243,6 +239,8 @@ add_files_recursive (notmuch_database_t *notmuch,
+ free (entry);
+ if (dir)
+ closedir (dir);
++ if (namelist)
++ free (namelist);
+
+ return ret;
+ }
+--
+1.6.3.3
+
+
--- /dev/null
+From: "Keith Packard" <keithp@keithp.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 17:59:49 -0800
+Subject: [notmuch] New to the list
+In-Reply-To: <1258498485-sup-142@elly>
+References: <1258498485-sup-142@elly>
+Message-ID: <yun3a4cegoa.fsf@aiko.keithp.com>
+
+On Tue, 17 Nov 2009 23:57:18 +0100, Israel Herraiz <isra at herraiz.org> wrote:
+
+> "Not much" sounds interesting, and I wonder whether it could be
+> integrated with the views of Sup (inbox, threads, etc). So I have
+> subscribed to the list to keep an eye on what's going on here.
+
+We've tried to clone much of the sup UI inside emacs, including the
+inbox and threaded message presentation. Of course, we had to "improve"
+it a bit, as much due to the differences between curses and emacs as due
+to personal preferences...
+
+-keith
+
--- /dev/null
+From: "Keith Packard" <keithp@keithp.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 18:03:17 -0800
+Subject: [notmuch] Introducing myself
+In-Reply-To: <20091118002059.067214ed@hikari>
+References: <20091118002059.067214ed@hikari>
+Message-ID: <yun1vjwegii.fsf@aiko.keithp.com>
+
+On Wed, 18 Nov 2009 00:20:59 +0100, Adrian Perez de Castro <aperez at igalia.com> wrote:
+
+> Some time ago I thought
+> about doing something like Not Much and in fact I played a bit with the
+> Python+Xapian and the Python+Whoosh combinations, because I find relaxing
+> to code things in Python when I am not working and also it is installed
+> by default on most distribution. I got to have some mailboxes indexed and
+> basic searching working a couple of months ago.
+
+Sup certainly started a lot of people thinking...
+
+> Also, I would like to share one idea I had in mind, that you might find
+> interesting: One thing I have found very annoying is having to re-tag my
+> mail when the indexes get b0rked (it happened a couple of times to me while
+> using Sup), so I was planning to mails as read/unread and adding the tags
+> not just to the index, but to the mail text itself, e.g. by adding a
+> "X-Tags" header field or by reusing the "Keywords" one.
+
+Easier than that, notmuch (and sup too), provide a 'dump' command which
+just lists all of the message IDs and their associated tags. Makes
+saving tags easy and doesn't involve rewriting messages. I do this once
+a day just before my computer is backed up to an external drive.
+
+If the index is destroyed, you can reindex the messages and then reapply
+all of the tags with 'notmuch restore'.
+
+--
+keith.packard at intel.com
+
+
--- /dev/null
+From: "Ingmar Vanhassel" <ingmar@exherbo.org>
+To: notmuch@notmuchmail.org
+Date: Wed, 18 Nov 2009 00:23:42 +0100
+Subject: [notmuch] [PATCH] Typsos
+Message-ID: <1258500222-32066-1-git-send-email-ingmar@exherbo.org>
+
+---
+ Makefile | 4 ++--
+ README | 6 +++---
+ gmime-filter-reply.h | 2 +-
+ lib/database.cc | 2 +-
+ lib/index.cc | 2 +-
+ lib/message.cc | 2 +-
+ lib/messages.c | 2 +-
+ lib/notmuch-private.h | 2 +-
+ lib/notmuch.h | 10 +++++-----
+ lib/sha1.c | 2 +-
+ lib/thread.cc | 2 +-
+ notmuch-completion.bash | 2 +-
+ notmuch-new.c | 4 ++--
+ notmuch-search.c | 2 +-
+ notmuch.1 | 4 ++--
+ notmuch.el | 10 +++++-----
+ show-message.c | 2 +-
+ 17 files changed, 30 insertions(+), 30 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 436dacf..96aaa73 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,4 +1,4 @@
+-# Default FLAGS, (can be overriden by user such as "make CFLAGS=-O2")
++# Default FLAGS, (can be overridden by user such as "make CFLAGS=-O2")
+ WARN_FLAGS=-Wall -Wextra -Wmissing-declarations -Wwrite-strings -Wswitch-enum
+ CFLAGS=-O2
+
+@@ -14,7 +14,7 @@ override CXXFLAGS += $(WARN_FLAGS) $(extra_cflags) $(extra_cxxflags)
+ override LDFLAGS += `pkg-config --libs glib-2.0 gmime-2.4 talloc` \
+ `xapian-config --libs`
+
+-# Include our local Makfile.local first so that its first target is default
++# Include our local Makefile.local first so that its first target is default
+ include Makefile.local
+ include lib/Makefile.local
+
+diff --git a/README b/README
+index 40f05ab..27af77f 100644
+--- a/README
++++ b/README
+@@ -3,7 +3,7 @@ Notmuch - thread-based email index, search and tagging.
+ Notmuch is a system for indexing, searching, reading, and tagging
+ large collections of email messages. It uses the Xapian library to
+ provide fast, full-text search of very large collection of email with
+-a very convenient search syntas.
++a very convenient search syntax.
+
+ Notmuch is free software, released under the GNU General Public
+ License version 3 (or later).
+@@ -45,7 +45,7 @@ obtaining a more sophisticated interface:
+ notmuch.el file in this distribution.
+
+ If someone were to write a curses-based interface, or similar,
+- it might also be reasonable to buil on the "notmuch"
++ it might also be reasonable to build on the "notmuch"
+ command-line interface.
+
+ 2. Build on top of the notmuch library interface.
+@@ -67,4 +67,4 @@ still in development. We would appreciate any contributions to these
+ efforts.
+
+
+-
+\ No newline at end of file
++
+diff --git a/gmime-filter-reply.h b/gmime-filter-reply.h
+index 41cbc13..b7cbc6b 100644
+--- a/gmime-filter-reply.h
++++ b/gmime-filter-reply.h
+@@ -40,7 +40,7 @@ typedef struct _GMimeFilterReplyClass GMimeFilterReplyClass;
+ * @saw_nl: previous char was a \n
+ * @saw_angle: previous char was a >
+ *
+- * A filter to insert/remove reply markers (lines begining with >)
++ * A filter to insert/remove reply markers (lines beginning with >)
+ **/
+ struct _GMimeFilterReply {
+ GMimeFilter parent_object;
+diff --git a/lib/database.cc b/lib/database.cc
+index 3c8d626..27597cf 100644
+--- a/lib/database.cc
++++ b/lib/database.cc
+@@ -180,7 +180,7 @@ notmuch_status_to_string (notmuch_status_t status)
+ case NOTMUCH_STATUS_TAG_TOO_LONG:
+ return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)";
+ case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
+- return "Unblanced number of calls to notmuch_message_freeze/thaw";
++ return "Unbalanced number of calls to notmuch_message_freeze/thaw";
+ default:
+ case NOTMUCH_STATUS_LAST_STATUS:
+ return "Unknown error status value";
+diff --git a/lib/index.cc b/lib/index.cc
+index 65b83b3..80df64b 100644
+--- a/lib/index.cc
++++ b/lib/index.cc
+@@ -198,7 +198,7 @@ _index_mime_part (notmuch_message_t *message,
+ if (i == 1)
+ continue;
+ if (i > 1)
+- fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Indexing anyway.\n");
++ fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n");
+ }
+ _index_mime_part (message,
+ g_mime_multipart_get_part (multipart, i));
+diff --git a/lib/message.cc b/lib/message.cc
+index a4b090b..1d6623f 100644
+--- a/lib/message.cc
++++ b/lib/message.cc
+@@ -144,7 +144,7 @@ _notmuch_message_create (const void *talloc_owner,
+ }
+
+ /* Create a new notmuch_message_t object for a specific message ID,
+- * (which may or may not already exist in the databas).
++ * (which may or may not already exist in the database).
+ *
+ * Here, 'talloc owner' is an optional talloc context to which the new
+ * message will belong. This allows for the caller to not bother
+diff --git a/lib/messages.c b/lib/messages.c
+index a588f8f..2f7c283 100644
+--- a/lib/messages.c
++++ b/lib/messages.c
+@@ -47,7 +47,7 @@ _notmuch_message_list_create (const void *ctx)
+ return list;
+ }
+
+-/* Append 'node' (which can of course point to an aribtrarily long
++/* Append 'node' (which can of course point to an arbitrarily long
+ * list of nodes) to the end of 'list'.
+ */
+ void
+diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
+index 6036ce4..af82e58 100644
+--- a/lib/notmuch-private.h
++++ b/lib/notmuch-private.h
+@@ -235,7 +235,7 @@ notmuch_message_file_open (const char *filename);
+ notmuch_message_file_t *
+ _notmuch_message_file_open_ctx (void *ctx, const char *filename);
+
+-/* Close a notmuch message preivously opened with notmuch_message_open. */
++/* Close a notmuch message previously opened with notmuch_message_open. */
+ void
+ notmuch_message_file_close (notmuch_message_file_t *message);
+
+diff --git a/lib/notmuch.h b/lib/notmuch.h
+index 32b5332..384c177 100644
+--- a/lib/notmuch.h
++++ b/lib/notmuch.h
+@@ -222,7 +222,7 @@ notmuch_database_get_timestamp (notmuch_database_t *database,
+
+ /* Add a new message to the given notmuch database.
+ *
+- * Here,'filename' should be a path relative to the the path of
++ * Here,'filename' should be a path relative to the path of
+ * 'database' (see notmuch_database_get_path), or else should be an
+ * absolute filename with initial components that match the path of
+ * 'database'.
+@@ -258,7 +258,7 @@ notmuch_database_add_message (notmuch_database_t *database,
+ const char *filename,
+ notmuch_message_t **message);
+
+-/* Find a message with the given messsage_id.
++/* Find a message with the given message_id.
+ *
+ * If the database contains a message with the given message_id, then
+ * a new notmuch_message_t object is returned. The caller should call
+@@ -620,7 +620,7 @@ notmuch_messages_advance (notmuch_messages_t *messages);
+ /* Destroy a notmuch_messages_t object.
+ *
+ * It's not strictly necessary to call this function. All memory from
+- * the notmuch_messages_t object will be reclaimed when the containg
++ * the notmuch_messages_t object will be reclaimed when the containing
+ * query object is destroyed.
+ */
+ void
+@@ -865,7 +865,7 @@ notmuch_tags_has_more (notmuch_tags_t *tags);
+ /* Get the current tag from 'tags' as a string.
+ *
+ * Note: The returned string belongs to 'tags' and has a lifetime
+- * identical to it (and the query to which it utlimately belongs).
++ * identical to it (and the query to which it ultimately belongs).
+ *
+ * See the documentation of notmuch_message_get_tags for example code
+ * showing how to iterate over a notmuch_tags_t object.
+@@ -884,7 +884,7 @@ notmuch_tags_advance (notmuch_tags_t *tags);
+ /* Destroy a notmuch_tags_t object.
+ *
+ * It's not strictly necessary to call this function. All memory from
+- * the notmuch_tags_t object will be reclaimed when the containg
++ * the notmuch_tags_t object will be reclaimed when the containing
+ * message or query objects are destroyed.
+ */
+ void
+diff --git a/lib/sha1.c b/lib/sha1.c
+index ff4dd16..cc48108 100644
+--- a/lib/sha1.c
++++ b/lib/sha1.c
+@@ -43,7 +43,7 @@ _hex_of_sha1_digest (const unsigned char digest[SHA1_DIGEST_SIZE])
+ return result;
+ }
+
+-/* Create a hexadcimal string version of the SHA-1 digest of 'str'
++/* Create a hexadecimal string version of the SHA-1 digest of 'str'
+ * (including its null terminating character).
+ *
+ * This function returns a newly allocated string which the caller
+diff --git a/lib/thread.cc b/lib/thread.cc
+index 4411d64..da58edc 100644
+--- a/lib/thread.cc
++++ b/lib/thread.cc
+@@ -190,7 +190,7 @@ _resolve_thread_relationships (unused (notmuch_thread_t *thread))
+ * subject line, the total count of messages, and all authors). The
+ * second search is for all messages that are in the thread and that
+ * also match the given query_string. This is to allow for a separate
+- * count of matched messages, and to allow a viewer to diplay these
++ * count of matched messages, and to allow a viewer to display these
+ * messages differently.
+ *
+ * Here, 'ctx' is talloc context for the resulting thread object.
+diff --git a/notmuch-completion.bash b/notmuch-completion.bash
+index ad55f6d..cdad05d 100644
+--- a/notmuch-completion.bash
++++ b/notmuch-completion.bash
+@@ -1,4 +1,4 @@
+-# Bash completion for notmutch
++# Bash completion for notmuch
+ #
+ # Copyright ?? 2009 Carl Worth
+ #
+diff --git a/notmuch-new.c b/notmuch-new.c
+index 83a05ba..5405a9f 100644
+--- a/notmuch-new.c
++++ b/notmuch-new.c
+@@ -303,7 +303,7 @@ add_files (notmuch_database_t *notmuch,
+
+ /* XXX: This should be merged with the add_files function since it
+ * shares a lot of logic with it. */
+-/* Recursively count all regular files in path and all sub-direcotries
++/* Recursively count all regular files in path and all sub-directories
+ * of path. The result is added to *count (which should be
+ * initialized to zero by the top-level caller before calling
+ * count_files). */
+@@ -469,7 +469,7 @@ notmuch_new_command (void *ctx,
+
+ if (elapsed > 1 && ! add_files_state.saw_read_only_directory) {
+ printf ("\nTip: If you have any sub-directories that are archives (that is,\n"
+- "they will never receive new mail), marking these directores as\n"
++ "they will never receive new mail), marking these directories as\n"
+ "read-only (chmod u-w /path/to/dir) will make \"notmuch new\"\n"
+ "much more efficient (it won't even look in those directories).\n");
+ }
+diff --git a/notmuch-search.c b/notmuch-search.c
+index 8db09c7..ac81372 100644
+--- a/notmuch-search.c
++++ b/notmuch-search.c
+@@ -76,7 +76,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
+
+ query_str = query_string_from_args (ctx, argc, argv);
+ if (query_str == NULL) {
+- fprintf (stderr, "Out of moemory.\n");
++ fprintf (stderr, "Out of memory.\n");
+ return 1;
+ }
+
+diff --git a/notmuch.1 b/notmuch.1
+index 6c3d10f..86d5f59 100644
+--- a/notmuch.1
++++ b/notmuch.1
+@@ -60,7 +60,7 @@ archives, and will then proceed to build a database that indexes the
+ mail to allow for fast search of the archive.
+
+ This directory can contain any number of sub-directories and should
+-primarily contain only files with indvidual email messages
++primarily contain only files with individual email messages
+ (eg. maildir or mh archives are perfect). If there are other,
+ non-email files (such as indexes maintained by other email programs)
+ then notmuch will do its best to detect those and ignore them.
+@@ -173,7 +173,7 @@ Constructs a reply template for a set of messages.
+
+ See the documentation of
+ .B search
+-for deatils of the supported syntax of search terms.
++for details of the supported syntax of search terms.
+
+ To make replying to email easier,
+ .B notmuch reply
+diff --git a/notmuch.el b/notmuch.el
+index 8894a8e..7e01ed6 100644
+--- a/notmuch.el
++++ b/notmuch.el
+@@ -205,7 +205,7 @@ Unlike builtin `next-line' this version accepts no arguments."
+ (defun notmuch-show-mark-read-then-archive-thread ()
+ "Remove \"unread\" tag from each message, then archive and show next thread.
+
+-Archive each message currrently shown by removing the \"unread\"
++Archive each message currently shown by removing the \"unread\"
+ and \"inbox\" tag from each. Then kill this buffer and show the
+ next thread from the search from which this thread was originally
+ shown.
+@@ -220,7 +220,7 @@ buffer."
+ (defun notmuch-show-archive-thread ()
+ "Archive each message in thread, and show next thread from search.
+
+-Archive each message currrently shown by removing the \"inbox\"
++Archive each message currently shown by removing the \"inbox\"
+ tag from each. Then kill this buffer and show the next thread
+ from the search from which this thread was originally shown.
+
+@@ -340,7 +340,7 @@ there are no more unread messages past the current point."
+ (notmuch-show-next-message)))
+
+ (defun notmuch-show-next-open-message ()
+- "Advance to the the next message which is not hidden.
++ "Advance to the next message which is not hidden.
+
+ If read messages are currently hidden, advance to the next unread
+ message. Otherwise, advance to the next message."
+@@ -674,7 +674,7 @@ thread from that buffer can be show when done with this one)."
+ )))
+
+ (defvar notmuch-search-authors-width 40
+- "Number of columns to use to diplay authors in a notmuch-search buffer.")
++ "Number of columns to use to display authors in a notmuch-search buffer.")
+
+ (defvar notmuch-search-mode-map
+ (let ((map (make-sparse-keymap)))
+@@ -910,7 +910,7 @@ the beginning of the buffer).
+
+ This command toggles the sort order for the current search.
+
+-Note that any fitlered searches created by
++Note that any filtered searches created by
+ `notmuch-search-filter' retain the search order of the parent
+ search."
+ (interactive)
+diff --git a/show-message.c b/show-message.c
+index 79b02e2..38f5897 100644
+--- a/show-message.c
++++ b/show-message.c
+@@ -38,7 +38,7 @@ show_message_part (GMimeObject *part, int *part_count,
+ if (i == 1)
+ continue;
+ if (i > 1)
+- fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Continuing.\n");
++ fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Continuing.\n");
+ }
+ show_message_part (g_mime_multipart_get_part (multipart, i),
+ part_count, show_part);
+--
+1.6.5.2.433.g23cdb
+
+
--- /dev/null
+Date: Wed, 18 Nov 2009 00:20:59 +0100
+From: Adrian Perez de Castro <aperez@igalia.com>
+To: notmuch@notmuchmail.org
+Message-ID: <20091118002059.067214ed@hikari>
+Organization: Igalia
+X-Mailer: Claws Mail 3.7.3 (GTK+ 2.18.3; x86_64-redhat-linux-gnu)
+Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAAXNSR0IArs4c6QAAADBQTFRFBwcHFhYWKCgoNzc3SEhIV1dXaGhod3d3iIiIlpaWqKiouLi4x8fH2NjY5+fn/v7+rSjDkgAAAjVJREFUOE9l07tvE0EQwOHfrkV9O+eko7g701BBfECJsIigT2IpooIqaSiRUEB0REj00FBQgYSCkhry+gecUPJybJeIxLumTbilsH2PMNXufDOa3ZVW+1JkpbUmD/8+vXR3c7or4Gz93mH309Kz8/C9/RQge7VfhW/LW+PF8IkrQ7Z6OKmQr1tl+LU/yWP9mxJka9O88fZHPwf/7u0kLyCnX3I4fQhgjAgIfi+HHw5A1Y2ggIMcFKAEnRoL0M3BosI4TI2IATjuT8DvSNJoNNJgkIhxlr9TUHeSpDnfohlIrMBlU+BGmsZqfr69FMfGMw4NoG835+J62riWyjQ/uXlTQjNUIoYegMsBM0pCD8oDas7n4HQsBghXFxJTW42KDs+4XLfjsN0wOYgABqARjMKIHIaAQnmHjsI5Cvi9Cf6k03OoWBkpIP3Q7354+dEimFBKHbMP9oKjwfd9gbrxR5KDToczK4uPF8UgNomKU2GaENRi77zyDKICxKBS4xXYbONPMQMdYZTBwMiMWiUg9g6UJ3OBogzjV8E7sBVwyvfAOYdQhsABzuOxI1MGZbs98Q6Md5UOfbbR2R0eWOesrnRw5ajT6f60LrNhWIHZpBnUWv2s14ukArWWTqTes3YQxRXgFkcMu70TPYqqUBs0YwmO967OVIdTG4bY4a7WLaqgLm5vbHdH5np0Dri//fmg7y8scB4u3+zsuNlH0X+g19bby69b+TYH6isvns8VdQWgxj9tHP8AR5/hSdYqkwsAAAAASUVORK5CYII=
+Mime-Version: 1.0
+Subject: [notmuch] Introducing myself
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============1167731900=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+--===============1167731900==
+Content-Type: multipart/signed; micalg=PGP-SHA1;
+ boundary="Sig_/ayZz9m37AOMROJCyUudvXvZ"; protocol="application/pgp-signature"
+
+--Sig_/ayZz9m37AOMROJCyUudvXvZ
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: quoted-printable
+
+
+Hello to all,
+
+I have just heard about Not Much today in some random Linux-related news
+site (LWN?), my name is Adrian Perez and I work as systems administrator
+(although I can do some code as well :P). I have always thought that the
+ideas behind Sup were great, but after some time using it, I got tired of
+the oddities that it has. I also do not like doing things like having to
+install Ruby just for reading and sorting mails. Some time ago I thought
+about doing something like Not Much and in fact I played a bit with the
+Python+Xapian and the Python+Whoosh combinations, because I find relaxing
+to code things in Python when I am not working and also it is installed
+by default on most distribution. I got to have some mailboxes indexed and
+basic searching working a couple of months ago. Lately I have been very
+busy and had no time for coding, and them... boom! Not Much appears -- and
+it is almost exactly what I was trying to do, but faster. I have been
+playing a bit with Not Much today, and I think it has potential.
+
+Also, I would like to share one idea I had in mind, that you might find
+interesting: One thing I have found very annoying is having to re-tag my
+mail when the indexes get b0rked (it happened a couple of times to me while
+using Sup), so I was planning to mails as read/unread and adding the tags
+not just to the index, but to the mail text itself, e.g. by adding a
+"X-Tags" header field or by reusing the "Keywords" one. This way, the index
+could be totally recreated by re-reading the mail directories, and this
+would also allow to a tools like OfflineIMAP [1] to get the mails into a
+local maildir, tagging and indexing the mails with the e-mail reader and
+then syncing back the messages with the "X-Tags" header to the IMAP server.
+This would allow to use the mail reader from a different computer and still
+have everything tagged finely.
+
+Best regards,
+
+
+---
+[1] http://software.complete.org/software/projects/show/offlineimap
+
+--=20
+Adrian Perez de Castro <aperez@igalia.com>
+Igalia - Free Software Engineering
+
+--Sig_/ayZz9m37AOMROJCyUudvXvZ
+Content-Type: application/pgp-signature; name=signature.asc
+Content-Disposition: attachment; filename=signature.asc
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.13 (GNU/Linux)
+
+iEYEARECAAYFAksDL+AACgkQkcVZ2+TJEjtsuQCfXmilW8WpMQHCnwwJjRE1PWZy
+oFAAn3MmXC5sW7MvCFjs7ks6U16zgMEg
+=eL9p
+-----END PGP SIGNATURE-----
+
+--Sig_/ayZz9m37AOMROJCyUudvXvZ--
+
+--===============1167731900==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============1167731900==--
+
--- /dev/null
+MIME-Version: 1.0
+Date: Tue, 17 Nov 2009 16:23:53 -0800
+Message-ID: <cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com>
+From: Alex Botero-Lowry <alex.boterolowry@gmail.com>
+To: notmuch@notmuchmail.org
+Content-Type: multipart/mixed; boundary=0016e64ca4d8f27a4804789a4139
+Subject: [notmuch] [PATCH] Error out if no query is supplied to search
+ instead of going into an infinite loop
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+--0016e64ca4d8f27a4804789a4139
+Content-Type: multipart/alternative; boundary=0016e64ca4d8f27a3604789a4137
+
+--0016e64ca4d8f27a3604789a4137
+Content-Type: text/plain; charset=ISO-8859-1
+
+In this case error out when no query is supplied. There seems to be an
+infinite-loop casued by i think notmuch_query_search_threads having
+an exception:
+
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+A Xapian exception occurred: Syntax: <expression> AND <expression>
+
+I'll look into that bug specifically a bit later.
+
+It might be better to do a usage instead of just throwing an error here?
+
+alex
+
+--0016e64ca4d8f27a3604789a4137
+Content-Type: text/html; charset=ISO-8859-1
+
+In this case error out when no query is supplied. There seems to be an infinite-loop casued by i think notmuch_query_search_threads having<br>an exception:<br><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
+A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
+A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
+A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
+A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
+A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br><br>I'll look into that bug specifically a bit later.<br>
+<br>It might be better to do a usage instead of just throwing an error here?<br><br>alex<br>
+
+--0016e64ca4d8f27a3604789a4137--
+--0016e64ca4d8f27a4804789a4139
+Content-Type: application/octet-stream;
+ name="0001-Error-out-if-no-query-is-supplied-to-search-instead-.patch"
+Content-Disposition: attachment;
+ filename="0001-Error-out-if-no-query-is-supplied-to-search-instead-.patch"
+Content-Transfer-Encoding: base64
+X-Attachment-Id: f_g25cms190
+
+RnJvbSAzZjk0MzFmNzRhNWZmNjZjODRjODY5YTNlMjZjMmJhZDQyYmVkMWIxIE1vbiBTZXAgMTcg
+MDA6MDA6MDAgMjAwMQpGcm9tOiBBbGV4YW5kZXIgQm90ZXJvLUxvd3J5IDxhbGV4LmJvdGVyb2xv
+d3J5QGdtYWlsLmNvbT4KRGF0ZTogVHVlLCAxNyBOb3YgMjAwOSAxNjoyMDoyOCAtMDgwMApTdWJq
+ZWN0OiBbUEFUQ0hdIEVycm9yIG91dCBpZiBubyBxdWVyeSBpcyBzdXBwbGllZCB0byBzZWFyY2gg
+aW5zdGVhZCBvZiBnb2luZyBpbnRvIGFuIGluZmluaXRlIGxvb3AKCi0tLQogbm90bXVjaC1zZWFy
+Y2guYyB8ICAgIDUgKysrKysKIDEgZmlsZXMgY2hhbmdlZCwgNSBpbnNlcnRpb25zKCspLCAwIGRl
+bGV0aW9ucygtKQoKZGlmZiAtLWdpdCBhL25vdG11Y2gtc2VhcmNoLmMgYi9ub3RtdWNoLXNlYXJj
+aC5jCmluZGV4IDhkYjA5YzcuLmQ5NGZjY2QgMTAwNjQ0Ci0tLSBhL25vdG11Y2gtc2VhcmNoLmMK
+KysrIGIvbm90bXVjaC1zZWFyY2guYwpAQCAtNjYsNiArNjYsMTEgQEAgbm90bXVjaF9zZWFyY2hf
+Y29tbWFuZCAodm9pZCAqY3R4LCBpbnQgYXJnYywgY2hhciAqYXJndltdKQogICAgIGFyZ2MgLT0g
+aTsKICAgICBhcmd2ICs9IGk7CiAKKyAgICBpZiAoYXJnYyA9PSAwKSB7CisgICAgICAgIGZwcmlu
+dGYgKHN0ZGVyciwgIk5vIHF1ZXJ5IHByb3ZpZGVkXG4iKTsKKyAgICAgICAgcmV0dXJuIDE7Cisg
+ICAgfQorCiAgICAgY29uZmlnID0gbm90bXVjaF9jb25maWdfb3BlbiAoY3R4LCBOVUxMLCBOVUxM
+KTsKICAgICBpZiAoY29uZmlnID09IE5VTEwpCiAJcmV0dXJuIDE7Ci0tIAoxLjYuNS4yCgo=
+--0016e64ca4d8f27a4804789a4139
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--0016e64ca4d8f27a4804789a4139--
+
--- /dev/null
+Date: Tue, 17 Nov 2009 19:50:40 -0500
+From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
+To: Keith Packard <keithp@keithp.com>
+Message-ID: <20091118005040.GA25380@dottiness.seas.harvard.edu>
+References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+ <87iqd9rn3l.fsf@vertex.dottedmag>
+ <20091117203301.GV3165@dottiness.seas.harvard.edu>
+ <yunaayketfm.fsf@aiko.keithp.com>
+MIME-Version: 1.0
+In-Reply-To: <yunaayketfm.fsf@aiko.keithp.com>
+User-Agent: Mutt/1.5.19 (2009-01-05)
+Cc: notmuch@notmuchmail.org
+Subject: Re: [notmuch] Working with Maildir storage?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============1483126515=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+
+--===============1483126515==
+Content-Type: multipart/signed; micalg=pgp-sha256;
+ protocol="application/pgp-signature"; boundary="9amGYk9869ThD9tj"
+Content-Disposition: inline
+
+
+--9amGYk9869ThD9tj
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+> I've also pushed a slightly more complicated (and complete) fix to my
+> private notmuch repository
+
+The version of lib/messages.cc in your repo doesn't build because it's
+missing "#include <stdint.h>" (for the uint32_t on line 466).
+
+--=20
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Senior Technologist, Computing and Information Technology
+Harvard University School of Engineering and Applied Sciences
+
+
+--9amGYk9869ThD9tj
+Content-Type: application/pgp-signature
+Content-Disposition: inline
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQEcBAEBCAAGBQJLA0TgAAoJENdGlQYxQazYsG0IAJ1t9h4Q3ma8z8ejeKR22Xh0
+WcuRX2x9yEXy/+aG9W7Mot0mqUQCiLdmHM/2h5N9BFHyJvfOUf8lmssrJ5OS/kp5
+j7FIx3GUELBmEZqFUPjRSQPk1hZURYdRsloKkrbQ2kAivjjb50zAAQ8Av4Cgj6cS
+3HvNNmeVfJt1NS75vm+/wn48M8Vrcdv4gvNlSOhgFOixknvRoxSyNDOHYBKvHnSV
+2HnO0GzhAQzDZAwdHBzJtb8vRmglrH33TVdrE7OW+sojYB3Wyz8r9+HIt8Q8ovzX
+nQ8p0Nf5DlF7tye3JYo0EeNm5EQJ4q0YyVYInhmtpi3A5Cyu50GcB/GZ5Sd6ajo=
+=WULe
+-----END PGP SIGNATURE-----
+
+--9amGYk9869ThD9tj--
+
+--===============1483126515==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============1483126515==--
+
+++ /dev/null
-From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 21:28:37 +0600
-Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
- headers
-Message-ID: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
-
-Keeping unused files open helps to see "Too many open files" often.
-
-Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
----
- lib/message-file.c | 5 +++++
- 1 files changed, 5 insertions(+), 0 deletions(-)
-
-diff --git a/lib/message-file.c b/lib/message-file.c
-index 8a3f8ee..197ab01 100644
---- a/lib/message-file.c
-+++ b/lib/message-file.c
-@@ -325,6 +325,11 @@ notmuch_message_file_get_header (notmuch_message_file_t *message,
- return decoded_value;
- }
-
-+ if (message->parsing_finished) {
-+ fclose (message->file);
-+ message->file = NULL;
-+ }
-+
- if (message->line)
- free (message->line);
- message->line = NULL;
---
-1.6.3.3
-
-
+++ /dev/null
-From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 21:28:38 +0600
-Subject: [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++
- file with gcc 4.4
-In-Reply-To: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
-References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
-Message-ID: <1258471718-6781-2-git-send-email-dottedmag@dottedmag.net>
-
-
-Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
----
- lib/message.cc | 2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
-
-diff --git a/lib/message.cc b/lib/message.cc
-index 72c350f..a4b090b 100644
---- a/lib/message.cc
-+++ b/lib/message.cc
-@@ -21,6 +21,8 @@
- #include "notmuch-private.h"
- #include "database-private.h"
-
-+#include <stdint.h>
-+
- #include <gmime/gmime.h>
-
- #include <xapian.h>
---
-1.6.3.3
-
-
+++ /dev/null
-Date: Tue, 17 Nov 2009 14:00:54 -0500
-From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
-To: notmuch@notmuchmail.org
-Message-ID: <20091117190054.GU3165@dottiness.seas.harvard.edu>
-MIME-Version: 1.0
-User-Agent: Mutt/1.5.19 (2009-01-05)
-Subject: [notmuch] Working with Maildir storage?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============1685355122=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
-
---===============1685355122==
-Content-Type: multipart/signed; micalg=pgp-sha256;
- protocol="application/pgp-signature"; boundary="5Dr6Wqe9hdyl7LAI"
-Content-Disposition: inline
-
-
---5Dr6Wqe9hdyl7LAI
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: quoted-printable
-
-I saw the LWN article and decided to take a look at notmuch. I'm
-currently using mutt and mairix to index and read a collection of
-Maildir mail folders (around 40,000 messages total).
-
-notmuch indexed the messages without complaint, but my attempt at
-searching bombed out. Running, for example:
-
- notmuch search storage
-
-Resulted in 4604 lines of errors along the lines of:
-
- Error opening
- /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=
-=3D3026:2,S:
- Too many open files
-
-I'm curious if this is expected behavior (i.e., notmuch does not work
-with Maildir) or if something else is going on.
-
-Cheers,
-
---=20
-Lars Kellogg-Stedman <lars@seas.harvard.edu>
-Senior Technologist, Computing and Information Technology
-Harvard University School of Engineering and Applied Sciences
-
-
---5Dr6Wqe9hdyl7LAI
-Content-Type: application/pgp-signature
-Content-Disposition: inline
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQEcBAEBCAAGBQJLAvLmAAoJENdGlQYxQazYRtcH/0usClQ1Z+EoTsA+URwIK6hD
-FsZUxFxRjMuOQRn2idZ/zhhg5jJj11ZaHjqxSkDvi2ywkTKUf1vX9LLzVy5hSR9M
-E6XQUd5QWAQXo1VsTeKkukIL0YqsPjdgrT8+Yt+OS2NvhEncql23oxnL2/pHkIFq
-r0NdTmVV5Jcar7w9J6X1Mi9m229a/9jV5FImsWISkIhIWznXU5SiU6zIw8xhP4E0
-xhvVSNJnFryjVHtva870aSQduhHfeLPzpYhqbkMPvlq+bcz6Q/Q2SwxJcGLNMPHa
-os9s9FGhCvFKUhVzezHWPgXNCcNT8qK89rcUldb5Oq4jaJb8RCZCYABplfoyaFs=
-=vO4s
------END PGP SIGNATURE-----
-
---5Dr6Wqe9hdyl7LAI--
-
---===============1685355122==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============1685355122==--
-
+++ /dev/null
-From: Mikhail Gusarov <dottedmag@dottedmag.net>
-To: notmuch@notmuchmail.org
-References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
-Date: Wed, 18 Nov 2009 01:02:38 +0600
-In-Reply-To: <20091117190054.GU3165@dottiness.seas.harvard.edu> (Lars
- Kellogg-Stedman's message of "Tue, 17 Nov 2009 14:00:54 -0500")
-Message-ID: <87iqd9rn3l.fsf@vertex.dottedmag>
-User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux)
-MIME-Version: 1.0
-Subject: Re: [notmuch] Working with Maildir storage?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============1958295626=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
---===============1958295626==
-Content-Type: multipart/signed; boundary="=-=-=";
- micalg=pgp-sha1; protocol="application/pgp-signature"
-
---=-=-=
-Content-Transfer-Encoding: quoted-printable
-
-
-Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did g=
-yre and gimble:
-
- LK> Resulted in 4604 lines of errors along the lines of:
-
- LK> Error opening
- LK> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostna=
-me,U=3D3026:2,S:
- LK> Too many open files
-
-See the patch just posted here.
-
-=2D-=20
- http://fossarchy.blogspot.com/
-
---=-=-=
-Content-Type: application/pgp-signature
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQIcBAEBAgAGBQJLAvNOAAoJEJ0g9lA+M4iIjLYQAKp0PXEgl3JMOEBisH52AsIK
-CzzfP4Fzd41K9VH/c1EdQWDYR6FCAA4IUSNICnJhITsYUb0eC5AKJiey3JP0+rmd
-s4qEFBKH2iuphv8Llltcv2Q8DyPuJBkVa3mO9XCCeABZ6v4UvnTSWRVG12csSEih
-ScgienU8sMrM9LwvvVI1ZB2flm2TzsH2hWi30jIgmtBntIKJaTgbFXB50FYFwULa
-gGL/oH3u+YpumedWzPZdCJrw2q7nMvYx8aQ29EDCNLZibAZe+6oDTa6Fv6/0ldpQ
-U+DptR0nJGbJTWa26OTSvmyeIORjAfM+TEI68n7KO9VHYPmVh6awcf0MNKYh2xWk
-eRQNBcKyQNWxeKyCCpT/rrTlpxBWahpvg+V8lkDH2W09wjRp6CUKvifK3Sz3am9m
-5ZUMpvXbwkZD6Ci6l/QytbYK50e8UpvFSu5DBaxBz59ykoypuNg2ayO5Kdi6IF5d
-T+Sw6wo8UKn9a33+vheIc0fkhZXbeSotEmDm7huazm6CgM3dcWXUpTuJvik1cSWp
-4buv98gY6IKWKoUTXODWUr+7VR4gei8du8qOsKem+QDfNX7tmaIRjhrbB24B91Wy
-td3MTJD7GjMNid0INqRY1CRMLo8YlPaq6NBZfcYtYgwa6gpJijz1/MAn8+GMrfhF
-9LI8b9jopNP+pMYBohLA
-=/ksP
------END PGP SIGNATURE-----
---=-=-=--
-
---===============1958295626==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============1958295626==--
-
+++ /dev/null
-MIME-Version: 1.0
-Date: Tue, 17 Nov 2009 11:36:14 -0800
-Message-ID: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
-From: Alex Botero-Lowry <alex.boterolowry@gmail.com>
-To: notmuch@notmuchmail.org
-Content-Type: multipart/mixed; boundary=0016e687869333b1570478963d35
-Subject: [notmuch] preliminary FreeBSD support
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
---0016e687869333b1570478963d35
-Content-Type: multipart/alternative; boundary=0016e687869333b14e0478963d33
-
---0016e687869333b14e0478963d33
-Content-Type: text/plain; charset=ISO-8859-1
-
-I saw the announcement this morning, and was very excited, as I had been
-hoping sup would be turned into a library,
-since I like the concept more than the UI (I'd rather an emacs interface).
-
-I did a preliminary compile which worked out fine, but
-sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
-FreeBSD, so notmuch_config_open segfaulted.
-
-Attached is a patch that supplies a default buffer size of 64 in cases where
--1 is returned.
-
-http://www.opengroup.org/austin/docs/austin_328.txt - seems to indicate this
-is acceptable behavior,
-and http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.htmlspecifically
-uses 64 as the
-buffer size.
-
---0016e687869333b14e0478963d33
-Content-Type: text/html; charset=ISO-8859-1
-Content-Transfer-Encoding: quoted-printable
-
-I saw the announcement this morning, and was very excited, as I had been ho=
-ping sup would be turned into a library,<br>since I like the concept more t=
-han the UI (I'd rather an emacs interface).<br><br>I did a preliminary =
-compile which worked out fine, but sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns=
- -1 on<br>
-FreeBSD, so notmuch_config_open segfaulted.<br><br>Attached is a patch that=
- supplies a default buffer size of 64 in cases where -1 is returned.<br><br=
-><a href=3D"http://www.opengroup.org/austin/docs/austin_328.txt">http://www=
-.opengroup.org/austin/docs/austin_328.txt</a> - seems to indicate this is a=
-cceptable behavior,<br>
-and <a href=3D"http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg01680=
-8.html">http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.html<=
-/a> specifically uses 64 as the<br>buffer size.<br><br><br>
-
---0016e687869333b14e0478963d33--
---0016e687869333b1570478963d35
-Content-Type: application/octet-stream;
- name="0001-Deal-with-situation-where-sysconf-_SC_GETPW_R_SIZE_M.patch"
-Content-Disposition: attachment;
- filename="0001-Deal-with-situation-where-sysconf-_SC_GETPW_R_SIZE_M.patch"
-Content-Transfer-Encoding: base64
-X-Attachment-Id: f_g252e6gs0
-
-RnJvbSBlM2JjNGJiZDdiOWQwZDA4NjgxNmFiNWY4ZjJkNmZmZWExZGQzZWE0IE1vbiBTZXAgMTcg
-MDA6MDA6MDAgMjAwMQpGcm9tOiBBbGV4YW5kZXIgQm90ZXJvLUxvd3J5IDxhbGV4LmJvdGVyb2xv
-d3J5QGdtYWlsLmNvbT4KRGF0ZTogVHVlLCAxNyBOb3YgMjAwOSAxMTozMDozOSAtMDgwMApTdWJq
-ZWN0OiBbUEFUQ0hdIERlYWwgd2l0aCBzaXR1YXRpb24gd2hlcmUgc3lzY29uZihfU0NfR0VUUFdf
-Ul9TSVpFX01BWCkgcmV0dXJucyAtMQoKLS0tCiBub3RtdWNoLWNvbmZpZy5jIHwgICAgMiArKwog
-MSBmaWxlcyBjaGFuZ2VkLCAyIGluc2VydGlvbnMoKyksIDAgZGVsZXRpb25zKC0pCgpkaWZmIC0t
-Z2l0IGEvbm90bXVjaC1jb25maWcuYyBiL25vdG11Y2gtY29uZmlnLmMKaW5kZXggMjQ4MTQ5Yy4u
-ZTcyMjBkOCAxMDA2NDQKLS0tIGEvbm90bXVjaC1jb25maWcuYworKysgYi9ub3RtdWNoLWNvbmZp
-Zy5jCkBAIC03Nyw2ICs3Nyw3IEBAIHN0YXRpYyBjaGFyICoKIGdldF9uYW1lX2Zyb21fcGFzc3dk
-X2ZpbGUgKHZvaWQgKmN0eCkKIHsKICAgICBsb25nIHB3X2J1Zl9zaXplID0gc3lzY29uZihfU0Nf
-R0VUUFdfUl9TSVpFX01BWCk7CisgICAgaWYgKHB3X2J1Zl9zaXplID09IC0xKSBwd19idWZfc2l6
-ZSA9IDY0OwogICAgIGNoYXIgKnB3X2J1ZiA9IHRhbGxvY196ZXJvX3NpemUgKGN0eCwgcHdfYnVm
-X3NpemUpOwogICAgIHN0cnVjdCBwYXNzd2QgcGFzc3dkLCAqaWdub3JlZDsKICAgICBjaGFyICpu
-YW1lOwpAQCAtMTAxLDYgKzEwMiw3IEBAIHN0YXRpYyBjaGFyICoKIGdldF91c2VybmFtZV9mcm9t
-X3Bhc3N3ZF9maWxlICh2b2lkICpjdHgpCiB7CiAgICAgbG9uZyBwd19idWZfc2l6ZSA9IHN5c2Nv
-bmYoX1NDX0dFVFBXX1JfU0laRV9NQVgpOworICAgIGlmIChwd19idWZfc2l6ZSA9PSAtMSkgcHdf
-YnVmX3NpemUgPSA2NDsKICAgICBjaGFyICpwd19idWYgPSB0YWxsb2NfemVyb19zaXplIChjdHgs
-IHB3X2J1Zl9zaXplKTsKICAgICBzdHJ1Y3QgcGFzc3dkIHBhc3N3ZCwgKmlnbm9yZWQ7CiAgICAg
-Y2hhciAqbmFtZTsKLS0gCjEuNi41LjIKCg==
---0016e687869333b1570478963d35
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---0016e687869333b1570478963d35--
-
+++ /dev/null
-From: "Carl Worth" <cworth@cworth.org>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 12:19:24 -0800
-Subject: [notmuch] preliminary FreeBSD support
-In-Reply-To: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
-References: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
-Message-ID: <87lji4lx9v.fsf@yoom.home.cworth.org>
-
-On Tue, 17 Nov 2009 11:36:14 -0800, Alex Botero-Lowry <alex.boterolowry at gmail.com> wrote:
-> I saw the announcement this morning, and was very excited, as I had been
-> hoping sup would be turned into a library,
-> since I like the concept more than the UI (I'd rather an emacs interface).
-
-Hi Alex,
-
-That's great! It's good to hear that there are like-minded people out
-there. I hope that Notmuch will be useful for you.
-
-> I did a preliminary compile which worked out fine, but
-> sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
-> FreeBSD, so notmuch_config_open segfaulted.
->
-> Attached is a patch that supplies a default buffer size of 64 in cases where
-> -1 is returned.
-
-Thanks for the patch. As we discussed in IRC[*], we should probably
-do the correct thing and check for ERANGE and loop as necessary (even if
-sysconf returns a positive value). Example code here:
-
-http://www.opengroup.org/austin/docs/austin_328.txt
-
--Carl
-
-[*] #notmuch on irc.freenode.net for those who didn't just guess that
-already, (and I'll add that to the website soon).
-
+++ /dev/null
-From: "Carl Worth" <cworth@cworth.org>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 09:13:27 -0800
-Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
- headers
-In-Reply-To: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
-References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
-Message-ID: <87lji5cbwo.fsf@yoom.home.cworth.org>
-
-On Tue, 17 Nov 2009 21:28:37 +0600, Mikhail Gusarov <dottedmag at dottedmag.net> wrote:
-> Keeping unused files open helps to see "Too many open files" often.
->
-> Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
-...
-On Tue, 17 Nov 2009 21:28:38 +0600, Mikhail Gusarov <dottedmag at dottedmag.net> wrote:
->
-> Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
-> ---
-> lib/message.cc | 2 ++
-> 1 files changed, 2 insertions(+), 0 deletions(-)
-
-Hi Mikhail,
-
-Welcome to notmuch, and thanks for these patches! I've pushed both of
-them out now.
-
-Keith ran into the same problem of "too many open files" and wrote a
-more complex fix, (which included what you did here). His code can be
-seen at:
-
- git://keithp.com/git/notmuch
-
-I didn't apply Keith's fix yet, because I think I'd rather just fix the
-indexer to store the In-Reply-To header in a separate term prefix from
-the term used for the References header[*]. That will then let us lookup
-the in-reply-to value later for thread constructions without having to
-open the original email file at all.
-
--Carl
-
-[*] Yes, this is my first post to our new mailing list and I'm already
-spouting off about "terms" and "prefixes" without any definitions. I
-apologize for that. I hope that people will ask questions freely here on
-the list whenever anything is not clear, and I'll be glad to explain
-things as needed. (Then when can shove answers into a HACKING document.)
-
-PS. This reply is a great example of a feature that notmuch *almost*
-supports already---repling to multiple messages at once. The "notmuch
-reply" command line does everything necessary to make this work, but we
-haven't yet hooked up any keybindings for this in the emacs client yet.
-Obviously, 'r' from the search view could reply to the entire thread.
-But when viewing a thread, anyone have a good keybinding suggestion?
-(There's obviously 'R' as opposed to 'r', but I think we'll probably
-want to distinguish "reply to sender" from "reply to all" before trying
-to distinguish "reply to message" from "reply to thread" (which I
-imagine is more rare of an operation).
-
+++ /dev/null
-Date: Tue, 17 Nov 2009 15:33:01 -0500
-From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
-To: Mikhail Gusarov <dottedmag@dottedmag.net>
-Message-ID: <20091117203301.GV3165@dottiness.seas.harvard.edu>
-References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
- <87iqd9rn3l.fsf@vertex.dottedmag>
-MIME-Version: 1.0
-In-Reply-To: <87iqd9rn3l.fsf@vertex.dottedmag>
-User-Agent: Mutt/1.5.19 (2009-01-05)
-Cc: notmuch@notmuchmail.org
-Subject: Re: [notmuch] Working with Maildir storage?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============0063752545=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
-
---===============0063752545==
-Content-Type: multipart/signed; micalg=pgp-sha256;
- protocol="application/pgp-signature"; boundary="GGxZz/e2pmGePzrA"
-Content-Disposition: inline
-
-
---GGxZz/e2pmGePzrA
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: quoted-printable
-
-> See the patch just posted here.
-
-Is the list archived anywhere? The obvious archives
-(http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
-think I subscribed too late to get the patch (I only just saw the
-discussion about it).
-
-It doesn't look like the patch is in git yet.
-
--- Lars
-
---=20
-Lars Kellogg-Stedman <lars@seas.harvard.edu>
-Senior Technologist, Computing and Information Technology
-Harvard University School of Engineering and Applied Sciences
-
-
---GGxZz/e2pmGePzrA
-Content-Type: application/pgp-signature
-Content-Disposition: inline
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQEcBAEBCAAGBQJLAwh9AAoJENdGlQYxQazYHJMIAI+XTPOyBTZIxEGTdgVKd2fR
-k27ucKs6lXozfMIIGchNUDXQho+KmiuTfX1XFJeBkqOlhrd9zlGjBGoBM0YBq/Gs
-aStPdonREzsHORjmyQCCpjg4AcqCRTXFbDXzAeXlxMPOrZ3P0XNPzTEM1mVksbmg
-mBBDLdHncy4sSCfFgXwRGGgLv9z5Acqm8xGYr68c9PIXY939ozIKV9LVUhxiNz9g
-We2a9rLDhfwxUqDlGdiNwZZimiKvD/fsYSrBZMDb5HgIYkeNZ4SD8Xu+OgB550wN
-OFfwGi3o8WFK2AyDe5QJDh9Ub+euPNlVzePoGpkltZEHuCcLFJqCHv5XYpbxcjA=
-=GO2Q
------END PGP SIGNATURE-----
-
---GGxZz/e2pmGePzrA--
-
---===============0063752545==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============0063752545==--
-
+++ /dev/null
-From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
-To: notmuch@notmuchmail.org
-Date: Wed, 18 Nov 2009 02:50:48 +0600
-Subject: [notmuch] Working with Maildir storage?
-In-Reply-To: <20091117203301.GV3165@dottiness.seas.harvard.edu> (Lars
- Kellogg-Stedman's message of "Tue, 17 Nov 2009 15:33:01 -0500")
-References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
- <87iqd9rn3l.fsf@vertex.dottedmag>
- <20091117203301.GV3165@dottiness.seas.harvard.edu>
-Message-ID: <87fx8can9z.fsf@vertex.dottedmag>
-
-
-Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu did gyre and gimble:
-
- LK> Is the list archived anywhere? The obvious archives
- LK> (http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
- LK> think I subscribed too late to get the patch (I only just saw the
- LK> discussion about it).
-
- LK> It doesn't look like the patch is in git yet.
-
-Just has been pushed
-
---
- http://fossarchy.blogspot.com/
--------------- next part --------------
-A non-text attachment was scrubbed...
-Name: not available
-Type: application/pgp-signature
-Size: 834 bytes
-Desc: not available
-URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
-
+++ /dev/null
-From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
-To: notmuch@notmuchmail.org
-Date: Wed, 18 Nov 2009 02:51:18 +0600
-Subject: [notmuch] [PATCH] Handle rename of message file
-Message-ID: <1258491078-29658-1-git-send-email-dottedmag@dottedmag.net>
-
-If message file has been renamed, just update filename in the DB.
-
-Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
----
- lib/database.cc | 21 ++++++++++++---------
- 1 files changed, 12 insertions(+), 9 deletions(-)
-
-diff --git a/lib/database.cc b/lib/database.cc
-index 3c8d626..c4eb8b6 100644
---- a/lib/database.cc
-+++ b/lib/database.cc
-@@ -925,20 +925,23 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
- if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {
- _notmuch_message_set_filename (message, filename);
- _notmuch_message_add_term (message, "type", "mail");
-+
-+ ret = _notmuch_database_link_message (notmuch, message, message_file);
-+ if (ret)
-+ goto DONE;
-+
-+ date = notmuch_message_file_get_header (message_file, "date");
-+ _notmuch_message_set_date (message, date);
-+
-+ _notmuch_message_index_file (message, filename);
-+ } else if (strcmp(notmuch_message_get_filename(message), filename)) {
-+ /* Message file has been moved/renamed */
-+ _notmuch_message_set_filename (message, filename);
- } else {
- ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
- goto DONE;
- }
-
-- ret = _notmuch_database_link_message (notmuch, message, message_file);
-- if (ret)
-- goto DONE;
--
-- date = notmuch_message_file_get_header (message_file, "date");
-- _notmuch_message_set_date (message, date);
--
-- _notmuch_message_index_file (message, filename);
--
- _notmuch_message_sync (message);
- } catch (const Xapian::Error &error) {
- fprintf (stderr, "A Xapian exception occurred: %s.\n",
---
-1.6.3.3
-
-
+++ /dev/null
-From: "Keith Packard" <keithp@keithp.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 13:15:25 -0800
-Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
- headers
-In-Reply-To: <87lji5cbwo.fsf@yoom.home.cworth.org>
-References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
- <87lji5cbwo.fsf@yoom.home.cworth.org>
-Message-ID: <yunbpj0etua.fsf@aiko.keithp.com>
-
-On Tue, 17 Nov 2009 09:13:27 -0800, Carl Worth <cworth at cworth.org> wrote:
-
-> I didn't apply Keith's fix yet, because I think I'd rather just fix the
-> indexer to store the In-Reply-To header in a separate term prefix from
-> the term used for the References header[*]. That will then let us lookup
-> the in-reply-to value later for thread constructions without having to
-> open the original email file at all.
-
-Threading the message also involves displaying the from and to contents,
-which requires opening the message file. The alternative to the fix I
-provided is to just parse all of the message headers when first opening
-the message; it could then be immediately closed and the hash referred
-to for all header data. Given the choice, just having the caller say
-when it has finished with a message is probably a reasonable option...
-
--keith
-
+++ /dev/null
-From: "Keith Packard" <keithp@keithp.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 13:24:13 -0800
-Subject: [notmuch] Working with Maildir storage?
-In-Reply-To: <20091117203301.GV3165@dottiness.seas.harvard.edu>
-References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
- <87iqd9rn3l.fsf@vertex.dottedmag>
- <20091117203301.GV3165@dottiness.seas.harvard.edu>
-Message-ID: <yunaayketfm.fsf@aiko.keithp.com>
-
-On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
-> > See the patch just posted here.
-
-I've also pushed a slightly more complicated (and complete) fix to my
-private notmuch repository
-
-git://keithp.com/git/notmuch
-
-> Is the list archived anywhere?
-
-Oops. Looks like Carl's mail server is broken. He's traveling to
-Barcelona today and so it won't get fixed for a while.
-
-Thanks to everyone for trying out notmuch!
-
--keith
-
+++ /dev/null
-From: "Keith Packard" <keithp@keithp.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 13:32:45 -0800
-Subject: [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove
- inbox (and unread) tags
-Message-ID: <1258493565-13508-1-git-send-email-keithp@keithp.com>
-
-When closing a thread view, mark the thread as archived by removing
-the "inbox" tag, and for the 'x' variant, the "unread" tag as well,
-then kill the buffer and update the search window view as well.
-
-This makes 'x' much the same as 'a', but instead of taking you to the
-next message, it takes you back to the search window instead.
-
-Signed-off-by: Keith Packard <keithp at keithp.com>
----
- notmuch.el | 86 ++++++++++++++++++++++++++++++++++++++++++++++-------------
- 1 files changed, 67 insertions(+), 19 deletions(-)
-
-diff --git a/notmuch.el b/notmuch.el
-index 638d49d..7b0d72c 100644
---- a/notmuch.el
-+++ b/notmuch.el
-@@ -31,8 +31,8 @@
- ; Will be much preferable to switch to direct manipulation for
- ; toggling visibility of these components. Probably using
- ; overlays-at to query and manipulate the current overlay.
-- (define-key map "a" 'notmuch-show-archive-thread)
-- (define-key map "A" 'notmuch-show-mark-read-then-archive-thread)
-+ (define-key map "a" 'notmuch-show-mark-read-archive-thread-next-thread)
-+ (define-key map "A" 'notmuch-show-archive-thread-next-thread)
- (define-key map "b" 'notmuch-show-toggle-body-read-visible)
- (define-key map "c" 'notmuch-show-toggle-citations-visible)
- (define-key map "h" 'notmuch-show-toggle-headers-visible)
-@@ -47,7 +47,8 @@
- (define-key map "s" 'notmuch-show-toggle-signatures-visible)
- (define-key map "v" 'notmuch-show-view-all-mime-parts)
- (define-key map "w" 'notmuch-show-view-raw-message)
-- (define-key map "x" 'kill-this-buffer)
-+ (define-key map "x" 'notmuch-show-mark-read-archive-thread-kill-buffer)
-+ (define-key map "X" 'notmuch-show-archive-thread-kill-buffer)
- (define-key map "+" 'notmuch-show-add-tag)
- (define-key map "-" 'notmuch-show-remove-tag)
- (define-key map (kbd "DEL") 'notmuch-show-rewind)
-@@ -183,7 +184,33 @@ Unlike builtin `next-line' this version accepts no arguments."
- (cons (notmuch-show-get-message-id) nil)))
- (notmuch-show-set-tags (sort (set-difference tags toremove :test 'string=) 'string<))))))
-
--(defun notmuch-show-archive-thread-maybe-mark-read (markread)
-+(defun notmuch-show-next-thread (markread)
-+ (let ((parent-buffer notmuch-show-parent-buffer))
-+ (kill-this-buffer)
-+ (if parent-buffer
-+ (progn
-+ (switch-to-buffer parent-buffer)
-+ (forward-line)
-+ (notmuch-search-show-thread)))))
-+
-+(defun notmuch-delete-tags (to-remove from)
-+ (if to-remove
-+ (delete (car to-remove) (notmuch-delete-tags (cdr to-remove) from))
-+ from))
-+
-+(defun notmuch-kill-message-buffer (markread)
-+ (let ((parent-buffer notmuch-show-parent-buffer))
-+ (kill-this-buffer)
-+ (if parent-buffer
-+ (progn
-+ (switch-to-buffer parent-buffer)
-+ (let ((tags (notmuch-search-get-tags)))
-+ (setq tags (delete "inbox" tags))
-+ (if markread (setq tags (delete "unread" tags)))
-+ (notmuch-search-set-tags tags))
-+ (forward-line)))))
-+
-+(defun notmuch-show-archive-thread-maybe-mark-read (markread shownext)
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
-@@ -194,15 +221,9 @@ Unlike builtin `next-line' this version accepts no arguments."
- (forward-char))
- (if (not (re-search-forward notmuch-show-message-begin-regexp nil t))
- (goto-char (point-max)))))
-- (let ((parent-buffer notmuch-show-parent-buffer))
-- (kill-this-buffer)
-- (if parent-buffer
-- (progn
-- (switch-to-buffer parent-buffer)
-- (forward-line)
-- (notmuch-search-show-thread)))))
-+ (if shownext (notmuch-show-next-thread markread) (notmuch-kill-message-buffer markread)))
-
--(defun notmuch-show-mark-read-then-archive-thread ()
-+(defun notmuch-show-mark-read-archive-thread-next-thread ()
- "Remove \"unread\" tag from each message, then archive and show next thread.
-
- Archive each message currrently shown by removing the \"unread\"
-@@ -215,9 +236,22 @@ being delivered to the same thread. It does not archive the
- entire thread, but only the messages shown in the current
- buffer."
- (interactive)
-- (notmuch-show-archive-thread-maybe-mark-read t))
-+ (notmuch-show-archive-thread-maybe-mark-read t t))
-+
-+(defun notmuch-show-mark-read-archive-thread-kill-buffer ()
-+ "Remove \"unread\" tag from each message, then archive and kill the buffer.
-+
-+Archive each message currrently shown by removing the \"unread\"
-+and \"inbox\" tag from each. Then kill this buffer.
-+
-+Note: This command is safe from any race condition of new messages
-+being delivered to the same thread. It does not archive the
-+entire thread, but only the messages shown in the current
-+buffer."
-+ (interactive)
-+ (notmuch-show-archive-thread-maybe-mark-read t nil))
-
--(defun notmuch-show-archive-thread ()
-+(defun notmuch-show-archive-thread-next-thread ()
- "Archive each message in thread, and show next thread from search.
-
- Archive each message currrently shown by removing the \"inbox\"
-@@ -229,7 +263,20 @@ being delivered to the same thread. It does not archive the
- entire thread, but only the messages shown in the current
- buffer."
- (interactive)
-- (notmuch-show-archive-thread-maybe-mark-read nil))
-+ (notmuch-show-archive-thread-maybe-mark-read nil t))
-+
-+(defun notmuch-show-archive-thread-kill-buffer ()
-+ "Archive each message in thread, and kill the thread buffer.
-+
-+Archive each message currrently shown by removing the \"inbox\"
-+tag from each. Then kill this buffer.
-+
-+Note: This command is safe from any race condition of new messages
-+being delivered to the same thread. It does not archive the
-+entire thread, but only the messages shown in the current
-+buffer."
-+ (interactive)
-+ (notmuch-show-archive-thread-maybe-mark-read nil t))
-
- (defun notmuch-show-view-raw-message ()
- "View the raw email of the current message."
-@@ -297,7 +344,7 @@ by searching backward)."
- (not (re-search-forward notmuch-show-message-begin-regexp nil t)))))
-
- (defun notmuch-show-message-unread-p ()
-- "Preficate testing whether current message is unread."
-+ "Predicate testing whether current message is unread."
- (member "unread" (notmuch-show-get-tags)))
-
- (defun notmuch-show-next-message ()
-@@ -434,7 +481,7 @@ which this thread was originally shown."
- (let ((last (notmuch-show-last-message-p)))
- (notmuch-show-mark-read-then-next-open-message)
- (if last
-- (notmuch-show-archive-thread))))))
-+ (notmuch-show-archive-thread-next-thread))))))
-
- (defun notmuch-show-markup-citations-region (beg end depth)
- (goto-char beg)
-@@ -618,8 +665,9 @@ messages. Each time you navigate away from a message with
-
- You can add or remove tags from the current message with '+' and
- '-'. You can also archive all messages in the current
--view, (remove the \"inbox\" tag from each), with
--`notmuch-show-archive-thread' (bound to 'a' by default).
-+view, (remove the \"inbox\" tag from each), with either
-+`notmuch-show-archive-thread-next-thread' (bound to 'a' by default) or
-+`notmuch-show-archive-thread-kill-buffer' (bound to 'x' by default).
-
- \\{notmuch-show-mode-map}"
- (interactive)
---
-1.6.5.2
-
-
+++ /dev/null
-From: "Jan Janak" <jan@ryngle.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 23:18:47 +0100
-Subject: [notmuch] [PATCH] Older versions of install do not support -C.
-Message-ID: <1258496327-12086-1-git-send-email-jan@ryngle.com>
-
-Do not use -C cmdline option of install, older versions, commonly found in
-distributions like Debian, do not seem to support it. Running make install
-on such systems (tested on Debian Lenny) fails.
-
-Signed-off-by: Jan Janak <jan at ryngle.com>
----
- Makefile.local | 8 ++++----
- 1 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/Makefile.local b/Makefile.local
-index f824bed..f51f1d1 100644
---- a/Makefile.local
-+++ b/Makefile.local
-@@ -27,11 +27,11 @@ install: all notmuch.1.gz
- for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 \
- $(DESTDIR)/etc/bash_completion.d/ ; \
- do \
-- install -C -d $$d ; \
-+ install -d $$d ; \
- done ;
-- install -C notmuch $(DESTDIR)$(prefix)/bin/
-- install -C -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
-- install -C notmuch-completion.bash \
-+ install notmuch $(DESTDIR)$(prefix)/bin/
-+ install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
-+ install notmuch-completion.bash \
- $(DESTDIR)/etc/bash_completion.d/notmuch
-
- SRCS := $(SRCS) $(notmuch_client_srcs)
---
-1.6.3.3
-
-
+++ /dev/null
-From: "Jan Janak" <jan@ryngle.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 23:35:30 +0100
-Subject: [notmuch] What a great idea!
-Message-ID: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
-
-Hello,
-
-First of all, notmuch is a wonderful idea, both the cmdline tool and
-the emacs interface! Thanks a lot for writing it, I was really excited
-when I read the announcement today.
-
-Have you considered sending an announcement to the org-mode mailing list?
-http://org-mode.org
-
-Various ways of searching/referencing emails from emacs were discussed
-there several times and none of them were as elegant as notmuch (not
-even close). Maybe notmuch would attract some of the developers
-there..
-
- -- Jan
-
+++ /dev/null
-From: "Jan Janak" <jan@ryngle.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 23:38:47 +0100
-Subject: [notmuch] What a great idea!
-In-Reply-To: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
-References: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
-Message-ID: <f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com>
-
-On Tue, Nov 17, 2009 at 11:35 PM, Jan Janak <jan at ryngle.com> wrote:
-> Hello,
->
-> First of all, notmuch is a wonderful idea, both the cmdline tool and
-> the emacs interface! Thanks a lot for writing it, I was really excited
-> when I read the announcement today.
->
-> Have you considered sending an announcement to the org-mode mailing list?
-> http://org-mode.org
-
-Sorry, wrong URL, the correct one is: http://orgmode.org
-
-> Various ways of searching/referencing emails from emacs were discussed
-> there several times and none of them were as elegant as notmuch (not
-> even close). Maybe notmuch would attract some of the developers
-> there..
-
- -- Jan
-
+++ /dev/null
-From: "Israel Herraiz" <isra@herraiz.org>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 23:57:18 +0100
-Subject: [notmuch] New to the list
-Message-ID: <1258498485-sup-142@elly>
-
-Hi all,
-
-I have subscribed to the list. As suggested by the welcome message, I
-am introducing myself. My name is Israel Herraiz, and I have done a
-couple of contributions to Sup, the probably well-known here e-mail
-client.
-
-"Not much" sounds interesting, and I wonder whether it could be
-integrated with the views of Sup (inbox, threads, etc). So I have
-subscribed to the list to keep an eye on what's going on here.
-
-I have just heard of "Not much". I have not even tried to download the
-code yet.
-
-Cheers,
-Israel
-
+++ /dev/null
-From: "Aron Griffis" <agriffis@n01se.net>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 18:21:38 -0500
-Subject: [notmuch] archive
-Message-ID: <20091117232137.GA7669@griffis1.net>
-
-Just subscribed, I'd like to catch up on the previous postings,
-but the archive link seems to be bogus?
-
-Thanks,
-Aron
-
+++ /dev/null
-From: "Ingmar Vanhassel" <ingmar@exherbo.org>
-To: notmuch@notmuchmail.org
-Date: Wed, 18 Nov 2009 00:23:42 +0100
-Subject: [notmuch] [PATCH] Typsos
-Message-ID: <1258500222-32066-1-git-send-email-ingmar@exherbo.org>
-
----
- Makefile | 4 ++--
- README | 6 +++---
- gmime-filter-reply.h | 2 +-
- lib/database.cc | 2 +-
- lib/index.cc | 2 +-
- lib/message.cc | 2 +-
- lib/messages.c | 2 +-
- lib/notmuch-private.h | 2 +-
- lib/notmuch.h | 10 +++++-----
- lib/sha1.c | 2 +-
- lib/thread.cc | 2 +-
- notmuch-completion.bash | 2 +-
- notmuch-new.c | 4 ++--
- notmuch-search.c | 2 +-
- notmuch.1 | 4 ++--
- notmuch.el | 10 +++++-----
- show-message.c | 2 +-
- 17 files changed, 30 insertions(+), 30 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 436dacf..96aaa73 100644
---- a/Makefile
-+++ b/Makefile
-@@ -1,4 +1,4 @@
--# Default FLAGS, (can be overriden by user such as "make CFLAGS=-O2")
-+# Default FLAGS, (can be overridden by user such as "make CFLAGS=-O2")
- WARN_FLAGS=-Wall -Wextra -Wmissing-declarations -Wwrite-strings -Wswitch-enum
- CFLAGS=-O2
-
-@@ -14,7 +14,7 @@ override CXXFLAGS += $(WARN_FLAGS) $(extra_cflags) $(extra_cxxflags)
- override LDFLAGS += `pkg-config --libs glib-2.0 gmime-2.4 talloc` \
- `xapian-config --libs`
-
--# Include our local Makfile.local first so that its first target is default
-+# Include our local Makefile.local first so that its first target is default
- include Makefile.local
- include lib/Makefile.local
-
-diff --git a/README b/README
-index 40f05ab..27af77f 100644
---- a/README
-+++ b/README
-@@ -3,7 +3,7 @@ Notmuch - thread-based email index, search and tagging.
- Notmuch is a system for indexing, searching, reading, and tagging
- large collections of email messages. It uses the Xapian library to
- provide fast, full-text search of very large collection of email with
--a very convenient search syntas.
-+a very convenient search syntax.
-
- Notmuch is free software, released under the GNU General Public
- License version 3 (or later).
-@@ -45,7 +45,7 @@ obtaining a more sophisticated interface:
- notmuch.el file in this distribution.
-
- If someone were to write a curses-based interface, or similar,
-- it might also be reasonable to buil on the "notmuch"
-+ it might also be reasonable to build on the "notmuch"
- command-line interface.
-
- 2. Build on top of the notmuch library interface.
-@@ -67,4 +67,4 @@ still in development. We would appreciate any contributions to these
- efforts.
-
-
--
-\ No newline at end of file
-+
-diff --git a/gmime-filter-reply.h b/gmime-filter-reply.h
-index 41cbc13..b7cbc6b 100644
---- a/gmime-filter-reply.h
-+++ b/gmime-filter-reply.h
-@@ -40,7 +40,7 @@ typedef struct _GMimeFilterReplyClass GMimeFilterReplyClass;
- * @saw_nl: previous char was a \n
- * @saw_angle: previous char was a >
- *
-- * A filter to insert/remove reply markers (lines begining with >)
-+ * A filter to insert/remove reply markers (lines beginning with >)
- **/
- struct _GMimeFilterReply {
- GMimeFilter parent_object;
-diff --git a/lib/database.cc b/lib/database.cc
-index 3c8d626..27597cf 100644
---- a/lib/database.cc
-+++ b/lib/database.cc
-@@ -180,7 +180,7 @@ notmuch_status_to_string (notmuch_status_t status)
- case NOTMUCH_STATUS_TAG_TOO_LONG:
- return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)";
- case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
-- return "Unblanced number of calls to notmuch_message_freeze/thaw";
-+ return "Unbalanced number of calls to notmuch_message_freeze/thaw";
- default:
- case NOTMUCH_STATUS_LAST_STATUS:
- return "Unknown error status value";
-diff --git a/lib/index.cc b/lib/index.cc
-index 65b83b3..80df64b 100644
---- a/lib/index.cc
-+++ b/lib/index.cc
-@@ -198,7 +198,7 @@ _index_mime_part (notmuch_message_t *message,
- if (i == 1)
- continue;
- if (i > 1)
-- fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Indexing anyway.\n");
-+ fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n");
- }
- _index_mime_part (message,
- g_mime_multipart_get_part (multipart, i));
-diff --git a/lib/message.cc b/lib/message.cc
-index a4b090b..1d6623f 100644
---- a/lib/message.cc
-+++ b/lib/message.cc
-@@ -144,7 +144,7 @@ _notmuch_message_create (const void *talloc_owner,
- }
-
- /* Create a new notmuch_message_t object for a specific message ID,
-- * (which may or may not already exist in the databas).
-+ * (which may or may not already exist in the database).
- *
- * Here, 'talloc owner' is an optional talloc context to which the new
- * message will belong. This allows for the caller to not bother
-diff --git a/lib/messages.c b/lib/messages.c
-index a588f8f..2f7c283 100644
---- a/lib/messages.c
-+++ b/lib/messages.c
-@@ -47,7 +47,7 @@ _notmuch_message_list_create (const void *ctx)
- return list;
- }
-
--/* Append 'node' (which can of course point to an aribtrarily long
-+/* Append 'node' (which can of course point to an arbitrarily long
- * list of nodes) to the end of 'list'.
- */
- void
-diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
-index 6036ce4..af82e58 100644
---- a/lib/notmuch-private.h
-+++ b/lib/notmuch-private.h
-@@ -235,7 +235,7 @@ notmuch_message_file_open (const char *filename);
- notmuch_message_file_t *
- _notmuch_message_file_open_ctx (void *ctx, const char *filename);
-
--/* Close a notmuch message preivously opened with notmuch_message_open. */
-+/* Close a notmuch message previously opened with notmuch_message_open. */
- void
- notmuch_message_file_close (notmuch_message_file_t *message);
-
-diff --git a/lib/notmuch.h b/lib/notmuch.h
-index 32b5332..384c177 100644
---- a/lib/notmuch.h
-+++ b/lib/notmuch.h
-@@ -222,7 +222,7 @@ notmuch_database_get_timestamp (notmuch_database_t *database,
-
- /* Add a new message to the given notmuch database.
- *
-- * Here,'filename' should be a path relative to the the path of
-+ * Here,'filename' should be a path relative to the path of
- * 'database' (see notmuch_database_get_path), or else should be an
- * absolute filename with initial components that match the path of
- * 'database'.
-@@ -258,7 +258,7 @@ notmuch_database_add_message (notmuch_database_t *database,
- const char *filename,
- notmuch_message_t **message);
-
--/* Find a message with the given messsage_id.
-+/* Find a message with the given message_id.
- *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
-@@ -620,7 +620,7 @@ notmuch_messages_advance (notmuch_messages_t *messages);
- /* Destroy a notmuch_messages_t object.
- *
- * It's not strictly necessary to call this function. All memory from
-- * the notmuch_messages_t object will be reclaimed when the containg
-+ * the notmuch_messages_t object will be reclaimed when the containing
- * query object is destroyed.
- */
- void
-@@ -865,7 +865,7 @@ notmuch_tags_has_more (notmuch_tags_t *tags);
- /* Get the current tag from 'tags' as a string.
- *
- * Note: The returned string belongs to 'tags' and has a lifetime
-- * identical to it (and the query to which it utlimately belongs).
-+ * identical to it (and the query to which it ultimately belongs).
- *
- * See the documentation of notmuch_message_get_tags for example code
- * showing how to iterate over a notmuch_tags_t object.
-@@ -884,7 +884,7 @@ notmuch_tags_advance (notmuch_tags_t *tags);
- /* Destroy a notmuch_tags_t object.
- *
- * It's not strictly necessary to call this function. All memory from
-- * the notmuch_tags_t object will be reclaimed when the containg
-+ * the notmuch_tags_t object will be reclaimed when the containing
- * message or query objects are destroyed.
- */
- void
-diff --git a/lib/sha1.c b/lib/sha1.c
-index ff4dd16..cc48108 100644
---- a/lib/sha1.c
-+++ b/lib/sha1.c
-@@ -43,7 +43,7 @@ _hex_of_sha1_digest (const unsigned char digest[SHA1_DIGEST_SIZE])
- return result;
- }
-
--/* Create a hexadcimal string version of the SHA-1 digest of 'str'
-+/* Create a hexadecimal string version of the SHA-1 digest of 'str'
- * (including its null terminating character).
- *
- * This function returns a newly allocated string which the caller
-diff --git a/lib/thread.cc b/lib/thread.cc
-index 4411d64..da58edc 100644
---- a/lib/thread.cc
-+++ b/lib/thread.cc
-@@ -190,7 +190,7 @@ _resolve_thread_relationships (unused (notmuch_thread_t *thread))
- * subject line, the total count of messages, and all authors). The
- * second search is for all messages that are in the thread and that
- * also match the given query_string. This is to allow for a separate
-- * count of matched messages, and to allow a viewer to diplay these
-+ * count of matched messages, and to allow a viewer to display these
- * messages differently.
- *
- * Here, 'ctx' is talloc context for the resulting thread object.
-diff --git a/notmuch-completion.bash b/notmuch-completion.bash
-index ad55f6d..cdad05d 100644
---- a/notmuch-completion.bash
-+++ b/notmuch-completion.bash
-@@ -1,4 +1,4 @@
--# Bash completion for notmutch
-+# Bash completion for notmuch
- #
- # Copyright ?? 2009 Carl Worth
- #
-diff --git a/notmuch-new.c b/notmuch-new.c
-index 83a05ba..5405a9f 100644
---- a/notmuch-new.c
-+++ b/notmuch-new.c
-@@ -303,7 +303,7 @@ add_files (notmuch_database_t *notmuch,
-
- /* XXX: This should be merged with the add_files function since it
- * shares a lot of logic with it. */
--/* Recursively count all regular files in path and all sub-direcotries
-+/* Recursively count all regular files in path and all sub-directories
- * of path. The result is added to *count (which should be
- * initialized to zero by the top-level caller before calling
- * count_files). */
-@@ -469,7 +469,7 @@ notmuch_new_command (void *ctx,
-
- if (elapsed > 1 && ! add_files_state.saw_read_only_directory) {
- printf ("\nTip: If you have any sub-directories that are archives (that is,\n"
-- "they will never receive new mail), marking these directores as\n"
-+ "they will never receive new mail), marking these directories as\n"
- "read-only (chmod u-w /path/to/dir) will make \"notmuch new\"\n"
- "much more efficient (it won't even look in those directories).\n");
- }
-diff --git a/notmuch-search.c b/notmuch-search.c
-index 8db09c7..ac81372 100644
---- a/notmuch-search.c
-+++ b/notmuch-search.c
-@@ -76,7 +76,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
-
- query_str = query_string_from_args (ctx, argc, argv);
- if (query_str == NULL) {
-- fprintf (stderr, "Out of moemory.\n");
-+ fprintf (stderr, "Out of memory.\n");
- return 1;
- }
-
-diff --git a/notmuch.1 b/notmuch.1
-index 6c3d10f..86d5f59 100644
---- a/notmuch.1
-+++ b/notmuch.1
-@@ -60,7 +60,7 @@ archives, and will then proceed to build a database that indexes the
- mail to allow for fast search of the archive.
-
- This directory can contain any number of sub-directories and should
--primarily contain only files with indvidual email messages
-+primarily contain only files with individual email messages
- (eg. maildir or mh archives are perfect). If there are other,
- non-email files (such as indexes maintained by other email programs)
- then notmuch will do its best to detect those and ignore them.
-@@ -173,7 +173,7 @@ Constructs a reply template for a set of messages.
-
- See the documentation of
- .B search
--for deatils of the supported syntax of search terms.
-+for details of the supported syntax of search terms.
-
- To make replying to email easier,
- .B notmuch reply
-diff --git a/notmuch.el b/notmuch.el
-index 8894a8e..7e01ed6 100644
---- a/notmuch.el
-+++ b/notmuch.el
-@@ -205,7 +205,7 @@ Unlike builtin `next-line' this version accepts no arguments."
- (defun notmuch-show-mark-read-then-archive-thread ()
- "Remove \"unread\" tag from each message, then archive and show next thread.
-
--Archive each message currrently shown by removing the \"unread\"
-+Archive each message currently shown by removing the \"unread\"
- and \"inbox\" tag from each. Then kill this buffer and show the
- next thread from the search from which this thread was originally
- shown.
-@@ -220,7 +220,7 @@ buffer."
- (defun notmuch-show-archive-thread ()
- "Archive each message in thread, and show next thread from search.
-
--Archive each message currrently shown by removing the \"inbox\"
-+Archive each message currently shown by removing the \"inbox\"
- tag from each. Then kill this buffer and show the next thread
- from the search from which this thread was originally shown.
-
-@@ -340,7 +340,7 @@ there are no more unread messages past the current point."
- (notmuch-show-next-message)))
-
- (defun notmuch-show-next-open-message ()
-- "Advance to the the next message which is not hidden.
-+ "Advance to the next message which is not hidden.
-
- If read messages are currently hidden, advance to the next unread
- message. Otherwise, advance to the next message."
-@@ -674,7 +674,7 @@ thread from that buffer can be show when done with this one)."
- )))
-
- (defvar notmuch-search-authors-width 40
-- "Number of columns to use to diplay authors in a notmuch-search buffer.")
-+ "Number of columns to use to display authors in a notmuch-search buffer.")
-
- (defvar notmuch-search-mode-map
- (let ((map (make-sparse-keymap)))
-@@ -910,7 +910,7 @@ the beginning of the buffer).
-
- This command toggles the sort order for the current search.
-
--Note that any fitlered searches created by
-+Note that any filtered searches created by
- `notmuch-search-filter' retain the search order of the parent
- search."
- (interactive)
-diff --git a/show-message.c b/show-message.c
-index 79b02e2..38f5897 100644
---- a/show-message.c
-+++ b/show-message.c
-@@ -38,7 +38,7 @@ show_message_part (GMimeObject *part, int *part_count,
- if (i == 1)
- continue;
- if (i > 1)
-- fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Continuing.\n");
-+ fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Continuing.\n");
- }
- show_message_part (g_mime_multipart_get_part (multipart, i),
- part_count, show_part);
---
-1.6.5.2.433.g23cdb
-
-
+++ /dev/null
-Date: Wed, 18 Nov 2009 00:20:59 +0100
-From: Adrian Perez de Castro <aperez@igalia.com>
-To: notmuch@notmuchmail.org
-Message-ID: <20091118002059.067214ed@hikari>
-Organization: Igalia
-X-Mailer: Claws Mail 3.7.3 (GTK+ 2.18.3; x86_64-redhat-linux-gnu)
-Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAAXNSR0IArs4c6QAAADBQTFRFBwcHFhYWKCgoNzc3SEhIV1dXaGhod3d3iIiIlpaWqKiouLi4x8fH2NjY5+fn/v7+rSjDkgAAAjVJREFUOE9l07tvE0EQwOHfrkV9O+eko7g701BBfECJsIigT2IpooIqaSiRUEB0REj00FBQgYSCkhry+gecUPJybJeIxLumTbilsH2PMNXufDOa3ZVW+1JkpbUmD/8+vXR3c7or4Gz93mH309Kz8/C9/RQge7VfhW/LW+PF8IkrQ7Z6OKmQr1tl+LU/yWP9mxJka9O88fZHPwf/7u0kLyCnX3I4fQhgjAgIfi+HHw5A1Y2ggIMcFKAEnRoL0M3BosI4TI2IATjuT8DvSNJoNNJgkIhxlr9TUHeSpDnfohlIrMBlU+BGmsZqfr69FMfGMw4NoG835+J62riWyjQ/uXlTQjNUIoYegMsBM0pCD8oDas7n4HQsBghXFxJTW42KDs+4XLfjsN0wOYgABqARjMKIHIaAQnmHjsI5Cvi9Cf6k03OoWBkpIP3Q7354+dEimFBKHbMP9oKjwfd9gbrxR5KDToczK4uPF8UgNomKU2GaENRi77zyDKICxKBS4xXYbONPMQMdYZTBwMiMWiUg9g6UJ3OBogzjV8E7sBVwyvfAOYdQhsABzuOxI1MGZbs98Q6Md5UOfbbR2R0eWOesrnRw5ajT6f60LrNhWIHZpBnUWv2s14ukArWWTqTes3YQxRXgFkcMu70TPYqqUBs0YwmO967OVIdTG4bY4a7WLaqgLm5vbHdH5np0Dri//fmg7y8scB4u3+zsuNlH0X+g19bby69b+TYH6isvns8VdQWgxj9tHP8AR5/hSdYqkwsAAAAASUVORK5CYII=
-Mime-Version: 1.0
-Subject: [notmuch] Introducing myself
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============1167731900=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
---===============1167731900==
-Content-Type: multipart/signed; micalg=PGP-SHA1;
- boundary="Sig_/ayZz9m37AOMROJCyUudvXvZ"; protocol="application/pgp-signature"
-
---Sig_/ayZz9m37AOMROJCyUudvXvZ
-Content-Type: text/plain; charset=US-ASCII
-Content-Transfer-Encoding: quoted-printable
-
-
-Hello to all,
-
-I have just heard about Not Much today in some random Linux-related news
-site (LWN?), my name is Adrian Perez and I work as systems administrator
-(although I can do some code as well :P). I have always thought that the
-ideas behind Sup were great, but after some time using it, I got tired of
-the oddities that it has. I also do not like doing things like having to
-install Ruby just for reading and sorting mails. Some time ago I thought
-about doing something like Not Much and in fact I played a bit with the
-Python+Xapian and the Python+Whoosh combinations, because I find relaxing
-to code things in Python when I am not working and also it is installed
-by default on most distribution. I got to have some mailboxes indexed and
-basic searching working a couple of months ago. Lately I have been very
-busy and had no time for coding, and them... boom! Not Much appears -- and
-it is almost exactly what I was trying to do, but faster. I have been
-playing a bit with Not Much today, and I think it has potential.
-
-Also, I would like to share one idea I had in mind, that you might find
-interesting: One thing I have found very annoying is having to re-tag my
-mail when the indexes get b0rked (it happened a couple of times to me while
-using Sup), so I was planning to mails as read/unread and adding the tags
-not just to the index, but to the mail text itself, e.g. by adding a
-"X-Tags" header field or by reusing the "Keywords" one. This way, the index
-could be totally recreated by re-reading the mail directories, and this
-would also allow to a tools like OfflineIMAP [1] to get the mails into a
-local maildir, tagging and indexing the mails with the e-mail reader and
-then syncing back the messages with the "X-Tags" header to the IMAP server.
-This would allow to use the mail reader from a different computer and still
-have everything tagged finely.
-
-Best regards,
-
-
----
-[1] http://software.complete.org/software/projects/show/offlineimap
-
---=20
-Adrian Perez de Castro <aperez@igalia.com>
-Igalia - Free Software Engineering
-
---Sig_/ayZz9m37AOMROJCyUudvXvZ
-Content-Type: application/pgp-signature; name=signature.asc
-Content-Disposition: attachment; filename=signature.asc
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v2.0.13 (GNU/Linux)
-
-iEYEARECAAYFAksDL+AACgkQkcVZ2+TJEjtsuQCfXmilW8WpMQHCnwwJjRE1PWZy
-oFAAn3MmXC5sW7MvCFjs7ks6U16zgMEg
-=eL9p
------END PGP SIGNATURE-----
-
---Sig_/ayZz9m37AOMROJCyUudvXvZ--
-
---===============1167731900==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============1167731900==--
-
+++ /dev/null
-MIME-Version: 1.0
-Date: Tue, 17 Nov 2009 16:23:53 -0800
-Message-ID: <cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com>
-From: Alex Botero-Lowry <alex.boterolowry@gmail.com>
-To: notmuch@notmuchmail.org
-Content-Type: multipart/mixed; boundary=0016e64ca4d8f27a4804789a4139
-Subject: [notmuch] [PATCH] Error out if no query is supplied to search
- instead of going into an infinite loop
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
---0016e64ca4d8f27a4804789a4139
-Content-Type: multipart/alternative; boundary=0016e64ca4d8f27a3604789a4137
-
---0016e64ca4d8f27a3604789a4137
-Content-Type: text/plain; charset=ISO-8859-1
-
-In this case error out when no query is supplied. There seems to be an
-infinite-loop casued by i think notmuch_query_search_threads having
-an exception:
-
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-A Xapian exception occurred: Syntax: <expression> AND <expression>
-
-I'll look into that bug specifically a bit later.
-
-It might be better to do a usage instead of just throwing an error here?
-
-alex
-
---0016e64ca4d8f27a3604789a4137
-Content-Type: text/html; charset=ISO-8859-1
-
-In this case error out when no query is supplied. There seems to be an infinite-loop casued by i think notmuch_query_search_threads having<br>an exception:<br><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
-A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
-A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
-A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
-A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br>
-A Xapian exception occurred: Syntax: <expression> AND <expression><br>A Xapian exception occurred: Syntax: <expression> AND <expression><br><br>I'll look into that bug specifically a bit later.<br>
-<br>It might be better to do a usage instead of just throwing an error here?<br><br>alex<br>
-
---0016e64ca4d8f27a3604789a4137--
---0016e64ca4d8f27a4804789a4139
-Content-Type: application/octet-stream;
- name="0001-Error-out-if-no-query-is-supplied-to-search-instead-.patch"
-Content-Disposition: attachment;
- filename="0001-Error-out-if-no-query-is-supplied-to-search-instead-.patch"
-Content-Transfer-Encoding: base64
-X-Attachment-Id: f_g25cms190
-
-RnJvbSAzZjk0MzFmNzRhNWZmNjZjODRjODY5YTNlMjZjMmJhZDQyYmVkMWIxIE1vbiBTZXAgMTcg
-MDA6MDA6MDAgMjAwMQpGcm9tOiBBbGV4YW5kZXIgQm90ZXJvLUxvd3J5IDxhbGV4LmJvdGVyb2xv
-d3J5QGdtYWlsLmNvbT4KRGF0ZTogVHVlLCAxNyBOb3YgMjAwOSAxNjoyMDoyOCAtMDgwMApTdWJq
-ZWN0OiBbUEFUQ0hdIEVycm9yIG91dCBpZiBubyBxdWVyeSBpcyBzdXBwbGllZCB0byBzZWFyY2gg
-aW5zdGVhZCBvZiBnb2luZyBpbnRvIGFuIGluZmluaXRlIGxvb3AKCi0tLQogbm90bXVjaC1zZWFy
-Y2guYyB8ICAgIDUgKysrKysKIDEgZmlsZXMgY2hhbmdlZCwgNSBpbnNlcnRpb25zKCspLCAwIGRl
-bGV0aW9ucygtKQoKZGlmZiAtLWdpdCBhL25vdG11Y2gtc2VhcmNoLmMgYi9ub3RtdWNoLXNlYXJj
-aC5jCmluZGV4IDhkYjA5YzcuLmQ5NGZjY2QgMTAwNjQ0Ci0tLSBhL25vdG11Y2gtc2VhcmNoLmMK
-KysrIGIvbm90bXVjaC1zZWFyY2guYwpAQCAtNjYsNiArNjYsMTEgQEAgbm90bXVjaF9zZWFyY2hf
-Y29tbWFuZCAodm9pZCAqY3R4LCBpbnQgYXJnYywgY2hhciAqYXJndltdKQogICAgIGFyZ2MgLT0g
-aTsKICAgICBhcmd2ICs9IGk7CiAKKyAgICBpZiAoYXJnYyA9PSAwKSB7CisgICAgICAgIGZwcmlu
-dGYgKHN0ZGVyciwgIk5vIHF1ZXJ5IHByb3ZpZGVkXG4iKTsKKyAgICAgICAgcmV0dXJuIDE7Cisg
-ICAgfQorCiAgICAgY29uZmlnID0gbm90bXVjaF9jb25maWdfb3BlbiAoY3R4LCBOVUxMLCBOVUxM
-KTsKICAgICBpZiAoY29uZmlnID09IE5VTEwpCiAJcmV0dXJuIDE7Ci0tIAoxLjYuNS4yCgo=
---0016e64ca4d8f27a4804789a4139
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---0016e64ca4d8f27a4804789a4139--
-
+++ /dev/null
-Date: Tue, 17 Nov 2009 19:50:40 -0500
-From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
-To: Keith Packard <keithp@keithp.com>
-Message-ID: <20091118005040.GA25380@dottiness.seas.harvard.edu>
-References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
- <87iqd9rn3l.fsf@vertex.dottedmag>
- <20091117203301.GV3165@dottiness.seas.harvard.edu>
- <yunaayketfm.fsf@aiko.keithp.com>
-MIME-Version: 1.0
-In-Reply-To: <yunaayketfm.fsf@aiko.keithp.com>
-User-Agent: Mutt/1.5.19 (2009-01-05)
-Cc: notmuch@notmuchmail.org
-Subject: Re: [notmuch] Working with Maildir storage?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============1483126515=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
-
---===============1483126515==
-Content-Type: multipart/signed; micalg=pgp-sha256;
- protocol="application/pgp-signature"; boundary="9amGYk9869ThD9tj"
-Content-Disposition: inline
-
-
---9amGYk9869ThD9tj
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: quoted-printable
-
-> I've also pushed a slightly more complicated (and complete) fix to my
-> private notmuch repository
-
-The version of lib/messages.cc in your repo doesn't build because it's
-missing "#include <stdint.h>" (for the uint32_t on line 466).
-
---=20
-Lars Kellogg-Stedman <lars@seas.harvard.edu>
-Senior Technologist, Computing and Information Technology
-Harvard University School of Engineering and Applied Sciences
-
-
---9amGYk9869ThD9tj
-Content-Type: application/pgp-signature
-Content-Disposition: inline
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQEcBAEBCAAGBQJLA0TgAAoJENdGlQYxQazYsG0IAJ1t9h4Q3ma8z8ejeKR22Xh0
-WcuRX2x9yEXy/+aG9W7Mot0mqUQCiLdmHM/2h5N9BFHyJvfOUf8lmssrJ5OS/kp5
-j7FIx3GUELBmEZqFUPjRSQPk1hZURYdRsloKkrbQ2kAivjjb50zAAQ8Av4Cgj6cS
-3HvNNmeVfJt1NS75vm+/wn48M8Vrcdv4gvNlSOhgFOixknvRoxSyNDOHYBKvHnSV
-2HnO0GzhAQzDZAwdHBzJtb8vRmglrH33TVdrE7OW+sojYB3Wyz8r9+HIt8Q8ovzX
-nQ8p0Nf5DlF7tye3JYo0EeNm5EQJ4q0YyVYInhmtpi3A5Cyu50GcB/GZ5Sd6ajo=
-=WULe
------END PGP SIGNATURE-----
-
---9amGYk9869ThD9tj--
-
---===============1483126515==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============1483126515==--
-
+++ /dev/null
-Date: Tue, 17 Nov 2009 19:58:29 -0500
-From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
-To: notmuch <notmuch@notmuchmail.org>
-Message-ID: <20091118005829.GB25380@dottiness.seas.harvard.edu>
-MIME-Version: 1.0
-User-Agent: Mutt/1.5.19 (2009-01-05)
-Subject: [notmuch] "notmuch help" outputs to stderr?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============1359248349=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
-
---===============1359248349==
-Content-Type: multipart/signed; micalg=pgp-sha256;
- protocol="application/pgp-signature"; boundary="L6iaP+gRLNZHKoI4"
-Content-Disposition: inline
-
-
---L6iaP+gRLNZHKoI4
-Content-Type: multipart/mixed; boundary="z6Eq5LdranGa6ru8"
-Content-Disposition: inline
-
-
---z6Eq5LdranGa6ru8
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: quoted-printable
-
-I'm just noticing that 'notmuch help ...' outputs to stderr, which
-isn't terribly intuitive. For example, the obvious invocation:
-
- notmuch help | less
-
-=2E..isn't terribly helpful.
-
-I've attached a patch that lets usage() take a FILE * argument so that
-you can output to stderr in response to usage errors, and stdout in
-response to an explicit request.
-
---=20
-Lars Kellogg-Stedman <lars@seas.harvard.edu>
-Senior Technologist, Computing and Information Technology
-Harvard University School of Engineering and Applied Sciences
-
-
---z6Eq5LdranGa6ru8
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: attachment; filename="notmuch-help.patch"
-Content-Transfer-Encoding: quoted-printable
-
-diff --git a/notmuch.c b/notmuch.c
-index c47e640..a35cb99 100644
---- a/notmuch.c
-+++ b/notmuch.c
-@@ -157,23 +157,23 @@ command_t commands[] =3D {
- };
-=20
- static void
--usage (void)
-+usage (FILE *out)
- {
- command_t *command;
- unsigned int i;
-=20
-- fprintf (stderr, "Usage: notmuch <command> [args...]\n");
-- fprintf (stderr, "\n");
-- fprintf (stderr, "Where <command> and [args...] are as follows:\n");
-- fprintf (stderr, "\n");
-+ fprintf (out, "Usage: notmuch <command> [args...]\n");
-+ fprintf (out, "\n");
-+ fprintf (out, "Where <command> and [args...] are as follows:\n");
-+ fprintf (out, "\n");
-=20
- for (i =3D 0; i < ARRAY_SIZE (commands); i++) {
- command =3D &commands[i];
-=20
-- fprintf (stderr, "\t%s\t%s\n\n", command->name, command->summary);
-+ fprintf (out, "\t%s\t%s\n\n", command->name, command->summary);
- }
-=20
-- fprintf (stderr, "Use \"notmuch help <command>\" for more details on e=
-ach command.\n\n");
-+ fprintf (out, "Use \"notmuch help <command>\" for more details on each=
- command.\n\n");
- }
-=20
- static int
-@@ -183,8 +183,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
-r *argv[])
- unsigned int i;
-=20
- if (argc =3D=3D 0) {
-- fprintf (stderr, "The notmuch mail system.\n\n");
-- usage ();
-+ fprintf (stdout, "The notmuch mail system.\n\n");
-+ usage (stdout);
- return 0;
- }
-=20
-
---z6Eq5LdranGa6ru8--
-
---L6iaP+gRLNZHKoI4
-Content-Type: application/pgp-signature
-Content-Disposition: inline
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQEcBAEBCAAGBQJLA0a1AAoJENdGlQYxQazYr78IAJtqTWIpBqSdOWqTzt/r4XNn
-KJ5mWAoNfq4H+3kx3xoWOFYS7qAYeJoHQWCDbMdb+zEXvPX6hMFn9+OxRN+N5FdQ
-uxGTugSG9xSsK28oGDCQUtr5uheo+tH0jygPjI+LTD97vjUYS4K2qzhLGFJmpLcj
-1akMJXM0gSdPZT8dJyjxvC15pgboLspE4+b6jexXmd4UoFvXgqvjkYHeV4Wk+s0L
-xu+HkCGXL9WHYc3t171fFAru4Zd1AUxFQl4BZ2Y+OqRZUrD28Mtz3zGQxbJQoifl
-JFrgPAWioLN71SkVq/y+efjvGSl0osPpKU5dftMmyY1zV7k7mMlO08ZSJU+wANA=
-=Iijt
------END PGP SIGNATURE-----
-
---L6iaP+gRLNZHKoI4--
-
---===============1359248349==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============1359248349==--
-
+++ /dev/null
-Return-path: <notmuch-bounces@notmuchmail.org>
-Envelope-to: cworth@localhost
-Delivery-date: Wed, 18 Nov 2009 01:43:47 -0800
-Received: from yoom.home.cworth.org ([127.0.0.1])
- by yoom.home.cworth.org with esmtp (Exim 4.69)
- (envelope-from <notmuch-bounces@notmuchmail.org>)
- id 1NAgpH-0005Ab-20
- for cworth@localhost; Wed, 18 Nov 2009 01:27:47 -0800
-X-Original-To: cworth@cworth.org
-Delivered-To: cworth@cworth.org
-Received: from olra.theworths.org [82.165.184.25]
- by yoom.home.cworth.org with IMAP (fetchmail-6.3.9-rc2)
- for <cworth@localhost> (single-drop); Wed, 18 Nov 2009 01:27:47 -0800 (PST)
-Received: from localhost (localhost [127.0.0.1])
- by olra.theworths.org (Postfix) with ESMTP id 12248431FC3
- for <cworth@cworth.org>; Tue, 17 Nov 2009 17:01:22 -0800 (PST)
-X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
-X-Spam-Flag: NO
-X-Spam-Score: -6.17
-X-Spam-Level:
-X-Spam-Status: No, score=-6.17 tagged_above=-999 required=2 tests=[AWL=0.429,
- BAYES_00=-2.599, RCVD_IN_DNSWL_MED=-4] autolearn=unavailable
-Received: from olra.theworths.org ([127.0.0.1])
- by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
- with ESMTP id TmBdVd1i-Wjb; Tue, 17 Nov 2009 17:01:20 -0800 (PST)
-Received: from olra.theworths.org (localhost [127.0.0.1])
- by olra.theworths.org (Postfix) with ESMTP id AF876431FBC;
- Tue, 17 Nov 2009 17:01:20 -0800 (PST)
-X-Original-To: notmuch@notmuchmail.org
-Delivered-To: notmuch@notmuchmail.org
-Received: from localhost (localhost [127.0.0.1])
- by olra.theworths.org (Postfix) with ESMTP id 75784431FBC
- for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 17:01:19 -0800 (PST)
-X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
-Received: from olra.theworths.org ([127.0.0.1])
- by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
- with ESMTP id IoYHzHoKBskU for <notmuch@notmuchmail.org>;
- Tue, 17 Nov 2009 17:01:18 -0800 (PST)
-Received: from smtp-outbound.seas.harvard.edu (smtp-outbound.seas.harvard.edu
- [140.247.51.171])
- by olra.theworths.org (Postfix) with ESMTP id 7E033431FAE
- for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 17:01:18 -0800 (PST)
-Received: from dottiness.seas.harvard.edu (dottiness.seas.harvard.edu
- [140.247.52.224])
- by smtp-outbound.seas.harvard.edu (8.13.8/8.13.8) with SMTP id
- nAI11Gkj008772
- for <notmuch@notmuchmail.org>; Tue, 17 Nov 2009 20:01:16 -0500
-Received: by dottiness.seas.harvard.edu (sSMTP sendmail emulation);
- Tue, 17 Nov 2009 20:01:16 -0500
-Date: Tue, 17 Nov 2009 20:01:16 -0500
-From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
-To: notmuch <notmuch@notmuchmail.org>
-Message-ID: <20091118010116.GC25380@dottiness.seas.harvard.edu>
-References: <20091118005829.GB25380@dottiness.seas.harvard.edu>
-MIME-Version: 1.0
-In-Reply-To: <20091118005829.GB25380@dottiness.seas.harvard.edu>
-User-Agent: Mutt/1.5.19 (2009-01-05)
-Subject: Re: [notmuch] "notmuch help" outputs to stderr?
-X-BeenThere: notmuch@notmuchmail.org
-X-Mailman-Version: 2.1.12
-Precedence: list
-List-Id: "Use and development of the notmuch mail system."
- <notmuch.notmuchmail.org>
-List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
-List-Archive: <http://notmuchmail.org/pipermail/notmuch>
-List-Post: <mailto:notmuch@notmuchmail.org>
-List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
-List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
- <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
-Content-Type: multipart/mixed; boundary="===============0848253760=="
-Sender: notmuch-bounces@notmuchmail.org
-Errors-To: notmuch-bounces@notmuchmail.org
-
-
---===============0848253760==
-Content-Type: multipart/signed; micalg=pgp-sha256;
- protocol="application/pgp-signature"; boundary="ZInfyf7laFu/Kiw7"
-Content-Disposition: inline
-
-
---ZInfyf7laFu/Kiw7
-Content-Type: multipart/mixed; boundary="KdquIMZPjGJQvRdI"
-Content-Disposition: inline
-
-
---KdquIMZPjGJQvRdI
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: quoted-printable
-
-> I've attached a patch that lets usage() take a FILE * argument so that
-> you can output to stderr in response to usage errors, and stdout in
-> response to an explicit request.
-
-Whoops, missed a couple of stderr's in that last patch. New one
-attached.
-
---=20
-Lars Kellogg-Stedman <lars@seas.harvard.edu>
-Senior Technologist, Computing and Information Technology
-Harvard University School of Engineering and Applied Sciences
-
-
---KdquIMZPjGJQvRdI
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: attachment; filename="notmuch-help.patch"
-Content-Transfer-Encoding: quoted-printable
-
-diff --git a/notmuch.c b/notmuch.c
-index c47e640..446c810 100644
---- a/notmuch.c
-+++ b/notmuch.c
-@@ -157,23 +157,23 @@ command_t commands[] =3D {
- };
-=20
- static void
--usage (void)
-+usage (FILE *out)
- {
- command_t *command;
- unsigned int i;
-=20
-- fprintf (stderr, "Usage: notmuch <command> [args...]\n");
-- fprintf (stderr, "\n");
-- fprintf (stderr, "Where <command> and [args...] are as follows:\n");
-- fprintf (stderr, "\n");
-+ fprintf (out, "Usage: notmuch <command> [args...]\n");
-+ fprintf (out, "\n");
-+ fprintf (out, "Where <command> and [args...] are as follows:\n");
-+ fprintf (out, "\n");
-=20
- for (i =3D 0; i < ARRAY_SIZE (commands); i++) {
- command =3D &commands[i];
-=20
-- fprintf (stderr, "\t%s\t%s\n\n", command->name, command->summary);
-+ fprintf (out, "\t%s\t%s\n\n", command->name, command->summary);
- }
-=20
-- fprintf (stderr, "Use \"notmuch help <command>\" for more details on e=
-ach command.\n\n");
-+ fprintf (out, "Use \"notmuch help <command>\" for more details on each=
- command.\n\n");
- }
-=20
- static int
-@@ -183,8 +183,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
-r *argv[])
- unsigned int i;
-=20
- if (argc =3D=3D 0) {
-- fprintf (stderr, "The notmuch mail system.\n\n");
-- usage ();
-+ fprintf (stdout, "The notmuch mail system.\n\n");
-+ usage (stdout);
- return 0;
- }
-=20
-@@ -192,8 +192,8 @@ notmuch_help_command (unused (void *ctx), int argc, cha=
-r *argv[])
- command =3D &commands[i];
-=20
- if (strcmp (argv[0], command->name) =3D=3D 0) {
-- fprintf (stderr, "Help for \"notmuch %s\":\n\n", argv[0]);
-- fprintf (stderr, "\t%s\t%s\n\n%s\n\n", command->name,
-+ fprintf (stdout, "Help for \"notmuch %s\":\n\n", argv[0]);
-+ fprintf (stdout, "\t%s\t%s\n\n%s\n\n", command->name,
- command->summary, command->documentation);
- return 0;
- }
-
---KdquIMZPjGJQvRdI--
-
---ZInfyf7laFu/Kiw7
-Content-Type: application/pgp-signature
-Content-Disposition: inline
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.9 (GNU/Linux)
-
-iQEcBAEBCAAGBQJLA0dcAAoJENdGlQYxQazY4nIIAIBCds86/uTmnouvyoPruUUR
-Bg5mXcnjuopz1Nwotl9s9U5sGeZuZngxyEvDz1Z1aTEjwab8ndNTf1xCwIoqBs+l
-i/sc4nPYubLdy1Ab/84DKVtCSbj+v5rtqhegwUWV7S1BY7t8dKNPNv7YBg7P0Azs
-6s3CUxDV5eJCcxCGxxWHH8JDKRf7rDs6vzDwyPWLxlg1Xb1lEM/sRgPCKiShPdO3
-Ak2hECusjskALhSDYX8/FLMd9HwLBC13sfWuSi/pHUAIOI2jru2p5sXrVSlTnFIJ
-fiMbPhKWiEaJj2kmm4pRwAhbTWp/J8ZvXWp0AyosxXQhQUWqujiyxgfiXS70SdQ=
-=t3Yc
------END PGP SIGNATURE-----
-
---ZInfyf7laFu/Kiw7--
-
---===============0848253760==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-notmuch mailing list
-notmuch@notmuchmail.org
-http://notmuchmail.org/mailman/listinfo/notmuch
-
---===============0848253760==--
-
+++ /dev/null
-From: "Stewart Smith" <stewart@flamingspork.com>
-To: notmuch@notmuchmail.org
-Date: Wed, 18 Nov 2009 12:05:53 +1100
-Subject: [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++
- libs.
-Message-ID: <1258506353-20352-1-git-send-email-stewart@flamingspork.com>
-
-Previously, Ubuntu 9.10, gcc 4.4.1 was getting:
-
-ccache gcc `pkg-config --libs glib-2.0 gmime-2.4 talloc` `xapian-config --libs` notmuch.o notmuch-config.o notmuch-dump.o notmuch-new.o notmuch-reply.o notmuch-restore.o notmuch-search.o notmuch-setup.o notmuch-show.o notmuch-tag.o notmuch-time.o gmime-filter-reply.o query-string.o show-message.o lib/notmuch.a -o notmuch
-/usr/bin/ld: lib/notmuch.a(database.o): in function global constructors keyed to BOOLEAN_PREFIX_INTERNAL:database.cc(.text+0x3a): error: undefined reference to 'std::ios_base::Init::Init()'
----
- Makefile.local | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/Makefile.local b/Makefile.local
-index f824bed..dbd3e20 100644
---- a/Makefile.local
-+++ b/Makefile.local
-@@ -18,7 +18,7 @@ notmuch_client_srcs = \
-
- notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
- notmuch: $(notmuch_client_modules) lib/notmuch.a
-- $(CC) $(LDFLAGS) $^ -o $@
-+ $(CXX) $(LDFLAGS) $^ -o $@
-
- notmuch.1.gz:
- gzip --stdout notmuch.1 > notmuch.1.gz
---
-1.6.3.3
-
-
+++ /dev/null
-From: "Stewart Smith" <stewart@flamingspork.com>
-To: notmuch@notmuchmail.org
-Date: Wed, 18 Nov 2009 12:56:40 +1100
-Subject: [notmuch] [PATCH 2/2] Read mail directory in inode number order
-Message-ID: <1258509400-32511-1-git-send-email-stewart@flamingspork.com>
-
-This gives a rather decent reduction in number of seeks required when
-reading a Maildir that isn't in pagecache.
-
-Most filesystems give some locality on disk based on inode numbers.
-In ext[234] this is the inode tables, in XFS groups of sequential inode
-numbers are together on disk and the most significant bits indicate
-allocation group (i.e inode 1,000,000 is always after inode 1,000).
-
-With this patch, we read in the whole directory, sort by inode number
-before stat()ing the contents.
-
-Ideally, directory is sequential and then we make one scan through the
-file system stat()ing.
-
-Since the universe is not ideal, we'll probably seek during reading the
-directory and a fair bit while reading the inodes themselves.
-
-However... with readahead, and stat()ing in inode order, we should be
-in the best place possible to hit the cache.
-
-In a (not very good) benchmark of "how long does it take to find the first
-15,000 messages in my Maildir after 'echo 3 > /proc/sys/vm/drop_caches'",
-this patch consistently cut at least 8 seconds off the scan time.
-
-Without patch: 50 seconds
-With patch: 38-42 seconds.
-
-(I did this in a previous maildir reading project and saw large improvements too)
----
- notmuch-new.c | 32 +++++++++++++++-----------------
- 1 files changed, 15 insertions(+), 17 deletions(-)
-
-diff --git a/notmuch-new.c b/notmuch-new.c
-index 83a05ba..11fad8c 100644
---- a/notmuch-new.c
-+++ b/notmuch-new.c
-@@ -73,6 +73,11 @@ add_files_print_progress (add_files_state_t *state)
- fflush (stdout);
- }
-
-+static int ino_cmp(const struct dirent **a, const struct dirent **b)
-+{
-+ return ((*a)->d_ino < (*b)->d_ino)? -1: 1;
-+}
-+
- /* Examine 'path' recursively as follows:
- *
- * o Ask the filesystem for the mtime of 'path' (path_mtime)
-@@ -100,13 +105,12 @@ add_files_recursive (notmuch_database_t *notmuch,
- add_files_state_t *state)
- {
- DIR *dir = NULL;
-- struct dirent *e, *entry = NULL;
-- int entry_length;
-- int err;
-+ struct dirent *entry = NULL;
- char *next = NULL;
- time_t path_mtime, path_dbtime;
- notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
- notmuch_message_t *message = NULL;
-+ struct dirent **namelist = NULL;
-
- /* If we're told to, we bail out on encountering a read-only
- * directory, (with this being a clear clue from the user to
-@@ -122,31 +126,23 @@ add_files_recursive (notmuch_database_t *notmuch,
- path_mtime = st->st_mtime;
-
- path_dbtime = notmuch_database_get_timestamp (notmuch, path);
-+ int n_entries= scandir(path, &namelist, 0, ino_cmp);
-
-- dir = opendir (path);
-- if (dir == NULL) {
-+ if (n_entries == -1) {
- fprintf (stderr, "Error opening directory %s: %s\n",
- path, strerror (errno));
- ret = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
-- entry_length = offsetof (struct dirent, d_name) +
-- pathconf (path, _PC_NAME_MAX) + 1;
-- entry = malloc (entry_length);
-+ int i=0;
-
- while (!interrupted) {
-- err = readdir_r (dir, entry, &e);
-- if (err) {
-- fprintf (stderr, "Error reading directory: %s\n",
-- strerror (errno));
-- ret = NOTMUCH_STATUS_FILE_ERROR;
-- goto DONE;
-- }
--
-- if (e == NULL)
-+ if (i == n_entries)
- break;
-
-+ entry= namelist[i++];
-+
- /* If this directory hasn't been modified since the last
- * add_files, then we only need to look further for
- * sub-directories. */
-@@ -243,6 +239,8 @@ add_files_recursive (notmuch_database_t *notmuch,
- free (entry);
- if (dir)
- closedir (dir);
-+ if (namelist)
-+ free (namelist);
-
- return ret;
- }
---
-1.6.3.3
-
-
+++ /dev/null
-From: "Keith Packard" <keithp@keithp.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 17:59:49 -0800
-Subject: [notmuch] New to the list
-In-Reply-To: <1258498485-sup-142@elly>
-References: <1258498485-sup-142@elly>
-Message-ID: <yun3a4cegoa.fsf@aiko.keithp.com>
-
-On Tue, 17 Nov 2009 23:57:18 +0100, Israel Herraiz <isra at herraiz.org> wrote:
-
-> "Not much" sounds interesting, and I wonder whether it could be
-> integrated with the views of Sup (inbox, threads, etc). So I have
-> subscribed to the list to keep an eye on what's going on here.
-
-We've tried to clone much of the sup UI inside emacs, including the
-inbox and threaded message presentation. Of course, we had to "improve"
-it a bit, as much due to the differences between curses and emacs as due
-to personal preferences...
-
--keith
-
+++ /dev/null
-From: "Keith Packard" <keithp@keithp.com>
-To: notmuch@notmuchmail.org
-Date: Tue, 17 Nov 2009 18:03:17 -0800
-Subject: [notmuch] Introducing myself
-In-Reply-To: <20091118002059.067214ed@hikari>
-References: <20091118002059.067214ed@hikari>
-Message-ID: <yun1vjwegii.fsf@aiko.keithp.com>
-
-On Wed, 18 Nov 2009 00:20:59 +0100, Adrian Perez de Castro <aperez at igalia.com> wrote:
-
-> Some time ago I thought
-> about doing something like Not Much and in fact I played a bit with the
-> Python+Xapian and the Python+Whoosh combinations, because I find relaxing
-> to code things in Python when I am not working and also it is installed
-> by default on most distribution. I got to have some mailboxes indexed and
-> basic searching working a couple of months ago.
-
-Sup certainly started a lot of people thinking...
-
-> Also, I would like to share one idea I had in mind, that you might find
-> interesting: One thing I have found very annoying is having to re-tag my
-> mail when the indexes get b0rked (it happened a couple of times to me while
-> using Sup), so I was planning to mails as read/unread and adding the tags
-> not just to the index, but to the mail text itself, e.g. by adding a
-> "X-Tags" header field or by reusing the "Keywords" one.
-
-Easier than that, notmuch (and sup too), provide a 'dump' command which
-just lists all of the message IDs and their associated tags. Makes
-saving tags easy and doesn't involve rewriting messages. I do this once
-a day just before my computer is backed up to an external drive.
-
-If the index is destroyed, you can reindex the messages and then reapply
-all of the tags with 'notmuch restore'.
-
---
-keith.packard at intel.com
-
-
--- /dev/null
+From: "Carl Worth" <cworth@cworth.org>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 12:19:24 -0800
+Subject: [notmuch] preliminary FreeBSD support
+In-Reply-To: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
+References: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
+Message-ID: <87lji4lx9v.fsf@yoom.home.cworth.org>
+
+On Tue, 17 Nov 2009 11:36:14 -0800, Alex Botero-Lowry <alex.boterolowry at gmail.com> wrote:
+> I saw the announcement this morning, and was very excited, as I had been
+> hoping sup would be turned into a library,
+> since I like the concept more than the UI (I'd rather an emacs interface).
+
+Hi Alex,
+
+That's great! It's good to hear that there are like-minded people out
+there. I hope that Notmuch will be useful for you.
+
+> I did a preliminary compile which worked out fine, but
+> sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
+> FreeBSD, so notmuch_config_open segfaulted.
+>
+> Attached is a patch that supplies a default buffer size of 64 in cases where
+> -1 is returned.
+
+Thanks for the patch. As we discussed in IRC[*], we should probably
+do the correct thing and check for ERANGE and loop as necessary (even if
+sysconf returns a positive value). Example code here:
+
+http://www.opengroup.org/austin/docs/austin_328.txt
+
+-Carl
+
+[*] #notmuch on irc.freenode.net for those who didn't just guess that
+already, (and I'll add that to the website soon).
+
--- /dev/null
+From: "Keith Packard" <keithp@keithp.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 13:15:25 -0800
+Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
+ headers
+In-Reply-To: <87lji5cbwo.fsf@yoom.home.cworth.org>
+References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+ <87lji5cbwo.fsf@yoom.home.cworth.org>
+Message-ID: <yunbpj0etua.fsf@aiko.keithp.com>
+
+On Tue, 17 Nov 2009 09:13:27 -0800, Carl Worth <cworth at cworth.org> wrote:
+
+> I didn't apply Keith's fix yet, because I think I'd rather just fix the
+> indexer to store the In-Reply-To header in a separate term prefix from
+> the term used for the References header[*]. That will then let us lookup
+> the in-reply-to value later for thread constructions without having to
+> open the original email file at all.
+
+Threading the message also involves displaying the from and to contents,
+which requires opening the message file. The alternative to the fix I
+provided is to just parse all of the message headers when first opening
+the message; it could then be immediately closed and the hash referred
+to for all header data. Given the choice, just having the caller say
+when it has finished with a message is probably a reasonable option...
+
+-keith
+
--- /dev/null
+From: "Keith Packard" <keithp@keithp.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 13:24:13 -0800
+Subject: [notmuch] Working with Maildir storage?
+In-Reply-To: <20091117203301.GV3165@dottiness.seas.harvard.edu>
+References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+ <87iqd9rn3l.fsf@vertex.dottedmag>
+ <20091117203301.GV3165@dottiness.seas.harvard.edu>
+Message-ID: <yunaayketfm.fsf@aiko.keithp.com>
+
+On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+> > See the patch just posted here.
+
+I've also pushed a slightly more complicated (and complete) fix to my
+private notmuch repository
+
+git://keithp.com/git/notmuch
+
+> Is the list archived anywhere?
+
+Oops. Looks like Carl's mail server is broken. He's traveling to
+Barcelona today and so it won't get fixed for a while.
+
+Thanks to everyone for trying out notmuch!
+
+-keith
+
--- /dev/null
+From: "Keith Packard" <keithp@keithp.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 13:32:45 -0800
+Subject: [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove
+ inbox (and unread) tags
+Message-ID: <1258493565-13508-1-git-send-email-keithp@keithp.com>
+
+When closing a thread view, mark the thread as archived by removing
+the "inbox" tag, and for the 'x' variant, the "unread" tag as well,
+then kill the buffer and update the search window view as well.
+
+This makes 'x' much the same as 'a', but instead of taking you to the
+next message, it takes you back to the search window instead.
+
+Signed-off-by: Keith Packard <keithp at keithp.com>
+---
+ notmuch.el | 86 ++++++++++++++++++++++++++++++++++++++++++++++-------------
+ 1 files changed, 67 insertions(+), 19 deletions(-)
+
+diff --git a/notmuch.el b/notmuch.el
+index 638d49d..7b0d72c 100644
+--- a/notmuch.el
++++ b/notmuch.el
+@@ -31,8 +31,8 @@
+ ; Will be much preferable to switch to direct manipulation for
+ ; toggling visibility of these components. Probably using
+ ; overlays-at to query and manipulate the current overlay.
+- (define-key map "a" 'notmuch-show-archive-thread)
+- (define-key map "A" 'notmuch-show-mark-read-then-archive-thread)
++ (define-key map "a" 'notmuch-show-mark-read-archive-thread-next-thread)
++ (define-key map "A" 'notmuch-show-archive-thread-next-thread)
+ (define-key map "b" 'notmuch-show-toggle-body-read-visible)
+ (define-key map "c" 'notmuch-show-toggle-citations-visible)
+ (define-key map "h" 'notmuch-show-toggle-headers-visible)
+@@ -47,7 +47,8 @@
+ (define-key map "s" 'notmuch-show-toggle-signatures-visible)
+ (define-key map "v" 'notmuch-show-view-all-mime-parts)
+ (define-key map "w" 'notmuch-show-view-raw-message)
+- (define-key map "x" 'kill-this-buffer)
++ (define-key map "x" 'notmuch-show-mark-read-archive-thread-kill-buffer)
++ (define-key map "X" 'notmuch-show-archive-thread-kill-buffer)
+ (define-key map "+" 'notmuch-show-add-tag)
+ (define-key map "-" 'notmuch-show-remove-tag)
+ (define-key map (kbd "DEL") 'notmuch-show-rewind)
+@@ -183,7 +184,33 @@ Unlike builtin `next-line' this version accepts no arguments."
+ (cons (notmuch-show-get-message-id) nil)))
+ (notmuch-show-set-tags (sort (set-difference tags toremove :test 'string=) 'string<))))))
+
+-(defun notmuch-show-archive-thread-maybe-mark-read (markread)
++(defun notmuch-show-next-thread (markread)
++ (let ((parent-buffer notmuch-show-parent-buffer))
++ (kill-this-buffer)
++ (if parent-buffer
++ (progn
++ (switch-to-buffer parent-buffer)
++ (forward-line)
++ (notmuch-search-show-thread)))))
++
++(defun notmuch-delete-tags (to-remove from)
++ (if to-remove
++ (delete (car to-remove) (notmuch-delete-tags (cdr to-remove) from))
++ from))
++
++(defun notmuch-kill-message-buffer (markread)
++ (let ((parent-buffer notmuch-show-parent-buffer))
++ (kill-this-buffer)
++ (if parent-buffer
++ (progn
++ (switch-to-buffer parent-buffer)
++ (let ((tags (notmuch-search-get-tags)))
++ (setq tags (delete "inbox" tags))
++ (if markread (setq tags (delete "unread" tags)))
++ (notmuch-search-set-tags tags))
++ (forward-line)))))
++
++(defun notmuch-show-archive-thread-maybe-mark-read (markread shownext)
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+@@ -194,15 +221,9 @@ Unlike builtin `next-line' this version accepts no arguments."
+ (forward-char))
+ (if (not (re-search-forward notmuch-show-message-begin-regexp nil t))
+ (goto-char (point-max)))))
+- (let ((parent-buffer notmuch-show-parent-buffer))
+- (kill-this-buffer)
+- (if parent-buffer
+- (progn
+- (switch-to-buffer parent-buffer)
+- (forward-line)
+- (notmuch-search-show-thread)))))
++ (if shownext (notmuch-show-next-thread markread) (notmuch-kill-message-buffer markread)))
+
+-(defun notmuch-show-mark-read-then-archive-thread ()
++(defun notmuch-show-mark-read-archive-thread-next-thread ()
+ "Remove \"unread\" tag from each message, then archive and show next thread.
+
+ Archive each message currrently shown by removing the \"unread\"
+@@ -215,9 +236,22 @@ being delivered to the same thread. It does not archive the
+ entire thread, but only the messages shown in the current
+ buffer."
+ (interactive)
+- (notmuch-show-archive-thread-maybe-mark-read t))
++ (notmuch-show-archive-thread-maybe-mark-read t t))
++
++(defun notmuch-show-mark-read-archive-thread-kill-buffer ()
++ "Remove \"unread\" tag from each message, then archive and kill the buffer.
++
++Archive each message currrently shown by removing the \"unread\"
++and \"inbox\" tag from each. Then kill this buffer.
++
++Note: This command is safe from any race condition of new messages
++being delivered to the same thread. It does not archive the
++entire thread, but only the messages shown in the current
++buffer."
++ (interactive)
++ (notmuch-show-archive-thread-maybe-mark-read t nil))
+
+-(defun notmuch-show-archive-thread ()
++(defun notmuch-show-archive-thread-next-thread ()
+ "Archive each message in thread, and show next thread from search.
+
+ Archive each message currrently shown by removing the \"inbox\"
+@@ -229,7 +263,20 @@ being delivered to the same thread. It does not archive the
+ entire thread, but only the messages shown in the current
+ buffer."
+ (interactive)
+- (notmuch-show-archive-thread-maybe-mark-read nil))
++ (notmuch-show-archive-thread-maybe-mark-read nil t))
++
++(defun notmuch-show-archive-thread-kill-buffer ()
++ "Archive each message in thread, and kill the thread buffer.
++
++Archive each message currrently shown by removing the \"inbox\"
++tag from each. Then kill this buffer.
++
++Note: This command is safe from any race condition of new messages
++being delivered to the same thread. It does not archive the
++entire thread, but only the messages shown in the current
++buffer."
++ (interactive)
++ (notmuch-show-archive-thread-maybe-mark-read nil t))
+
+ (defun notmuch-show-view-raw-message ()
+ "View the raw email of the current message."
+@@ -297,7 +344,7 @@ by searching backward)."
+ (not (re-search-forward notmuch-show-message-begin-regexp nil t)))))
+
+ (defun notmuch-show-message-unread-p ()
+- "Preficate testing whether current message is unread."
++ "Predicate testing whether current message is unread."
+ (member "unread" (notmuch-show-get-tags)))
+
+ (defun notmuch-show-next-message ()
+@@ -434,7 +481,7 @@ which this thread was originally shown."
+ (let ((last (notmuch-show-last-message-p)))
+ (notmuch-show-mark-read-then-next-open-message)
+ (if last
+- (notmuch-show-archive-thread))))))
++ (notmuch-show-archive-thread-next-thread))))))
+
+ (defun notmuch-show-markup-citations-region (beg end depth)
+ (goto-char beg)
+@@ -618,8 +665,9 @@ messages. Each time you navigate away from a message with
+
+ You can add or remove tags from the current message with '+' and
+ '-'. You can also archive all messages in the current
+-view, (remove the \"inbox\" tag from each), with
+-`notmuch-show-archive-thread' (bound to 'a' by default).
++view, (remove the \"inbox\" tag from each), with either
++`notmuch-show-archive-thread-next-thread' (bound to 'a' by default) or
++`notmuch-show-archive-thread-kill-buffer' (bound to 'x' by default).
+
+ \\{notmuch-show-mode-map}"
+ (interactive)
+--
+1.6.5.2
+
+
--- /dev/null
+From: "Jan Janak" <jan@ryngle.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 23:18:47 +0100
+Subject: [notmuch] [PATCH] Older versions of install do not support -C.
+Message-ID: <1258496327-12086-1-git-send-email-jan@ryngle.com>
+
+Do not use -C cmdline option of install, older versions, commonly found in
+distributions like Debian, do not seem to support it. Running make install
+on such systems (tested on Debian Lenny) fails.
+
+Signed-off-by: Jan Janak <jan at ryngle.com>
+---
+ Makefile.local | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile.local b/Makefile.local
+index f824bed..f51f1d1 100644
+--- a/Makefile.local
++++ b/Makefile.local
+@@ -27,11 +27,11 @@ install: all notmuch.1.gz
+ for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 \
+ $(DESTDIR)/etc/bash_completion.d/ ; \
+ do \
+- install -C -d $$d ; \
++ install -d $$d ; \
+ done ;
+- install -C notmuch $(DESTDIR)$(prefix)/bin/
+- install -C -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
+- install -C notmuch-completion.bash \
++ install notmuch $(DESTDIR)$(prefix)/bin/
++ install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
++ install notmuch-completion.bash \
+ $(DESTDIR)/etc/bash_completion.d/notmuch
+
+ SRCS := $(SRCS) $(notmuch_client_srcs)
+--
+1.6.3.3
+
+
--- /dev/null
+From: "Jan Janak" <jan@ryngle.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 23:35:30 +0100
+Subject: [notmuch] What a great idea!
+Message-ID: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
+
+Hello,
+
+First of all, notmuch is a wonderful idea, both the cmdline tool and
+the emacs interface! Thanks a lot for writing it, I was really excited
+when I read the announcement today.
+
+Have you considered sending an announcement to the org-mode mailing list?
+http://org-mode.org
+
+Various ways of searching/referencing emails from emacs were discussed
+there several times and none of them were as elegant as notmuch (not
+even close). Maybe notmuch would attract some of the developers
+there..
+
+ -- Jan
+
--- /dev/null
+From: "Jan Janak" <jan@ryngle.com>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 23:38:47 +0100
+Subject: [notmuch] What a great idea!
+In-Reply-To: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
+References: <f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com>
+Message-ID: <f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com>
+
+On Tue, Nov 17, 2009 at 11:35 PM, Jan Janak <jan at ryngle.com> wrote:
+> Hello,
+>
+> First of all, notmuch is a wonderful idea, both the cmdline tool and
+> the emacs interface! Thanks a lot for writing it, I was really excited
+> when I read the announcement today.
+>
+> Have you considered sending an announcement to the org-mode mailing list?
+> http://org-mode.org
+
+Sorry, wrong URL, the correct one is: http://orgmode.org
+
+> Various ways of searching/referencing emails from emacs were discussed
+> there several times and none of them were as elegant as notmuch (not
+> even close). Maybe notmuch would attract some of the developers
+> there..
+
+ -- Jan
+
--- /dev/null
+From: "Carl Worth" <cworth@cworth.org>
+To: notmuch@notmuchmail.org
+Date: Tue, 17 Nov 2009 09:13:27 -0800
+Subject: [notmuch] [PATCH 1/2] Close message file after parsing message
+ headers
+In-Reply-To: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+References: <1258471718-6781-1-git-send-email-dottedmag@dottedmag.net>
+Message-ID: <87lji5cbwo.fsf@yoom.home.cworth.org>
+
+On Tue, 17 Nov 2009 21:28:37 +0600, Mikhail Gusarov <dottedmag at dottedmag.net> wrote:
+> Keeping unused files open helps to see "Too many open files" often.
+>
+> Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
+...
+On Tue, 17 Nov 2009 21:28:38 +0600, Mikhail Gusarov <dottedmag at dottedmag.net> wrote:
+>
+> Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
+> ---
+> lib/message.cc | 2 ++
+> 1 files changed, 2 insertions(+), 0 deletions(-)
+
+Hi Mikhail,
+
+Welcome to notmuch, and thanks for these patches! I've pushed both of
+them out now.
+
+Keith ran into the same problem of "too many open files" and wrote a
+more complex fix, (which included what you did here). His code can be
+seen at:
+
+ git://keithp.com/git/notmuch
+
+I didn't apply Keith's fix yet, because I think I'd rather just fix the
+indexer to store the In-Reply-To header in a separate term prefix from
+the term used for the References header[*]. That will then let us lookup
+the in-reply-to value later for thread constructions without having to
+open the original email file at all.
+
+-Carl
+
+[*] Yes, this is my first post to our new mailing list and I'm already
+spouting off about "terms" and "prefixes" without any definitions. I
+apologize for that. I hope that people will ask questions freely here on
+the list whenever anything is not clear, and I'll be glad to explain
+things as needed. (Then when can shove answers into a HACKING document.)
+
+PS. This reply is a great example of a feature that notmuch *almost*
+supports already---repling to multiple messages at once. The "notmuch
+reply" command line does everything necessary to make this work, but we
+haven't yet hooked up any keybindings for this in the emacs client yet.
+Obviously, 'r' from the search view could reply to the entire thread.
+But when viewing a thread, anyone have a good keybinding suggestion?
+(There's obviously 'R' as opposed to 'r', but I think we'll probably
+want to distinguish "reply to sender" from "reply to all" before trying
+to distinguish "reply to message" from "reply to thread" (which I
+imagine is more rare of an operation).
+
--- /dev/null
+Date: Tue, 17 Nov 2009 15:33:01 -0500
+From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
+To: Mikhail Gusarov <dottedmag@dottedmag.net>
+Message-ID: <20091117203301.GV3165@dottiness.seas.harvard.edu>
+References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+ <87iqd9rn3l.fsf@vertex.dottedmag>
+MIME-Version: 1.0
+In-Reply-To: <87iqd9rn3l.fsf@vertex.dottedmag>
+User-Agent: Mutt/1.5.19 (2009-01-05)
+Cc: notmuch@notmuchmail.org
+Subject: Re: [notmuch] Working with Maildir storage?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============0063752545=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+
+--===============0063752545==
+Content-Type: multipart/signed; micalg=pgp-sha256;
+ protocol="application/pgp-signature"; boundary="GGxZz/e2pmGePzrA"
+Content-Disposition: inline
+
+
+--GGxZz/e2pmGePzrA
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+> See the patch just posted here.
+
+Is the list archived anywhere? The obvious archives
+(http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
+think I subscribed too late to get the patch (I only just saw the
+discussion about it).
+
+It doesn't look like the patch is in git yet.
+
+-- Lars
+
+--=20
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Senior Technologist, Computing and Information Technology
+Harvard University School of Engineering and Applied Sciences
+
+
+--GGxZz/e2pmGePzrA
+Content-Type: application/pgp-signature
+Content-Disposition: inline
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQEcBAEBCAAGBQJLAwh9AAoJENdGlQYxQazYHJMIAI+XTPOyBTZIxEGTdgVKd2fR
+k27ucKs6lXozfMIIGchNUDXQho+KmiuTfX1XFJeBkqOlhrd9zlGjBGoBM0YBq/Gs
+aStPdonREzsHORjmyQCCpjg4AcqCRTXFbDXzAeXlxMPOrZ3P0XNPzTEM1mVksbmg
+mBBDLdHncy4sSCfFgXwRGGgLv9z5Acqm8xGYr68c9PIXY939ozIKV9LVUhxiNz9g
+We2a9rLDhfwxUqDlGdiNwZZimiKvD/fsYSrBZMDb5HgIYkeNZ4SD8Xu+OgB550wN
+OFfwGi3o8WFK2AyDe5QJDh9Ub+euPNlVzePoGpkltZEHuCcLFJqCHv5XYpbxcjA=
+=GO2Q
+-----END PGP SIGNATURE-----
+
+--GGxZz/e2pmGePzrA--
+
+--===============0063752545==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============0063752545==--
+
--- /dev/null
+Date: Tue, 17 Nov 2009 14:00:54 -0500
+From: Lars Kellogg-Stedman <lars@seas.harvard.edu>
+To: notmuch@notmuchmail.org
+Message-ID: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+MIME-Version: 1.0
+User-Agent: Mutt/1.5.19 (2009-01-05)
+Subject: [notmuch] Working with Maildir storage?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============1685355122=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+
+--===============1685355122==
+Content-Type: multipart/signed; micalg=pgp-sha256;
+ protocol="application/pgp-signature"; boundary="5Dr6Wqe9hdyl7LAI"
+Content-Disposition: inline
+
+
+--5Dr6Wqe9hdyl7LAI
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+I saw the LWN article and decided to take a look at notmuch. I'm
+currently using mutt and mairix to index and read a collection of
+Maildir mail folders (around 40,000 messages total).
+
+notmuch indexed the messages without complaint, but my attempt at
+searching bombed out. Running, for example:
+
+ notmuch search storage
+
+Resulted in 4604 lines of errors along the lines of:
+
+ Error opening
+ /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=
+=3D3026:2,S:
+ Too many open files
+
+I'm curious if this is expected behavior (i.e., notmuch does not work
+with Maildir) or if something else is going on.
+
+Cheers,
+
+--=20
+Lars Kellogg-Stedman <lars@seas.harvard.edu>
+Senior Technologist, Computing and Information Technology
+Harvard University School of Engineering and Applied Sciences
+
+
+--5Dr6Wqe9hdyl7LAI
+Content-Type: application/pgp-signature
+Content-Disposition: inline
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQEcBAEBCAAGBQJLAvLmAAoJENdGlQYxQazYRtcH/0usClQ1Z+EoTsA+URwIK6hD
+FsZUxFxRjMuOQRn2idZ/zhhg5jJj11ZaHjqxSkDvi2ywkTKUf1vX9LLzVy5hSR9M
+E6XQUd5QWAQXo1VsTeKkukIL0YqsPjdgrT8+Yt+OS2NvhEncql23oxnL2/pHkIFq
+r0NdTmVV5Jcar7w9J6X1Mi9m229a/9jV5FImsWISkIhIWznXU5SiU6zIw8xhP4E0
+xhvVSNJnFryjVHtva870aSQduhHfeLPzpYhqbkMPvlq+bcz6Q/Q2SwxJcGLNMPHa
+os9s9FGhCvFKUhVzezHWPgXNCcNT8qK89rcUldb5Oq4jaJb8RCZCYABplfoyaFs=
+=vO4s
+-----END PGP SIGNATURE-----
+
+--5Dr6Wqe9hdyl7LAI--
+
+--===============1685355122==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============1685355122==--
+
--- /dev/null
+From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
+To: notmuch@notmuchmail.org
+Date: Wed, 18 Nov 2009 02:50:48 +0600
+Subject: [notmuch] Working with Maildir storage?
+In-Reply-To: <20091117203301.GV3165@dottiness.seas.harvard.edu> (Lars
+ Kellogg-Stedman's message of "Tue, 17 Nov 2009 15:33:01 -0500")
+References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+ <87iqd9rn3l.fsf@vertex.dottedmag>
+ <20091117203301.GV3165@dottiness.seas.harvard.edu>
+Message-ID: <87fx8can9z.fsf@vertex.dottedmag>
+
+
+Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu did gyre and gimble:
+
+ LK> Is the list archived anywhere? The obvious archives
+ LK> (http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
+ LK> think I subscribed too late to get the patch (I only just saw the
+ LK> discussion about it).
+
+ LK> It doesn't look like the patch is in git yet.
+
+Just has been pushed
+
+--
+ http://fossarchy.blogspot.com/
+-------------- next part --------------
+A non-text attachment was scrubbed...
+Name: not available
+Type: application/pgp-signature
+Size: 834 bytes
+Desc: not available
+URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
+
--- /dev/null
+From: "Mikhail Gusarov" <dottedmag@dottedmag.net>
+To: notmuch@notmuchmail.org
+Date: Wed, 18 Nov 2009 02:51:18 +0600
+Subject: [notmuch] [PATCH] Handle rename of message file
+Message-ID: <1258491078-29658-1-git-send-email-dottedmag@dottedmag.net>
+
+If message file has been renamed, just update filename in the DB.
+
+Signed-off-by: Mikhail Gusarov <dottedmag at dottedmag.net>
+---
+ lib/database.cc | 21 ++++++++++++---------
+ 1 files changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/lib/database.cc b/lib/database.cc
+index 3c8d626..c4eb8b6 100644
+--- a/lib/database.cc
++++ b/lib/database.cc
+@@ -925,20 +925,23 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
+ if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {
+ _notmuch_message_set_filename (message, filename);
+ _notmuch_message_add_term (message, "type", "mail");
++
++ ret = _notmuch_database_link_message (notmuch, message, message_file);
++ if (ret)
++ goto DONE;
++
++ date = notmuch_message_file_get_header (message_file, "date");
++ _notmuch_message_set_date (message, date);
++
++ _notmuch_message_index_file (message, filename);
++ } else if (strcmp(notmuch_message_get_filename(message), filename)) {
++ /* Message file has been moved/renamed */
++ _notmuch_message_set_filename (message, filename);
+ } else {
+ ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
+ goto DONE;
+ }
+
+- ret = _notmuch_database_link_message (notmuch, message, message_file);
+- if (ret)
+- goto DONE;
+-
+- date = notmuch_message_file_get_header (message_file, "date");
+- _notmuch_message_set_date (message, date);
+-
+- _notmuch_message_index_file (message, filename);
+-
+ _notmuch_message_sync (message);
+ } catch (const Xapian::Error &error) {
+ fprintf (stderr, "A Xapian exception occurred: %s.\n",
+--
+1.6.3.3
+
+
--- /dev/null
+From: Mikhail Gusarov <dottedmag@dottedmag.net>
+To: notmuch@notmuchmail.org
+References: <20091117190054.GU3165@dottiness.seas.harvard.edu>
+Date: Wed, 18 Nov 2009 01:02:38 +0600
+In-Reply-To: <20091117190054.GU3165@dottiness.seas.harvard.edu> (Lars
+ Kellogg-Stedman's message of "Tue, 17 Nov 2009 14:00:54 -0500")
+Message-ID: <87iqd9rn3l.fsf@vertex.dottedmag>
+User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux)
+MIME-Version: 1.0
+Subject: Re: [notmuch] Working with Maildir storage?
+X-BeenThere: notmuch@notmuchmail.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: "Use and development of the notmuch mail system."
+ <notmuch.notmuchmail.org>
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>
+List-Post: <mailto:notmuch@notmuchmail.org>
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============1958295626=="
+Sender: notmuch-bounces@notmuchmail.org
+Errors-To: notmuch-bounces@notmuchmail.org
+
+--===============1958295626==
+Content-Type: multipart/signed; boundary="=-=-=";
+ micalg=pgp-sha1; protocol="application/pgp-signature"
+
+--=-=-=
+Content-Transfer-Encoding: quoted-printable
+
+
+Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did g=
+yre and gimble:
+
+ LK> Resulted in 4604 lines of errors along the lines of:
+
+ LK> Error opening
+ LK> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostna=
+me,U=3D3026:2,S:
+ LK> Too many open files
+
+See the patch just posted here.
+
+=2D-=20
+ http://fossarchy.blogspot.com/
+
+--=-=-=
+Content-Type: application/pgp-signature
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+
+iQIcBAEBAgAGBQJLAvNOAAoJEJ0g9lA+M4iIjLYQAKp0PXEgl3JMOEBisH52AsIK
+CzzfP4Fzd41K9VH/c1EdQWDYR6FCAA4IUSNICnJhITsYUb0eC5AKJiey3JP0+rmd
+s4qEFBKH2iuphv8Llltcv2Q8DyPuJBkVa3mO9XCCeABZ6v4UvnTSWRVG12csSEih
+ScgienU8sMrM9LwvvVI1ZB2flm2TzsH2hWi30jIgmtBntIKJaTgbFXB50FYFwULa
+gGL/oH3u+YpumedWzPZdCJrw2q7nMvYx8aQ29EDCNLZibAZe+6oDTa6Fv6/0ldpQ
+U+DptR0nJGbJTWa26OTSvmyeIORjAfM+TEI68n7KO9VHYPmVh6awcf0MNKYh2xWk
+eRQNBcKyQNWxeKyCCpT/rrTlpxBWahpvg+V8lkDH2W09wjRp6CUKvifK3Sz3am9m
+5ZUMpvXbwkZD6Ci6l/QytbYK50e8UpvFSu5DBaxBz59ykoypuNg2ayO5Kdi6IF5d
+T+Sw6wo8UKn9a33+vheIc0fkhZXbeSotEmDm7huazm6CgM3dcWXUpTuJvik1cSWp
+4buv98gY6IKWKoUTXODWUr+7VR4gei8du8qOsKem+QDfNX7tmaIRjhrbB24B91Wy
+td3MTJD7GjMNid0INqRY1CRMLo8YlPaq6NBZfcYtYgwa6gpJijz1/MAn8+GMrfhF
+9LI8b9jopNP+pMYBohLA
+=/ksP
+-----END PGP SIGNATURE-----
+--=-=-=--
+
+--===============1958295626==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+notmuch mailing list
+notmuch@notmuchmail.org
+http://notmuchmail.org/mailman/listinfo/notmuch
+
+--===============1958295626==--
+
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch count" for messages and threads'
-. ./test-lib.sh
-
-add_email_corpus
-
-# Note: The 'wc -l' results below are wrapped in arithmetic evaluation
-# $((...)) to strip whitespace. This is for portability, as 'wc -l'
-# emits whitespace on some BSD variants.
-
-test_begin_subtest "message count is the default for notmuch count"
-test_expect_equal \
- "$((`notmuch search --output=messages '*' | wc -l`))" \
- "`notmuch count '*'`"
-
-test_begin_subtest "message count with --output=messages"
-test_expect_equal \
- "$((`notmuch search --output=messages '*' | wc -l`))" \
- "`notmuch count --output=messages '*'`"
-
-test_begin_subtest "thread count with --output=threads"
-test_expect_equal \
- "$((`notmuch search --output=threads '*' | wc -l`))" \
- "`notmuch count --output=threads '*'`"
-
-test_begin_subtest "thread count is the default for notmuch search"
-test_expect_equal \
- "$((`notmuch search '*' | wc -l`))" \
- "`notmuch count --output=threads '*'`"
-
-test_begin_subtest "files count"
-test_expect_equal \
- "$((`notmuch search --output=files '*' | wc -l`))" \
- "`notmuch count --output=files '*'`"
-
-test_begin_subtest "files count for a duplicate message-id"
-test_expect_equal \
- "2" \
- "`notmuch count --output=files id:20091117232137.GA7669@griffis1.net`"
-
-test_begin_subtest "count with no matching messages"
-test_expect_equal \
- "0" \
- "`notmuch count --output=messages from:cworth and not from:cworth`"
-
-test_begin_subtest "count with no matching threads"
-test_expect_equal \
- "0" \
- "`notmuch count --output=threads from:cworth and not from:cworth`"
-
-test_begin_subtest "message count is the default for batch count"
-notmuch count --batch >OUTPUT <<EOF
-
-from:cworth
-EOF
-notmuch count --output=messages >EXPECTED
-notmuch count --output=messages from:cworth >>EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "batch message count"
-notmuch count --batch --output=messages >OUTPUT <<EOF
-from:cworth
-
-tag:inbox
-EOF
-notmuch count --output=messages from:cworth >EXPECTED
-notmuch count --output=messages >>EXPECTED
-notmuch count --output=messages tag:inbox >>EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "batch thread count"
-notmuch count --batch --output=threads >OUTPUT <<EOF
-
-from:cworth
-from:cworth and not from:cworth
-foo
-EOF
-notmuch count --output=threads >EXPECTED
-notmuch count --output=threads from:cworth >>EXPECTED
-notmuch count --output=threads from:cworth and not from:cworth >>EXPECTED
-notmuch count --output=threads foo >>EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "batch message count with input file"
-cat >INPUT <<EOF
-from:cworth
-
-tag:inbox
-EOF
-notmuch count --input=INPUT --output=messages >OUTPUT
-notmuch count --output=messages from:cworth >EXPECTED
-notmuch count --output=messages >>EXPECTED
-notmuch count --output=messages tag:inbox >>EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
-
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-# TODO:
-# - decryption/verification with signer key not available
-# - verification of signatures from expired/revoked keys
-
-test_description='PGP/MIME signature verification and decryption'
-. ./test-lib.sh
-
-add_gnupg_home ()
-{
- local output
- [ -d ${GNUPGHOME} ] && return
- mkdir -m 0700 "$GNUPGHOME"
- gpg --no-tty --import <$TEST_DIRECTORY/gnupg-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
- elif (gpg --debug-quick-random --version >/dev/null 2>&1) ; then
- echo debug-quick-random >> "$GNUPGHOME"/gpg.conf
- fi
- echo no-emit-version >> "$GNUPGHOME"/gpg.conf
-}
-
-##################################################
-
-add_gnupg_home
-# get key fingerprint
-FINGERPRINT=$(gpg --no-tty --list-secret-keys --with-colons --fingerprint | grep '^fpr:' | cut -d: -f10)
-
-test_expect_success 'emacs delivery of signed message' \
-'emacs_fcc_message \
- "test signed message 001" \
- "This is a test signed message." \
- "(mml-secure-message-sign)"'
-
-test_begin_subtest "signature verification"
-output=$(notmuch show --format=json --verify subject:"test signed message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["inbox","signed"],
- "headers": {"Subject": "test signed message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "sigstatus": [{"status": "good",
- "fingerprint": "'$FINGERPRINT'",
- "created": 946728000}],
- "content-type": "multipart/signed",
- "content": [{"id": 2,
- "content-type": "text/plain",
- "content": "This is a test signed message.\n"},
- {"id": 3,
- "content-type": "application/pgp-signature",
- "content-length": 280}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_begin_subtest "signature verification with full owner trust"
-# give the key full owner trust
-echo "${FINGERPRINT}:6:" | gpg --no-tty --import-ownertrust >>"$GNUPGHOME"/trust.log 2>&1
-gpg --no-tty --check-trustdb >>"$GNUPGHOME"/trust.log 2>&1
-output=$(notmuch show --format=json --verify subject:"test signed message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["inbox","signed"],
- "headers": {"Subject": "test signed message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "sigstatus": [{"status": "good",
- "fingerprint": "'$FINGERPRINT'",
- "created": 946728000,
- "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
- "content-type": "multipart/signed",
- "content": [{"id": 2,
- "content-type": "text/plain",
- "content": "This is a test signed message.\n"},
- {"id": 3,
- "content-type": "application/pgp-signature",
- "content-length": 280}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_begin_subtest "signature verification with signer key unavailable"
-# move the gnupghome temporarily out of the way
-mv "${GNUPGHOME}"{,.bak}
-output=$(notmuch show --format=json --verify subject:"test signed message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["inbox","signed"],
- "headers": {"Subject": "test signed message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "sigstatus": [{"status": "error",
- "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'",
- "errors": 2}],
- "content-type": "multipart/signed",
- "content": [{"id": 2,
- "content-type": "text/plain",
- "content": "This is a test signed message.\n"},
- {"id": 3,
- "content-type": "application/pgp-signature",
- "content-length": 280}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-mv "${GNUPGHOME}"{.bak,}
-
-# create a test encrypted message with attachment
-cat <<EOF >TESTATTACHMENT
-This is a test file.
-EOF
-test_expect_success 'emacs delivery of encrypted message with attachment' \
-'emacs_fcc_message \
- "test encrypted message 001" \
- "This is a test encrypted message.\n" \
- "(mml-attach-file \"TESTATTACHMENT\") (mml-secure-message-encrypt)"'
-
-test_begin_subtest "decryption, --format=text"
-output=$(notmuch show --format=text --decrypt subject:"test encrypted message 001" \
- | notmuch_show_sanitize_all \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (encrypted inbox)
-Subject: test encrypted message 001
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: test_suite@notmuchmail.org
-Date: Sat, 01 Jan 2000 12:00:00 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: multipart/encrypted
-\fpart{ ID: 2, Content-type: application/pgp-encrypted
-Non-text part: application/pgp-encrypted
-\fpart}
-\fpart{ ID: 3, Content-type: multipart/mixed
-\fpart{ ID: 4, Content-type: text/plain
-This is a test encrypted message.
-\fpart}
-\fattachment{ ID: 5, Filename: TESTATTACHMENT, Content-type: application/octet-stream
-Non-text part: application/octet-stream
-\fattachment}
-\fpart}
-\fpart}
-\fbody}
-\fmessage}'
-test_expect_equal \
- "$output" \
- "$expected"
-
-test_begin_subtest "decryption, --format=json"
-output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["encrypted","inbox"],
- "headers": {"Subject": "test encrypted message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "encstatus": [{"status": "good"}],
- "sigstatus": [],
- "content-type": "multipart/encrypted",
- "content": [{"id": 2,
- "content-type": "application/pgp-encrypted",
- "content-length": 11},
- {"id": 3,
- "content-type": "multipart/mixed",
- "content": [{"id": 4,
- "content-type": "text/plain",
- "content": "This is a test encrypted message.\n"},
- {"id": 5,
- "content-type": "application/octet-stream",
- "content-length": 28,
- "content-transfer-encoding": "base64",
- "filename": "TESTATTACHMENT"}]}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_begin_subtest "decryption, --format=json, --part=4"
-output=$(notmuch show --format=json --part=4 --decrypt subject:"test encrypted message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='{"id": 4,
- "content-type": "text/plain",
- "content": "This is a test encrypted message.\n"}'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_begin_subtest "decrypt attachment (--part=5 --format=raw)"
-notmuch show \
- --format=raw \
- --part=5 \
- --decrypt \
- subject:"test encrypted message 001" >OUTPUT
-test_expect_equal_file OUTPUT TESTATTACHMENT
-
-test_begin_subtest "decryption failure with missing key"
-mv "${GNUPGHOME}"{,.bak}
-# The length of the encrypted attachment varies so must be normalized.
-output=$(notmuch show --format=json --decrypt subject:"test encrypted message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|' \
- | sed -e 's|"content-length": 6[1234567890]*|"content-length": 652|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["encrypted","inbox"],
- "headers": {"Subject": "test encrypted message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "encstatus": [{"status": "bad"}],
- "content-type": "multipart/encrypted",
- "content": [{"id": 2,
- "content-type": "application/pgp-encrypted",
- "content-length": 11},
- {"id": 3,
- "content-type": "application/octet-stream",
- "content-length": 652}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-mv "${GNUPGHOME}"{.bak,}
-
-test_expect_success 'emacs delivery of encrypted + signed message' \
-'emacs_fcc_message \
- "test encrypted message 002" \
- "This is another test encrypted message.\n" \
- "(mml-secure-message-sign-encrypt)"'
-
-test_begin_subtest "decryption + signature verification"
-output=$(notmuch show --format=json --decrypt subject:"test encrypted message 002" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["encrypted","inbox"],
- "headers": {"Subject": "test encrypted message 002",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "encstatus": [{"status": "good"}],
- "sigstatus": [{"status": "good",
- "fingerprint": "'$FINGERPRINT'",
- "created": 946728000,
- "userid": " Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"}],
- "content-type": "multipart/encrypted",
- "content": [{"id": 2,
- "content-type": "application/pgp-encrypted",
- "content-length": 11},
- {"id": 3,
- "content-type": "text/plain",
- "content": "This is another test encrypted message.\n"}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_begin_subtest "reply to encrypted message"
-output=$(notmuch reply --decrypt subject:"test encrypted message 002" \
- | grep -v -e '^In-Reply-To:' -e '^References:')
-expected='From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: test encrypted message 002
-
-On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> This is another test encrypted message.'
-test_expect_equal \
- "$output" \
- "$expected"
-
-test_begin_subtest "signature verification with revoked key"
-# generate revocation certificate and load it to revoke key
-echo "y
-1
-Notmuch Test Suite key revocation (automated) $(date '+%F_%T%z')
-
-y
-
-" \
- | gpg --no-tty --quiet --command-fd 0 --armor --gen-revoke "0x${FINGERPRINT}!" 2>/dev/null \
- | gpg --no-tty --quiet --import
-output=$(notmuch show --format=json --verify subject:"test signed message 001" \
- | notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
-expected='[[[{"id": "XXXXX",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["inbox","signed"],
- "headers": {"Subject": "test signed message 001",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "test_suite@notmuchmail.org",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "sigstatus": [{"status": "error",
- "keyid": "6D92612D94E46381",
- "errors": 8}],
- "content-type": "multipart/signed",
- "content": [{"id": 2,
- "content-type": "text/plain",
- "content": "This is a test signed message.\n"},
- {"id": 3,
- "content-type": "application/pgp-signature",
- "content-length": 280}]}]},
- []]]]'
-test_expect_equal_json \
- "$output" \
- "$expected"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="\"notmuch dump\" and \"notmuch restore\""
-. ./test-lib.sh
-
-add_email_corpus
-
-test_expect_success 'Dumping all tags' \
- 'generate_message &&
- notmuch new &&
- notmuch dump > dump.expected'
-
-# The use of from:cworth is rather arbitrary: it matches some of the
-# email corpus' messages, but not all of them.
-
-test_expect_success 'Dumping all tags II' \
- 'notmuch tag +ABC +DEF -- from:cworth &&
- notmuch dump > dump-ABC_DEF.expected &&
- ! cmp dump.expected dump-ABC_DEF.expected'
-
-test_expect_success 'Clearing all tags' \
- 'sed -e "s/(\([^(]*\))$/()/" < dump.expected > clear.expected &&
- notmuch restore --input=clear.expected &&
- notmuch dump > clear.actual &&
- test_cmp clear.expected clear.actual'
-
-test_expect_success 'Accumulate original tags' \
- 'notmuch tag +ABC +DEF -- from:cworth &&
- notmuch restore --accumulate < dump.expected &&
- notmuch dump > dump.actual &&
- test_cmp dump-ABC_DEF.expected dump.actual'
-
-test_expect_success 'Restoring original tags' \
- 'notmuch restore --input=dump.expected &&
- notmuch dump > dump.actual &&
- test_cmp dump.expected dump.actual'
-
-test_expect_success 'Restore with nothing to do' \
- 'notmuch restore < dump.expected &&
- notmuch dump > dump.actual &&
- test_cmp dump.expected dump.actual'
-
-test_expect_success 'Accumulate with existing tags' \
- 'notmuch restore --accumulate --input=dump.expected &&
- notmuch dump > dump.actual &&
- test_cmp dump.expected dump.actual'
-
-test_expect_success 'Accumulate with no tags' \
- 'notmuch restore --accumulate < clear.expected &&
- notmuch dump > dump.actual &&
- test_cmp dump.expected dump.actual'
-
-test_expect_success 'Accumulate with new tags' \
- 'notmuch restore --input=dump.expected &&
- notmuch restore --accumulate --input=dump-ABC_DEF.expected &&
- notmuch dump > OUTPUT.$test_count &&
- notmuch restore --input=dump.expected &&
- test_cmp dump-ABC_DEF.expected OUTPUT.$test_count'
-
-# notmuch restore currently only considers the first argument.
-test_expect_success 'Invalid restore invocation' \
- 'test_must_fail notmuch restore --input=dump.expected another_one'
-
-test_begin_subtest "dump --output=outfile"
-notmuch dump --output=dump-outfile.actual
-test_expect_equal_file dump.expected dump-outfile.actual
-
-test_begin_subtest "dump --output=outfile --"
-notmuch dump --output=dump-1-arg-dash.actual --
-test_expect_equal_file dump.expected dump-1-arg-dash.actual
-
-# Note, we assume all messages from cworth have a message-id
-# containing cworth.org
-
-grep 'cworth[.]org' dump.expected > dump-cworth.expected
-
-test_begin_subtest "dump -- from:cworth"
-notmuch dump -- from:cworth > dump-dash-cworth.actual
-test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
-
-test_begin_subtest "dump --output=outfile from:cworth"
-notmuch dump --output=dump-outfile-cworth.actual from:cworth
-test_expect_equal_file dump-cworth.expected dump-outfile-cworth.actual
-
-test_begin_subtest "dump --output=outfile -- from:cworth"
-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"
-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
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "format=batch-tag, dump sanity check."
-notmuch dump --format=sup from:cworth | cut -f1 -d' ' | \
- sort > EXPECTED.$test_count
-notmuch dump --format=batch-tag from:cworth | sed 's/^.*-- id://' | \
- sort > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "format=batch-tag, # round-trip"
-notmuch dump --format=sup | sort > EXPECTED.$test_count
-notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
-notmuch dump --format=sup | sort > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "format=batch-tag, # blank lines and comments"
-notmuch dump --format=batch-tag| sort > EXPECTED.$test_count
-notmuch restore <<EOF
-# this line is a comment; the next has only white space
-
-
-# the previous line is empty
-EOF
-notmuch dump --format=batch-tag | sort > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "format=batch-tag, # reverse-round-trip empty tag"
-cat <<EOF >EXPECTED.$test_count
-+ -- id:20091117232137.GA7669@griffis1.net
-EOF
-notmuch restore --format=batch-tag < EXPECTED.$test_count
-notmuch dump --format=batch-tag id:20091117232137.GA7669@griffis1.net > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-tag1='comic_swear=$&^%$^%\\//-+$^%$'
-enc1=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag1")
-
-tag2=$(printf 'this\n tag\t has\n spaces')
-enc2=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag2")
-
-enc3='%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a'
-tag3=$($TEST_DIRECTORY/hex-xcode --direction=decode $enc3)
-
-notmuch dump --format=batch-tag > BACKUP
-
-notmuch tag +"$tag1" +"$tag2" +"$tag3" -inbox -unread "*"
-
-# initial segment of file used for several tests below.
-cat <<EOF > comments-and-blanks
-# this is a comment
-
-# next line has leading whitespace
-
-
-EOF
-
-test_begin_subtest 'restoring empty file is not an error'
-notmuch restore < /dev/null 2>OUTPUT.$test_count
-cp /dev/null EXPECTED
-test_expect_equal_file EXPECTED OUTPUT.$test_count
-
-test_begin_subtest 'file of comments and blank lines is not an error'
-notmuch restore --input=comments-and-blanks
-ret_val=$?
-test_expect_equal "$ret_val" "0"
-
-cp comments-and-blanks leading-comments-blanks-batch-tag
-echo "+some_tag -- id:yun1vjwegii.fsf@aiko.keithp.com" \
- >> leading-comments-blanks-batch-tag
-
-test_begin_subtest 'detect format=batch-tag with leading comments and blanks'
-notmuch restore --input=leading-comments-blanks-batch-tag
-notmuch search --output=tags id:yun1vjwegii.fsf@aiko.keithp.com > OUTPUT.$test_count
-echo "some_tag" > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT.$test_count
-
-cp comments-and-blanks leading-comments-blanks-sup
-echo "yun1vjwegii.fsf@aiko.keithp.com (another_tag)" \
- >> leading-comments-blanks-sup
-
-test_begin_subtest 'detect format=sup with leading comments and blanks'
-notmuch restore --input=leading-comments-blanks-sup
-notmuch search --output=tags id:yun1vjwegii.fsf@aiko.keithp.com > OUTPUT.$test_count
-echo "another_tag" > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT.$test_count
-
-test_begin_subtest 'format=batch-tag, round trip with strange tags'
-notmuch dump --format=batch-tag > EXPECTED.$test_count
-notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
-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'
-notmuch dump --format=batch-tag -- from:cworth |\
- awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
-notmuch dump --format=batch-tag -- from:cworth > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest 'restoring sane tags'
-notmuch restore --format=batch-tag < BACKUP
-notmuch dump --format=batch-tag > OUTPUT.$test_count
-test_expect_equal_file BACKUP OUTPUT.$test_count
-
-test_begin_subtest 'format=batch-tag, restore=auto'
-notmuch dump --format=batch-tag > EXPECTED.$test_count
-notmuch tag -inbox -unread "*"
-notmuch restore --format=auto < EXPECTED.$test_count
-notmuch dump --format=batch-tag > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest 'format=sup, restore=auto'
-notmuch dump --format=sup > EXPECTED.$test_count
-notmuch tag -inbox -unread "*"
-notmuch restore --format=auto < EXPECTED.$test_count
-notmuch dump --format=sup > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest 'format=batch-tag, restore=default'
-notmuch dump --format=batch-tag > EXPECTED.$test_count
-notmuch tag -inbox -unread "*"
-notmuch restore < EXPECTED.$test_count
-notmuch dump --format=batch-tag > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest 'format=sup, restore=default'
-notmuch dump --format=sup > EXPECTED.$test_count
-notmuch tag -inbox -unread "*"
-notmuch restore < EXPECTED.$test_count
-notmuch dump --format=sup > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest 'restore: checking error messages'
-notmuch restore <<EOF 2>OUTPUT
-# the next line has a space
-
-a
-+0
-+a +b
-# trailing whitespace
-+a +b
-+c +d --
-# this is a harmless comment, do not yell about it.
-
-# the previous line was blank; also no yelling please
-+%zz -- id:whatever
-+e +f id:"
-+e +f tag:abc
-# the next non-comment line should report an an empty tag error for
-# batch tagging, but not for restore
-+ +e -- id:20091117232137.GA7669@griffis1.net
-# valid id, but warning about missing message
-+e id:missing_message_id
-# exercise parser
-+e -- id:some)stuff
-+e -- id:some stuff
-+e -- id:some"stuff
-+e -- id:"a_message_id_with""_a_quote"
-+e -- id:"a message id with spaces"
-+e -- id:an_id_with_leading_and_trailing_ws \
-
-EOF
-
-cat <<EOF > EXPECTED
-Warning: cannot parse query: a (skipping)
-Warning: no query string [+0]
-Warning: no query string [+a +b]
-Warning: missing query string [+a +b ]
-Warning: no query string after -- [+c +d --]
-Warning: hex decoding of tag %zz failed [+%zz -- id:whatever]
-Warning: cannot parse query: id:" (skipping)
-Warning: not an id query: tag:abc (skipping)
-Warning: cannot apply tags to missing message: missing_message_id
-Warning: cannot parse query: id:some)stuff (skipping)
-Warning: cannot parse query: id:some stuff (skipping)
-Warning: cannot apply tags to missing message: some"stuff
-Warning: cannot apply tags to missing message: a_message_id_with"_a_quote
-Warning: cannot apply tags to missing message: a message id with spaces
-Warning: cannot apply tags to missing message: an_id_with_leading_and_trailing_ws
-EOF
-
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest 'roundtripping random message-ids and tags'
-
- ${TEST_DIRECTORY}/random-corpus --config-path=${NOTMUCH_CONFIG} \
- --num-messages=100
-
- notmuch dump --format=batch-tag| \
- sort > EXPECTED.$test_count
-
- notmuch tag +this_tag_is_very_unlikely_to_be_random '*'
-
- notmuch restore --format=batch-tag < EXPECTED.$test_count
-
- notmuch dump --format=batch-tag| \
- sort > OUTPUT.$test_count
-
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_done
-
-# Note the database is "poisoned" for sup format at this point.
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs interface"
-. ./test-lib.sh
-
-EXPECTED=$TEST_DIRECTORY/emacs.expected-output
-
-add_email_corpus
-
-test_begin_subtest "Basic notmuch-hello view in emacs"
-test_emacs '(notmuch-hello)
- (test-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello
-
-test_begin_subtest "Saved search with 0 results"
-test_emacs '(let ((notmuch-show-empty-saved-searches t)
- (notmuch-saved-searches
- '\''(("inbox" . "tag:inbox")
- ("unread" . "tag:unread")
- ("empty" . "tag:doesnotexist"))))
- (notmuch-hello)
- (test-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-with-empty
-
-test_begin_subtest "No saved searches displayed (all with 0 results)"
-test_emacs '(let ((notmuch-saved-searches
- '\''(("empty" . "tag:doesnotexist"))))
- (notmuch-hello)
- (test-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-no-saved-searches
-
-test_begin_subtest "Basic notmuch-search view in emacs"
-test_emacs '(notmuch-search "tag:inbox")
- (notmuch-test-wait)
- (test-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-search-tag-inbox
-
-test_begin_subtest "Incremental parsing of search results"
-test_emacs "(ad-enable-advice 'notmuch-search-process-filter 'around 'pessimal)
- (ad-activate 'notmuch-search-process-filter)
- (notmuch-search \"tag:inbox\")
- (notmuch-test-wait)
- (ad-disable-advice 'notmuch-search-process-filter 'around 'pessimal)
- (ad-activate 'notmuch-search-process-filter)
- (test-output)"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-search-tag-inbox
-
-test_begin_subtest "Navigation of notmuch-hello to search results"
-test_emacs '(notmuch-hello)
- (goto-char (point-min))
- (re-search-forward "inbox")
- (widget-button-press (1- (point)))
- (notmuch-test-wait)
- (test-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-view-inbox
-
-test_begin_subtest "Basic notmuch-show view in emacs"
-maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
-test_emacs "(notmuch-show \"$maildir_storage_thread\")
- (test-output)"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
-
-test_begin_subtest "Basic notmuch-show view in emacs default indentation"
-maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
-test_emacs "(let ((notmuch-show-indent-messages-width 1))
- (notmuch-show \"$maildir_storage_thread\")
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
-
-test_begin_subtest "Basic notmuch-show view in emacs without indentation"
-maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
-test_emacs "(let ((notmuch-show-indent-messages-width 0))
- (notmuch-show \"$maildir_storage_thread\")
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage-without-indentation
-
-test_begin_subtest "Basic notmuch-show view in emacs with fourfold indentation"
-maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
-test_emacs "(let ((notmuch-show-indent-messages-width 4))
- (notmuch-show \"$maildir_storage_thread\")
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage-with-fourfold-indentation
-
-test_begin_subtest "notmuch-show for message with invalid From"
-add_message "[subject]=\"message-with-invalid-from\"" \
- "[from]=\"\\\"Invalid \\\" From\\\" <test_suite@notmuchmail.org>\""
-thread=$(notmuch search --output=threads subject:message-with-invalid-from)
-test_emacs "(notmuch-show \"$thread\")
- (test-output \"OUTPUT.raw\")"
-cat <<EOF >EXPECTED
-"Invalid " (2001-01-05) (inbox)
-Subject: message-with-invalid-from
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-
-This is just a test message (#1)
-EOF
-notmuch_date_sanitize < OUTPUT.raw > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Navigation of notmuch-search to thread view"
-test_emacs '(notmuch-search "tag:inbox")
- (notmuch-test-wait)
- (goto-char (point-min))
- (re-search-forward "Working with Maildir")
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (test-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
-
-test_begin_subtest "Add tag from search view"
-os_x_darwin_thread=$(notmuch search --output=threads id:ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com)
-test_emacs "(notmuch-search \"$os_x_darwin_thread\")
- (notmuch-test-wait)
- (execute-kbd-macro \"+tag-from-search-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-search-view unread)"
-
-test_begin_subtest "Remove tag from search view"
-test_emacs "(notmuch-search \"$os_x_darwin_thread\")
- (notmuch-test-wait)
- (execute-kbd-macro \"-tag-from-search-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
-
-test_begin_subtest "Add tag (large query)"
-# We use a long query to force us into batch mode and use a funny tag
-# that requires escaping for batch tagging.
-test_emacs "(notmuch-tag (concat \"$os_x_darwin_thread\" \" or \" (make-string notmuch-tag-argument-limit ?x)) (list \"+tag-from-%-large-query\"))"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-%-large-query unread)"
-notmuch tag -tag-from-%-large-query $os_x_darwin_thread
-
-test_begin_subtest "notmuch-show: add single tag to single message"
-test_emacs "(notmuch-show \"$os_x_darwin_thread\")
- (execute-kbd-macro \"+tag-from-show-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag-from-show-view unread)"
-
-test_begin_subtest "notmuch-show: remove single tag from single message"
-test_emacs "(notmuch-show \"$os_x_darwin_thread\")
- (execute-kbd-macro \"-tag-from-show-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
-
-test_begin_subtest "notmuch-show: add multiple tags to single message"
-test_emacs "(notmuch-show \"$os_x_darwin_thread\")
- (execute-kbd-macro \"+tag1-from-show-view +tag2-from-show-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox tag1-from-show-view tag2-from-show-view unread)"
-
-test_begin_subtest "notmuch-show: remove multiple tags from single message"
-test_emacs "(notmuch-show \"$os_x_darwin_thread\")
- (execute-kbd-macro \"-tag1-from-show-view -tag2-from-show-view\")"
-output=$(notmuch search $os_x_darwin_thread | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
-
-test_begin_subtest "Message with .. in Message-Id:"
-add_message [id]=123..456@example '[subject]="Message with .. in Message-Id"'
-test_emacs '(notmuch-search "id:\"123..456@example\"")
- (notmuch-test-wait)
- (execute-kbd-macro "+search-add")
- (execute-kbd-macro "+search-remove")
- (execute-kbd-macro "-search-remove")
- (notmuch-show "id:\"123..456@example\"")
- (notmuch-test-wait)
- (execute-kbd-macro "+show-add")
- (execute-kbd-macro "+show-remove")
- (execute-kbd-macro "-show-remove")'
-output=$(notmuch search 'id:"123..456@example"' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message with .. in Message-Id (inbox search-add show-add)"
-
-test_begin_subtest "Message with quote in Message-Id:"
-add_message '[id]="\"quote\"@example"' '[subject]="Message with quote in Message-Id"'
-test_emacs '(notmuch-search "subject:\"Message with quote\"")
- (notmuch-test-wait)
- (execute-kbd-macro "+search-add")
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (execute-kbd-macro "+show-add")'
-output=$(notmuch search 'id:"""quote""@example"' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message with quote in Message-Id (inbox search-add show-add)"
-
-test_begin_subtest "Sending a message via (fake) SMTP"
-emacs_deliver_message \
- 'Testing message sent via SMTP' \
- 'This is a test that messages are sent via SMTP' \
- '(message-goto-to)
- (kill-whole-line)
- (insert "To: user@example.com\n")'
-sed \
- -e s',^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' \
- -e s',^Message-ID: <.*>$,Message-ID: <XXX>,' \
- -e s',^\(Content-Type: text/plain\); charset=us-ascii$,\1,' < sent_message >OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: user@example.com
-Subject: Testing message sent via SMTP
-Date: 01 Jan 2000 12:00:00 -0000
-User-Agent: Notmuch/XXX Emacs/XXX
-Message-ID: <XXX>
-MIME-Version: 1.0
-Content-Type: text/plain
-
-This is a test that messages are sent via SMTP
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
-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)"
-
-test_begin_subtest "notmuch-fcc-dirs set to nil"
-test_emacs "(let ((notmuch-fcc-dirs nil))
- (notmuch-mua-mail)
- (test-output))"
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject:
---text follows this line--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-# Make another FCC maildir specific for the next test
-mkdir -p mail/sent-string/cur
-mkdir -p mail/sent-string/new
-mkdir -p mail/sent-string/tmp
-
-test_begin_subtest "notmuch-fcc-dirs set to a string"
-test_emacs "(let ((notmuch-fcc-dirs \"sent-string\"))
- (notmuch-mua-mail)
- (test-output))"
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject:
-Fcc: ${MAIL_DIR}/sent-string
---text follows this line--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-# Make more FCC maildirs specific for the next test
-mkdir -p mail/sent-list-match/cur
-mkdir -p mail/sent-list-match/new
-mkdir -p mail/sent-list-match/tmp
-mkdir -p mail/failure/cur
-mkdir -p mail/failure/new
-mkdir -p mail/failure/tmp
-
-test_begin_subtest "notmuch-fcc-dirs set to a list (with match)"
-test_emacs "(let ((notmuch-fcc-dirs
- '((\"notmuchmail.org\" . \"sent-list-match\")
- (\".*\" . \"failure\"))))
- (notmuch-mua-mail)
- (test-output))"
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject:
-Fcc: ${MAIL_DIR}/sent-list-match
---text follows this line--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-# Make another FCC maildir specific for the next test
-mkdir -p mail/sent-list-catch-all/cur
-mkdir -p mail/sent-list-catch-all/new
-mkdir -p mail/sent-list-catch-all/tmp
-
-test_begin_subtest "notmuch-fcc-dirs set to a list (catch-all)"
-test_emacs "(let ((notmuch-fcc-dirs
- '((\"example.com\" . \"failure\")
- (\".*\" . \"sent-list-catch-all\"))))
- (notmuch-mua-mail)
- (test-output))"
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject:
-Fcc: ${MAIL_DIR}/sent-list-catch-all
---text follows this line--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "notmuch-fcc-dirs set to a list (no match)"
-test_emacs "(let ((notmuch-fcc-dirs
- '((\"example.com\" . \"failure\")
- (\"nomatchhere.net\" . \"failure\"))))
- (notmuch-mua-mail)
- (test-output))"
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject:
---text follows this line--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply within emacs"
-test_emacs '(let ((message-hidden-headers ''()))
- (notmuch-search "subject:\"testing message sent via SMTP\"")
- (notmuch-test-wait)
- (notmuch-search-reply-to-thread)
- (test-output))'
-sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: <XXX>/' OUTPUT
-sed -i -e 's/^References: <.*>$/References: <XXX>/' OUTPUT
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: user@example.com
-Subject: Re: Testing message sent via SMTP
-In-Reply-To: <XXX>
-Fcc: ${MAIL_DIR}/sent
-References: <XXX>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Notmuch Test Suite <test_suite@notmuchmail.org> writes:
-
-> This is a test that messages are sent via SMTP
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply from alternate address within emacs"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite_other@notmuchmail.org
-
-test_emacs "(let ((message-hidden-headers '()))
- (notmuch-search \"id:\\\"${gen_msg_id}\\\"\")
- (notmuch-test-wait)
- (notmuch-search-reply-to-thread)
- (test-output))"
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-To: Sender <sender@example.com>
-Subject: Re: ${test_subtest_name}
-In-Reply-To: <${gen_msg_id}>
-Fcc: ${MAIL_DIR}/sent
-References: <${gen_msg_id}>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Sender <sender@example.com> writes:
-
-> This is just a test message (#${gen_msg_cnt})
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply from address in named group list within emacs"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]=group:test_suite@notmuchmail.org,someone@example.com\;' \
- [cc]=test_suite_other@notmuchmail.org
-
-test_emacs "(let ((message-hidden-headers '()))
- (notmuch-search \"id:\\\"${gen_msg_id}\\\"\")
- (notmuch-test-wait)
- (notmuch-search-reply-to-thread)
- (test-output))"
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Sender <sender@example.com>, someone@example.com
-Subject: Re: ${test_subtest_name}
-In-Reply-To: <${gen_msg_id}>
-Fcc: ${MAIL_DIR}/sent
-References: <${gen_msg_id}>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Sender <sender@example.com> writes:
-
-> This is just a test message (#${gen_msg_cnt})
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply within emacs to a multipart/mixed message"
-test_emacs '(let ((message-hidden-headers ''()))
- (notmuch-show "id:20091118002059.067214ed@hikari")
- (notmuch-show-reply)
- (test-output))'
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Adrian Perez de Castro <aperez@igalia.com>, notmuch@notmuchmail.org
-Subject: Re: [notmuch] Introducing myself
-In-Reply-To: <20091118002059.067214ed@hikari>
-Fcc: ${MAIL_DIR}/sent
-References: <20091118002059.067214ed@hikari>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Adrian Perez de Castro <aperez@igalia.com> writes:
-
-> Hello to all,
->
-> I have just heard about Not Much today in some random Linux-related news
-> site (LWN?), my name is Adrian Perez and I work as systems administrator
-> (although I can do some code as well :P). I have always thought that the
-> ideas behind Sup were great, but after some time using it, I got tired of
-> the oddities that it has. I also do not like doing things like having to
-> install Ruby just for reading and sorting mails. Some time ago I thought
-> about doing something like Not Much and in fact I played a bit with the
-> Python+Xapian and the Python+Whoosh combinations, because I find relaxing
-> to code things in Python when I am not working and also it is installed
-> by default on most distribution. I got to have some mailboxes indexed and
-> basic searching working a couple of months ago. Lately I have been very
-> busy and had no time for coding, and them... boom! Not Much appears -- and
-> it is almost exactly what I was trying to do, but faster. I have been
-> playing a bit with Not Much today, and I think it has potential.
->
-> Also, I would like to share one idea I had in mind, that you might find
-> interesting: One thing I have found very annoying is having to re-tag my
-> mail when the indexes get b0rked (it happened a couple of times to me while
-> using Sup), so I was planning to mails as read/unread and adding the tags
-> not just to the index, but to the mail text itself, e.g. by adding a
-> "X-Tags" header field or by reusing the "Keywords" one. This way, the index
-> could be totally recreated by re-reading the mail directories, and this
-> would also allow to a tools like OfflineIMAP [1] to get the mails into a
-> local maildir, tagging and indexing the mails with the e-mail reader and
-> then syncing back the messages with the "X-Tags" header to the IMAP server.
-> This would allow to use the mail reader from a different computer and still
-> have everything tagged finely.
->
-> Best regards,
->
->
-> ---
-> [1] http://software.complete.org/software/projects/show/offlineimap
->
-> --
-> Adrian Perez de Castro <aperez@igalia.com>
-> Igalia - Free Software Engineering
-> _______________________________________________
-> notmuch mailing list
-> notmuch@notmuchmail.org
-> http://notmuchmail.org/mailman/listinfo/notmuch
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply within emacs to a multipart/alternative message"
-test_emacs '(let ((message-hidden-headers ''()))
- (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
- (notmuch-show-reply)
- (test-output))'
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Alex Botero-Lowry <alex.boterolowry@gmail.com>, notmuch@notmuchmail.org
-Subject: Re: [notmuch] preliminary FreeBSD support
-In-Reply-To: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
-Fcc: ${MAIL_DIR}/sent
-References: <cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Alex Botero-Lowry <alex.boterolowry@gmail.com> writes:
-
-> I saw the announcement this morning, and was very excited, as I had been
-> hoping sup would be turned into a library,
-> since I like the concept more than the UI (I'd rather an emacs interface).
->
-> I did a preliminary compile which worked out fine, but
-> sysconf(_SC_SC_GETPW_R_SIZE_MAX) returns -1 on
-> FreeBSD, so notmuch_config_open segfaulted.
->
-> Attached is a patch that supplies a default buffer size of 64 in cases where
-> -1 is returned.
->
-> http://www.opengroup.org/austin/docs/austin_328.txt - seems to indicate this
-> is acceptable behavior,
-> and http://mail-index.netbsd.org/pkgsrc-bugs/2006/06/07/msg016808.htmlspecifically
-> uses 64 as the
-> buffer size.
-> _______________________________________________
-> notmuch mailing list
-> notmuch@notmuchmail.org
-> http://notmuchmail.org/mailman/listinfo/notmuch
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Reply within emacs to an html-only message"
-add_message '[content-type]="text/html"' \
- '[body]="Hi,<br />This is an <b>HTML</b> test message.<br /><br />OK?"'
-test_emacs "(let ((message-hidden-headers '()) (mm-text-html-renderer 'html2text))
- (notmuch-show \"id:${gen_msg_id}\")
- (notmuch-show-reply)
- (test-output))"
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject: Re: Reply within emacs to an html-only message
-In-Reply-To: <${gen_msg_id}>
-Fcc: ${MAIL_DIR}/sent
-References: <${gen_msg_id}>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Notmuch Test Suite <test_suite@notmuchmail.org> writes:
-
-> Hi,This is an HTML test message.OK?
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Quote MML tags in reply"
-message_id='test-emacs-mml-quoting@message.id'
-add_message [id]="$message_id" \
- "[subject]='$test_subtest_name'" \
- '[body]="<#part disposition=inline>"'
-test_emacs "(let ((message-hidden-headers '()))
- (notmuch-show \"id:$message_id\")
- (notmuch-show-reply)
- (test-output))"
-sed -i -e 's,^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To:
-Subject: Re: Quote MML tags in reply
-In-Reply-To: <test-emacs-mml-quoting@message.id>
-Fcc: ${MAIL_DIR}/sent
-References: <test-emacs-mml-quoting@message.id>
-User-Agent: Notmuch/XXX Emacs/XXX
---text follows this line--
-Notmuch Test Suite <test_suite@notmuchmail.org> writes:
-
-> <#!part disposition=inline>
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Save attachment from within emacs using notmuch-show-save-attachments"
-# save as archive to test that Emacs does not re-compress .gz
-test_emacs '(let ((standard-input "\"attachment1.gz\""))
- (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
- (notmuch-show-save-attachments))'
-test_expect_equal_file attachment1.gz "$EXPECTED/attachment"
-
-test_begin_subtest "Save attachment from within emacs using notmuch-show-save-part"
-# save as archive to test that Emacs does not re-compress .gz
-test_emacs '(let ((standard-input "\"attachment2.gz\""))
- (notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
- (search-forward "0001-Deal-with")
- (notmuch-show-save-part))'
-test_expect_equal_file attachment2.gz "$EXPECTED/attachment"
-
-test_begin_subtest "Save 8bit attachment from within emacs using notmuch-show-save-attachments"
-
-add_message '[subject]="Attachment with 8bit chars"' \
- '[header]="MIME-Version: 1.0"' \
- '[content-type]="multipart/mixed; boundary=\"abcd\""' \
- '[body]="--abcd
-Content-Type: text/plain
-
-Attachment follows:
-
---abcd
-Content-Type: application/octet-stream; name=\"sample\"
-Content-Transfer-Encoding: 8bit
-Content-Disposition: attachment; filename=\"sample\"
-
-“¡ Hey ! It compiles ¡ Ship it !”
-
---abcd--
-"'
-test_emacs '(notmuch-show "id:'"${gen_msg_id}"'")
- (delete-file "OUTPUT")
- (let ((standard-input "\"OUTPUT\""))
- (notmuch-show-save-attachments))'
-
-test_expect_equal "$(cat OUTPUT)" '“¡ Hey ! It compiles ¡ Ship it !”'
-
-test_begin_subtest "View raw message within emacs"
-test_emacs '(notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")
- (notmuch-show-view-raw-message)
- (test-output)'
-test_expect_equal_file OUTPUT $EXPECTED/raw-message-cf0c4d-52ad0a
-
-test_begin_subtest "Hiding/showing signature in notmuch-show view"
-maildir_storage_thread=$(notmuch search --output=threads id:20091117190054.GU3165@dottiness.seas.harvard.edu)
-test_emacs "(notmuch-show \"$maildir_storage_thread\")
- (search-forward \"Click/Enter to show.\")
- (button-activate (button-at (point)))
- (search-backward \"Click/Enter to hide.\")
- (button-activate (button-at (point)))
- (test-output)"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-maildir-storage
-
-test_begin_subtest "Detection and hiding of top-post quoting of message"
-add_message '[subject]="The problem with top-posting"' \
- [id]=top-post-target \
- '[body]="A: Because it messes up the order in which people normally read text.
-Q: Why is top-posting such a bad thing?
-A: Top-posting.
-Q: What is the most annoying thing in e-mail?"'
-add_message '[from]="Top Poster <top@poster.com>"' \
- [in-reply-to]=top-post-target \
- [references]=top-post-target \
- '[subject]="Re: The problem with top-posting"' \
- '[body]="Thanks for the advice! I will be sure to put it to good use.
-
--Top Poster
-
------ Original Message -----
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmai.org>
-Sent: Fri, 05 Jan 2001 15:43:57 +0000
-Subject: The problem with top-posting
-
-Q: Why is top-posting such a bad thing?
-A: Top-posting.
-Q: What is the most annoying thing in e-mail?"'
-test_emacs "(notmuch-show \"top-posting\")
- (test-visible-output \"OUTPUT.raw\")"
-echo "Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
-Subject: The problem with top-posting
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-
-A: Because it messes up the order in which people normally read text.
-Q: Why is top-posting such a bad thing?
-A: Top-posting.
-Q: What is the most annoying thing in e-mail?
-Top Poster <top@poster.com> (2001-01-05) (inbox unread)
-Subject: Re: The problem with top-posting
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-
-Thanks for the advice! I will be sure to put it to good use.
-
--Top Poster
-
-[ 9-line hidden original message. Click/Enter to show. ]" > EXPECTED
-notmuch_date_sanitize < OUTPUT.raw > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Hiding message in notmuch-show view"
-test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (notmuch-show-toggle-message)
- (test-visible-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-hidden-messages
-
-test_begin_subtest "Hiding message with visible citation in notmuch-show view"
-test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (search-forward "Click/Enter to show.")
- (button-activate (button-at (point)))
- (notmuch-show-toggle-message)
- (test-visible-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-hidden-messages
-
-test_begin_subtest "notmuch-show: show message headers"
-test_emacs \
- '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
- (notmuch-message-headers-visible t))
- (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-visible
-
-test_begin_subtest "notmuch-show: hide message headers"
-test_emacs \
- '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
- (notmuch-message-headers-visible nil))
- (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-hidden
-
-test_begin_subtest "notmuch-show: hide message headers (w/ notmuch-show-toggle-visibility-headers)"
-test_emacs \
- '(let ((notmuch-message-headers '\''("Subject" "To" "Cc" "Date"))
- (notmuch-message-headers-visible t))
- (notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (notmuch-show-toggle-visibility-headers)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-message-with-headers-hidden
-
-test_begin_subtest "notmuch-show: collapse all messages in thread"
-test_emacs '(notmuch-show "id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com")
- (let ((current-prefix-arg t))
- (notmuch-show-open-or-close-all)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-all-messages-collapsed
-
-test_begin_subtest "notmuch-show: uncollapse all messages in thread"
-test_emacs '(notmuch-show "id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com")
- (notmuch-show-open-or-close-all)
- (test-visible-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-thread-with-all-messages-uncollapsed
-
-test_begin_subtest "Stashing in notmuch-show"
-add_message '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' \
- '[from]="Some One <someone@somewhere.org>"' \
- '[to]="Some One Else <notsomeone@somewhere.org>"' \
- '[cc]="Notmuch <notmuch@notmuchmail.org>"' \
- '[subject]="Stash my stashables"' \
- '[id]="bought"' \
- '[body]="Unable to stash body. Where did you get it in the first place?!?"'
-notmuch tag +stashtest id:${gen_msg_id}
-test_emacs '(notmuch-show "id:\"bought\"")
- (notmuch-show-stash-date)
- (notmuch-show-stash-from)
- (notmuch-show-stash-to)
- (notmuch-show-stash-cc)
- (notmuch-show-stash-subject)
- (notmuch-show-stash-message-id)
- (notmuch-show-stash-message-id-stripped)
- (notmuch-show-stash-tags)
- (notmuch-show-stash-filename)
- (notmuch-show-stash-mlarchive-link "Gmane")
- (notmuch-show-stash-mlarchive-link "MARC")
- (notmuch-show-stash-mlarchive-link "Mail Archive, The")
- (switch-to-buffer
- (generate-new-buffer "*test-stashing*"))
- (dotimes (i 12)
- (yank)
- (insert "\n")
- (rotate-yank-pointer 1))
- (reverse-region (point-min) (point-max))
- (test-output)'
-cat <<EOF >EXPECTED
-Sat, 01 Jan 2000 12:00:00 +0000
-Some One <someone@somewhere.org>
-Some One Else <notsomeone@somewhere.org>
-Notmuch <notmuch@notmuchmail.org>
-Stash my stashables
-id:bought
-bought
-inbox,stashtest
-${gen_msg_filename}
-http://mid.gmane.org/bought
-http://marc.info/?i=bought
-http://mail-archive.com/search?l=mid&q=bought
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Stashing in notmuch-search"
-test_emacs '(notmuch-search "id:\"bought\"")
- (notmuch-test-wait)
- (notmuch-search-stash-thread-id)
- (switch-to-buffer
- (generate-new-buffer "*test-stashing*"))
- (yank)
- (test-output)'
-sed -i -e 's/^thread:.*$/thread:XXX/' OUTPUT
-test_expect_equal "$(cat OUTPUT)" "thread:XXX"
-
-test_begin_subtest 'notmuch-show-advance-and-archive with invisible signature'
-message1='id:20091118010116.GC25380@dottiness.seas.harvard.edu'
-message2='id:1258491078-29658-1-git-send-email-dottedmag@dottedmag.net'
-test_emacs "(notmuch-show \"$message2\")
- (test-output \"EXPECTED\")"
-test_emacs "(notmuch-search \"$message1 or $message2\")
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (goto-char (point-max))
- (redisplay)
- (notmuch-show-advance-and-archive)
- (test-output)"
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Refresh show buffer"
-test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (test-visible-output "EXPECTED")
- (notmuch-show-refresh-view)
- (test-visible-output)'
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Refresh modified show buffer"
-test_emacs '(notmuch-show "id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com")
- (notmuch-show-toggle-message)
- (notmuch-show-next-message)
- (notmuch-show-toggle-message)
- (test-visible-output "EXPECTED")
- (notmuch-show-refresh-view)
- (test-visible-output)'
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Do not call notmuch for non-inlinable application/mpeg parts"
-id='message-with-application/mpeg-attachment@notmuchmail.org'
-emacs_fcc_message \
- 'Message with application/mpeg attachment' \
- '' \
- "(message-goto-eoh)
- (insert \"Message-ID: <$id>\n\")
- (message-goto-body)
- (mml-insert-part \"application/mpeg\")
- (insert \"a fake mp3 file\")"
-notmuch_counter_reset
-test_emacs "(let ((notmuch-command \"$notmuch_counter_command\"))
- (notmuch-show \"id:$id\"))"
-test_expect_equal $(notmuch_counter_value) 1
-
-test_begin_subtest "Do not call notmuch for non-inlinable audio/mpeg parts"
-id='message-with-audio/mpeg-attachment@notmuchmail.org'
-emacs_fcc_message \
- 'Message with audio/mpeg attachment' \
- '' \
- "(message-goto-eoh)
- (insert \"Message-ID: <$id>\n\")
- (message-goto-body)
- (mml-insert-part \"audio/mpeg\")
- (insert \"a fake mp3 file\")"
-notmuch_counter_reset
-test_emacs "(let ((notmuch-command \"$notmuch_counter_command\"))
- (notmuch-show \"id:$id\"))"
-test_expect_equal $(notmuch_counter_value) 1
-
-test_begin_subtest "notmuch-hello-mode hook is called"
-counter=$(test_emacs \
- '(let ((notmuch-hello-mode-hook-counter 0))
- (kill-buffer "*notmuch-hello*")
- (notmuch-hello)
- notmuch-hello-mode-hook-counter)'
-)
-test_expect_equal "$counter" 1
-
-test_begin_subtest "notmuch-hello-mode hook is not called on updates"
-counter=$(test_emacs \
- '(let ((notmuch-hello-mode-hook-counter 0))
- (kill-buffer "*notmuch-hello*")
- (notmuch-hello)
- (notmuch-hello-update)
- notmuch-hello-mode-hook-counter)'
-)
-test_expect_equal "$counter" 1
-
-test_begin_subtest "notmuch-hello-refresh hook is called"
-counter=$(test_emacs \
- '(let ((notmuch-hello-refresh-hook-counter 0))
- (kill-buffer "*notmuch-hello*")
- (notmuch-hello)
- notmuch-hello-refresh-hook-counter)'
-)
-test_expect_equal "$counter" 1
-
-test_begin_subtest "notmuch-hello-refresh hook is called on updates"
-counter=$(test_emacs \
- '(let ((notmuch-hello-refresh-hook-counter 0))
- (kill-buffer "*notmuch-hello*")
- (notmuch-hello)
- (notmuch-hello-update)
- notmuch-hello-refresh-hook-counter)'
-)
-test_expect_equal "$counter" 2
-
-
-add_message '[subject]="HTML mail with images"' \
- '[content-type]="multipart/related; boundary=abcd"' \
- '[body]="--abcd
-Content-Type: text/html
-
-<img src="cid:330@goomoji.gmail"> smiley
-
---abcd
-Content-Type: image/gif
-Content-Transfer-Encoding: base64
-Content-ID: <330@goomoji.gmail>
-
-R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMl
-WLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7
---abcd--"'
-test_emacs "(let ((mm-text-html-renderer
- (if (assq 'shr mm-text-html-renderer-alist)
- 'shr 'html2text)))
- (notmuch-show \"id:${gen_msg_id}\"))
- (test-output)" > /dev/null
-# Different Emacs versions and renderers give very different results,
-# so just check that something reasonable showed up. We first cat the
-# output so the test framework will print it if the test fails.
-test_expect_success "Rendering HTML mail with images" \
- 'cat OUTPUT && grep -q smiley OUTPUT'
-
-
-test_begin_subtest "Search handles subprocess error exit codes"
-cat > notmuch_fail <<EOF
-#!/bin/sh
-echo '()'
-exit 1
-EOF
-chmod a+x notmuch_fail
-test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
- (with-current-buffer \"*Messages*\" (erase-buffer))
- (with-current-buffer (get-buffer-create \"*Notmuch errors*\")
- (erase-buffer))
- (notmuch-search \"tag:inbox\")
- (notmuch-test-wait)
- (with-current-buffer \"*Messages*\"
- (test-output \"MESSAGES\"))
- (with-current-buffer \"*Notmuch errors*\"
- (test-output \"ERROR\"))
- (test-output))"
-
-test_expect_equal "$(notmuch_emacs_error_sanitize notmuch_fail OUTPUT MESSAGES ERROR)" "\
-=== OUTPUT ===
-End of search results.
-=== MESSAGES ===
-YYY/notmuch_fail exited with status 1 (see *Notmuch errors* for more details)
-=== ERROR ===
-[XXX]
-YYY/notmuch_fail exited with status 1
-command: YYY/notmuch_fail search --format\=sexp --format-version\=2 --sort\=newest-first tag\:inbox
-exit status: 1"
-
-test_begin_subtest "Search handles subprocess warnings"
-cat > notmuch_fail <<EOF
-#!/bin/sh
-echo '()'
-echo This is a warning >&2
-echo This is another warning >&2
-exit 0
-EOF
-chmod a+x notmuch_fail
-test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
- (with-current-buffer \"*Messages*\" (erase-buffer))
- (with-current-buffer (get-buffer-create \"*Notmuch errors*\")
- (erase-buffer))
- (notmuch-search \"tag:inbox\")
- (notmuch-test-wait)
- (with-current-buffer \"*Messages*\"
- (test-output \"MESSAGES\"))
- (with-current-buffer \"*Notmuch errors*\"
- (test-output \"ERROR\"))
- (test-output))"
-sed -i -e 's/^\[.*\]$/[XXX]/' ERROR
-test_expect_equal "$(cat OUTPUT; echo ---; cat MESSAGES; echo ---; cat ERROR)" "\
-End of search results.
----
-This is a warning (see *Notmuch errors* for more details)
----
-[XXX]
-This is a warning
-This is another warning"
-
-test_begin_subtest "Search thread tag operations are race-free"
-add_message '[subject]="Search race test"'
-gen_msg_id_1=$gen_msg_id
-generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \
- '[references]="<'$gen_msg_id_1'>"' \
- '[subject]="Search race test two"'
-test_emacs '(notmuch-search "subject:\"search race test\"")
- (notmuch-test-wait)
- (notmuch-poll)
- (execute-kbd-macro "+search-thread-race-tag")'
-output=$(notmuch search --output=messages 'tag:search-thread-race-tag')
-test_expect_equal "$output" "id:$gen_msg_id_1"
-
-test_begin_subtest "Search global tag operations are race-free"
-generate_message '[in-reply-to]="<'$gen_msg_id_1'>"' \
- '[references]="<'$gen_msg_id_1'>"' \
- '[subject]="Re: Search race test"'
-test_emacs '(notmuch-search "subject:\"search race test\" -subject:two")
- (notmuch-test-wait)
- (notmuch-poll)
- (execute-kbd-macro "*+search-global-race-tag")'
-output=$(notmuch search --output=messages 'tag:search-global-race-tag')
-test_expect_equal "$output" "id:$gen_msg_id_1"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs address cleaning"
-. ./test-lib.sh
-
-test_begin_subtest "notmuch-test-address-clean part 1"
-test_emacs_expect_t '(notmuch-test-address-cleaning-1)'
-
-test_begin_subtest "notmuch-test-address-clean part 2"
-test_emacs_expect_t '(notmuch-test-address-cleaning-2)'
-
-test_begin_subtest "notmuch-test-address-clean part 3"
-test_emacs_expect_t '(notmuch-test-address-cleaning-3)'
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs notmuch-hello view"
-. ./test-lib.sh
-
-EXPECTED=$TEST_DIRECTORY/emacs.expected-output
-
-add_email_corpus
-
-test_begin_subtest "User-defined section with inbox tag"
-test_emacs "(let ((notmuch-hello-sections
- (list (lambda () (notmuch-hello-insert-searches
- \"Test\" '((\"inbox\" . \"tag:inbox\")))))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-new-section
-
-test_begin_subtest "User-defined section with empty, hidden entry"
-test_emacs "(let ((notmuch-hello-sections
- (list (lambda () (notmuch-hello-insert-searches
- \"Test-with-empty\"
- '((\"inbox\" . \"tag:inbox\")
- (\"doesnotexist\" . \"tag:doesnotexist\"))
- :hide-empty-searches t)))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-with-empty
-
-test_begin_subtest "User-defined section, unread tag filtered out"
-test_emacs "(let ((notmuch-hello-sections
- (list (lambda () (notmuch-hello-insert-tags-section
- \"Test-with-filtered\"
- :hide-tags '(\"unread\"))))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-hidden-tag
-
-test_begin_subtest "User-defined section, different query for counts"
-test_emacs "(let ((notmuch-hello-sections
- (list (lambda () (notmuch-hello-insert-tags-section
- \"Test-with-counts\"
- :filter-count \"tag:signed\")))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-section-counts
-
-test_begin_subtest "Empty custom tags section"
-test_emacs "(let* ((widget (widget-create 'notmuch-hello-tags-section))
- (notmuch-hello-sections (list (widget-value widget))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-empty-custom-tags-section
-
-test_begin_subtest "Empty custom queries section"
-test_emacs "(let* ((widget (widget-create 'notmuch-hello-query-section))
- (notmuch-hello-sections (list (widget-value widget))))
- (notmuch-hello)
- (test-output))"
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-empty-custom-queries-section
-
-test_begin_subtest "Column alignment for tag/queries with long names"
-tag=a-very-long-tag # length carefully calculated for 80 characters window width
-notmuch tag +$tag '*'
-test_emacs '(notmuch-hello)
- (test-output)'
-notmuch tag -$tag '*'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-long-names
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="Emacs with large search results buffer"
-. ./test-lib.sh
-
-x=xxxxxxxxxx # 10
-x=$x$x$x$x$x$x$x$x$x$x # 100
-x=$x$x$x$x$x$x$x$x$x # 900
-
-# We generate a long subject here (over 900 bytes) so that the emacs
-# search results get large quickly. With 30 such messages we should
-# cross several 4kB page boundaries and see the bug.
-n=30
-for i in $(seq 1 $n); do
- # Roughly 100B2 KiB per message. That is, we need two messages in order to
- # exceed the typical size of the pipe buffer (4 KiB on commodity systems).
- generate_message '[subject]="$x $i of $n"'
-done
-
-notmuch new > /dev/null
-
-test_begin_subtest "Ensure that emacs doesn't drop results"
-notmuch search '*' > EXPECTED
-sed -i -e 's/^thread:[0-9a-f]* //' -e 's/;//' -e 's/xx*/[BLOB]/' EXPECTED
-echo 'End of search results.' >> EXPECTED
-
-test_emacs '(notmuch-search "*")
- (notmuch-test-wait)
- (test-output)'
-sed -i -e s', *, ,g' -e 's/xxx*/[BLOB]/g' OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs notmuch-show view"
-. ./test-lib.sh
-
-EXPECTED=$TEST_DIRECTORY/emacs-show.expected-output
-
-add_email_corpus
-
-test_begin_subtest "Hiding Original Message region at beginning of a message"
-message_id='OriginalMessageHiding.1@notmuchmail.org'
-add_message \
- [id]="$message_id" \
- '[subject]="Hiding Original Message region at beginning of a message"' \
- '[body]="-----Original Message-----
-Text here."'
-
-cat <<EOF >EXPECTED
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
-Subject: Hiding Original Message region at beginning of a message
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-
-[ 2-line hidden original message. Click/Enter to show. ]
-EOF
-
-test_emacs "(notmuch-show \"id:$message_id\")
- (test-visible-output \"OUTPUT.raw\")"
-notmuch_date_sanitize < OUTPUT.raw > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Bare subject #1"
-output=$(test_emacs '(notmuch-show-strip-re "Re: subject")')
-test_expect_equal "$output" '"subject"'
-
-test_begin_subtest "Bare subject #2"
-output=$(test_emacs '(notmuch-show-strip-re "re:Re: re: Re: re:subject")')
-test_expect_equal "$output" '"subject"'
-
-test_begin_subtest "Bare subject #3"
-output=$(test_emacs '(notmuch-show-strip-re "the cure: fix the regexp")')
-test_expect_equal "$output" '"the cure: fix the regexp"'
-
-test_begin_subtest "don't process cryptographic MIME parts"
-test_emacs '(let ((notmuch-crypto-process-mime nil))
- (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-off
-
-test_begin_subtest "process cryptographic MIME parts"
-test_emacs '(let ((notmuch-crypto-process-mime t))
- (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-on
-
-test_begin_subtest "process cryptographic MIME parts (w/ notmuch-show-toggle-process-crypto)"
-test_emacs '(let ((notmuch-crypto-process-mime nil))
- (notmuch-show "id:20091117203301.GV3165@dottiness.seas.harvard.edu")
- (notmuch-show-toggle-process-crypto)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-process-crypto-mime-parts-on
-
-test_begin_subtest "notmuch-show: don't elide non-matching messages"
-test_emacs '(let ((notmuch-show-only-matching-messages nil))
- (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-off
-
-test_begin_subtest "notmuch-show: elide non-matching messages"
-test_emacs '(let ((notmuch-show-only-matching-messages t))
- (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
-
-test_begin_subtest "notmuch-show: elide non-matching messages (w/ notmuch-show-toggle-elide-non-matching)"
-test_emacs '(let ((notmuch-show-only-matching-messages nil))
- (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (notmuch-show-toggle-elide-non-matching)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
-
-test_begin_subtest "notmuch-show: elide non-matching messages (w/ prefix arg to notmuch-show)"
-test_emacs '(let ((notmuch-show-only-matching-messages nil))
- (notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
- (notmuch-test-wait)
- (notmuch-search-show-thread t)
- (notmuch-test-wait)
- (test-visible-output))'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-elide-non-matching-messages-on
-
-test_begin_subtest "notmuch-show: disable indentation of thread content (w/ notmuch-show-toggle-thread-indentation)"
-test_emacs '(notmuch-search "from:lars@seas.harvard.edu and subject:\"Maildir storage\"")
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (notmuch-test-wait)
- (notmuch-show-toggle-thread-indentation)
- (test-visible-output)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-show-indent-thread-content-off
-
-test_begin_subtest "id buttonization"
-add_message '[body]="
-id:abc
-id:abc.def. id:abc,def, id:abc;def; id:abc:def:
-id:foo@bar.?baz? id:foo@bar!.baz!
-(id:foo@bar.baz) [id:foo@bar.baz]
-id:foo@bar.baz...
-id:2+2=5
-id:=_-:/.[]@$%+
-id:abc)def
-id:ab\"c def
-id:\"abc\"def
-id:\"ab\"\"c\"def
-id:\"ab c\"def
-id:\"abc\".def
-id:\"abc
-\"
-id:)
-id:
-cid:xxx
-mid:abc mid:abc/def
-mid:abc%20def
-mid:abc. mid:abc, mid:abc;"'
-test_emacs '(notmuch-show "id:'$gen_msg_id'")
- (notmuch-test-mark-links)
- (test-visible-output "OUTPUT.raw")'
-cat <<EOF >EXPECTED
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
-Subject: id buttonization
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-
-<<id:abc>>
-<<id:abc.def>>. <<id:abc,def>>, <<id:abc;def>>; <<id:abc:def>>:
-<<id:foo@bar.?baz>>? <<id:foo@bar!.baz>>!
-(<<id:foo@bar.baz>>) [<<id:foo@bar.baz>>]
-<<id:foo@bar.baz>>...
-<<id:2+2=5>>
-<<id:=_-:/.[]@$%+>>
-<<id:abc>>)def
-<<id:ab"c>> def
-<<id:"abc">>def
-<<id:"ab""c">>def
-<<id:"ab c">>def
-<<id:"abc">>.def
-id:"abc
-"
-id:)
-id:
-cid:xxx
-<<mid:abc>> <<mid:abc/def>>
-<<mid:abc%20def>>
-<<mid:abc>>. <<mid:abc>>, <<mid:abc>>;
-EOF
-notmuch_date_sanitize < OUTPUT.raw > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-
-test_begin_subtest "Show handles subprocess errors"
-cat > notmuch_fail <<EOF
-#!/bin/sh
-echo This is output
-echo This is an error >&2
-exit 1
-EOF
-chmod a+x notmuch_fail
-test_emacs "(let ((notmuch-command \"$PWD/notmuch_fail\"))
- (with-current-buffer \"*Messages*\" (erase-buffer))
- (condition-case err
- (notmuch-show \"*\")
- (error (message \"%s\" (second err))))
- (notmuch-test-wait)
- (with-current-buffer \"*Messages*\"
- (test-output \"MESSAGES\"))
- (with-current-buffer \"*Notmuch errors*\"
- (test-output \"ERROR\"))
- (test-output))"
-test_expect_equal "$(notmuch_emacs_error_sanitize notmuch_fail OUTPUT MESSAGES ERROR)" "\
-=== OUTPUT ===
-=== MESSAGES ===
-This is an error (see *Notmuch errors* for more details)
-=== ERROR ===
-[XXX]
-This is an error
-command: YYY/notmuch_fail show --format\\=sexp --format-version\\=1 --exclude\\=false \\' \\* \\'
-exit status: 1
-stderr:
-This is an error
-stdout:
-This is output"
-
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs: mail subject to filename"
-. ./test-lib.sh
-
-# emacs server can't be started in a child process with $(test_emacs ...)
-test_emacs '(ignore)' > /dev/null
-
-# test notmuch-wash-subject-to-patch-sequence-number (subject)
-test_begin_subtest "no patch sequence number"
-output=$(test_emacs '(format "%S" (notmuch-wash-subject-to-patch-sequence-number
- "[PATCH] A normal patch subject without numbers"))'
-)
-test_expect_equal "$output" '"nil"'
-
-test_begin_subtest "patch sequence number #1"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[PATCH 2/3] A most regular patch subject")'
-)
-test_expect_equal "$output" 2
-
-test_begin_subtest "patch sequence number #2"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- " [dummy list prefix] [RFC PATCH v2 13/42] Special prefixes")'
-)
-test_expect_equal "$output" 13
-
-test_begin_subtest "patch sequence number #3"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[PATCH 2/3] [PATCH 032/037] use the last prefix")'
-)
-test_expect_equal "$output" 32
-
-test_begin_subtest "patch sequence number #4"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[dummy list prefix] [PATCH 2/3] PATCH 3/3] do not use a broken prefix")'
-)
-test_expect_equal "$output" 2
-
-test_begin_subtest "patch sequence number #5"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[RFC][PATCH 3/5][PATCH 4/5][PATCH 5/5] A made up test")'
-)
-test_expect_equal "$output" 5
-
-test_begin_subtest "patch sequence number #6"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[PATCH 2/3] this -> [PATCH 3/3] is not a prefix anymore [nor this 4/4]")'
-)
-test_expect_equal "$output" 2
-
-test_begin_subtest "patch sequence number #7"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
- "[liberally accept crapola right before123/456and after] the numbers")'
-)
-test_expect_equal "$output" 123
-
-# test notmuch-wash-subject-to-filename (subject &optional maxlen)
-test_begin_subtest "filename #1"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "just a subject line")'
-)
-test_expect_equal "$output" '"just-a-subject-line"'
-
-test_begin_subtest "filename #2"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- " [any] [prefixes are ] [removed!] from the subject")'
-)
-test_expect_equal "$output" '"from-the-subject"'
-
-test_begin_subtest "filename #3"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- " leading and trailing space ")'
-)
-test_expect_equal "$output" '"leading-and-trailing-space"'
-
-test_begin_subtest "filename #4"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "!# leading ()// &%, and in between_and_trailing garbage ()(&%%")'
-)
-test_expect_equal "$output" '"-leading-and-in-between_and_trailing-garbage"'
-
-test_begin_subtest "filename #5"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890")'
-)
-test_expect_equal "$output" '"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890"'
-
-test_begin_subtest "filename #6"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "sequences of ... are squashed and trailing are removed ...")'
-)
-test_expect_equal "$output" '"sequences-of-.-are-squashed-and-trailing-are-removed"'
-
-test_begin_subtest "filename #7"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "max length test" 1)'
-)
-test_expect_equal "$output" '"m"'
-
-test_begin_subtest "filename #8"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "max length test /&(/%&/%%&¤%¤" 20)'
-)
-test_expect_equal "$output" '"max-length-test"'
-
-test_begin_subtest "filename #9"
-output=$(test_emacs '(notmuch-wash-subject-to-filename
- "[a prefix] [is only separated] by [spaces], so \"by\" is not okay!")'
-)
-test_expect_equal "$output" '"by-spaces-so-by-is-not-okay"'
-
-# test notmuch-wash-subject-to-patch-filename (subject)
-test_begin_subtest "patch filename #1"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
- "[RFC][PATCH 099/100] rewrite notmuch")'
-)
-test_expect_equal "$output" '"0099-rewrite-notmuch.patch"'
-
-test_begin_subtest "patch filename #2"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
- "[RFC PATCH v1] has no patch number, default to 1")'
-)
-test_expect_equal "$output" '"0001-has-no-patch-number-default-to-1.patch"'
-
-test_begin_subtest "patch filename #3"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
- "[PATCH 4/5] the maximum length of a patch filename is 52 + patch sequence number + .patch extension")'
-)
-test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patch-s.patch"'
-
-test_begin_subtest "patch filename #4"
-output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
- "[PATCH 4/5] the maximum length of a patch filename is 52 + patchh ! sequence number + .patch extension, *before* trimming trailing - and .")'
-)
-test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patchh.patch"'
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs test function sanity"
-. ./test-lib.sh
-
-test_begin_subtest "emacs test function sanity"
-test_emacs_expect_t 't'
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="emacs tree view interface"
-. test-lib.sh
-
-EXPECTED=$TEST_DIRECTORY/tree.expected-output
-
-add_email_corpus
-
-test_begin_subtest "Basic notmuch-tree view in emacs"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
-
-test_begin_subtest "Refreshed notmuch-tree view in emacs"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (notmuch-tree-refresh-view)
- (notmuch-test-wait)
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
-
-# In the following tag tests we make sure the display is updated
-# correctly and, in a separate test, that the database is updated
-# correctly.
-
-test_begin_subtest "Tag message in notmuch tree view (display)"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (forward-line)
- (notmuch-tree-tag (list "+test_tag"))
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox-tagged
-
-test_begin_subtest "Tag message in notmuch tree view (database)"
-output=$(notmuch search --output=messages 'tag:test_tag')
-test_expect_equal "$output" "id:877h1wv7mg.fsf@inf-8657.int-evry.fr"
-
-test_begin_subtest "Untag message in notmuch tree view"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (forward-line)
- (notmuch-tree-tag (list "-test_tag"))
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
-
-test_begin_subtest "Untag message in notmuch tree view (database)"
-output=$(notmuch search --output=messages 'tag:test_tag')
-test_expect_equal "$output" ""
-
-test_begin_subtest "Tag thread in notmuch tree view"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- ;; move to a sizable thread
- (forward-line 26)
- (notmuch-tree-tag-thread (list "+test_thread_tag"))
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox-thread-tagged
-
-test_begin_subtest "Tag message in notmuch tree view (database)"
-output=$(notmuch search --output=messages 'tag:test_thread_tag')
-test_expect_equal "$output" \
-"id:87ocn0qh6d.fsf@yoom.home.cworth.org
-id:20091118005040.GA25380@dottiness.seas.harvard.edu
-id:yunaayketfm.fsf@aiko.keithp.com
-id:87fx8can9z.fsf@vertex.dottedmag
-id:20091117203301.GV3165@dottiness.seas.harvard.edu
-id:87iqd9rn3l.fsf@vertex.dottedmag
-id:20091117190054.GU3165@dottiness.seas.harvard.edu"
-
-test_begin_subtest "Untag thread in notmuch tree view"
-test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- ;; move to the same sizable thread as above
- (forward-line 26)
- (notmuch-tree-tag-thread (list "-test_thread_tag"))
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-tag-inbox
-
-test_begin_subtest "Untag message in notmuch tree view (database)"
-output=$(notmuch search --output=messages 'tag:test_thread_tag')
-test_expect_equal "$output" ""
-
-test_begin_subtest "Navigation of notmuch-hello to search results"
-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 OUTPUT $EXPECTED/notmuch-tree-tag-inbox
-
-test_begin_subtest "Tree view of a single thread (from 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-thread)
- (notmuch-test-wait)
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-single-thread
-
-test_begin_subtest "Tree view of a single thread (from show)"
-test_emacs '(notmuch-hello)
- (goto-char (point-min))
- (re-search-forward "inbox")
- (widget-button-press (1- (point)))
- (notmuch-test-wait)
- (notmuch-search-show-thread)
- (notmuch-tree-from-show-current-query)
- (notmuch-test-wait)
- (test-output)
- (delete-other-windows)'
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-single-thread
-
-test_begin_subtest "Message window of tree view"
-test_emacs '(notmuch-hello)
- (goto-char (point-min))
- (re-search-forward "inbox")
- (widget-button-press (1- (point)))
- (notmuch-test-wait)
- (notmuch-search-next-thread)
- (notmuch-tree-from-search-thread)
- (notmuch-test-wait)
- (select-window notmuch-tree-message-window)
- (test-output)
- (delete-other-windows)'
-cp OUTPUT /tmp/mjwout
-test_expect_equal_file OUTPUT $EXPECTED/notmuch-tree-show-window
-
-test_begin_subtest "Stash id"
-output=$(test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (require (quote notmuch-tree))
- (notmuch-tree "id:1258498485-sup-142@elly")
- (notmuch-test-wait)
- (notmuch-show-stash-message-id)')
-test_expect_equal "$output" "\"Stashed: id:1258498485-sup-142@elly\""
-
-test_begin_subtest "Move to next matching message"
-output=$(test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (require (quote notmuch-tree))
- (notmuch-tree "from:cworth")
- (notmuch-test-wait)
- (notmuch-tree-next-matching-message)
- (notmuch-show-stash-message-id)')
-test_expect_equal "$output" "\"Stashed: id:878we4qdqf.fsf@yoom.home.cworth.org\""
-
-test_begin_subtest "Move to next thread"
-output=$(test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (require (quote notmuch-tree))
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (forward-line 26)
- (notmuch-tree-next-thread)
- (notmuch-show-stash-message-id)')
-test_expect_equal "$output" "\"Stashed: id:1258471718-6781-1-git-send-email-dottedmag@dottedmag.net\""
-
-test_begin_subtest "Move to previous thread"
-output=$(test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (require (quote notmuch-tree))
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (forward-line 26)
- (notmuch-tree-prev-thread)
- (notmuch-show-stash-message-id)')
-test_expect_equal "$output" "\"Stashed: id:20091117190054.GU3165@dottiness.seas.harvard.edu\""
-
-test_begin_subtest "Move to previous previous thread"
-output=$(test_emacs '(add-to-list (quote load-path) "'$PICK_DIR'")
- (require (quote notmuch-tree))
- (notmuch-tree "tag:inbox")
- (notmuch-test-wait)
- (forward-line 26)
- (notmuch-tree-prev-thread)
- (notmuch-tree-prev-thread)
- (notmuch-show-stash-message-id)')
-test_expect_equal "$output" "\"Stashed: id:1258493565-13508-1-git-send-email-keithp@keithp.com\""
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="encoding issues"
-. ./test-lib.sh
-
-test_begin_subtest "Message with text of unknown charset"
-add_message '[content-type]="text/plain; charset=unknown-8bit"' \
- "[body]=irrelevant"
-output=$(notmuch show id:${gen_msg_id} 2>&1 | notmuch_show_sanitize_all)
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox unread)
-Subject: Message with text of unknown charset
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: GENERATED_DATE
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-irrelevant
-\fpart}
-\fbody}
-\fmessage}"
-
-test_begin_subtest "Search for ISO-8859-2 encoded message"
-add_message '[content-type]="text/plain; charset=iso-8859-2"' \
- '[content-transfer-encoding]=8bit' \
- '[subject]="ISO-8859-2 encoded message"' \
- "[body]=$'Czech word tu\350\362\341\350\350\355 means pinguin\'s.'" # ISO-8859-2 characters are generated by shell's escape sequences
-output=$(notmuch search tučňáččí 2>&1 | notmuch_show_sanitize_all)
-test_expect_equal "$output" "thread:0000000000000002 2001-01-05 [1/1] Notmuch Test Suite; ISO-8859-2 encoded message (inbox unread)"
-
-test_begin_subtest "RFC 2047 encoded word with spaces"
-add_message '[subject]="=?utf-8?q?encoded word with spaces?="'
-output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
-test_expect_equal "$output" "thread:0000000000000003 2001-01-05 [1/1] Notmuch Test Suite; encoded word with spaces (inbox unread)"
-
-test_begin_subtest "RFC 2047 encoded words back to back"
-add_message '[subject]="=?utf-8?q?encoded-words-back?==?utf-8?q?to-back?="'
-output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
-test_expect_equal "$output" "thread:0000000000000004 2001-01-05 [1/1] Notmuch Test Suite; encoded-words-backto-back (inbox unread)"
-
-test_begin_subtest "RFC 2047 encoded words without space before or after"
-add_message '[subject]="=?utf-8?q?encoded?=word without=?utf-8?q?space?=" '
-output=$(notmuch search id:${gen_msg_id} 2>&1 | notmuch_show_sanitize)
-test_expect_equal "$output" "thread:0000000000000005 2001-01-05 [1/1] Notmuch Test Suite; encodedword withoutspace (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch search, count and show" with excludes in several variations'
-. ./test-lib.sh
-
-# Generates a thread consisting of a top level message and 'length'
-# replies. The subject of the top message 'subject: top message"
-# and the subject of the nth reply in the thread is "subject: reply n"
-generate_thread ()
-{
- local subject="$1"
- local length="$2"
- generate_message '[subject]="'"${subject}: top message"'"' '[body]="'"body of top message"'"'
- parent_id=$gen_msg_id
- gen_thread_msg_id[0]=$gen_msg_id
- for i in `seq 1 $length`
- do
- generate_message '[subject]="'"${subject}: reply $i"'"' \
- "[in-reply-to]=\<$parent_id\>" \
- '[body]="'"body of reply $i"'"'
- gen_thread_msg_id[$i]=$gen_msg_id
- parent_id=$gen_msg_id
- done
- notmuch new > /dev/null
- # We cannot retrieve the thread_id until after we have run notmuch new.
- gen_thread_id=`notmuch search --output=threads id:${gen_thread_msg_id[0]}`
-}
-
-#############################################
-# These are the original search exclude tests.
-
-test_begin_subtest "Search, exclude \"deleted\" messages from search"
-notmuch config set search.exclude_tags deleted
-generate_message '[subject]="Not deleted"'
-not_deleted_id=$gen_msg_id
-generate_message '[subject]="Deleted"'
-notmuch new > /dev/null
-notmuch tag +deleted id:$gen_msg_id
-deleted_id=$gen_msg_id
-output=$(notmuch search subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)"
-
-test_begin_subtest "Search, exclude \"deleted\" messages from message search"
-output=$(notmuch search --output=messages subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "id:$not_deleted_id"
-
-test_begin_subtest "Search, exclude \"deleted\" messages from message search --exclude=false"
-output=$(notmuch search --exclude=false --output=messages subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "id:$not_deleted_id
-id:$deleted_id"
-
-test_begin_subtest "Search, exclude \"deleted\" messages from message search (non-existent exclude-tag)"
-notmuch config set search.exclude_tags deleted non_existent_tag
-output=$(notmuch search --output=messages subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "id:$not_deleted_id"
-notmuch config set search.exclude_tags deleted
-
-test_begin_subtest "Search, exclude \"deleted\" messages from search, overridden"
-output=$(notmuch search subject:deleted and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Deleted (deleted inbox unread)"
-
-test_begin_subtest "Search, exclude \"deleted\" messages from threads"
-add_message '[subject]="Not deleted reply"' '[in-reply-to]="<$gen_msg_id>"'
-output=$(notmuch search subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
-thread:XXX 2001-01-05 [1/2] Notmuch Test Suite; Not deleted reply (deleted inbox unread)"
-
-test_begin_subtest "Search, don't exclude \"deleted\" messages when --exclude=flag specified"
-output=$(notmuch search --exclude=flag subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
-thread:XXX 2001-01-05 [1/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
-
-test_begin_subtest "Search, don't exclude \"deleted\" messages from search if not configured"
-notmuch config set search.exclude_tags
-output=$(notmuch search subject:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
-thread:XXX 2001-01-05 [2/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
-
-
-########################################################
-# We construct some threads for the tests. We use the tag "test" to
-# indicate which messages we will search for.
-
-# A thread of deleted messages; test matches one of them.
-generate_thread "All messages excluded: single match" 5
-notmuch tag +deleted $gen_thread_id
-notmuch tag +test id:${gen_thread_msg_id[2]}
-
-# A thread of deleted messages; test matches two of them.
-generate_thread "All messages excluded: double match" 5
-notmuch tag +deleted $gen_thread_id
-notmuch tag +test id:${gen_thread_msg_id[2]}
-notmuch tag +test id:${gen_thread_msg_id[4]}
-
-# A thread some messages deleted; test only matches a deleted message.
-generate_thread "Some messages excluded: single excluded match" 5
-notmuch tag +deleted +test id:${gen_thread_msg_id[3]}
-
-# A thread some messages deleted; test only matches a non-deleted message.
-generate_thread "Some messages excluded: single non-excluded match" 5
-notmuch tag +deleted id:${gen_thread_msg_id[2]}
-notmuch tag +test id:${gen_thread_msg_id[4]}
-
-# A thread no messages deleted; test matches a message.
-generate_thread "No messages excluded: single match" 5
-notmuch tag +test id:${gen_thread_msg_id[3]}
-
-# Temporarily remove excludes to get list of matching messages
-notmuch config set search.exclude_tags
-matching_message_ids=( `notmuch search --output=messages tag:test` )
-notmuch config set search.exclude_tags deleted
-
-#########################################
-# Notmuch search tests
-
-test_begin_subtest "Search, default exclusion (thread summary)"
-output=$(notmuch search tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
-
-test_begin_subtest "Search, default exclusion (messages)"
-output=$(notmuch search --output=messages tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[4]}
-${matching_message_ids[5]}"
-
-test_begin_subtest "Search, exclude=true (thread summary)"
-output=$(notmuch search --exclude=true tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
-
-test_begin_subtest "Search, exclude=true (messages)"
-output=$(notmuch search --exclude=true --output=messages tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[4]}
-${matching_message_ids[5]}"
-
-test_begin_subtest "Search, exclude=false (thread summary)"
-output=$(notmuch search --exclude=false tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
-
-test_begin_subtest "Search, exclude=false (messages)"
-output=$(notmuch search --exclude=false --output=messages tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}
-${matching_message_ids[4]}
-${matching_message_ids[5]}"
-
-test_begin_subtest "Search, exclude=flag (thread summary)"
-output=$(notmuch search --exclude=flag tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [0/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
-
-test_begin_subtest "Search, exclude=flag (messages)"
-output=$(notmuch search --exclude=flag --output=messages tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}
-${matching_message_ids[4]}
-${matching_message_ids[5]}"
-
-test_begin_subtest "Search, exclude=all (thread summary)"
-output=$(notmuch search --exclude=all tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/5] Notmuch Test Suite; Some messages excluded: single non-excluded match: reply 4 (inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; No messages excluded: single match: reply 3 (inbox test unread)"
-
-test_begin_subtest "Search, exclude=all (messages)"
-output=$(notmuch search --exclude=all --output=messages tag:test | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[4]}
-${matching_message_ids[5]}"
-
-test_begin_subtest "Search, default exclusion: tag in query (thread summary)"
-output=$(notmuch search tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
-
-test_begin_subtest "Search, default exclusion: tag in query (messages)"
-output=$(notmuch search --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}"
-
-test_begin_subtest "Search, exclude=true: tag in query (thread summary)"
-output=$(notmuch search --exclude=true tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
-
-test_begin_subtest "Search, exclude=true: tag in query (messages)"
-output=$(notmuch search --exclude=true --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}"
-
-test_begin_subtest "Search, exclude=false: tag in query (thread summary)"
-output=$(notmuch search --exclude=false tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
-
-test_begin_subtest "Search, exclude=false: tag in query (messages)"
-output=$(notmuch search --exclude=false --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}"
-
-test_begin_subtest "Search, exclude=flag: tag in query (thread summary)"
-output=$(notmuch search --exclude=flag tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
-
-test_begin_subtest "Search, exclude=flag: tag in query (messages)"
-output=$(notmuch search --exclude=flag --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}"
-
-test_begin_subtest "Search, exclude=all: tag in query (thread summary)"
-output=$(notmuch search --exclude=all tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; All messages excluded: single match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [2/6] Notmuch Test Suite; All messages excluded: double match: reply 2 (deleted inbox test unread)
-thread:XXX 2001-01-05 [1/6] Notmuch Test Suite; Some messages excluded: single excluded match: reply 3 (deleted inbox test unread)"
-
-test_begin_subtest "Search, exclude=all: tag in query (messages)"
-output=$(notmuch search --exclude=all --output=messages tag:test and tag:deleted | notmuch_search_sanitize)
-test_expect_equal "$output" "${matching_message_ids[0]}
-${matching_message_ids[1]}
-${matching_message_ids[2]}
-${matching_message_ids[3]}"
-
-#########################################################
-# Notmuch count tests
-
-test_begin_subtest "Count, default exclusion (messages)"
-output=$(notmuch count tag:test)
-test_expect_equal "$output" "2"
-
-test_begin_subtest "Count, default exclusion (threads)"
-output=$(notmuch count --output=threads tag:test)
-test_expect_equal "$output" "2"
-
-test_begin_subtest "Count, exclude=true (messages)"
-output=$(notmuch count --exclude=true tag:test)
-test_expect_equal "$output" "2"
-
-test_begin_subtest "Count, exclude=true (threads)"
-output=$(notmuch count --output=threads --exclude=true tag:test)
-test_expect_equal "$output" "2"
-
-test_begin_subtest "Count, exclude=false (messages)"
-output=$(notmuch count --exclude=false tag:test)
-test_expect_equal "$output" "6"
-
-test_begin_subtest "Count, exclude=false (threads)"
-output=$(notmuch count --output=threads --exclude=false tag:test)
-test_expect_equal "$output" "5"
-
-test_begin_subtest "Count, default exclusion: tag in query (messages)"
-output=$(notmuch count tag:test and tag:deleted)
-test_expect_equal "$output" "4"
-
-test_begin_subtest "Count, default exclusion: tag in query (threads)"
-output=$(notmuch count --output=threads tag:test and tag:deleted)
-test_expect_equal "$output" "3"
-
-test_begin_subtest "Count, exclude=true: tag in query (messages)"
-output=$(notmuch count --exclude=true tag:test and tag:deleted)
-test_expect_equal "$output" "4"
-
-test_begin_subtest "Count, exclude=true: tag in query (threads)"
-output=$(notmuch count --output=threads --exclude=true tag:test and tag:deleted)
-test_expect_equal "$output" "3"
-
-test_begin_subtest "Count, exclude=false: tag in query (messages)"
-output=$(notmuch count --exclude=false tag:test and tag:deleted)
-test_expect_equal "$output" "4"
-
-test_begin_subtest "Count, exclude=false: tag in query (threads)"
-output=$(notmuch count --output=threads --exclude=false tag:test and tag:deleted)
-test_expect_equal "$output" "3"
-
-#############################################################
-# Show tests
-
-test_begin_subtest "Show, default exclusion"
-output=$(notmuch show tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3"
-
-test_begin_subtest "Show, default exclusion (entire-thread)"
-output=$(notmuch show --entire-thread tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 2
-\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 3
-\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 2
-\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3
-\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 5"
-
-test_begin_subtest "Show, exclude=true"
-output=$(notmuch show --exclude=true tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3"
-
-test_begin_subtest "Show, exclude=true (entire-thread)"
-output=$(notmuch show --entire-thread --exclude=true tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 2
-\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 3
-\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 2
-\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3
-\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 5"
-
-test_begin_subtest "Show, exclude=false"
-output=$(notmuch show --exclude=false tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 2
-\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 2
-\fmessage{ id:XXXXX depth:1 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 4
-\fmessage{ id:XXXXX depth:0 match:1 excluded:1 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 3
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3"
-
-test_begin_subtest "Show, exclude=false (entire-thread)"
-output=$(notmuch show --entire-thread --exclude=false tag:test | notmuch_show_sanitize_all | egrep "Subject:|message{")
-test_expect_equal "$output" "\fmessage{ id:XXXXX depth:0 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 1
-\fmessage{ id:XXXXX depth:2 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 2
-\fmessage{ id:XXXXX depth:3 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 3
-\fmessage{ id:XXXXX depth:4 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: single match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 1
-\fmessage{ id:XXXXX depth:2 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 2
-\fmessage{ id:XXXXX depth:3 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 3
-\fmessage{ id:XXXXX depth:4 match:1 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:1 filename:XXXXX
-Subject: All messages excluded: double match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single excluded match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 2
-\fmessage{ id:XXXXX depth:3 match:1 excluded:1 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 3
-\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single excluded match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:1 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 2
-\fmessage{ id:XXXXX depth:3 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 3
-\fmessage{ id:XXXXX depth:4 match:1 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: Some messages excluded: single non-excluded match: reply 5
-\fmessage{ id:XXXXX depth:0 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: top message
-\fmessage{ id:XXXXX depth:1 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 1
-\fmessage{ id:XXXXX depth:2 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 2
-\fmessage{ id:XXXXX depth:3 match:1 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 3
-\fmessage{ id:XXXXX depth:4 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 4
-\fmessage{ id:XXXXX depth:5 match:0 excluded:0 filename:XXXXX
-Subject: No messages excluded: single match: reply 5"
-
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="From line heuristics (with multiple configured addresses)"
-. ./test-lib.sh
-
-test_begin_subtest "Magic from guessing (nothing to go on)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Envelope-to:)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[header]="Envelope-To: test_suite_other@notmuchmail.org"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (X-Original-To:)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[header]="X-Original-To: test_suite_other@notmuchmail.org"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Received: .. for ..)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
- by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
- for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Received: domain)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
- by mail.otherdomain.org (some MTA) with ESMTP id 12345678
- Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@otherdomain.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (multiple Received: headers)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- "[header]=\"Received: from extraneous.example.com (extraneous.example.com [1.1.1.1])
-Received: from mail.example.com (mail.example.com [1.1.1.1])
- by mail.otherdomain.org (some MTA) with ESMTP id 12345678
- for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)
-Received: from extraneous.example.com (extraneous.example.com [1.1.1.1])\"" \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output="$(notmuch reply id:${gen_msg_id})"
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Testing From line heuristics (with single configured address)"
-sed -i -e "s/^other_email.*//" "${NOTMUCH_CONFIG}"
-test_expect_equal '' ''
-
-test_begin_subtest "Magic from guessing (nothing to go on)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Envelope-to:)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[header]="Envelope-To: test_suite_other@notmuchmail.org"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (X-Original-To:)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[header]="X-Original-To: test_suite_other@notmuchmail.org"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Received: .. for ..)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
- by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
- for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_begin_subtest "Magic from guessing (Received: domain)"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=mailinglist@notmuchmail.org \
- [subject]=notmuch-reply-test \
- "[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
- by mail.otherdomain.org (some MTA) with ESMTP id 12345678
- Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="from guessing test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, mailinglist@notmuchmail.org
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> from guessing test"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="online help"
-. ./test-lib.sh
-
-test_expect_success 'notmuch --help' 'notmuch --help'
-test_expect_success 'notmuch --help tag' 'notmuch --help tag'
-test_expect_success 'notmuch help' 'notmuch help'
-test_expect_success 'notmuch help tag' 'notmuch help tag'
-test_expect_success 'notmuch --version' 'notmuch --version'
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="hex encoding and decoding"
-. ./test-lib.sh
-
-test_begin_subtest "round trip"
-find $TEST_DIRECTORY/corpus -type f -print | sort | xargs cat > EXPECTED
-$TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "punctuation"
-tag1='comic_swear=$&^%$^%\\//-+$^%$'
-tag_enc1=$($TEST_DIRECTORY/hex-xcode --direction=encode "$tag1")
-test_expect_equal "$tag_enc1" "comic_swear=%24%26%5e%25%24%5e%25%5c%5c%2f%2f-+%24%5e%25%24"
-
-test_begin_subtest "round trip newlines"
-printf 'this\n tag\t has\n spaces\n' > EXPECTED.$test_count
-$TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED.$test_count |\
- $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "round trip 8bit chars"
-echo '%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a' > EXPECTED.$test_count
-$TEST_DIRECTORY/hex-xcode --direction=decode < EXPECTED.$test_count |\
- $TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "round trip (in-place)"
-find $TEST_DIRECTORY/corpus -type f -print | sort | xargs cat > EXPECTED
-$TEST_DIRECTORY/hex-xcode --in-place --direction=encode < EXPECTED |\
- $TEST_DIRECTORY/hex-xcode --in-place --direction=decode > OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "punctuation (in-place)"
-tag1='comic_swear=$&^%$^%\\//-+$^%$'
-tag_enc1=$($TEST_DIRECTORY/hex-xcode --in-place --direction=encode "$tag1")
-test_expect_equal "$tag_enc1" "comic_swear=%24%26%5e%25%24%5e%25%5c%5c%2f%2f-+%24%5e%25%24"
-
-test_begin_subtest "round trip newlines (in-place)"
-printf 'this\n tag\t has\n spaces\n' > EXPECTED.$test_count
-$TEST_DIRECTORY/hex-xcode --in-place --direction=encode < EXPECTED.$test_count |\
- $TEST_DIRECTORY/hex-xcode --in-place --direction=decode > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_begin_subtest "round trip 8bit chars (in-place)"
-echo '%c3%91%c3%a5%c3%b0%c3%a3%c3%a5%c3%a9-%c3%8f%c3%8a' > EXPECTED.$test_count
-$TEST_DIRECTORY/hex-xcode --in-place --direction=decode < EXPECTED.$test_count |\
- $TEST_DIRECTORY/hex-xcode --in-place --direction=encode > OUTPUT.$test_count
-test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='hooks'
-. ./test-lib.sh
-
-HOOK_DIR=${MAIL_DIR}/.notmuch/hooks
-
-create_echo_hook () {
- local TOKEN="${RANDOM}"
- mkdir -p ${HOOK_DIR}
- cat <<EOF >"${HOOK_DIR}/${1}"
-#!/bin/sh
-echo "${TOKEN}" > ${3}
-EOF
- chmod +x "${HOOK_DIR}/${1}"
- echo "${TOKEN}" > ${2}
-}
-
-create_failing_hook () {
- mkdir -p ${HOOK_DIR}
- cat <<EOF >"${HOOK_DIR}/${1}"
-#!/bin/sh
-exit 13
-EOF
- chmod +x "${HOOK_DIR}/${1}"
-}
-
-rm_hooks () {
- rm -rf ${HOOK_DIR}
-}
-
-# add a message to generate mail dir and database
-add_message
-
-test_begin_subtest "pre-new is run"
-rm_hooks
-generate_message
-create_echo_hook "pre-new" expected output
-notmuch new > /dev/null
-test_expect_equal_file expected output
-
-test_begin_subtest "post-new is run"
-rm_hooks
-generate_message
-create_echo_hook "post-new" expected output
-notmuch new > /dev/null
-test_expect_equal_file expected output
-
-test_begin_subtest "pre-new is run before post-new"
-rm_hooks
-generate_message
-create_echo_hook "pre-new" pre-new.expected pre-new.output
-create_echo_hook "post-new" post-new.expected post-new.output
-notmuch new > /dev/null
-test_expect_equal_file post-new.expected post-new.output
-
-test_begin_subtest "pre-new non-zero exit status (hook status)"
-rm_hooks
-generate_message
-create_failing_hook "pre-new"
-output=`notmuch new 2>&1`
-test_expect_equal "$output" "Error: pre-new hook failed with status 13"
-
-# depends on the previous subtest leaving broken hook behind
-test_expect_code 1 "pre-new non-zero exit status (notmuch status)" "notmuch new"
-
-# depends on the previous subtests leaving 1 new message behind
-test_begin_subtest "pre-new non-zero exit status aborts new"
-rm_hooks
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "post-new non-zero exit status (hook status)"
-rm_hooks
-generate_message
-create_failing_hook "post-new"
-NOTMUCH_NEW 2>output.stderr >output
-cat output.stderr >> output
-echo "Added 1 new message to the database." > expected
-echo "Error: post-new hook failed with status 13" >> expected
-test_expect_equal_file expected output
-
-# depends on the previous subtest leaving broken hook behind
-test_expect_code 1 "post-new non-zero exit status (notmuch status)" "notmuch new"
-
-# test_begin_subtest "hook without executable permissions"
-rm_hooks
-mkdir -p ${HOOK_DIR}
-cat <<EOF >"${HOOK_DIR}/pre-new"
-#!/bin/sh
-echo foo
-EOF
-output=`notmuch new 2>&1`
-test_expect_code 1 "hook without executable permissions" "notmuch new"
-
-# test_begin_subtest "hook execution failure"
-rm_hooks
-mkdir -p ${HOOK_DIR}
-cat <<EOF >"${HOOK_DIR}/pre-new"
-no hashbang, execl fails
-EOF
-chmod +x "${HOOK_DIR}/pre-new"
-test_expect_code 1 "hook execution failure" "notmuch new"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch insert"'
-. ./test-lib.sh
-
-# Create directories and database before inserting.
-mkdir -p "$MAIL_DIR"/{cur,new,tmp}
-mkdir -p "$MAIL_DIR"/Drafts/{cur,new,tmp}
-notmuch new > /dev/null
-
-# We use generate_message to create the temporary message files.
-# They happen to be in the mail directory already but that is okay
-# since we do not call notmuch new hereafter.
-
-gen_insert_msg() {
- generate_message \
- "[subject]=\"insert-subject\"" \
- "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" \
- "[body]=\"insert-message\""
-}
-
-test_expect_code 1 "Insert zero-length file" \
- "notmuch insert < /dev/null"
-
-# This test is a proxy for other errors that may occur while trying to
-# add a message to the notmuch database, e.g. database locked.
-test_expect_code 0 "Insert non-message" \
- "echo bad_message | notmuch insert"
-
-test_begin_subtest "Database empty so far"
-test_expect_equal "0" "`notmuch count --output=messages '*'`"
-
-test_begin_subtest "Insert message"
-gen_insert_msg
-notmuch insert < "$gen_msg_filename"
-cur_msg_filename=$(notmuch search --output=files "subject:insert-subject")
-test_expect_equal_file "$cur_msg_filename" "$gen_msg_filename"
-
-test_begin_subtest "Insert message adds default tags"
-output=$(notmuch show --format=json "subject:insert-subject")
-expected='[[[{
- "id": "'"${gen_msg_id}"'",
- "match": true,
- "excluded": false,
- "filename": "'"${cur_msg_filename}"'",
- "timestamp": 946728000,
- "date_relative": "2000-01-01",
- "tags": ["inbox","unread"],
- "headers": {
- "Subject": "insert-subject",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Sat, 01 Jan 2000 12:00:00 +0000"},
- "body": [{"id": 1,
- "content-type": "text/plain",
- "content": "insert-message\n"}]},
- []]]]'
-test_expect_equal_json "$output" "$expected"
-
-test_begin_subtest "Insert duplicate message"
-notmuch insert +duptag -unread < "$gen_msg_filename"
-output=$(notmuch search --output=files "subject:insert-subject" | wc -l)
-test_expect_equal "$output" 2
-
-test_begin_subtest "Duplicate message does not change tags"
-output=$(notmuch search --format=json --output=tags "subject:insert-subject")
-test_expect_equal_json "$output" '["inbox", "unread"]'
-
-test_begin_subtest "Insert message, add tag"
-gen_insert_msg
-notmuch insert +custom < "$gen_msg_filename"
-output=$(notmuch search --output=messages tag:custom)
-test_expect_equal "$output" "id:$gen_msg_id"
-
-test_begin_subtest "Insert message, add/remove tags"
-gen_insert_msg
-notmuch insert +custom -unread < "$gen_msg_filename"
-output=$(notmuch search --output=messages tag:custom NOT tag:unread)
-test_expect_equal "$output" "id:$gen_msg_id"
-
-test_begin_subtest "Insert message with default tags stays in new/"
-gen_insert_msg
-notmuch insert < "$gen_msg_filename"
-output=$(notmuch search --output=files id:$gen_msg_id)
-dirname=$(dirname "$output")
-test_expect_equal "$dirname" "$MAIL_DIR/new"
-
-test_begin_subtest "Insert message with non-maildir synced tags stays in new/"
-gen_insert_msg
-notmuch insert +custom -inbox < "$gen_msg_filename"
-output=$(notmuch search --output=files id:$gen_msg_id)
-dirname=$(dirname "$output")
-test_expect_equal "$dirname" "$MAIL_DIR/new"
-
-test_begin_subtest "Insert message with custom new.tags goes to cur/"
-OLDCONFIG=$(notmuch config get new.tags)
-notmuch config set new.tags test
-gen_insert_msg
-notmuch insert < "$gen_msg_filename"
-output=$(notmuch search --output=files id:$gen_msg_id)
-dirname=$(dirname "$output")
-notmuch config set new.tags $OLDCONFIG
-test_expect_equal "$dirname" "$MAIL_DIR/cur"
-
-# additional check on the previous message
-test_begin_subtest "Insert message with custom new.tags actually gets the tags"
-output=$(notmuch search --output=tags id:$gen_msg_id)
-test_expect_equal "$output" "test"
-
-test_begin_subtest "Insert message with maildir synced tags goes to cur/"
-gen_insert_msg
-notmuch insert +flagged < "$gen_msg_filename"
-output=$(notmuch search --output=files id:$gen_msg_id)
-dirname=$(dirname "$output")
-test_expect_equal "$dirname" "$MAIL_DIR/cur"
-
-test_begin_subtest "Insert message into folder"
-gen_insert_msg
-notmuch insert --folder=Drafts < "$gen_msg_filename"
-output=$(notmuch search --output=files folder:Drafts)
-dirname=$(dirname "$output")
-test_expect_equal "$dirname" "$MAIL_DIR/Drafts/new"
-
-test_begin_subtest "Insert message into folder, add/remove tags"
-gen_insert_msg
-notmuch insert --folder=Drafts +draft -unread < "$gen_msg_filename"
-output=$(notmuch search --output=messages folder:Drafts tag:draft NOT tag:unread)
-test_expect_equal "$output" "id:$gen_msg_id"
-
-gen_insert_msg
-test_expect_code 1 "Insert message into non-existent folder" \
- "notmuch insert --folder=nonesuch < $gen_msg_filename"
-
-test_begin_subtest "Insert message, create folder"
-gen_insert_msg
-notmuch insert --folder=F --create-folder +folder < "$gen_msg_filename"
-output=$(notmuch search --output=files folder:F tag:folder)
-basename=$(basename "$output")
-test_expect_equal_file "$gen_msg_filename" "$MAIL_DIR/F/new/${basename}"
-
-test_begin_subtest "Insert message, create subfolder"
-gen_insert_msg
-notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename"
-output=$(notmuch search --output=files folder:F/G/H/I/J tag:folder)
-basename=$(basename "$output")
-test_expect_equal_file "$gen_msg_filename" "${MAIL_DIR}/F/G/H/I/J/new/${basename}"
-
-test_begin_subtest "Insert message, create existing subfolder"
-gen_insert_msg
-notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename"
-output=$(notmuch count folder:F/G/H/I/J tag:folder)
-test_expect_equal "$output" "2"
-
-gen_insert_msg
-test_expect_code 1 "Insert message, create invalid subfolder" \
- "notmuch insert --folder=../G --create-folder $gen_msg_filename"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="--format=json output"
-. ./test-lib.sh
-
-test_begin_subtest "Show message: json"
-add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"json-show-message\""
-output=$(notmuch show --format=json "json-show-message")
-test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"json-show-message\n\"}]}, []]]]"
-
-# This should be the same output as above.
-test_begin_subtest "Show message: json --body=true"
-output=$(notmuch show --format=json --body=true "json-show-message")
-test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"json-show-message\n\"}]}, []]]]"
-
-test_begin_subtest "Show message: json --body=false"
-output=$(notmuch show --format=json --body=false "json-show-message")
-test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Bcc\": \"test_suite+bcc@notmuchmail.org\", \"Reply-To\": \"test_suite+replyto@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}}, []]]]"
-
-test_begin_subtest "Search message: json"
-add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
-output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
-test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
- \"timestamp\": 946728000,
- \"date_relative\": \"2000-01-01\",
- \"matched\": 1,
- \"total\": 1,
- \"authors\": \"Notmuch Test Suite\",
- \"subject\": \"json-search-subject\",
- \"query\": [\"id:$gen_msg_id\", null],
- \"tags\": [\"inbox\",
- \"unread\"]}]"
-
-test_begin_subtest "Show message: json, utf-8"
-add_message "[subject]=\"json-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
-output=$(notmuch show --format=json "jsön-show-méssage")
-test_expect_equal_json "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"excluded\": false, \"filename\": \"${gen_msg_filename}\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\",\"unread\"], \"headers\": {\"Subject\": \"json-show-utf8-body-sübjéct\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"text/plain\", \"content\": \"jsön-show-méssage\n\"}]}, []]]]"
-
-test_begin_subtest "Show message: json, inline attachment filename"
-subject='json-show-inline-attachment-filename'
-id="json-show-inline-attachment-filename@notmuchmail.org"
-emacs_fcc_message \
- "$subject" \
- 'This is a test message with inline attachment with a filename' \
- "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
- (message-goto-eoh)
- (insert \"Message-ID: <$id>\n\")"
-output=$(notmuch show --format=json "id:$id")
-filename=$(notmuch search --output=files "id:$id")
-# Get length of README after base64-encoding, minus additional newline.
-attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
-test_expect_equal_json "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\": false, \"filename\": \"$filename\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"tags\": [\"inbox\"], \"headers\": {\"Subject\": \"$subject\", \"From\": \"Notmuch Test Suite <test_suite@notmuchmail.org>\", \"To\": \"test_suite@notmuchmail.org\", \"Date\": \"Sat, 01 Jan 2000 12:00:00 +0000\"}, \"body\": [{\"id\": 1, \"content-type\": \"multipart/mixed\", \"content\": [{\"id\": 2, \"content-type\": \"text/plain\", \"content\": \"This is a test message with inline attachment with a filename\"}, {\"id\": 3, \"content-type\": \"application/octet-stream\", \"content-length\": $attachment_length, \"content-transfer-encoding\": \"base64\", \"filename\": \"README\"}]}]}, []]]]"
-
-test_begin_subtest "Search message: json, utf-8"
-add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
-output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
-test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
- \"timestamp\": 946728000,
- \"date_relative\": \"2000-01-01\",
- \"matched\": 1,
- \"total\": 1,
- \"authors\": \"Notmuch Test Suite\",
- \"subject\": \"json-search-utf8-body-sübjéct\",
- \"query\": [\"id:$gen_msg_id\", null],
- \"tags\": [\"inbox\",
- \"unread\"]}]"
-
-test_expect_code 20 "Format version: too low" \
- "notmuch search --format-version=0 \\*"
-
-test_expect_code 21 "Format version: too high" \
- "notmuch search --format-version=999 \\*"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="messages with ridiculously-long message IDs"
-. ./test-lib.sh
-
-test_begin_subtest "Referencing long ID before adding"
-generate_message '[subject]="Reference of ridiculously-long message ID"' \
- "[references]=\<abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-\>"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Adding message with long ID"
-generate_message '[subject]="A ridiculously-long message ID"' \
- "[id]=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Referencing long ID after adding"
-generate_message '[subject]="Reply to ridiculously-long message ID"' \
- "[in-reply-to]=\<abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-\>"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Ensure all messages were threaded together"
-output=$(notmuch search 'subject:"a ridiculously-long message ID"' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/3] Notmuch Test Suite; A ridiculously-long message ID (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description="maildir synchronization"
-
-. ./test-lib.sh
-
-# Create the expected maildir structure
-mkdir $MAIL_DIR/cur
-mkdir $MAIL_DIR/new
-mkdir $MAIL_DIR/tmp
-
-test_begin_subtest "Adding 'S' flag to existing filename removes 'unread' tag"
-add_message [subject]='"Adding S flag"' [filename]='adding-s-flag:2,' [dir]=cur
-output=$(notmuch search subject:"Adding S flag" | notmuch_search_sanitize)
-output+="
-"
-mv "${gen_msg_filename}" "${gen_msg_filename}S"
-output+=$(NOTMUCH_NEW)
-output+="
-"
-output+=$(notmuch search subject:"Adding S flag" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding S flag (inbox unread)
-No new mail. Detected 1 file rename.
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding S flag (inbox)"
-
-test_begin_subtest "Adding message with 'S' flag prevents 'unread' tag"
-add_message [subject]='"Adding message with S"' [filename]='adding-with-s-flag:2,S' [dir]=cur
-output=$(notmuch search subject:"Adding message with S" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Adding message with S (inbox)"
-
-test_begin_subtest "Adding 'replied' tag adds 'R' flag to filename"
-add_message [subject]='"Adding replied tag"' [filename]='adding-replied-tag:2,S' [dir]=cur
-notmuch tag +replied subject:"Adding replied tag"
-output=$(cd ${MAIL_DIR}/cur; ls -1 adding-replied*)
-test_expect_equal "$output" "adding-replied-tag:2,RS"
-
-test_begin_subtest "notmuch show works with renamed file (without notmuch new)"
-output=$(notmuch show --format=json id:${gen_msg_id} | notmuch_json_show_sanitize)
-test_expect_equal_json "$output" '[[[{"id": "XXXXX",
-"match": true,
-"excluded": false,
-"filename": "YYYYY",
-"timestamp": 42,
-"date_relative": "2001-01-05",
-"tags": ["inbox","replied"],
-"headers": {"Subject": "Adding replied tag",
-"From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
-"To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
-"Date": "GENERATED_DATE"},
-"body": [{"id": 1,
-"content-type": "text/plain",
-"content": "This is just a test message (#3)\n"}]},
-[]]]]'
-
-test_expect_success 'notmuch reply works with renamed file (without notmuch new)' 'notmuch reply id:${gen_msg_id}'
-
-test_begin_subtest "notmuch new detects no file rename after tag->flag synchronization"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-
-test_begin_subtest "When read, message moved from new to cur"
-add_message [subject]='"Message to move to cur"' [date]='"Sat, 01 Jan 2000 12:00:00 -0000"' [filename]='message-to-move-to-cur' [dir]=new
-notmuch tag -unread subject:"Message to move to cur"
-output=$(cd "$MAIL_DIR/cur"; ls message-to-move*)
-test_expect_equal "$output" "message-to-move-to-cur:2,S"
-
-test_begin_subtest "No rename should be detected by notmuch new"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-# (*) If notmuch new was not run we've got "Processed 1 file in almost
-# no time" here. The reason is that removing unread tag in a previous
-# test created directory document in the database but this document
-# was not linked as subdirectory of $MAIL_DIR. Therefore notmuch new
-# could not reach the cur/ directory and its files in it during
-# recursive traversal.
-#
-# XXX: The above sounds like a bug that should be fixed. If notmuch is
-# creating new directories in the mail store, then it should be
-# creating all necessary database state for those directories.
-
-test_begin_subtest "Adding non-maildir tags does not move message from new to cur"
-add_message [subject]='"Message to stay in new"' \
- [date]='"Sat, 01 Jan 2000 12:00:00 -0000"' \
- [filename]='message-to-stay-in-new' [dir]=new
-notmuch tag +donotmove subject:"Message to stay in new"
-output=$(cd "$MAIL_DIR"; ls */message-to-stay-in-new*)
-test_expect_equal "$output" "new/message-to-stay-in-new"
-
-test_begin_subtest "Message in cur lacking maildir info gets one on any tag change"
-add_message [filename]='message-to-get-maildir-info' [dir]=cur
-notmuch tag +anytag id:$gen_msg_id
-output=$(cd "$MAIL_DIR"; ls */message-to-get-maildir-info*)
-test_expect_equal "$output" "cur/message-to-get-maildir-info:2,"
-
-test_begin_subtest "Message in new with maildir info is moved to cur on any tag change"
-add_message [filename]='message-with-info-to-be-moved-to-cur:2,' [dir]=new
-notmuch tag +anytag id:$gen_msg_id
-output=$(cd "$MAIL_DIR"; ls */message-with-info-to-be-moved-to-cur*)
-test_expect_equal "$output" "cur/message-with-info-to-be-moved-to-cur:2,"
-
-test_begin_subtest "Removing 'S' flag from existing filename adds 'unread' tag"
-add_message [subject]='"Removing S flag"' [filename]='removing-s-flag:2,S' [dir]=cur
-output=$(notmuch search subject:"Removing S flag" | notmuch_search_sanitize)
-output+="
-"
-mv "${gen_msg_filename}" "${gen_msg_filename%S}"
-output+=$(NOTMUCH_NEW)
-output+="
-"
-output+=$(notmuch search subject:"Removing S flag" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Removing S flag (inbox)
-No new mail. Detected 1 file rename.
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Removing S flag (inbox unread)"
-
-test_begin_subtest "Removing info from filename leaves tags unchanged"
-add_message [subject]='"Message to lose maildir info"' [filename]='message-to-lose-maildir-info' [dir]=cur
-notmuch tag -unread subject:"Message to lose maildir info"
-mv "$MAIL_DIR/cur/message-to-lose-maildir-info:2,S" "$MAIL_DIR/cur/message-without-maildir-info"
-output=$(NOTMUCH_NEW)
-output+="
-"
-output+=$(notmuch search subject:"Message to lose maildir info" | notmuch_search_sanitize)
-test_expect_equal "$output" "No new mail. Detected 1 file rename.
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message to lose maildir info (inbox)"
-
-add_message [subject]='"Non-maildir message"' [dir]=notmaildir [filename]='non-maildir-message'
-expected=$(notmuch search --output=files subject:"Non-maildir message")
-test_expect_success "Can remove unread tag from message in non-maildir directory" 'notmuch tag -unread subject:"Non-maildir message"'
-
-test_begin_subtest "Message in non-maildir directory does not get renamed"
-output=$(notmuch search --output=files subject:"Non-maildir message")
-test_expect_equal "$output" "$expected"
-
-test_begin_subtest "notmuch dump/restore re-synchronizes maildir tags with flags"
-# Capture current filename state
-expected=$(ls $MAIL_DIR/cur)
-# Add/remove some flags from filenames
-mv $MAIL_DIR/cur/adding-replied-tag:2,RS $MAIL_DIR/cur/adding-replied-tag:2,S
-mv $MAIL_DIR/cur/adding-s-flag:2,S $MAIL_DIR/cur/adding-s-flag:2,
-mv $MAIL_DIR/cur/adding-with-s-flag:2,S $MAIL_DIR/cur/adding-with-s-flag:2,RS
-mv $MAIL_DIR/cur/message-to-move-to-cur:2,S $MAIL_DIR/cur/message-to-move-to-cur:2,DS
-notmuch dump --output=dump.txt
-NOTMUCH_NEW >/dev/null
-notmuch restore --input=dump.txt
-output=$(ls $MAIL_DIR/cur)
-test_expect_equal "$output" "$expected"
-
-test_begin_subtest 'Adding flags to duplicate message tags the mail'
-add_message [subject]='"Duplicated message"' [dir]=cur [filename]='duplicated-message:2,'
-cp "$MAIL_DIR/cur/duplicated-message:2," "$MAIL_DIR/cur/duplicated-message-copy:2,RS"
-NOTMUCH_NEW > output
-notmuch search subject:"Duplicated message" | notmuch_search_sanitize >> output
-test_expect_equal "$(< output)" "No new mail.
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Duplicated message (inbox replied)"
-
-test_begin_subtest "Adding duplicate message without flags does not remove tags"
-cp "$MAIL_DIR/cur/duplicated-message-copy:2,RS" "$MAIL_DIR/cur/duplicated-message-another-copy:2,"
-NOTMUCH_NEW > output
-notmuch search subject:"Duplicated message" | notmuch_search_sanitize >> output
-test_expect_equal "$(< output)" "No new mail.
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Duplicated message (inbox replied)"
-
-test_begin_subtest "Tag changes modify flags of multiple files"
-notmuch tag -replied subject:"Duplicated message"
-(cd $MAIL_DIR/cur/; ls duplicated*) > actual
-test_expect_equal "$(< actual)" "duplicated-message-another-copy:2,S
-duplicated-message-copy:2,S
-duplicated-message:2,S"
-
-test_begin_subtest "Synchronizing tag changes preserves unsupported maildir flags"
-add_message [subject]='"Unsupported maildir flags"' [dir]=cur [filename]='unsupported-maildir-flags:2,FSZxyz'
-notmuch tag +unread +draft -flagged subject:"Unsupported maildir flags"
-test_expect_equal "$(cd $MAIL_DIR/cur/; ls unsupported*)" "unsupported-maildir-flags:2,DZxyz"
-
-test_begin_subtest "A file with non-compliant maildir info will not be renamed"
-add_message [subject]='"Non-compliant maildir info"' [dir]=cur [filename]='non-compliant-maildir-info:2,These-are-not-flags-in-ASCII-order-donottouch'
-notmuch tag +unread +draft -flagged subject:"Non-compliant maildir info"
-test_expect_equal "$(cd $MAIL_DIR/cur/; ls non-compliant*)" "non-compliant-maildir-info:2,These-are-not-flags-in-ASCII-order-donottouch"
-
-test_begin_subtest "Files in new/ get default synchronized tags"
-OLDCONFIG=$(notmuch config get new.tags)
-notmuch config set new.tags test
-add_message [subject]='"File in new/"' [dir]=new [filename]='file-in-new'
-notmuch config set new.tags $OLDCONFIG
-notmuch search 'subject:"File in new"' | notmuch_search_sanitize > output
-test_expect_equal "$(< output)" \
-"thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; File in new/ (test unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='messages with missing headers'
-. ./test-lib.sh
-
-# Notmuch requires at least one of from, subject, or to or it will
-# ignore the file. Generate two messages so that together they cover
-# all possible missing headers. We also give one of the messages a
-# date to ensure stable result ordering.
-
-cat <<EOF > "${MAIL_DIR}/msg-2"
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Fri, 05 Jan 2001 15:43:57 +0000
-
-Body
-EOF
-
-cat <<EOF > "${MAIL_DIR}/msg-1"
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-
-Body
-EOF
-
-NOTMUCH_NEW
-
-test_begin_subtest "Search: text"
-output=$(notmuch search '*' | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] (null); (inbox unread)
-thread:XXX 1970-01-01 [1/1] Notmuch Test Suite; (inbox unread)"
-
-test_begin_subtest "Search: json"
-output=$(notmuch search --format=json '*' | notmuch_search_sanitize)
-test_expect_equal_json "$output" '
-[
- {
- "authors": "",
- "date_relative": "2001-01-05",
- "matched": 1,
- "subject": "",
- "tags": [
- "inbox",
- "unread"
- ],
- "thread": "XXX",
- "timestamp": 978709437,
- "total": 1,
- "query": ["id:notmuch-sha1-7a6e4eac383ef958fcd3ebf2143db71b8ff01161", null]
- },
- {
- "authors": "Notmuch Test Suite",
- "date_relative": "1970-01-01",
- "matched": 1,
- "subject": "",
- "tags": [
- "inbox",
- "unread"
- ],
- "thread": "XXX",
- "timestamp": 0,
- "total": 1,
- "query": ["id:notmuch-sha1-ca55943aff7a72baf2ab21fa74fab3d632401334", null]
- }
-]'
-
-test_begin_subtest "Show: text"
-output=$(notmuch show '*' | notmuch_show_sanitize)
-test_expect_equal "$output" "\
-\fmessage{ id:notmuch-sha1-7a6e4eac383ef958fcd3ebf2143db71b8ff01161 depth:0 match:1 excluded:0 filename:/XXX/mail/msg-2
-\fheader{
- (2001-01-05) (inbox unread)
-Subject: (null)
-From: (null)
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Fri, 05 Jan 2001 15:43:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-Body
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:notmuch-sha1-ca55943aff7a72baf2ab21fa74fab3d632401334 depth:0 match:1 excluded:0 filename:/XXX/mail/msg-1
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (1970-01-01) (inbox unread)
-Subject: (null)
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Thu, 01 Jan 1970 00:00:00 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-Body
-\fpart}
-\fbody}
-\fmessage}"
-
-test_begin_subtest "Show: json"
-output=$(notmuch show --format=json '*' | notmuch_json_show_sanitize)
-expected=$(notmuch_json_show_sanitize <<EOF
-[
- [
- [
- {
- "body": [
- {
- "content": "Body\n",
- "content-type": "text/plain",
- "id": 1
- }
- ],
- "date_relative": "2001-01-05",
- "excluded": false,
- "filename": "YYYYY",
- "headers": {
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000",
- "From": "",
- "Subject": "",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>"
- },
- "id": "XXXXX",
- "match": true,
- "tags": [
- "inbox",
- "unread"
- ],
- "timestamp": 978709437
- },
- []
- ]
- ],
- [
- [
- {
- "body": [
- {
- "content": "Body\n",
- "content-type": "text/plain",
- "id": 1
- }
- ],
- "date_relative": "1970-01-01",
- "excluded": false,
- "filename": "YYYYY",
- "headers": {
- "Date": "Thu, 01 Jan 1970 00:00:00 +0000",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Subject": ""
- },
- "id": "XXXXX",
- "match": true,
- "tags": [
- "inbox",
- "unread"
- ],
- "timestamp": 0
- },
- []
- ]
- ]
-]
-EOF
-)
-test_expect_equal_json "$output" "$expected"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="output of multipart message"
-. ./test-lib.sh
-
-cat <<EOF > embedded_message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Subject: html message
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
-Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
-MIME-Version: 1.0
-Content-Type: multipart/alternative; boundary="==-=-=="
-
---==-=-==
-Content-Type: text/html
-
-<p>This is an embedded message, with a multipart/alternative part.</p>
-
---==-=-==
-Content-Type: text/plain
-
-This is an embedded message, with a multipart/alternative part.
-
---==-=-==--
-EOF
-
-cat <<EOF > ${MAIL_DIR}/multipart
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Subject: Multipart message
-Date: Fri, 05 Jan 2001 15:43:57 +0000
-User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
-Message-ID: <87liy5ap00.fsf@yoom.home.cworth.org>
-MIME-Version: 1.0
-Content-Type: multipart/signed; boundary="==-=-=";
- micalg=pgp-sha1; protocol="application/pgp-signature"
-
---==-=-=
-Content-Type: multipart/mixed; boundary="=-=-="
-
---=-=-=
-Content-Type: message/rfc822
-Content-Disposition: inline
-
-EOF
-cat embedded_message >> ${MAIL_DIR}/multipart
-cat <<EOF >> ${MAIL_DIR}/multipart
-
---=-=-=
-Content-Disposition: attachment; filename=attachment
-
-This is a text attachment.
-
---=-=-=
-
-And this message is signed.
-
--Carl
-
---=-=-=--
-
---==-=-=
-Content-Type: application/pgp-signature
-
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.11 (GNU/Linux)
-
-iEYEARECAAYFAk3SA/gACgkQ6JDdNq8qSWj0sACghqVJEQJUs3yV8zbTzhgnSIcD
-W6cAmQE4dcYrx/LPLtYLZm1jsGauE5hE
-=zkga
------END PGP SIGNATURE-----
---==-=-=--
-EOF
-
-cat <<EOF > ${MAIL_DIR}/base64-part-with-crlf
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Subject: Test message with a BASE64 encoded binary containing CRLF pair
-Date: Fri, 05 Jan 2001 15:43:57 +0000
-User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
-Message-ID: <base64-part-with-crlf>
-MIME-Version: 1.0
-Content-Type: multipart/mixed; boundary="==-=-=";
-
---==-=-=
-
-The attached BASE64-encoded part expands to a binary containing a CRLF
-pair (that is one bye of 0x0D followed by one byte of 0x0A). This is
-designed to ensure that notmuch is not corrupting the output of this
-part by converting the CRLF pair to an LF only (as would be appropriate
-for display of a text part on a Linux system, for example).
-
-The part should be a 3-byte file with the following sequence of 3
-hexadecimal bytes:
-
- EF 0D 0A
-
---==-=-=
-Content-Type: application/octet-stream
-Content-Disposition: attachment; filename=crlf.bin
-Content-Transfer-Encoding: base64
-
-7w0K
---==-=-=--
-EOF
-notmuch new > /dev/null
-
-test_begin_subtest "--format=text --part=0, full message"
-notmuch show --format=text --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fmessage{ id:87liy5ap00.fsf@yoom.home.cworth.org depth:0 match:1 excluded:0 filename:${MAIL_DIR}/multipart
-\fheader{
-Carl Worth <cworth@cworth.org> (2001-01-05) (attachment inbox signed unread)
-Subject: Multipart message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Date: Fri, 05 Jan 2001 15:43:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: multipart/signed
-\fpart{ ID: 2, Content-type: multipart/mixed
-\fpart{ ID: 3, Content-type: message/rfc822
-\fheader{
-Subject: html message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 4, Content-type: multipart/alternative
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-\fpart}
-\fbody}
-\fpart}
-\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
-This is a text attachment.
-\fattachment}
-\fpart{ ID: 8, Content-type: text/plain
-And this message is signed.
-
--Carl
-\fpart}
-\fpart}
-\fpart{ ID: 9, Content-type: application/pgp-signature
-Non-text part: application/pgp-signature
-\fpart}
-\fpart}
-\fbody}
-\fmessage}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=1, message body"
-notmuch show --format=text --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 1, Content-type: multipart/signed
-\fpart{ ID: 2, Content-type: multipart/mixed
-\fpart{ ID: 3, Content-type: message/rfc822
-\fheader{
-Subject: html message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 4, Content-type: multipart/alternative
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-\fpart}
-\fbody}
-\fpart}
-\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
-This is a text attachment.
-\fattachment}
-\fpart{ ID: 8, Content-type: text/plain
-And this message is signed.
-
--Carl
-\fpart}
-\fpart}
-\fpart{ ID: 9, Content-type: application/pgp-signature
-Non-text part: application/pgp-signature
-\fpart}
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=2, multipart/mixed"
-notmuch show --format=text --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 2, Content-type: multipart/mixed
-\fpart{ ID: 3, Content-type: message/rfc822
-\fheader{
-Subject: html message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 4, Content-type: multipart/alternative
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-\fpart}
-\fbody}
-\fpart}
-\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
-This is a text attachment.
-\fattachment}
-\fpart{ ID: 8, Content-type: text/plain
-And this message is signed.
-
--Carl
-\fpart}
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=3, rfc822 part"
-notmuch show --format=text --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 3, Content-type: message/rfc822
-\fheader{
-Subject: html message
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 4, Content-type: multipart/alternative
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-\fpart}
-\fbody}
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=4, rfc822's multipart"
-notmuch show --format=text --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 4, Content-type: multipart/alternative
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=5, rfc822's html part"
-notmuch show --format=text --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 5, Content-type: text/html
-Non-text part: text/html
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=6, rfc822's text part"
-notmuch show --format=text --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 6, Content-type: text/plain
-This is an embedded message, with a multipart/alternative part.
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=7, inline attachement"
-notmuch show --format=text --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fattachment{ ID: 7, Filename: attachment, Content-type: text/plain
-This is a text attachment.
-\fattachment}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=8, plain text part"
-notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 8, Content-type: text/plain
-And this message is signed.
-
--Carl
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=text --part=9, pgp signature (unverified)"
-notmuch show --format=text --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-\fpart{ ID: 9, Content-type: application/pgp-signature
-Non-text part: application/pgp-signature
-\fpart}
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_expect_success \
- "--format=text --part=8, no part, expect error" \
- "notmuch show --format=text --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
-
-test_begin_subtest "--format=json --part=0, full message"
-notmuch show --format=json --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": "87liy5ap00.fsf@yoom.home.cworth.org", "match": true, "excluded": false, "filename": "${MAIL_DIR}/multipart", "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["attachment","inbox","signed","unread"], "headers": {"Subject": "Multipart message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [
-{"id": 1, "content-type": "multipart/signed", "content": [
-{"id": 2, "content-type": "multipart/mixed", "content": [
-{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
-{"id": 4, "content-type": "multipart/alternative", "content": [
-{"id": 5, "content-type": "text/html", "content-length": 71},
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
-{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
-{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
-{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}]}]}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=1, message body"
-notmuch show --format=json --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 1, "content-type": "multipart/signed", "content": [
-{"id": 2, "content-type": "multipart/mixed", "content": [
-{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
-{"id": 4, "content-type": "multipart/alternative", "content": [
-{"id": 5, "content-type": "text/html", "content-length": 71},
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
-{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
-{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]},
-{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}]}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=2, multipart/mixed"
-notmuch show --format=json --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 2, "content-type": "multipart/mixed", "content": [
-{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
-{"id": 4, "content-type": "multipart/alternative", "content": [
-{"id": 5, "content-type": "text/html", "content-length": 71},
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
-{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"},
-{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}]}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=3, rfc822 part"
-notmuch show --format=json --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 3, "content-type": "message/rfc822", "content": [{"headers": {"Subject": "html message", "From": "Carl Worth <cworth@cworth.org>", "To": "cworth@cworth.org", "Date": "Fri, 05 Jan 2001 15:42:57 +0000"}, "body": [
-{"id": 4, "content-type": "multipart/alternative", "content": [
-{"id": 5, "content-type": "text/html", "content-length": 71},
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=4, rfc822's multipart/alternative"
-notmuch show --format=json --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 4, "content-type": "multipart/alternative", "content": [
-{"id": 5, "content-type": "text/html", "content-length": 71},
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}]}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=5, rfc822's html part"
-notmuch show --format=json --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 5, "content-type": "text/html", "content-length": 71}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=6, rfc822's text part"
-notmuch show --format=json --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 6, "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=7, inline attachment"
-notmuch show --format=json --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 7, "content-type": "text/plain", "filename": "attachment", "content": "This is a text attachment.\n"}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=8, plain text part"
-notmuch show --format=json --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 8, "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--format=json --part=9, pgp signature (unverified)"
-notmuch show --format=json --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-{"id": 9, "content-type": "application/pgp-signature", "content-length": 197}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_expect_success \
- "--format=json --part=10, no part, expect error" \
- "notmuch show --format=json --part=10 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
-
-test_begin_subtest "--format=raw"
-notmuch show --format=raw 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
-
-test_begin_subtest "--format=raw --part=0, full message"
-notmuch show --format=raw --part=0 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
-
-test_begin_subtest "--format=raw --part=1, message body"
-notmuch show --format=raw --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-test_expect_equal_file OUTPUT "${MAIL_DIR}"/multipart
-
-test_begin_subtest "--format=raw --part=2, multipart/mixed"
-notmuch show --format=raw --part=2 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-Content-Type: multipart/mixed; boundary="=-=-="
-
---=-=-=
-Content-Type: message/rfc822
-Content-Disposition: inline
-
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Subject: html message
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
-Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
-MIME-Version: 1.0
-Content-Type: multipart/alternative; boundary="==-=-=="
-
---==-=-==
-Content-Type: text/html
-
-<p>This is an embedded message, with a multipart/alternative part.</p>
-
---==-=-==
-Content-Type: text/plain
-
-This is an embedded message, with a multipart/alternative part.
-
---==-=-==--
-
---=-=-=
-Content-Disposition: attachment; filename=attachment
-
-This is a text attachment.
-
---=-=-=
-
-And this message is signed.
-
--Carl
-
---=-=-=--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=3, rfc822 part"
-notmuch show --format=raw --part=3 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-test_expect_equal_file OUTPUT embedded_message
-
-test_begin_subtest "--format=raw --part=4, rfc822's multipart"
-notmuch show --format=raw --part=4 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-From: Carl Worth <cworth@cworth.org>
-To: cworth@cworth.org
-Subject: html message
-Date: Fri, 05 Jan 2001 15:42:57 +0000
-User-Agent: Notmuch/0.5 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
-Message-ID: <87liy5ap01.fsf@yoom.home.cworth.org>
-MIME-Version: 1.0
-Content-Type: multipart/alternative; boundary="==-=-=="
-
---==-=-==
-Content-Type: text/html
-
-<p>This is an embedded message, with a multipart/alternative part.</p>
-
---==-=-==
-Content-Type: text/plain
-
-This is an embedded message, with a multipart/alternative part.
-
---==-=-==--
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=5, rfc822's html part"
-notmuch show --format=raw --part=5 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-<p>This is an embedded message, with a multipart/alternative part.</p>
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=6, rfc822's text part"
-notmuch show --format=raw --part=6 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-This is an embedded message, with a multipart/alternative part.
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=7, inline attachment"
-notmuch show --format=raw --part=7 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-This is a text attachment.
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=8, plain text part"
-notmuch show --format=raw --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-And this message is signed.
-
--Carl
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--format=raw --part=9, pgp signature (unverified)"
-notmuch show --format=raw --part=9 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-# output should *not* include newline
-echo >>OUTPUT
-cat <<EOF >EXPECTED
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.11 (GNU/Linux)
-
-iEYEARECAAYFAk3SA/gACgkQ6JDdNq8qSWj0sACghqVJEQJUs3yV8zbTzhgnSIcD
-W6cAmQE4dcYrx/LPLtYLZm1jsGauE5hE
-=zkga
------END PGP SIGNATURE-----
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_expect_success \
- "--format=raw --part=10, no part, expect error" \
- "notmuch show --format=raw --part=8 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
-
-test_begin_subtest "--format=mbox"
-notmuch show --format=mbox 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-printf "From cworth@cworth.org Fri Jan 5 15:43:57 2001\n" >EXPECTED
-cat "${MAIL_DIR}"/multipart >>EXPECTED
-# mbox output is expected to include a blank line
-echo >>EXPECTED
-test_expect_equal_file OUTPUT EXPECTED
-
-test_expect_success \
- "--format=mbox --part=1, incompatible, expect error" \
- "! notmuch show --format=mbox --part=1 'id:87liy5ap00.fsf@yoom.home.cworth.org'"
-
-test_begin_subtest "'notmuch reply' to a multipart message"
-notmuch reply 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
-cat <<EOF >EXPECTED
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: Multipart message
-To: Carl Worth <cworth@cworth.org>, cworth@cworth.org
-In-Reply-To: <87liy5ap00.fsf@yoom.home.cworth.org>
-References: <87liy5ap00.fsf@yoom.home.cworth.org>
-
-On Fri, 05 Jan 2001 15:43:57 +0000, Carl Worth <cworth@cworth.org> wrote:
-> From: Carl Worth <cworth@cworth.org>
-> To: cworth@cworth.org
-> Subject: html message
-> Date: Fri, 05 Jan 2001 15:42:57 +0000
->
-Non-text part: text/html
-> This is an embedded message, with a multipart/alternative part.
-> This is a text attachment.
-> And this message is signed.
->
-> -Carl
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "'notmuch reply' to a multipart message with json format"
-notmuch reply --format=json 'id:87liy5ap00.fsf@yoom.home.cworth.org' | notmuch_json_show_sanitize >OUTPUT
-notmuch_json_show_sanitize <<EOF >EXPECTED
-{"reply-headers": {"Subject": "Re: Multipart message",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Carl Worth <cworth@cworth.org>, cworth@cworth.org",
- "In-reply-to": "<87liy5ap00.fsf@yoom.home.cworth.org>",
- "References": "<87liy5ap00.fsf@yoom.home.cworth.org>"},
- "original": {"id": "XXXXX",
- "match": false,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437,
- "date_relative": "2001-01-05",
- "tags": ["attachment","inbox","signed","unread"],
- "headers": {"Subject": "Multipart message",
- "From": "Carl Worth <cworth@cworth.org>",
- "To": "cworth@cworth.org",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
- "body": [{"id": 1,
- "content-type": "multipart/signed",
- "content": [{"id": 2,
- "content-type": "multipart/mixed",
- "content": [{"id": 3,
- "content-type": "message/rfc822",
- "content": [{"headers": {"Subject": "html message",
- "From": "Carl Worth <cworth@cworth.org>",
- "To": "cworth@cworth.org",
- "Date": "Fri, 05 Jan 2001 15:42:57 +0000"},
- "body": [{"id": 4,
- "content-type": "multipart/alternative",
- "content": [{"id": 5,
- "content-type": "text/html",
- "content-length": 71},
- {"id": 6,
- "content-type": "text/plain",
- "content": "This is an embedded message, with a multipart/alternative part.\n"}]}]}]},
- {"id": 7,
- "content-type": "text/plain",
- "filename": "attachment",
- "content": "This is a text attachment.\n"},
- {"id": 8,
- "content-type": "text/plain",
- "content": "And this message is signed.\n\n-Carl\n"}]},
- {"id": 9,
- "content-type": "application/pgp-signature",
- "content-length": 197}]}]}}
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "'notmuch show --part' does not corrupt a part with CRLF pair"
-notmuch show --format=raw --part=3 id:base64-part-with-crlf > crlf.out
-echo -n -e "\xEF\x0D\x0A" > crlf.expected
-test_expect_equal_file crlf.out crlf.expected
-
-
-# The ISO-8859-1 encoding of U+00BD is a single byte: octal 275
-# (Portability note: Dollar-Single ($'...', ANSI C-style escape sequences)
-# quoting works on bash, ksh, zsh, *BSD sh but not on dash, ash nor busybox sh)
-readonly u_00bd_latin1=$'\275'
-
-# The Unicode fraction symbol 1/2 is U+00BD and is encoded
-# in UTF-8 as two bytes: octal 302 275
-readonly u_00bd_utf8=$'\302\275'
-
-cat <<EOF > ${MAIL_DIR}/include-html
-From: A <a@example.com>
-To: B <b@example.com>
-Subject: html message
-Date: Sat, 01 January 2000 00:00:00 +0000
-Message-ID: <htmlmessage>
-MIME-Version: 1.0
-Content-Type: multipart/alternative; boundary="==-=="
-
---==-==
-Content-Type: text/html; charset=UTF-8
-
-<p>0.5 equals ${u_00bd_utf8}</p>
-
---==-==
-Content-Type: text/html; charset=ISO-8859-1
-
-<p>0.5 equals ${u_00bd_latin1}</p>
-
---==-==
-Content-Type: text/plain; charset=UTF-8
-
-0.5 equals ${u_00bd_utf8}
-
---==-==--
-EOF
-
-notmuch new > /dev/null
-
-cat_expected_head ()
-{
- cat <<EOF
-[[[{"id": "htmlmessage", "match":true, "excluded": false, "date_relative":"2000-01-01",
- "timestamp": 946684800,
- "filename": "${MAIL_DIR}/include-html",
- "tags": ["inbox", "unread"],
- "headers": { "Date": "Sat, 01 Jan 2000 00:00:00 +0000", "From": "A <a@example.com>",
- "Subject": "html message", "To": "B <b@example.com>"},
- "body": [{
- "content-type": "multipart/alternative", "id": 1,
-EOF
-}
-
-cat_expected_head > EXPECTED.nohtml
-cat <<EOF >> EXPECTED.nohtml
-"content": [
- { "id": 2, "content-charset": "UTF-8", "content-length": 21, "content-type": "text/html"},
- { "id": 3, "content-charset": "ISO-8859-1", "content-length": 20, "content-type": "text/html"},
- { "id": 4, "content-type": "text/plain", "content": "0.5 equals \\u00bd\\n"}
-]}]},[]]]]
-EOF
-
-# Both the UTF-8 and ISO-8859-1 part should have U+00BD
-cat_expected_head > EXPECTED.withhtml
-cat <<EOF >> EXPECTED.withhtml
-"content": [
- { "id": 2, "content-type": "text/html", "content": "<p>0.5 equals \\u00bd</p>\\n"},
- { "id": 3, "content-type": "text/html", "content": "<p>0.5 equals \\u00bd</p>\\n"},
- { "id": 4, "content-type": "text/plain", "content": "0.5 equals \\u00bd\\n"}
-]}]},[]]]]
-EOF
-
-test_begin_subtest "html parts excluded by default"
-notmuch show --format=json id:htmlmessage > OUTPUT
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED.nohtml)"
-
-test_begin_subtest "html parts included"
-notmuch show --format=json --include-html id:htmlmessage > OUTPUT
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED.withhtml)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch new" in several variations'
-. ./test-lib.sh
-
-test_begin_subtest "No new messages"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-
-
-test_begin_subtest "Single new message"
-generate_message
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "Multiple new messages"
-generate_message
-generate_message
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 2 new messages to the database."
-
-
-test_begin_subtest "No new messages (non-empty DB)"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-
-
-test_begin_subtest "New directories"
-rm -rf "${MAIL_DIR}"/* "${MAIL_DIR}"/.notmuch
-mkdir "${MAIL_DIR}"/def
-mkdir "${MAIL_DIR}"/ghi
-generate_message [dir]=def
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "Alternate inode order"
-
-rm -rf "${MAIL_DIR}"/.notmuch
-mv "${MAIL_DIR}"/ghi "${MAIL_DIR}"/abc
-rm "${MAIL_DIR}"/def/*
-generate_message [dir]=abc
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "Message moved in"
-rm -rf "${MAIL_DIR}"/* "${MAIL_DIR}"/.notmuch
-generate_message
-tmp_msg_filename=tmp/"$gen_msg_filename"
-mkdir -p "$(dirname "$tmp_msg_filename")"
-mv "$gen_msg_filename" "$tmp_msg_filename"
-notmuch new > /dev/null
-mv "$tmp_msg_filename" "$gen_msg_filename"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "Renamed message"
-
-generate_message
-notmuch new > /dev/null
-mv "$gen_msg_filename" "${gen_msg_filename}"-renamed
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Detected 1 file rename."
-
-
-test_begin_subtest "Deleted message"
-
-rm "${gen_msg_filename}"-renamed
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Removed 1 message."
-
-
-test_begin_subtest "Renamed directory"
-
-generate_message [dir]=dir
-generate_message [dir]=dir
-generate_message [dir]=dir
-
-notmuch new > /dev/null
-
-mv "${MAIL_DIR}"/dir "${MAIL_DIR}"/dir-renamed
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Detected 3 file renames."
-
-
-test_begin_subtest "Deleted directory"
-
-rm -rf "${MAIL_DIR}"/dir-renamed
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Removed 3 messages."
-
-
-test_begin_subtest "New directory (at end of list)"
-
-generate_message [dir]=zzz
-generate_message [dir]=zzz
-generate_message [dir]=zzz
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 3 new messages to the database."
-
-
-test_begin_subtest "Deleted directory (end of list)"
-
-rm -rf "${MAIL_DIR}"/zzz
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Removed 3 messages."
-
-
-test_begin_subtest "New symlink to directory"
-
-rm -rf "${MAIL_DIR}"/.notmuch
-mv "${MAIL_DIR}" "${TMP_DIRECTORY}"/actual_maildir
-
-mkdir "${MAIL_DIR}"
-ln -s "${TMP_DIRECTORY}"/actual_maildir "${MAIL_DIR}"/symlink
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "New symlink to a file"
-generate_message
-external_msg_filename="${TMP_DIRECTORY}"/external/"$(basename "$gen_msg_filename")"
-mkdir -p "$(dirname "$external_msg_filename")"
-mv "$gen_msg_filename" "$external_msg_filename"
-ln -s "$external_msg_filename" "$gen_msg_filename"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-
-test_begin_subtest "Broken symlink aborts"
-ln -s does-not-exist "${MAIL_DIR}/broken"
-output=$(NOTMUCH_NEW 2>&1)
-test_expect_equal "$output" \
-"Error reading file ${MAIL_DIR}/broken: No such file or directory
-Note: A fatal error was encountered: Something went wrong trying to read or write a file
-No new mail."
-rm "${MAIL_DIR}/broken"
-
-
-test_begin_subtest "New two-level directory"
-
-generate_message [dir]=two/levels
-generate_message [dir]=two/levels
-generate_message [dir]=two/levels
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 3 new messages to the database."
-
-
-test_begin_subtest "Deleted two-level directory"
-
-rm -rf "${MAIL_DIR}"/two
-
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Removed 3 messages."
-
-test_begin_subtest "Support single-message mbox (deprecated)"
-cat > "${MAIL_DIR}"/mbox_file1 <<EOF
-From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Test mbox message 1
-
-Body.
-EOF
-output=$(NOTMUCH_NEW 2>&1)
-test_expect_equal "$output" \
-"Warning: ${MAIL_DIR}/mbox_file1 is an mbox containing a single message,
-likely caused by misconfigured mail delivery. Support for single-message
-mboxes is deprecated and may be removed in the future.
-Added 1 new message to the database."
-
-# This test requires that notmuch new has been run at least once.
-test_begin_subtest "Skip and report non-mail files"
-generate_message
-mkdir -p "${MAIL_DIR}"/.git && touch "${MAIL_DIR}"/.git/config
-touch "${MAIL_DIR}"/ignored_file
-touch "${MAIL_DIR}"/.ignored_hidden_file
-cat > "${MAIL_DIR}"/mbox_file <<EOF
-From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Test mbox message 1
-
-Body.
-
-From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Test mbox message 2
-
-Body 2.
-EOF
-output=$(NOTMUCH_NEW 2>&1)
-test_expect_equal "$output" \
-"Note: Ignoring non-mail file: ${MAIL_DIR}/.git/config
-Note: Ignoring non-mail file: ${MAIL_DIR}/.ignored_hidden_file
-Note: Ignoring non-mail file: ${MAIL_DIR}/ignored_file
-Note: Ignoring non-mail file: ${MAIL_DIR}/mbox_file
-Added 1 new message to the database."
-rm "${MAIL_DIR}"/mbox_file
-
-test_begin_subtest "Ignore files and directories specified in new.ignore"
-generate_message
-notmuch config set new.ignore .git ignored_file .ignored_hidden_file
-touch "${MAIL_DIR}"/.git # change .git's mtime for notmuch new to rescan.
-output=$(NOTMUCH_NEW 2>&1)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Ignore files and directories specified in new.ignore (multiple occurrences)"
-notmuch config set new.ignore .git ignored_file .ignored_hidden_file
-notmuch new > /dev/null # ensure that files/folders will be printed in ASCII order.
-touch "${MAIL_DIR}"/.git # change .git's mtime for notmuch new to rescan.
-touch "${MAIL_DIR}" # likewise for MAIL_DIR
-mkdir -p "${MAIL_DIR}"/one/two/three/.git
-touch "${MAIL_DIR}"/{one,one/two,one/two/three}/ignored_file
-output=$(NOTMUCH_NEW --debug 2>&1 | sort)
-test_expect_equal "$output" \
-"(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/.git
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/.ignored_hidden_file
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/ignored_file
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/ignored_file
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/ignored_file
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/three/.git
-(D) add_files_recursive, pass 1: explicitly ignoring ${MAIL_DIR}/one/two/three/ignored_file
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/.git
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/.ignored_hidden_file
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/ignored_file
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/ignored_file
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/ignored_file
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/three/.git
-(D) add_files_recursive, pass 2: explicitly ignoring ${MAIL_DIR}/one/two/three/ignored_file
-No new mail."
-
-
-test_begin_subtest "Don't stop for ignored broken symlinks"
-notmuch config set new.ignore .git ignored_file .ignored_hidden_file broken_link
-ln -s i_do_not_exist "${MAIL_DIR}"/broken_link
-output=$(NOTMUCH_NEW 2>&1)
-test_expect_equal "$output" "No new mail."
-
-test_done
cd $(dirname "$0")
-TESTS="
- basic
- help-test
- compact
- config
- setup
- new
- count
- insert
- search
- search-output
- search-by-folder
- search-position-overlap-bug
- search-insufficient-from-quoting
- search-limiting
- excludes
- tagging
- json
- sexp
- text
- multipart
- thread-naming
- raw
- reply
- reply-to-sender
- dump-restore
- uuencode
- thread-order
- author-order
- from-guessing
- long-id
- encoding
- emacs
- emacs-large-search-buffer
- emacs-subject-to-filename
- maildir-sync
- crypto
- symbol-hiding
- search-folder-coherence
- atomicity
- python
- hooks
- argument-parsing
- emacs-test-functions
- emacs-address-cleaning
- emacs-hello
- emacs-show
- emacs-tree
- missing-headers
- hex-escaping
- parse-time-string
- search-date
- thread-replies
-"
-TESTS=${NOTMUCH_TESTS:=$TESTS}
+TESTS=${NOTMUCH_TESTS:-`echo T[0-9][0-9][0-9]-*.sh`}
# Clean up any results from a previous run
rm -r test-results >/dev/null 2>/dev/null
trap - HUP INT TERM
# Report results
+echo
./aggregate-results.sh test-results/*
ev=$?
+++ /dev/null
-#!/usr/bin/env bash
-test_description="date/time parser module"
-. ./test-lib.sh
-
-# Sanity/smoke tests for the date/time parser independent of notmuch
-
-_date ()
-{
- date -d "$*" +%s
-}
-
-_parse_time ()
-{
- ${TEST_DIRECTORY}/parse-time --format=%s "$*"
-}
-
-test_begin_subtest "date(1) default format without TZ code"
-test_expect_equal "$(_parse_time Fri Aug 3 23:06:06 2012)" "$(_date Fri Aug 3 23:06:06 2012)"
-
-test_begin_subtest "date(1) --rfc-2822 format"
-test_expect_equal "$(_parse_time Fri, 03 Aug 2012 23:07:46 +0100)" "$(_date Fri, 03 Aug 2012 23:07:46 +0100)"
-
-test_begin_subtest "date(1) --rfc=3339=seconds format"
-test_expect_equal "$(_parse_time 2012-08-03 23:09:37+03:00)" "$(_date 2012-08-03 23:09:37+03:00)"
-
-test_begin_subtest "Date parser tests"
-REFERENCE=$(_date Tue Jan 11 11:11:00 +0000 2011)
-cat <<EOF > INPUT
-now ==> Tue Jan 11 11:11:00 +0000 2011
-2010-1-1 ==> ERROR: DATEFORMAT
-Jan 2 ==> Sun Jan 02 11:11:00 +0000 2011
-Mon ==> Mon Jan 10 11:11:00 +0000 2011
-last Friday ==> ERROR: FORMAT
-2 hours ago ==> Tue Jan 11 09:11:00 +0000 2011
-last month ==> Sat Dec 11 11:11:00 +0000 2010
-month ago ==> Sat Dec 11 11:11:00 +0000 2010
-two mo ==> Thu Nov 11 11:11:00 +0000 2010
-3M ==> Mon Oct 11 11:11:00 +0000 2010
-4-mont ==> Sat Sep 11 11:11:00 +0000 2010
-5m ==> Tue Jan 11 11:06:00 +0000 2011
-dozen mi ==> Tue Jan 11 10:59:00 +0000 2011
-8am ==> Tue Jan 11 08:00:00 +0000 2011
-9:15 ==> Tue Jan 11 09:15:00 +0000 2011
-12:34 ==> Tue Jan 11 12:34:00 +0000 2011
-monday ==> Mon Jan 10 11:11:00 +0000 2011
-yesterday ==> Mon Jan 10 11:11:00 +0000 2011
-tomorrow ==> ERROR: KEYWORD
- ==> Tue Jan 11 11:11:00 +0000 2011 # empty string is reference time
-
-Aug 3 23:06:06 2012 ==> Fri Aug 03 23:06:06 +0000 2012 # date(1) default format without TZ code
-Fri, 03 Aug 2012 23:07:46 +0100 ==> Fri Aug 03 22:07:46 +0000 2012 # rfc-2822
-2012-08-03 23:09:37+03:00 ==> Fri Aug 03 20:09:37 +0000 2012 # rfc-3339 seconds
-
-10s ==> Tue Jan 11 11:10:50 +0000 2011
-19701223s ==> Fri May 28 10:37:17 +0000 2010
-19701223 ==> Wed Dec 23 11:11:00 +0000 1970
-
-19701223 +0100 ==> Wed Dec 23 11:11:00 +0000 1970 # Timezone is ignored without an error
-
-today ==^^> Wed Jan 12 00:00:00 +0000 2011
-today ==^> Tue Jan 11 23:59:59 +0000 2011
-today ==_> Tue Jan 11 00:00:00 +0000 2011
-
-this week ==^^> Sun Jan 16 00:00:00 +0000 2011
-this week ==^> Sat Jan 15 23:59:59 +0000 2011
-this week ==_> Sun Jan 09 00:00:00 +0000 2011
-
-two months ago ==> Thu Nov 11 11:11:00 +0000 2010
-two months ==> Thu Nov 11 11:11:00 +0000 2010
-
-@1348569850 ==> Tue Sep 25 10:44:10 +0000 2012
-@10 ==> Thu Jan 01 00:00:10 +0000 1970
-EOF
-
-${TEST_DIRECTORY}/parse-time --ref=${REFERENCE} < INPUT > OUTPUT
-test_expect_equal_file INPUT OUTPUT
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="python bindings"
-. ./test-lib.sh
-
-add_email_corpus
-
-test_begin_subtest "compare thread ids"
-test_python <<EOF
-import notmuch
-db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
-q_new = notmuch.Query(db, 'tag:inbox')
-q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
-for t in q_new.search_threads():
- print t.get_thread_id()
-EOF
-notmuch search --sort=oldest-first --output=threads tag:inbox | sed s/^thread:// > EXPECTED
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "compare message ids"
-test_python <<EOF
-import notmuch
-db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
-q_new = notmuch.Query(db, 'tag:inbox')
-q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
-for m in q_new.search_messages():
- print m.get_message_id()
-EOF
-notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "get non-existent file"
-test_python <<EOF
-import notmuch
-db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
-print db.find_message_by_filename("i-dont-exist")
-EOF
-test_expect_equal "$(cat OUTPUT)" "None"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description='notmuch show --format=raw'
-. ./test-lib.sh
-
-add_message
-add_message
-
-test_begin_subtest "Attempt to show multiple raw messages"
-output=$(notmuch show --format=raw "*" 2>&1)
-test_expect_equal "$output" "Error: search term did not match precisely one message."
-
-test_begin_subtest "Show a raw message"
-output=$(notmuch show --format=raw id:msg-001@notmuch-test-suite | notmuch_date_sanitize)
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Message-Id: <msg-001@notmuch-test-suite>
-Subject: Test message #1
-Date: GENERATED_DATE
-
-This is just a test message (#1)"
-
-test_begin_subtest "Show another raw message"
-output=$(notmuch show --format=raw id:msg-002@notmuch-test-suite | notmuch_date_sanitize)
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Message-Id: <msg-002@notmuch-test-suite>
-Subject: Test message #2
-Date: GENERATED_DATE
-
-This is just a test message (#2)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="\"notmuch reply\" in several variations"
-. ./test-lib.sh
-
-test_begin_subtest "Basic reply"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="basic reply test"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> basic reply test"
-
-test_begin_subtest "Multiple recipients"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Multiple recipients"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, Someone Else <someone@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> Multiple recipients"
-
-test_begin_subtest "Reply with CC"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- '[cc]="Other Parties <cc@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply with CC"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-Cc: Other Parties <cc@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> reply with CC"
-
-test_begin_subtest "Reply from alternate address"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite_other@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply from alternate address"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> reply from alternate address"
-
-test_begin_subtest "Reply from address in named group list"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]=group:test_suite@notmuchmail.org,someone@example.com\;' \
- [cc]=test_suite_other@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Reply from address in named group list"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, someone@example.com
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> Reply from address in named group list"
-
-test_begin_subtest "Support for Reply-To"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="support for reply-to"' \
- '[reply-to]="Sender <elsewhere@example.com>"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <elsewhere@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> support for reply-to"
-
-test_begin_subtest "Un-munging Reply-To"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="Some List <list@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Un-munging Reply-To"' \
- '[reply-to]="Evil Munging List <list@example.com>"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>, Some List <list@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> Un-munging Reply-To"
-
-test_begin_subtest "Message with header of exactly 200 bytes"
-add_message '[subject]="This subject is exactly 200 bytes in length. Other than its length there is not much of note here. Note that the length of 200 bytes includes the Subject: and Re: prefixes with two spaces"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="200-byte header"'
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: This subject is exactly 200 bytes in length. Other than its
- length there is not much of note here. Note that the length of 200 bytes
- includes the Subject: and Re: prefixes with two spaces
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> 200-byte header"
-
-test_begin_subtest "From guessing: Envelope-To"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="Recipient <recipient@example.com>"' \
- '[subject]="From guessing"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="From guessing"' \
- '[header]="Envelope-To: test_suite_other@notmuchmail.org"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: From guessing
-To: Sender <sender@example.com>, Recipient <recipient@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> From guessing"
-
-test_begin_subtest "From guessing: X-Original-To"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="Recipient <recipient@example.com>"' \
- '[subject]="From guessing"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="From guessing"' \
- '[header]="X-Original-To: test_suite@otherdomain.org"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@otherdomain.org>
-Subject: Re: From guessing
-To: Sender <sender@example.com>, Recipient <recipient@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> From guessing"
-
-test_begin_subtest "From guessing: Delivered-To"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="Recipient <recipient@example.com>"' \
- '[subject]="From guessing"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="From guessing"' \
- '[header]="Delivered-To: test_suite_other@notmuchmail.org"'
-
-output=$(notmuch reply id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: From guessing
-To: Sender <sender@example.com>, Recipient <recipient@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> From guessing"
-
-test_begin_subtest "Reply with RFC 2047-encoded headers"
-add_message '[subject]="=?iso-8859-1?q?=e0=df=e7?="' \
- '[from]="=?utf-8?q?=e2=98=83?= <snowman@example.com>"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Encoding"'
-
-# GMime happens to change from Q- to B-encoding. We canonicalize the
-# case of the encoding and charset because different versions of GMime
-# capitalize the encoding differently.
-output=$(notmuch reply id:${gen_msg_id} | perl -pe 's/=\?[^?]+\?[bB]\?/lc($&)/ge')
-test_expect_equal "$output" "\
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: =?iso-8859-1?b?4N/n?=
-To: =?utf-8?b?4piD?= <snowman@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, ☃ <snowman@example.com> wrote:
-> Encoding"
-
-test_begin_subtest "Reply with RFC 2047-encoded headers (JSON)"
-output=$(notmuch reply --format=json id:${gen_msg_id})
-test_expect_equal_json "$output" '
-{
- "original": {
- "body": [
- {
- "content": "Encoding\n",
- "content-type": "text/plain",
- "id": 1
- }
- ],
- "date_relative": "2010-01-05",
- "excluded": false,
- "filename": "'${MAIL_DIR}'/msg-012",
- "headers": {
- "Date": "Tue, 05 Jan 2010 15:43:56 +0000",
- "From": "\u2603 <snowman@example.com>",
- "Subject": "\u00e0\u00df\u00e7",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>"
- },
- "id": "'${gen_msg_id}'",
- "match": false,
- "tags": [
- "inbox",
- "unread"
- ],
- "timestamp": 1262706236
- },
- "reply-headers": {
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "In-reply-to": "<'${gen_msg_id}'>",
- "References": "<'${gen_msg_id}'>",
- "Subject": "Re: \u00e0\u00df\u00e7",
- "To": "\u2603 <snowman@example.com>"
- }
-}'
-
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="\"notmuch reply --reply-to=sender\" in several variations"
-. ./test-lib.sh
-
-test_begin_subtest "Basic reply-to-sender"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="basic reply-to-sender test"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> basic reply-to-sender test"
-
-test_begin_subtest "From Us, Basic reply to message"
-add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
- '[to]="Recipient <recipient@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="basic reply-to-from-us test"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Recipient <recipient@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> basic reply-to-from-us test"
-
-test_begin_subtest "Multiple recipients"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Multiple recipients"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> Multiple recipients"
-
-test_begin_subtest "From Us, Multiple TO recipients"
-add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
- '[to]="Recipient <recipient@example.com>, Someone Else <someone@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="From Us, Multiple TO recipients"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Recipient <recipient@example.com>, Someone Else <someone@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> From Us, Multiple TO recipients"
-
-test_begin_subtest "Reply with CC"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- '[cc]="Other Parties <cc@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply with CC"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> reply with CC"
-
-test_begin_subtest "From Us, Reply with CC"
-add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
- '[to]="Recipient <recipient@example.com>"' \
- '[cc]="Other Parties <cc@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply with CC"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Recipient <recipient@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> reply with CC"
-
-test_begin_subtest "From Us, Reply no TO but with CC"
-add_message '[from]="Notmuch Test Suite <test_suite@notmuchmail.org>"' \
- '[cc]="Other Parties <cc@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply with CC"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-Cc: Other Parties <cc@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> reply with CC"
-
-test_begin_subtest "Reply from alternate address"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite_other@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="reply from alternate address"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> reply from alternate address"
-
-test_begin_subtest "Support for Reply-To"
-add_message '[from]="Sender <sender@example.com>"' \
- [to]=test_suite@notmuchmail.org \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="support for reply-to"' \
- '[reply-to]="Sender <elsewhere@example.com>"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <elsewhere@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> support for reply-to"
-
-test_begin_subtest "Support for Reply-To with multiple recipients"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="test_suite@notmuchmail.org, Someone Else <someone@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="support for reply-to with multiple recipients"' \
- '[reply-to]="Sender <elsewhere@example.com>"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <elsewhere@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> support for reply-to with multiple recipients"
-
-test_begin_subtest "Un-munging Reply-To"
-add_message '[from]="Sender <sender@example.com>"' \
- '[to]="Some List <list@example.com>"' \
- [subject]=notmuch-reply-test \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="Un-munging Reply-To"' \
- '[reply-to]="Evil Munging List <list@example.com>"'
-
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: notmuch-reply-test
-To: Sender <sender@example.com>
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Sender <sender@example.com> wrote:
-> Un-munging Reply-To"
-
-test_begin_subtest "Message with header of exactly 200 bytes"
-add_message '[subject]="This subject is exactly 200 bytes in length. Other than its length there is not much of note here. Note that the length of 200 bytes includes the Subject: and Re: prefixes with two spaces"' \
- '[date]="Tue, 05 Jan 2010 15:43:56 -0000"' \
- '[body]="200-byte header"'
-output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
-test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.org>
-Subject: Re: This subject is exactly 200 bytes in length. Other than its
- length there is not much of note here. Note that the length of 200 bytes
- includes the Subject: and Re: prefixes with two spaces
-In-Reply-To: <${gen_msg_id}>
-References: <${gen_msg_id}>
-
-On Tue, 05 Jan 2010 15:43:56 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
-> 200-byte header"
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch search" in several variations'
-. ./test-lib.sh
-
-add_email_corpus
-
-test_begin_subtest "Search body"
-add_message '[subject]="body search"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [body]=bodysearchtest
-output=$(notmuch search bodysearchtest | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)"
-
-test_begin_subtest "Search by from:"
-add_message '[subject]="search by from"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom
-output=$(notmuch search from:searchbyfrom | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] searchbyfrom; search by from (inbox unread)"
-
-test_begin_subtest "Search by to:"
-add_message '[subject]="search by to"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto
-output=$(notmuch search to:searchbyto | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)"
-
-test_begin_subtest "Search by subject:"
-add_message [subject]=subjectsearchtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(notmuch search subject:subjectsearchtest | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)"
-
-test_begin_subtest "Search by subject (utf-8):"
-add_message [subject]=utf8-sübjéct '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(notmuch search subject:utf8-sübjéct | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
-
-test_begin_subtest "Search by id:"
-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)"
-
-test_begin_subtest "Search by tag:"
-add_message '[subject]="search by tag"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-notmuch tag +searchbytag id:${gen_msg_id}
-output=$(notmuch search tag:searchbytag | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)"
-
-test_begin_subtest "Search by thread:"
-add_message '[subject]="search by thread"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-thread_id=$(notmuch search id:${gen_msg_id} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")
-output=$(notmuch search thread:${thread_id} | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)"
-
-test_begin_subtest "Search body (phrase)"
-add_message '[subject]="body search (phrase)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="body search (phrase)"'
-add_message '[subject]="negative result"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="This phrase should not match the body search"'
-output=$(notmuch search '"body search (phrase)"' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox unread)"
-
-test_begin_subtest "Search by from: (address)"
-add_message '[subject]="search by from (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom@example.com
-output=$(notmuch search from:searchbyfrom@example.com | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] searchbyfrom@example.com; search by from (address) (inbox unread)"
-
-test_begin_subtest "Search by from: (name)"
-add_message '[subject]="search by from (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[from]="Search By From Name <test@example.com>"'
-output=$(notmuch search from:"Search By From Name" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
-
-test_begin_subtest "Search by to: (address)"
-add_message '[subject]="search by to (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto@example.com
-output=$(notmuch search to:searchbyto@example.com | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)"
-
-test_begin_subtest "Search by to: (name)"
-add_message '[subject]="search by to (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[to]="Search By To Name <test@example.com>"'
-output=$(notmuch search to:"Search By To Name" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
-
-test_begin_subtest "Search by subject: (phrase)"
-add_message '[subject]="subject search test (phrase)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-add_message '[subject]="this phrase should not match the subject search test"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(notmuch search 'subject:"subject search test (phrase)"' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)"
-
-test_begin_subtest 'Search for all messages ("*")'
-notmuch search '*' | notmuch_search_sanitize > OUTPUT
-cat <<EOF >EXPECTED
-thread:XXX 2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
-thread:XXX 2010-12-16 [1/1] Olivier Berger; Essai accentué (inbox unread)
-thread:XXX 2009-11-18 [1/1] Chris Wilson; [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
-thread:XXX 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)
-thread:XXX 2009-11-18 [2/2] Ingmar Vanhassel, Carl Worth; [notmuch] [PATCH] Typsos (inbox unread)
-thread:XXX 2009-11-18 [3/3] Adrian Perez de Castro, Keith Packard, Carl Worth; [notmuch] Introducing myself (inbox signed unread)
-thread:XXX 2009-11-18 [3/3] Israel Herraiz, Keith Packard, Carl Worth; [notmuch] New to the list (inbox unread)
-thread:XXX 2009-11-18 [3/3] Jan Janak, Carl Worth; [notmuch] What a great idea! (inbox unread)
-thread:XXX 2009-11-18 [2/2] Jan Janak, Carl Worth; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
-thread:XXX 2009-11-18 [3/3] Aron Griffis, Keith Packard, Carl Worth; [notmuch] archive (inbox unread)
-thread:XXX 2009-11-18 [2/2] Keith Packard, Carl Worth; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
-thread:XXX 2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
-thread:XXX 2009-11-18 [5/5] Mikhail Gusarov, Carl Worth, Keith Packard; [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
-thread:XXX 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)
-thread:XXX 2009-11-18 [1/1] Alexander Botero-Lowry; [notmuch] request for pull (inbox unread)
-thread:XXX 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
-thread:XXX 2009-11-18 [1/1] Rolland Santimano; [notmuch] Link to mailing list archives ? (inbox unread)
-thread:XXX 2009-11-18 [1/1] Jan Janak; [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
-thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
-thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
-thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
-thread:XXX 2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
-thread:XXX 2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
-thread:XXX 2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)
-thread:XXX 2000-01-01 [1/1] searchbyfrom; search by from (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; negative result (inbox unread)
-thread:XXX 2000-01-01 [1/1] searchbyfrom@example.com; search by from (address) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; this phrase should not match the subject search test (inbox unread)
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Search body (utf-8):"
-add_message '[subject]="utf8-message-body-subject"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="message body utf8: bödý"'
-output=$(notmuch search "bödý" | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-message-body-subject (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch search" by folder: (with variations)'
-. ./test-lib.sh
-
-add_message '[dir]=bad' '[subject]="To the bone"'
-add_message '[dir]=bad/news' '[subject]="Bears"'
-mkdir -p "${MAIL_DIR}/duplicate/bad/news"
-cp "$gen_msg_filename" "${MAIL_DIR}/duplicate/bad/news"
-
-add_message '[dir]=things' '[subject]="These are a few"'
-add_message '[dir]=things/favorite' '[subject]="Raindrops, whiskers, kettles"'
-add_message '[dir]=things/bad' '[subject]="Bites, stings, sad feelings"'
-
-test_begin_subtest "Single-world folder: specification (multiple results)"
-output=$(notmuch search folder:bad | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
-
-test_begin_subtest "Two-word path to narrow results to one"
-output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
-
-test_begin_subtest "After removing duplicate instance of matching path"
-rm -r "${MAIL_DIR}/bad/news"
-notmuch new
-output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
-
-test_begin_subtest "After rename, old path returns nothing"
-mv "${MAIL_DIR}/duplicate/bad/news" "${MAIL_DIR}/duplicate/bad/olds"
-notmuch new
-output=$(notmuch search folder:bad/news | notmuch_search_sanitize)
-test_expect_equal "$output" ""
-
-test_begin_subtest "After rename, new path returns result"
-output=$(notmuch search folder:bad/olds | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="date:since..until queries"
-. ./test-lib.sh
-
-add_email_corpus
-
-test_begin_subtest "Absolute date range"
-output=$(notmuch search date:2010-12-16..12/16/2010 | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2010-12-16 [1/1] Olivier Berger; Essai accentué (inbox unread)"
-
-test_begin_subtest "Absolute time range with TZ"
-notmuch search date:18-Nov-2009_02:19:26-0800..2009-11-18_04:49:52-06:00 | notmuch_search_sanitize > OUTPUT
-cat <<EOF >EXPECTED
-thread:XXX 2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
-thread:XXX 2009-11-18 [1/2] Carl Worth| Jan Janak; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
-thread:XXX 2009-11-18 [1/3] Carl Worth| Aron Griffis, Keith Packard; [notmuch] archive (inbox unread)
-thread:XXX 2009-11-18 [1/2] Carl Worth| Keith Packard; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='folder tags removed and added through file renames remain consistent'
-. ./test-lib.sh
-
-test_begin_subtest "No new messages"
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-
-
-test_begin_subtest "Single new message"
-generate_message
-file_x=$gen_msg_filename
-id_x=$gen_msg_id
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Add second folder for same message"
-dir=$(dirname $file_x)
-mkdir $dir/spam
-cp $file_x $dir/spam
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail."
-
-
-test_begin_subtest "Multiple files for same message"
-cat <<EOF >EXPECTED
-MAIL_DIR/msg-001
-MAIL_DIR/spam/msg-001
-EOF
-notmuch search --output=files id:$id_x | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "Test matches folder:spam"
-output=$(notmuch search folder:spam)
-test_expect_equal "$output" "thread:0000000000000001 2001-01-05 [1/1] Notmuch Test Suite; Single new message (inbox unread)"
-
-test_begin_subtest "Remove folder:spam copy of email"
-rm $dir/spam/$(basename $file_x)
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "No new mail. Detected 1 file rename."
-
-test_begin_subtest "No mails match the folder:spam search"
-output=$(notmuch search folder:spam)
-test_expect_equal "$output" ""
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='messages with unquoted . in name'
-. ./test-lib.sh
-
-add_message \
- '[from]="Some.Name for Someone <bugs@quoting.com>"' \
- '[subject]="This message needs more quoting on the From line"'
-
-add_message \
- '[from]="\"Some.Name for Someone\" <bugs@quoting.com>"' \
- '[subject]="This message has necessary quoting in place"'
-
-add_message \
- '[from]="No.match Here <filler@mail.com>"' \
- '[subject]="This message needs more quoting on the From line"'
-
-add_message \
- '[from]="\"No.match Here\" <filler@mail.com>"' \
- '[subject]="This message has necessary quoting in place"'
-
-
-test_begin_subtest "Search by first name"
-output=$(notmuch search from:Some.Name | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
-thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
-
-test_begin_subtest "Search by last name:"
-output=$(notmuch search from:Someone | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
-thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
-
-test_begin_subtest "Search by address:"
-output=$(notmuch search from:bugs@quoting.com | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
-thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)"
-
-test_begin_subtest "Search for all messages:"
-output=$(notmuch search '*' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message needs more quoting on the From line (inbox unread)
-thread:XXX 2001-01-05 [1/1] Some.Name for Someone; This message has necessary quoting in place (inbox unread)
-thread:XXX 2001-01-05 [1/1] No.match Here; This message needs more quoting on the From line (inbox unread)
-thread:XXX 2001-01-05 [1/1] No.match Here; This message has necessary quoting in place (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch search" --offset and --limit parameters'
-. ./test-lib.sh
-
-add_email_corpus
-
-for outp in messages threads; do
- test_begin_subtest "${outp}: limit does the right thing"
- notmuch search --output=${outp} "*" | head -n 20 >expected
- notmuch search --output=${outp} --limit=20 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: concatenation of limited searches"
- notmuch search --output=${outp} "*" | head -n 20 >expected
- notmuch search --output=${outp} --limit=10 "*" >output
- notmuch search --output=${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} "*"`
- notmuch search --output=${outp} "*" >expected
- notmuch search --output=${outp} --limit=$((1 + ${N})) "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: limit = 0"
- test_expect_equal "`notmuch search --output=${outp} --limit=0 "*"`" ""
-
- test_begin_subtest "${outp}: offset does the right thing"
- # note: tail -n +N is 1-based
- notmuch search --output=${outp} "*" | tail -n +21 >expected
- notmuch search --output=${outp} --offset=20 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: offset = 0"
- notmuch search --output=${outp} "*" >expected
- notmuch search --output=${outp} --offset=0 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset"
- notmuch search --output=${outp} "*" | tail -n 20 >expected
- notmuch search --output=${outp} --offset=-20 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset"
- notmuch search --output=${outp} "*" | tail -n 1 >expected
- notmuch search --output=${outp} --offset=-1 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset combined with limit"
- notmuch search --output=${outp} "*" | tail -n 20 | head -n 10 >expected
- notmuch search --output=${outp} --offset=-20 --limit=10 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset combined with equal limit"
- notmuch search --output=${outp} "*" | tail -n 20 >expected
- notmuch search --output=${outp} --offset=-20 --limit=20 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset combined with large limit"
- notmuch search --output=${outp} "*" | tail -n 20 >expected
- notmuch search --output=${outp} --offset=-20 --limit=50 "*" >output
- test_expect_equal_file expected output
-
- test_begin_subtest "${outp}: negative offset larger then results"
- N=`notmuch count --output=${outp} "*"`
- notmuch search --output=${outp} "*" >expected
- notmuch search --output=${outp} --offset=-$((1 + ${N})) "*" >output
- test_expect_equal_file expected output
-done
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='various settings for "notmuch search --output="'
-. ./test-lib.sh
-
-add_email_corpus
-
-test_begin_subtest "--output=threads"
-notmuch search --output=threads '*' | sed -e s/thread:.*/thread:THREADID/ >OUTPUT
-cat <<EOF >EXPECTED
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-thread:THREADID
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=threads --format=json"
-notmuch search --format=json --output=threads '*' | sed -e s/\".*\"/\"THREADID\"/ >OUTPUT
-cat <<EOF >EXPECTED
-["THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID",
-"THREADID"]
-EOF
-test_expect_equal_json "$(cat OUTPUT)" "$(cat EXPECTED)"
-
-test_begin_subtest "--output=messages"
-notmuch search --output=messages '*' >OUTPUT
-cat <<EOF >EXPECTED
-id:4EFC743A.3060609@april.org
-id:877h1wv7mg.fsf@inf-8657.int-evry.fr
-id:1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk
-id:877htoqdbo.fsf@yoom.home.cworth.org
-id:878we4qdqf.fsf@yoom.home.cworth.org
-id:87aaykqe24.fsf@yoom.home.cworth.org
-id:87bpj0qeng.fsf@yoom.home.cworth.org
-id:87fx8cqf8v.fsf@yoom.home.cworth.org
-id:87hbssqfix.fsf@yoom.home.cworth.org
-id:87iqd8qgiz.fsf@yoom.home.cworth.org
-id:87k4xoqgnl.fsf@yoom.home.cworth.org
-id:87ocn0qh6d.fsf@yoom.home.cworth.org
-id:87pr7gqidx.fsf@yoom.home.cworth.org
-id:867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
-id:1258532999-9316-1-git-send-email-keithp@keithp.com
-id:86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
-id:86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
-id:ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com
-id:86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me
-id:736613.51770.qm@web113505.mail.gq1.yahoo.com
-id:1258520223-15328-1-git-send-email-jan@ryngle.com
-id:ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com
-id:1258510940-7018-1-git-send-email-stewart@flamingspork.com
-id:yunzl6kd1w0.fsf@aiko.keithp.com
-id:yun1vjwegii.fsf@aiko.keithp.com
-id:yun3a4cegoa.fsf@aiko.keithp.com
-id:1258509400-32511-1-git-send-email-stewart@flamingspork.com
-id:1258506353-20352-1-git-send-email-stewart@flamingspork.com
-id:20091118010116.GC25380@dottiness.seas.harvard.edu
-id:20091118005829.GB25380@dottiness.seas.harvard.edu
-id:20091118005040.GA25380@dottiness.seas.harvard.edu
-id:cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com
-id:1258500222-32066-1-git-send-email-ingmar@exherbo.org
-id:20091117232137.GA7669@griffis1.net
-id:20091118002059.067214ed@hikari
-id:1258498485-sup-142@elly
-id:f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com
-id:f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com
-id:1258496327-12086-1-git-send-email-jan@ryngle.com
-id:1258493565-13508-1-git-send-email-keithp@keithp.com
-id:yunaayketfm.fsf@aiko.keithp.com
-id:yunbpj0etua.fsf@aiko.keithp.com
-id:1258491078-29658-1-git-send-email-dottedmag@dottedmag.net
-id:87fx8can9z.fsf@vertex.dottedmag
-id:20091117203301.GV3165@dottiness.seas.harvard.edu
-id:87lji4lx9v.fsf@yoom.home.cworth.org
-id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com
-id:87iqd9rn3l.fsf@vertex.dottedmag
-id:20091117190054.GU3165@dottiness.seas.harvard.edu
-id:87lji5cbwo.fsf@yoom.home.cworth.org
-id:1258471718-6781-2-git-send-email-dottedmag@dottedmag.net
-id:1258471718-6781-1-git-send-email-dottedmag@dottedmag.net
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=messages --format=json"
-notmuch search --format=json --output=messages '*' >OUTPUT
-cat <<EOF >EXPECTED
-["4EFC743A.3060609@april.org",
-"877h1wv7mg.fsf@inf-8657.int-evry.fr",
-"1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk",
-"877htoqdbo.fsf@yoom.home.cworth.org",
-"878we4qdqf.fsf@yoom.home.cworth.org",
-"87aaykqe24.fsf@yoom.home.cworth.org",
-"87bpj0qeng.fsf@yoom.home.cworth.org",
-"87fx8cqf8v.fsf@yoom.home.cworth.org",
-"87hbssqfix.fsf@yoom.home.cworth.org",
-"87iqd8qgiz.fsf@yoom.home.cworth.org",
-"87k4xoqgnl.fsf@yoom.home.cworth.org",
-"87ocn0qh6d.fsf@yoom.home.cworth.org",
-"87pr7gqidx.fsf@yoom.home.cworth.org",
-"867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
-"1258532999-9316-1-git-send-email-keithp@keithp.com",
-"86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
-"86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
-"ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com",
-"86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",
-"736613.51770.qm@web113505.mail.gq1.yahoo.com",
-"1258520223-15328-1-git-send-email-jan@ryngle.com",
-"ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com",
-"1258510940-7018-1-git-send-email-stewart@flamingspork.com",
-"yunzl6kd1w0.fsf@aiko.keithp.com",
-"yun1vjwegii.fsf@aiko.keithp.com",
-"yun3a4cegoa.fsf@aiko.keithp.com",
-"1258509400-32511-1-git-send-email-stewart@flamingspork.com",
-"1258506353-20352-1-git-send-email-stewart@flamingspork.com",
-"20091118010116.GC25380@dottiness.seas.harvard.edu",
-"20091118005829.GB25380@dottiness.seas.harvard.edu",
-"20091118005040.GA25380@dottiness.seas.harvard.edu",
-"cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com",
-"1258500222-32066-1-git-send-email-ingmar@exherbo.org",
-"20091117232137.GA7669@griffis1.net",
-"20091118002059.067214ed@hikari",
-"1258498485-sup-142@elly",
-"f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com",
-"f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com",
-"1258496327-12086-1-git-send-email-jan@ryngle.com",
-"1258493565-13508-1-git-send-email-keithp@keithp.com",
-"yunaayketfm.fsf@aiko.keithp.com",
-"yunbpj0etua.fsf@aiko.keithp.com",
-"1258491078-29658-1-git-send-email-dottedmag@dottedmag.net",
-"87fx8can9z.fsf@vertex.dottedmag",
-"20091117203301.GV3165@dottiness.seas.harvard.edu",
-"87lji4lx9v.fsf@yoom.home.cworth.org",
-"cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com",
-"87iqd9rn3l.fsf@vertex.dottedmag",
-"20091117190054.GU3165@dottiness.seas.harvard.edu",
-"87lji5cbwo.fsf@yoom.home.cworth.org",
-"1258471718-6781-2-git-send-email-dottedmag@dottedmag.net",
-"1258471718-6781-1-git-send-email-dottedmag@dottedmag.net"]
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=files"
-notmuch search --output=files '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
-cat <<EOF >EXPECTED
-MAIL_DIR/cur/52:2,
-MAIL_DIR/cur/53:2,
-MAIL_DIR/cur/50:2,
-MAIL_DIR/cur/49:2,
-MAIL_DIR/cur/48:2,
-MAIL_DIR/cur/47:2,
-MAIL_DIR/cur/46:2,
-MAIL_DIR/cur/45:2,
-MAIL_DIR/cur/44:2,
-MAIL_DIR/cur/43:2,
-MAIL_DIR/cur/42:2,
-MAIL_DIR/cur/41:2,
-MAIL_DIR/cur/40:2,
-MAIL_DIR/cur/39:2,
-MAIL_DIR/cur/38:2,
-MAIL_DIR/cur/37:2,
-MAIL_DIR/cur/36:2,
-MAIL_DIR/cur/35:2,
-MAIL_DIR/cur/34:2,
-MAIL_DIR/cur/33:2,
-MAIL_DIR/cur/32:2,
-MAIL_DIR/cur/31:2,
-MAIL_DIR/cur/30:2,
-MAIL_DIR/cur/29:2,
-MAIL_DIR/cur/28:2,
-MAIL_DIR/cur/27:2,
-MAIL_DIR/cur/26:2,
-MAIL_DIR/cur/25:2,
-MAIL_DIR/cur/24:2,
-MAIL_DIR/cur/23:2,
-MAIL_DIR/cur/22:2,
-MAIL_DIR/cur/21:2,
-MAIL_DIR/cur/19:2,
-MAIL_DIR/cur/18:2,
-MAIL_DIR/cur/51:2,
-MAIL_DIR/cur/20:2,
-MAIL_DIR/cur/17:2,
-MAIL_DIR/cur/16:2,
-MAIL_DIR/cur/15:2,
-MAIL_DIR/cur/14:2,
-MAIL_DIR/cur/13:2,
-MAIL_DIR/cur/12:2,
-MAIL_DIR/cur/11:2,
-MAIL_DIR/cur/10:2,
-MAIL_DIR/cur/09:2,
-MAIL_DIR/cur/08:2,
-MAIL_DIR/cur/06:2,
-MAIL_DIR/cur/05:2,
-MAIL_DIR/cur/04:2,
-MAIL_DIR/cur/03:2,
-MAIL_DIR/cur/07:2,
-MAIL_DIR/cur/02:2,
-MAIL_DIR/cur/01:2,
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=files --duplicate=1"
-notmuch search --output=files --duplicate=1 '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
-cat <<EOF >EXPECTED
-MAIL_DIR/cur/52:2,
-MAIL_DIR/cur/53:2,
-MAIL_DIR/cur/50:2,
-MAIL_DIR/cur/49:2,
-MAIL_DIR/cur/48:2,
-MAIL_DIR/cur/47:2,
-MAIL_DIR/cur/46:2,
-MAIL_DIR/cur/45:2,
-MAIL_DIR/cur/44:2,
-MAIL_DIR/cur/43:2,
-MAIL_DIR/cur/42:2,
-MAIL_DIR/cur/41:2,
-MAIL_DIR/cur/40:2,
-MAIL_DIR/cur/39:2,
-MAIL_DIR/cur/38:2,
-MAIL_DIR/cur/37:2,
-MAIL_DIR/cur/36:2,
-MAIL_DIR/cur/35:2,
-MAIL_DIR/cur/34:2,
-MAIL_DIR/cur/33:2,
-MAIL_DIR/cur/32:2,
-MAIL_DIR/cur/31:2,
-MAIL_DIR/cur/30:2,
-MAIL_DIR/cur/29:2,
-MAIL_DIR/cur/28:2,
-MAIL_DIR/cur/27:2,
-MAIL_DIR/cur/26:2,
-MAIL_DIR/cur/25:2,
-MAIL_DIR/cur/24:2,
-MAIL_DIR/cur/23:2,
-MAIL_DIR/cur/22:2,
-MAIL_DIR/cur/21:2,
-MAIL_DIR/cur/19:2,
-MAIL_DIR/cur/18:2,
-MAIL_DIR/cur/20:2,
-MAIL_DIR/cur/17:2,
-MAIL_DIR/cur/16:2,
-MAIL_DIR/cur/15:2,
-MAIL_DIR/cur/14:2,
-MAIL_DIR/cur/13:2,
-MAIL_DIR/cur/12:2,
-MAIL_DIR/cur/11:2,
-MAIL_DIR/cur/10:2,
-MAIL_DIR/cur/09:2,
-MAIL_DIR/cur/08:2,
-MAIL_DIR/cur/06:2,
-MAIL_DIR/cur/05:2,
-MAIL_DIR/cur/04:2,
-MAIL_DIR/cur/03:2,
-MAIL_DIR/cur/07:2,
-MAIL_DIR/cur/02:2,
-MAIL_DIR/cur/01:2,
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=files --format=json"
-notmuch search --format=json --output=files '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
-cat <<EOF >EXPECTED
-["MAIL_DIR/cur/52:2,",
-"MAIL_DIR/cur/53:2,",
-"MAIL_DIR/cur/50:2,",
-"MAIL_DIR/cur/49:2,",
-"MAIL_DIR/cur/48:2,",
-"MAIL_DIR/cur/47:2,",
-"MAIL_DIR/cur/46:2,",
-"MAIL_DIR/cur/45:2,",
-"MAIL_DIR/cur/44:2,",
-"MAIL_DIR/cur/43:2,",
-"MAIL_DIR/cur/42:2,",
-"MAIL_DIR/cur/41:2,",
-"MAIL_DIR/cur/40:2,",
-"MAIL_DIR/cur/39:2,",
-"MAIL_DIR/cur/38:2,",
-"MAIL_DIR/cur/37:2,",
-"MAIL_DIR/cur/36:2,",
-"MAIL_DIR/cur/35:2,",
-"MAIL_DIR/cur/34:2,",
-"MAIL_DIR/cur/33:2,",
-"MAIL_DIR/cur/32:2,",
-"MAIL_DIR/cur/31:2,",
-"MAIL_DIR/cur/30:2,",
-"MAIL_DIR/cur/29:2,",
-"MAIL_DIR/cur/28:2,",
-"MAIL_DIR/cur/27:2,",
-"MAIL_DIR/cur/26:2,",
-"MAIL_DIR/cur/25:2,",
-"MAIL_DIR/cur/24:2,",
-"MAIL_DIR/cur/23:2,",
-"MAIL_DIR/cur/22:2,",
-"MAIL_DIR/cur/21:2,",
-"MAIL_DIR/cur/19:2,",
-"MAIL_DIR/cur/18:2,",
-"MAIL_DIR/cur/51:2,",
-"MAIL_DIR/cur/20:2,",
-"MAIL_DIR/cur/17:2,",
-"MAIL_DIR/cur/16:2,",
-"MAIL_DIR/cur/15:2,",
-"MAIL_DIR/cur/14:2,",
-"MAIL_DIR/cur/13:2,",
-"MAIL_DIR/cur/12:2,",
-"MAIL_DIR/cur/11:2,",
-"MAIL_DIR/cur/10:2,",
-"MAIL_DIR/cur/09:2,",
-"MAIL_DIR/cur/08:2,",
-"MAIL_DIR/cur/06:2,",
-"MAIL_DIR/cur/05:2,",
-"MAIL_DIR/cur/04:2,",
-"MAIL_DIR/cur/03:2,",
-"MAIL_DIR/cur/07:2,",
-"MAIL_DIR/cur/02:2,",
-"MAIL_DIR/cur/01:2,"]
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=files --format=json --duplicate=2"
-notmuch search --format=json --output=files --duplicate=2 '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
-cat <<EOF >EXPECTED
-["MAIL_DIR/cur/51:2,"]
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=tags"
-notmuch search --output=tags '*' >OUTPUT
-cat <<EOF >EXPECTED
-attachment
-inbox
-signed
-unread
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=tags --format=json"
-notmuch search --format=json --output=tags '*' >OUTPUT
-cat <<EOF >EXPECTED
-["attachment",
-"inbox",
-"signed",
-"unread"]
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "sanitize output for quoted-printable line-breaks in author and subject"
-add_message "[subject]='two =?ISO-8859-1?Q?line=0A_subject?=
- headers'"
-notmuch search id:"$gen_msg_id" | notmuch_search_sanitize >OUTPUT
-cat <<EOF >EXPECTED
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; two line? subject headers (inbox unread)
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "search for non-existent message prints nothing"
-notmuch search "no-message-matches-this" > OUTPUT
-echo -n >EXPECTED
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "search --format=json for non-existent message prints proper empty json"
-notmuch search --format=json "no-message-matches-this" > OUTPUT
-echo "[]" >EXPECTED
-test_expect_equal_file OUTPUT EXPECTED
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-# Test to demonstrate a position overlap bug.
-#
-# At one point, notmuch would index terms incorrectly in the case of
-# calling index_terms multiple times for a single field. The term
-# generator was being reset to position 0 each time. This means that
-# with text such as:
-#
-# To: a@b.c, x@y.z
-#
-# one could get a bogus match by searching for:
-#
-# To: a@y.c
-#
-# Thanks to Mark Anderson for reporting the bug, (and providing a nice,
-# minimal test case that inspired what is used here), in
-# id:3wd4o8wa7fx.fsf@testarossa.amd.com
-
-test_description='that notmuch does not overlap term positions'
-. ./test-lib.sh
-
-add_message '[to]="a@b.c, x@y.z"'
-
-test_begin_subtest "Search for a@b.c matches"
-output=$(notmuch search a@b.c | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Test message #1 (inbox unread)"
-
-test_begin_subtest "Search for x@y.z matches"
-output=$(notmuch search x@y.z | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Test message #1 (inbox unread)"
-
-test_begin_subtest "Search for a@y.c must not match"
-output=$(notmuch search a@y.c | notmuch_search_sanitize)
-test_expect_equal "$output" ""
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-
-test_description='"notmuch setup"'
-. ./test-lib.sh
-
-test_begin_subtest "Create a new config interactively"
-notmuch --config=new-notmuch-config > /dev/null <<EOF
-Test Suite
-test.suite@example.com
-another.suite@example.com
-
-/path/to/maildir
-foo bar
-baz
-EOF
-output=$(notmuch --config=new-notmuch-config config list)
-test_expect_equal "$output" "\
-database.path=/path/to/maildir
-user.name=Test Suite
-user.primary_email=test.suite@example.com
-user.other_email=another.suite@example.com;
-new.tags=foo;bar;
-new.ignore=
-search.exclude_tags=baz;
-maildir.synchronize_flags=true"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="--format=sexp output"
-. ./test-lib.sh
-
-test_begin_subtest "Show message: sexp"
-add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"sexp-show-message\""
-output=$(notmuch show --format=sexp "sexp-show-message")
-test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"sexp-show-message\n\"))) ())))"
-
-# This should be the same output as above.
-test_begin_subtest "Show message: sexp --body=true"
-output=$(notmuch show --format=sexp --body=true "sexp-show-message")
-test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"sexp-show-message\n\"))) ())))"
-
-test_begin_subtest "Show message: sexp --body=false"
-output=$(notmuch show --format=sexp --body=false "sexp-show-message")
-test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-subject\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Bcc \"test_suite+bcc@notmuchmail.org\" :Reply-To \"test_suite+replyto@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\")) ())))"
-
-test_begin_subtest "Search message: sexp"
-add_message "[subject]=\"sexp-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"sexp-search-message\""
-output=$(notmuch search --format=sexp "sexp-search-message" | notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0000000000000002\" :timestamp 946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch Test Suite\" :subject \"sexp-search-subject\" :query (\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
-
-test_begin_subtest "Show message: sexp, utf-8"
-add_message "[subject]=\"sexp-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
-output=$(notmuch show --format=sexp "jsön-show-méssage")
-test_expect_equal "$output" "((((:id \"${gen_msg_id}\" :match t :excluded nil :filename \"${gen_msg_filename}\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\" \"unread\") :headers (:Subject \"sexp-show-utf8-body-sübjéct\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"text/plain\" :content \"jsön-show-méssage\n\"))) ())))"
-
-test_begin_subtest "Show message: sexp, inline attachment filename"
-subject='sexp-show-inline-attachment-filename'
-id="sexp-show-inline-attachment-filename@notmuchmail.org"
-emacs_fcc_message \
- "$subject" \
- 'This is a test message with inline attachment with a filename' \
- "(mml-attach-file \"$TEST_DIRECTORY/README\" nil nil \"inline\")
- (message-goto-eoh)
- (insert \"Message-ID: <$id>\n\")"
-output=$(notmuch show --format=sexp "id:$id")
-filename=$(notmuch search --output=files "id:$id")
-# Get length of README after base64-encoding, minus additional newline.
-attachment_length=$(( $(base64 $TEST_DIRECTORY/README | wc -c) - 1 ))
-test_expect_equal "$output" "((((:id \"$id\" :match t :excluded nil :filename \"$filename\" :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\") :headers (:Subject \"sexp-show-inline-attachment-filename\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"test_suite@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\") :body ((:id 1 :content-type \"multipart/mixed\" :content ((:id 2 :content-type \"text/plain\" :content \"This is a test message with inline attachment with a filename\") (:id 3 :content-type \"application/octet-stream\" :filename \"README\" :content-transfer-encoding \"base64\" :content-length $attachment_length))))) ())))"
-
-test_begin_subtest "Search message: sexp, utf-8"
-add_message "[subject]=\"sexp-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
-output=$(notmuch search --format=sexp "jsön-search-méssage" | notmuch_search_sanitize)
-test_expect_equal "$output" "((:thread \"0000000000000005\" :timestamp 946728000 :date_relative \"2000-01-01\" :matched 1 :total 1 :authors \"Notmuch Test Suite\" :subject \"sexp-search-utf8-body-sübjéct\" :query (\"id:$gen_msg_id\" nil) :tags (\"inbox\" \"unread\")))"
-
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-#
-# Copyright (c) 2011 David Bremner
-#
-
-# This test tests whether hiding Xapian::Error symbols in libnotmuch
-# also hides them for other users of libxapian. This is motivated by
-# the discussion in http://gcc.gnu.org/wiki/Visibility'
-
-test_description='exception symbol hiding'
-
-. ./test-lib.sh
-
-run_test(){
- result=$(LD_LIBRARY_PATH="$TEST_DIRECTORY/../lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" $TEST_DIRECTORY/symbol-test 2>&1)
-}
-
-output="A Xapian exception occurred opening database: Couldn't stat 'fakedb/.notmuch/xapian'
-caught No chert database found at path \`./nonexistant'"
-
-mkdir -p fakedb/.notmuch
-
-test_expect_success 'running test' run_test
-
-test_begin_subtest 'checking output'
-test_expect_equal "$result" "$output"
-
-test_begin_subtest 'comparing existing to exported symbols'
-objdump -t $TEST_DIRECTORY/../lib/*.o | awk '$4 == ".text" && $6 ~ "^notmuch" {print $6}' | sort | uniq > ACTUAL
-sed -n 's/[[:blank:]]*\(notmuch_[^;]*\);/\1/p' $TEST_DIRECTORY/../notmuch.sym | sort | uniq > EXPORTED
-test_expect_equal_file EXPORTED ACTUAL
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description='"notmuch tag"'
-. ./test-lib.sh
-
-add_message '[subject]=One'
-add_message '[subject]=Two'
-
-test_begin_subtest "Adding tags"
-notmuch tag +tag1 +tag2 +tag3 \*
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 tag2 tag3 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag2 tag3 unread)"
-
-test_begin_subtest "Removing tags"
-notmuch tag -tag1 -tag2 \*
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag3 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag3 unread)"
-
-test_expect_code 1 "No tag operations" 'notmuch tag One'
-test_expect_code 1 "No query" 'notmuch tag +tag2'
-
-test_begin_subtest "Redundant tagging"
-notmuch tag +tag1 -tag3 One
-notmuch tag +tag1 -tag3 \*
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
-
-test_begin_subtest "Remove all"
-notmuch tag --remove-all One
-notmuch tag --remove-all +tag5 +tag6 +unread Two
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One ()
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (tag5 tag6 unread)"
-
-test_begin_subtest "Remove all with a no-op"
-notmuch tag +inbox +tag1 +unread One
-notmuch tag --remove-all +foo +inbox +tag1 -foo +unread Two
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
-
-test_begin_subtest "Special characters in tags"
-notmuch tag +':" ' \*
-notmuch tag -':" ' Two
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)"
-
-test_begin_subtest "Tagging order"
-notmuch tag +tag4 -tag4 One
-notmuch tag -tag4 +tag4 Two
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag4 unread)"
-
-test_begin_subtest "--batch"
-notmuch tag --batch <<EOF
-# %20 is a space in tag
--:"%20 -tag1 +tag5 +tag6 -- One
-+tag1 -tag1 -tag4 +tag4 -- Two
--tag6 One
-+tag5 Two
-EOF
-output=$(notmuch search \* | notmuch_search_sanitize)
-test_expect_equal "$output" "\
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (inbox tag5 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag4 tag5 unread)"
-
-# generate a common input file for the next several tests.
-cat > batch.in <<EOF
-# %40 is an @ in tag
-+%40 -tag5 +tag6 -- One
-+tag1 -tag1 -tag4 +tag4 -- Two
--tag5 +tag6 Two
-EOF
-
-cat > batch.expected <<EOF
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (@ inbox tag6 unread)
-thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag4 tag6 unread)
-EOF
-
-test_begin_subtest "--input"
-notmuch dump --format=batch-tag > backup.tags
-notmuch tag --input=batch.in
-notmuch search \* | notmuch_search_sanitize > OUTPUT
-notmuch restore --format=batch-tag < backup.tags
-test_expect_equal_file batch.expected OUTPUT
-
-test_begin_subtest "--batch --input"
-notmuch dump --format=batch-tag > backup.tags
-notmuch tag --batch --input=batch.in
-notmuch search \* | notmuch_search_sanitize > OUTPUT
-notmuch restore --format=batch-tag < backup.tags
-test_expect_equal_file batch.expected OUTPUT
-
-test_begin_subtest "--batch, blank lines and comments"
-notmuch dump | sort > EXPECTED
-notmuch tag --batch <<EOF
-# this line is a comment; the next has only white space
-
-
-# the previous line is empty
-EOF
-notmuch dump | sort > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest '--batch: checking error messages'
-notmuch dump --format=batch-tag > BACKUP
-notmuch tag --batch <<EOF 2>OUTPUT
-# the next line has a space
-
-# this line has no tag operations, but this is permitted in batch format.
-a
-+0
-+a +b
-# trailing whitespace
-+a +b
-+c +d --
-# this is a harmless comment, do not yell about it.
-
-# the previous line was blank; also no yelling please
-+%zz -- id:whatever
-# the next non-comment line should report an an empty tag error for
-# batch tagging, but not for restore
-+ +e -- id:foo
-+- -- id:foo
-EOF
-
-cat <<EOF > EXPECTED
-Warning: no query string [+0]
-Warning: no query string [+a +b]
-Warning: missing query string [+a +b ]
-Warning: no query string after -- [+c +d --]
-Warning: hex decoding of tag %zz failed [+%zz -- id:whatever]
-Warning: empty tag forbidden [+ +e -- id:foo]
-Warning: tag starting with '-' forbidden [+- -- id:foo]
-EOF
-
-notmuch restore --format=batch-tag < BACKUP
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest '--batch: tags with quotes'
-notmuch dump --format=batch-tag > BACKUP
-
-notmuch tag --batch <<EOF
-+%22%27%22%27%22%22%27%27 -- One
--%22%27%22%27%22%22%27%27 -- One
-+%22%27%22%22%22%27 -- One
-+%22%27%22%27%22%22%27%27 -- Two
-EOF
-
-cat <<EOF > EXPECTED
-+%22%27%22%22%22%27 +inbox +tag5 +unread -- id:msg-001@notmuch-test-suite
-+%22%27%22%27%22%22%27%27 +inbox +tag4 +tag5 +unread -- id:msg-002@notmuch-test-suite
-EOF
-
-notmuch dump --format=batch-tag | sort > OUTPUT
-notmuch restore --format=batch-tag < BACKUP
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest '--batch: tags with punctuation and space'
-notmuch dump --format=batch-tag > BACKUP
-
-notmuch tag --batch <<EOF
-+%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
--%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
-+%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%20%60%7e -- Two
--%21@%23%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%20%60%7e -- Two
-+%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- One
-+%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e -- Two
-EOF
-
-cat <<EOF > EXPECTED
-+%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e +inbox +tag4 +tag5 +unread -- id:msg-002@notmuch-test-suite
-+%21@%23%20%24%25%5e%26%2a%29-_=+%5b%7b%5c%20%7c%3b%3a%27%20%22,.%3c%60%7e +inbox +tag5 +unread -- id:msg-001@notmuch-test-suite
-EOF
-
-notmuch dump --format=batch-tag | sort > OUTPUT
-notmuch restore --format=batch-tag < BACKUP
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest '--batch: unicode tags'
-notmuch dump --format=batch-tag > BACKUP
-
-notmuch tag --batch <<EOF
-+%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 -- One
-+=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d -- One
-+A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 -- One
-+R -- One
-+%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 -- One
-+%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- One
-+L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 -- One
-+P%c4%98%2f -- One
-+%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d -- One
-+%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b -- One
-+%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +R +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b -- Two
-EOF
-
-cat <<EOF > EXPECTED
-+%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +R +inbox +tag4 +tag5 +unread +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- id:msg-002@notmuch-test-suite
-+%2a@%7d%cf%b5%f4%85%80%adO3%da%a7 +=%e0%ac%95%c8%b3+%ef%aa%95%c8%a64w%c7%9d%c9%a2%cf%b3%d6%82%24B%c4%a9%c5%a1UX%ee%99%b0%27E7%ca%a4%d0%8b%5d +A%e1%a0%bc%de%8b%d5%b2V%d9%9b%f3%b5%a2%a3M%d8%a1u@%f0%a0%ac%948%7e%f0%ab%86%af%27 +L%df%85%ef%a1%a5m@%d3%96%c2%ab%d4%9f%ca%b8%f3%b3%a2%bf%c7%b1_u%d7%b4%c7%b1 +P%c4%98%2f +R +inbox +tag5 +unread +%7e%d1%8b%25%ec%a0%ae%d1%a0M%3b%e3%b6%b7%e9%a4%87%3c%db%9a%cc%a8%e1%96%9d +%c4%bf7%c7%ab9H%c4%99k%ea%91%bd%c3%8ck%e2%b3%8dk%c5%952V%e4%99%b2%d9%b3%e4%8b%bda%5b%24%c7%9b +%da%88=f%cc%b9I%ce%af%7b%c9%97%e3%b9%8bH%cb%92X%d2%8c6 +%dc%9crh%d2%86B%e5%97%a2%22t%ed%99%82d -- id:msg-001@notmuch-test-suite
-EOF
-
-notmuch dump --format=batch-tag | sort > OUTPUT
-notmuch restore --format=batch-tag < BACKUP
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "--batch: only space and % needs to be encoded."
-notmuch dump --format=batch-tag > BACKUP
-
-notmuch tag --batch <<EOF
-+winner *
-+foo::bar%25 -- (One and Two) or (One and tag:winner)
-+found::it -- tag:foo::bar%
-# ignore this line and the next
-
-+space%20in%20tags -- Two
-# add tag '(tags)', among other stunts.
-+crazy{ +(tags) +&are +#possible\ -- tag:"space in tags"
-+match*crazy -- tag:crazy{
-+some_tag -- id:"this is ""nauty)"""
-EOF
-
-cat <<EOF > EXPECTED
-+%23possible%5c +%26are +%28tags%29 +crazy%7b +inbox +match%2acrazy +space%20in%20tags +tag4 +tag5 +unread +winner -- id:msg-002@notmuch-test-suite
-+foo%3a%3abar%25 +found%3a%3ait +inbox +tag5 +unread +winner -- id:msg-001@notmuch-test-suite
-EOF
-
-notmuch dump --format=batch-tag | sort > OUTPUT
-notmuch restore --format=batch-tag < BACKUP
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest '--batch: unicode message-ids'
-
-${TEST_DIRECTORY}/random-corpus --config-path=${NOTMUCH_CONFIG} \
- --num-messages=100
-
-notmuch dump --format=batch-tag | sed 's/^.* -- /+common_tag -- /' | \
- sort > EXPECTED
-
-notmuch dump --format=batch-tag | sed 's/^.* -- / -- /' | \
- notmuch restore --format=batch-tag
-
-notmuch tag --batch < EXPECTED
-
-notmuch dump --format=batch-tag| \
- sort > OUTPUT
-
-test_expect_equal_file EXPECTED OUTPUT
-
-test_expect_code 1 "Empty tag names" 'notmuch tag + One'
-
-test_expect_code 1 "Tag name beginning with -" 'notmuch tag +- One'
-
-test_done
--- /dev/null
+# See Makefile.local for the list of files to be compiled in this
+# directory.
+all:
+ $(MAKE) -C ../.. all
+
+.DEFAULT:
+ $(MAKE) -C ../.. $@
--- /dev/null
+# -*- makefile -*-
+
+TEST_DATABASE_MIRROR=http://notmuchmail.org/releases/test-databases
+
+dir := test/test-databases
+
+test_databases := $(dir)/database-v1.tar.xz
+
+%.tar.xz:
+ wget -nv -O $@ ${TEST_DATABASE_MIRROR}/$(notdir $@);
+
+download-test-databases: ${test_databases}
+
+DISTCLEAN := $(DISTCLEAN) ${test_databases}
--- /dev/null
+4299e051b10e1fa7b33ea2862790a09ebfe96859681804e5251e130f800e69d2 database-v1.tar.xz
PATH=$GIT_VALGRIND/bin:$PATH
GIT_EXEC_PATH=$GIT_VALGRIND/bin
export GIT_VALGRIND
- test -n "$notmuch_path" && MANPATH="$notmuch_path/man:$MANPATH"
+ test -n "$notmuch_path" && MANPATH="$notmuch_path/doc/_build/man"
else # normal case
if test -n "$notmuch_path"
then
PATH="$notmuch_path:$PATH"
- MANPATH="$notmuch_path/man:$MANPATH"
+ MANPATH="$notmuch_path/doc/_build/man"
fi
fi
export PATH MANPATH
(t
(notmuch-test-report-unexpected output expected)))))
+
+;; For historical reasons, we hide deleted tags by default in the test
+;; suite
+(setq notmuch-tag-deleted-formats
+ '((".*" nil)))
# Make sure echo builtin does not expand backslash-escape sequences by default.
shopt -u xpg_echo
+this_test=${0##*/}
+this_test=${this_test%.sh}
+this_test_bare=${this_test#T[0-9][0-9][0-9]-}
+
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
case "$GIT_TEST_TEE_STARTED, $* " in
;;
*' --tee '*|*' --va'*)
mkdir -p test-results
- BASE=test-results/$(basename "$0" .sh)
+ BASE=test-results/$this_test
(GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
echo $? > $BASE.exit) | tee $BASE.out
test "$(cat $BASE.exit)" = 0
exit 0
fi
-echo $(basename "$0"): "Testing ${test_description}"
+test_description_printed=
+print_test_description ()
+{
+ test -z "$test_description_printed" || return 0
+ echo
+ echo $this_test: "Testing ${test_description}"
+ test_description_printed=1
+}
+if [ -z "$NOTMUCH_TEST_QUIET" ]
+then
+ print_test_description
+fi
exec 5>&1
# we use decreasing timestamps here for historical reasons;
# the existing test suite when we converted to unique timestamps just
# happened to have signicantly fewer failures with that choice.
- template[date]=$(TZ=UTC printf "%(%a, %d %b %Y %T %z)T\n" \
- $((978709437 - gen_msg_cnt)))
+ local date_secs=$((978709437 - gen_msg_cnt))
+ # printf %(..)T is bash 4.2+ feature. use perl fallback if needed...
+ TZ=UTC printf -v template[date] "%(%a, %d %b %Y %T %z)T" $date_secs 2>/dev/null ||
+ template[date]=`perl -le 'use POSIX "strftime";
+ @time = gmtime '"$date_secs"';
+ print strftime "%a, %d %b %Y %T +0000", @time'`
fi
additional_headers=""
test_expect_equal "$output" "$expected" "$@"
}
+# Sort the top-level list of JSON data from stdin.
+test_sort_json () {
+ PYTHONIOENCODING=utf-8 python -c \
+ "import sys, json; json.dump(sorted(json.load(sys.stdin)),sys.stdout)"
+}
+
test_emacs_expect_t () {
test "$#" = 2 && { prereq=$1; shift; } || prereq=
test "$#" = 1 ||
perl -pe 's/("?thread"?: ?)("?)................("?)/\1\2XXX\3/'
}
+notmuch_search_files_sanitize()
+{
+ sed -e "s,$MAIL_DIR,MAIL_DIR,"
+}
+
NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'
notmuch_show_sanitize ()
{
return
fi
test_success=$(($test_success + 1))
+ if test -n "$NOTMUCH_TEST_QUIET"; then
+ return 0
+ fi
say_color pass "%-6s" "PASS"
echo " $test_subtest_name"
}
return
fi
test_failure=$(($test_failure + 1))
+ print_test_description
test_failure_message_ "FAIL" "$test_subtest_name" "$@"
test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
return 1
case $this_test.$test_count in
$skp)
to_skip=t
+ break
+ esac
+ case $this_test_bare.$test_count in
+ $skp)
+ to_skip=t
+ break
esac
done
if test -z "$to_skip" && test -n "$prereq" &&
GIT_EXIT_OK=t
test_results_dir="$TEST_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
- test_results_path="$test_results_dir/${0%.sh}"
+ test_results_path="$test_results_dir/$this_test"
echo "total $test_count" >> $test_results_path
echo "success $test_success" >> $test_results_path
echo "failed $test_failure" >> $test_results_path
echo "" >> $test_results_path
- echo
-
[ -n "$EMACS_SERVER" ] && test_emacs '(kill-emacs)'
if [ "$test_failure" = "0" ]; then
# Here's what we are using here:
#
-# --no-init-file Don't load users ~/.emacs
-#
-# --no-site-file Don't load the site-wide startup stuff
+# --quick Use minimal customization. This implies --no-init-file,
+# --no-site-file and (emacs 24) --no-site-lisp
#
# --directory Ensure that the local elisp sources are found
#
# --load Force loading of notmuch.el and test-lib.el
-exec ${TEST_EMACS} --no-init-file --no-site-file \
+exec ${TEST_EMACS} --quick \
--directory "$TEST_DIRECTORY/../emacs" --load notmuch.el \
--directory "$TEST_DIRECTORY" --load test-lib.el \
"\$@"
test -z "$missing_dependencies" || return
if [ -z "$EMACS_SERVER" ]; then
- emacs_tests="$(basename $0).el"
+ emacs_tests="${this_test_bare}.el"
if [ -f "$TEST_DIRECTORY/$emacs_tests" ]; then
load_emacs_tests="--eval '(load \"$emacs_tests\")'"
else
exec 4>test.output 3>&4
fi
-this_test=${0##*/}
for skp in $NOTMUCH_SKIP_TESTS
do
to_skip=
case "$this_test" in
$skp)
to_skip=t
+ break
+ esac
+ case "$this_test_bare" in
+ $skp)
+ to_skip=t
+ break
esac
done
case "$to_skip" in
+
test-verbose: Testing the verbosity options of the test framework itself.
PASS print something in test_expect_success and pass
FAIL print something in test_expect_success and fail
+
test-verbose: Testing the verbosity options of the test framework itself.
hello stdout
hello stderr
+++ /dev/null
-#!/usr/bin/env bash
-test_description="--format=text output"
-. ./test-lib.sh
-
-test_begin_subtest "Show message: text"
-add_message "[subject]=\"text-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"text-show-message\""
-output=$(notmuch show --format=text "text-show-message" | notmuch_show_sanitize_all)
-test_expect_equal "$output" "\
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (inbox unread)
-Subject: text-show-subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Sat, 01 Jan 2000 12:00:00 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-text-show-message
-\fpart}
-\fbody}
-\fmessage}"
-
-test_begin_subtest "Search message: text"
-add_message "[subject]=\"text-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"text-search-message\""
-output=$(notmuch search --format=text "text-search-message" | notmuch_search_sanitize)
-test_expect_equal "$output" \
-"thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; text-search-subject (inbox unread)"
-
-test_begin_subtest "Show message: text, utf-8"
-add_message "[subject]=\"text-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"tëxt-show-méssage\""
-output=$(notmuch show --format=text "tëxt-show-méssage" | notmuch_show_sanitize_all)
-test_expect_equal "$output" "\
-\fmessage{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (inbox unread)
-Subject: text-show-utf8-body-sübjéct
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Sat, 01 Jan 2000 12:00:00 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-tëxt-show-méssage
-\fpart}
-\fbody}
-\fmessage}"
-
-test_begin_subtest "Search message: text, utf-8"
-add_message "[subject]=\"text-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"tëxt-search-méssage\""
-output=$(notmuch search --format=text "tëxt-search-méssage" | notmuch_search_sanitize)
-test_expect_equal "$output" \
-"thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; text-search-utf8-body-sübjéct (inbox unread)"
-
-add_email_corpus
-
-test_begin_subtest "Search message tags: text0"
-cat <<EOF > EXPECTED
-attachment inbox signed unread
-EOF
-notmuch search --format=text0 --output=tags '*' | xargs -0 | notmuch_search_sanitize > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-# Use tr(1) to convert --output=text0 to --output=text for
-# comparison. Also translate newlines to spaces to fail with more
-# noise if they are present as delimiters instead of null
-# characters. This assumes there are no newlines in the data.
-test_begin_subtest "Compare text vs. text0 for threads"
-notmuch search --format=text --output=threads '*' | notmuch_search_sanitize > EXPECTED
-notmuch search --format=text0 --output=threads '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "Compare text vs. text0 for messages"
-notmuch search --format=text --output=messages '*' | notmuch_search_sanitize > EXPECTED
-notmuch search --format=text0 --output=messages '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "Compare text vs. text0 for files"
-notmuch search --format=text --output=files '*' | notmuch_search_sanitize > EXPECTED
-notmuch search --format=text0 --output=files '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-test_begin_subtest "Compare text vs. text0 for tags"
-notmuch search --format=text --output=tags '*' | notmuch_search_sanitize > EXPECTED
-notmuch search --format=text0 --output=tags '*' | tr "\n\0" " \n" | notmuch_search_sanitize > OUTPUT
-test_expect_equal_file EXPECTED OUTPUT
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="naming of threads with changing subject"
-. ./test-lib.sh
-
-test_begin_subtest "Initial thread name (oldest-first search)"
-add_message '[subject]="thread-naming: Initial thread subject"' \
- '[date]="Fri, 05 Jan 2001 15:43:56 -0000"'
-first=${gen_msg_cnt}
-parent=${gen_msg_id}
-add_message '[subject]="thread-naming: Older changed subject"' \
- '[date]="Sat, 06 Jan 2001 15:43:56 -0000"' \
- "[in-reply-to]=\<$parent\>"
-add_message '[subject]="thread-naming: Newer changed subject"' \
- '[date]="Sun, 07 Jan 2001 15:43:56 -0000"' \
- "[in-reply-to]=\<$parent\>"
-add_message '[subject]="thread-naming: Final thread subject"' \
- '[date]="Mon, 08 Jan 2001 15:43:56 -0000"' \
- "[in-reply-to]=\<$parent\>"
-final=${gen_msg_id}
-output=$(notmuch search --sort=oldest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-05 [4/4] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
-
-test_begin_subtest "Initial thread name (newest-first search)"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-08 [4/4] Notmuch Test Suite; thread-naming: Final thread subject (inbox unread)"
-
-# Remove oldest and newest messages from search results
-notmuch tag -inbox id:$parent or id:$final
-
-test_begin_subtest "Changed thread name (oldest-first search)"
-output=$(notmuch search --sort=oldest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-06 [2/4] Notmuch Test Suite; thread-naming: Older changed subject (inbox unread)"
-
-test_begin_subtest "Changed thread name (newest-first search)"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-07 [2/4] Notmuch Test Suite; thread-naming: Newer changed subject (inbox unread)"
-
-test_begin_subtest "Ignore added reply prefix (Re:)"
-add_message '[subject]="Re: thread-naming: Initial thread subject"' \
- '[date]="Tue, 09 Jan 2001 15:43:45 -0000"' \
- "[in-reply-to]=\<$parent\>"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-09 [3/5] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
-
-test_begin_subtest "Ignore added reply prefix (Aw:)"
-add_message '[subject]="Aw: thread-naming: Initial thread subject"' \
- '[date]="Wed, 10 Jan 2001 15:43:45 -0000"' \
- "[in-reply-to]=\<$parent\>"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-10 [4/6] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
-
-test_begin_subtest "Ignore added reply prefix (Vs:)"
-add_message '[subject]="Vs: thread-naming: Initial thread subject"' \
- '[date]="Thu, 11 Jan 2001 15:43:45 -0000"' \
- "[in-reply-to]=\<$parent\>"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-11 [5/7] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
-
-test_begin_subtest "Ignore added reply prefix (Sv:)"
-add_message '[subject]="Sv: thread-naming: Initial thread subject"' \
- '[date]="Fri, 12 Jan 2001 15:43:45 -0000"' \
- "[in-reply-to]=\<$parent\>"
-output=$(notmuch search --sort=newest-first thread-naming and tag:inbox | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2001-01-12 [6/8] Notmuch Test Suite; thread-naming: Initial thread subject (inbox unread)"
-
-test_begin_subtest 'Test order of messages in "notmuch show"'
-output=$(notmuch show thread-naming | notmuch_show_sanitize)
-test_expect_equal "$output" "\fmessage{ id:msg-$(printf "%03d" $first)@notmuch-test-suite depth:0 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $first)
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (unread)
-Subject: thread-naming: Initial thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Fri, 05 Jan 2001 15:43:56 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$first)
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 1)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 1)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-06) (inbox unread)
-Subject: thread-naming: Older changed subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Sat, 06 Jan 2001 15:43:56 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 1)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 2)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 2)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-07) (inbox unread)
-Subject: thread-naming: Newer changed subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Sun, 07 Jan 2001 15:43:56 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 2)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 3)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 3)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-08) (unread)
-Subject: thread-naming: Final thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Mon, 08 Jan 2001 15:43:56 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 3)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 4)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 4)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-09) (inbox unread)
-Subject: Re: thread-naming: Initial thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Tue, 09 Jan 2001 15:43:45 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 4)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 5)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 5)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-10) (inbox unread)
-Subject: Aw: thread-naming: Initial thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Wed, 10 Jan 2001 15:43:45 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 5)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 6)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 6)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-11) (inbox unread)
-Subject: Vs: thread-naming: Initial thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Thu, 11 Jan 2001 15:43:45 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 6)))
-\fpart}
-\fbody}
-\fmessage}
-\fmessage{ id:msg-$(printf "%03d" $((first + 7)))@notmuch-test-suite depth:1 match:1 excluded:0 filename:/XXX/mail/msg-$(printf "%03d" $((first + 7)))
-\fheader{
-Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-12) (inbox unread)
-Subject: Sv: thread-naming: Initial thread subject
-From: Notmuch Test Suite <test_suite@notmuchmail.org>
-To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Fri, 12 Jan 2001 15:43:45 +0000
-\fheader}
-\fbody{
-\fpart{ ID: 1, Content-type: text/plain
-This is just a test message (#$((first + 7)))
-\fpart}
-\fbody}
-\fmessage}"
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-test_description="threading when messages received out of order"
-. ./test-lib.sh
-
-test_begin_subtest "Adding initial child message"
-generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching returns the message"
-output=$(notmuch search foo | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; brokenthreadtest (inbox unread)"
-
-test_begin_subtest "Adding second child message"
-generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching returns both messages in one thread"
-output=$(notmuch search foo | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [2/2] Notmuch Test Suite; brokenthreadtest (inbox unread)"
-
-test_begin_subtest "Adding parent message"
-generate_message [body]=foo [id]=parent-id [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
-output=$(NOTMUCH_NEW)
-test_expect_equal "$output" "Added 1 new message to the database."
-
-test_begin_subtest "Searching returns all three messages in one thread"
-output=$(notmuch search foo | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [3/3] Notmuch Test Suite; brokenthreadtest (inbox unread)"
-
-test_done
+++ /dev/null
-#!/usr/bin/env bash
-#
-# Copyright (c) 2013 Aaron Ecay
-#
-
-test_description='test of proper handling of in-reply-to and references headers'
-
-# This test makes sure that the thread structure in the notmuch
-# database is constructed properly, even in the presence of
-# non-RFC-compliant headers'
-
-. ./test-lib.sh
-
-test_begin_subtest "Use References when In-Reply-To is broken"
-add_message '[id]="foo@one.com"' \
- '[subject]=one'
-add_message '[in-reply-to]="mumble"' \
- '[references]="<foo@one.com>"' \
- '[subject]="Re: one"'
-output=$(notmuch show --format=json 'subject:one' | notmuch_json_show_sanitize)
-expected='[[[{"id": "foo@one.com",
- "match": true,
- "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437,
- "date_relative": "2001-01-05",
- "tags": ["inbox", "unread"],
- "headers": {"Subject": "one",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
- "body": [{"id": 1,
- "content-type": "text/plain",
- "content": "This is just a test message (#1)\n"}]},
- [[{"id": "msg-002@notmuch-test-suite",
- "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05",
- "tags": ["inbox", "unread"], "headers": {"Subject": "Re: one",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
- "body": [{"id": 1, "content-type": "text/plain",
- "content": "This is just a test message (#2)\n"}]}, []]]]]]'
-expected=`echo "$expected" | notmuch_json_show_sanitize`
-test_expect_equal_json "$output" "$expected"
-
-test_begin_subtest "Prefer References to In-Reply-To"
-add_message '[id]="foo@two.com"' \
- '[subject]=two'
-add_message '[in-reply-to]="<bar@baz.com>"' \
- '[references]="<foo@two.com>"' \
- '[subject]="Re: two"'
-output=$(notmuch show --format=json 'subject:two' | notmuch_json_show_sanitize)
-expected='[[[{"id": "foo@two.com",
- "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "two",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
- "body": [{"id": 1, "content-type": "text/plain",
- "content": "This is just a test message (#3)\n"}]},
- [[{"id": "msg-004@notmuch-test-suite", "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "Re: two",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"},
- "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#4)\n"}]},
- []]]]]]'
-expected=`echo "$expected" | notmuch_json_show_sanitize`
-test_expect_equal_json "$output" "$expected"
-
-test_begin_subtest "Use In-Reply-To when no References"
-add_message '[id]="foo@three.com"' \
- '[subject]="three"'
-add_message '[in-reply-to]="<foo@three.com>"' \
- '[subject]="Re: three"'
-output=$(notmuch show --format=json 'subject:three' | notmuch_json_show_sanitize)
-expected='[[[{"id": "foo@three.com", "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "three",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#5)\n"}]},
- [[{"id": "msg-006@notmuch-test-suite", "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "Re: three",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#6)\n"}]},
- []]]]]]'
-expected=`echo "$expected" | notmuch_json_show_sanitize`
-test_expect_equal_json "$output" "$expected"
-
-test_begin_subtest "Use last Reference"
-add_message '[id]="foo@four.com"' \
- '[subject]="four"'
-add_message '[id]="bar@four.com"' \
- '[subject]="not-four"'
-add_message '[in-reply-to]="<baz@four.com>"' \
- '[references]="<baz@four.com> <foo@four.com>"' \
- '[subject]="neither"'
-output=$(notmuch show --format=json 'subject:four' | notmuch_json_show_sanitize)
-expected='[[[{"id": "foo@four.com", "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "four",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#7)\n"}]},
- [[{"id": "msg-009@notmuch-test-suite", "match": false, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "neither",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#9)\n"}]},
- []]]]], [[{"id": "bar@four.com", "match": true, "excluded": false,
- "filename": "YYYYY",
- "timestamp": 978709437, "date_relative": "2001-01-05", "tags": ["inbox", "unread"],
- "headers": {"Subject": "not-four",
- "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
- "Date": "Fri, 05 Jan 2001 15:43:57 +0000"}, "body": [{"id": 1,
- "content-type": "text/plain", "content": "This is just a test message (#8)\n"}]}, []]]]'
-expected=`echo "$expected" | notmuch_json_show_sanitize`
-test_expect_equal_json "$output" "$expected"
-
-
-test_done
2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox)
- 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 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)
End of search results.
- 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 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 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-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 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 Alexander Botero-Low ╰┬► ... (inbox, unread)
- 2009-11-18 Jjgod Jiang ╰┬► ... (inbox, unread)
- 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
- 2009-11-17 Carl Worth ╰─► ... (inbox, unread)
+ 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 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 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-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 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 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
End of search results.
- 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox, unread)
- 2010-12-16 Olivier Berger ─►Essai accentué (inbox, test_tag, 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 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 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-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 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 Alexander Botero-Low ╰┬► ... (inbox, unread)
- 2009-11-18 Jjgod Jiang ╰┬► ... (inbox, unread)
- 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
- 2009-11-17 Carl Worth ╰─► ... (inbox, unread)
+ 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+ 2010-12-16 Olivier Berger ─►Essai accentué (inbox test_tag 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 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 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-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 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 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
End of search results.
- 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox, signed, test_thread_tag, unread)
- 2009-11-17 Mikhail Gusarov ├┬► ... (inbox, signed, test_thread_tag, unread)
- 2009-11-17 Lars Kellogg-Stedman │╰┬► ... (inbox, signed, test_thread_tag, unread)
- 2009-11-17 Mikhail Gusarov │ ├─► ... (inbox, test_thread_tag, unread)
- 2009-11-17 Keith Packard │ ╰┬► ... (inbox, test_thread_tag, unread)
- 2009-11-18 Lars Kellogg-Stedman │ ╰─► ... (inbox, signed, test_thread_tag, unread)
- 2009-11-18 Carl Worth ╰─► ... (inbox, test_thread_tag, unread)
- 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-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 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 Alexander Botero-Low ╰┬► ... (inbox, unread)
- 2009-11-18 Jjgod Jiang ╰┬► ... (inbox, unread)
- 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
- 2009-11-17 Carl Worth ╰─► ... (inbox, unread)
+ 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-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-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (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 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 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 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (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 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 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed test_thread_tag unread)
+ 2009-11-17 Mikhail Gusarov ├┬► ... (inbox signed test_thread_tag unread)
+ 2009-11-17 Lars Kellogg-Stedman │╰┬► ... (inbox signed test_thread_tag unread)
+ 2009-11-17 Mikhail Gusarov │ ├─► ... (inbox test_thread_tag unread)
+ 2009-11-17 Keith Packard │ ╰┬► ... (inbox test_thread_tag unread)
+ 2009-11-18 Lars Kellogg-Stedman │ ╰─► ... (inbox signed test_thread_tag unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox test_thread_tag unread)
+ 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-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 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 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (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-18 Lars Kellogg-Stedman ╰─► ... (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)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
End of search results.
+++ /dev/null
-#!/usr/bin/env bash
-test_description="handling of uuencoded data"
-. ./test-lib.sh
-
-add_message [subject]=uuencodetest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' \
-'[body]="This message is used to ensure that notmuch correctly handles a
-message containing a block of uuencoded data. First, we have a marker
-this content beforeuudata . Then we begin the uuencoded data itself:
-
-begin 644 bogus-uuencoded-data
-M0123456789012345678901234567890123456789012345678901234567890
-MOBVIOUSLY, THIS IS NOT ANY SORT OF USEFUL UUENCODED DATA.
-MINSTEAD THIS IS JUST A WAY TO ENSURE THAT THIS BLOCK OF DATA
-MIS CORRECTLY IGNORED WHEN NOTMUCH CREATES ITS INDEX. SO WE
-MINCLUDE A DURINGUUDATA MARKER THAT SHOULD NOT RESULT IN ANY
-MSEARCH RESULT.
-\\\`
-end
-
-Finally, we have our afteruudata marker as well."'
-
-test_begin_subtest "Ensure content before uu data is indexed"
-output=$(notmuch search beforeuudata | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; uuencodetest (inbox unread)"
-
-test_begin_subtest "Ensure uu data is not indexed"
-output=$(notmuch search DURINGUUDATA | notmuch_search_sanitize)
-test_expect_equal "$output" ""
-
-test_begin_subtest "Ensure content after uu data is indexed"
-output=$(notmuch search afteruudata | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; uuencodetest (inbox unread)"
-
-test_done
extra_cflags += -I$(srcdir)/$(dir)
libutil_c_srcs := $(dir)/xutil.c $(dir)/error_util.c $(dir)/hex-escape.c \
- $(dir)/string-util.c $(dir)/talloc-extra.c
+ $(dir)/string-util.c $(dir)/talloc-extra.c $(dir)/zlib-extra.c \
+ $(dir)/util.c
libutil_modules := $(libutil_c_srcs:.c=.o)
return *len ? s : NULL;
}
+char *
+sanitize_string (const void *ctx, const char *str)
+{
+ char *out, *loop;
+
+ if (! str)
+ return NULL;
+
+ out = talloc_strdup (ctx, str);
+ if (! out)
+ return NULL;
+
+ for (loop = out; *loop; loop++) {
+ if (*loop == '\t' || *loop == '\n')
+ *loop = ' ';
+ else if ((unsigned char)(*loop) < 32)
+ *loop = '?';
+ }
+
+ return out;
+}
+
static int
is_unquoted_terminator (unsigned char c)
{
int need_quoting = 0;
/* Do we need quoting? To be paranoid, we quote anything
- * containing a quote, even though it only matters at the
+ * containing a quote or '(', even though these only matter at the
* beginning, and anything containing non-ASCII text. */
+ if (! term[0])
+ need_quoting = 1;
for (in = term; *in && !need_quoting; in++)
- if (is_unquoted_terminator (*in) || *in == '"'
+ if (is_unquoted_terminator (*in) || *in == '"' || *in == '('
|| (unsigned char)*in > 127)
need_quoting = 1;
char *strtok_len (char *s, const char *delim, size_t *len);
+/* Return a talloced string with str sanitized.
+ *
+ * Whitespace characters (tabs and newlines) are replaced with spaces,
+ * non-printable characters with question marks.
+ */
+char *sanitize_string (const void *ctx, const char *str);
+
/* Construct a boolean term query with the specified prefix (e.g.,
* "id") and search term, quoting term as necessary. Specifically, if
* term contains any non-printable ASCII characters, non-ASCII
--- /dev/null
+#include "util.h"
+#include "error_util.h"
+#include <string.h>
+#include <errno.h>
+
+const char *
+util_error_string (util_status_t errnum)
+{
+ switch (errnum) {
+ case UTIL_SUCCESS:
+ return "success";
+ case UTIL_OUT_OF_MEMORY:
+ return "out of memory";
+ case UTIL_EOF:
+ return "end of file";
+ case UTIL_ERRNO:
+ return strerror (errno);
+ case UTIL_GZERROR:
+ /* we lack context to be more informative here */
+ return "zlib error";
+ default:
+ INTERNAL_ERROR("unexpected error status %d", errnum);
+ }
+}
--- /dev/null
+#ifndef _UTIL_H
+#define _UTIL_H
+
+typedef enum util_status {
+ /**
+ * No error occurred.
+ */
+ UTIL_SUCCESS = 0,
+ /**
+ * Out of memory.
+ */
+ UTIL_OUT_OF_MEMORY,
+ /**
+ * End of stream reached while attempting to read.
+ */
+ UTIL_EOF,
+ /**
+ * Low level error occured, consult errno.
+ */
+ UTIL_ERRNO,
+ /**
+ * Zlib error occured, call gzerror for details.
+ */
+ UTIL_GZERROR
+} util_status_t;
+
+const char *
+util_error_string (util_status_t status);
+#endif
--- /dev/null
+/* zlib-extra.c - Extra or enhanced routines for compressed I/O.
+ *
+ * Copyright (c) 2014 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 http://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#include "zlib-extra.h"
+#include <talloc.h>
+#include <stdio.h>
+#include <string.h>
+
+/* mimic POSIX/glibc getline, but on a zlib gzFile stream, and using talloc */
+util_status_t
+gz_getline (void *talloc_ctx, char **bufptr, ssize_t *bytes_read, gzFile stream)
+{
+ char *buf = *bufptr;
+ unsigned int len;
+ size_t offset = 0;
+
+ if (buf) {
+ len = talloc_array_length (buf);
+ } else {
+ /* same as getdelim from gnulib */
+ len = 120;
+ buf = talloc_array (talloc_ctx, char, len);
+ if (buf == NULL)
+ return UTIL_OUT_OF_MEMORY;
+ }
+
+ while (1) {
+ if (! gzgets (stream, buf + offset, len - offset)) {
+ /* Null indicates EOF or error */
+ int zlib_status = 0;
+ (void) gzerror (stream, &zlib_status);
+ switch (zlib_status) {
+ case Z_OK:
+ /* no data read before EOF */
+ if (offset == 0)
+ return UTIL_EOF;
+ else
+ goto SUCCESS;
+ case Z_ERRNO:
+ return UTIL_ERRNO;
+ default:
+ return UTIL_GZERROR;
+ }
+ }
+
+ offset += strlen (buf + offset);
+
+ if (buf[offset - 1] == '\n')
+ goto SUCCESS;
+
+ len *= 2;
+ buf = talloc_realloc (talloc_ctx, buf, char, len);
+ if (buf == NULL)
+ return UTIL_OUT_OF_MEMORY;
+ }
+ SUCCESS:
+ *bufptr = buf;
+ *bytes_read = offset;
+ return UTIL_SUCCESS;
+}
+
+const char *gz_error_string (util_status_t status, gzFile file)
+{
+ if (status == UTIL_GZERROR)
+ return gzerror (file, NULL);
+ else
+ return util_error_string (status);
+}
--- /dev/null
+#ifndef _ZLIB_EXTRA_H
+#define _ZLIB_EXTRA_H
+
+#include "util.h"
+#include <zlib.h>
+
+/* Like getline, but read from a gzFile. Allocation is with talloc.
+ * Returns:
+ *
+ * UTIL_SUCCESS, UTIL_OUT_OF_MEMORY, UTIL_ERRNO, UTIL_GZERROR
+ * Consult util.h for description
+ *
+ * UTIL_EOF End of file encountered before
+ * any characters read
+ */
+util_status_t
+gz_getline (void *ctx, char **lineptr, ssize_t *bytes_read, gzFile stream);
+
+/* return a suitable error string based on the return status
+ * from gz_readline
+ */
+
+const char *
+gz_error_string (util_status_t status, gzFile stream);
+#endif
function! s:compose_send()
let b:compose_done = 1
let fname = expand('%')
+ let lines = getline(5, '$')
- " remove headers
- 0,4d
- write
+ruby << EOF
+ # Generate proper mail to send
+ text = VIM::evaluate('lines').join("\n")
+ fname = VIM::evaluate('fname')
+ transport = Mail.new(text)
+ transport.message_id = generate_message_id
+ transport.charset = 'utf-8'
+ File.write(fname, transport.to_s)
+EOF
let cmdtxt = g:notmuch_sendmail . ' -t -f ' . s:reply_from . ' < ' . fname
let out = system(cmdtxt)
let err = v:shell_error
if err
- undo
- write
echohl Error
echo 'Eeek! unable to send mail'
echo out
end
m.cc = orig[:cc]
m.from = $email
- m.message_id = generate_message_id
m.charset = 'utf-8'
- m.content_transfer_encoding = '7bit'
end
lines = []
reply.body = body_lines.join("\n")
- lines += reply.to_s.lines.map { |e| e.chomp }
+ lines += reply.present.lines.map { |e| e.chomp }
lines << ""
cur = lines.count - 1
def open_compose()
lines = []
- lines << "Date: #{Time.now().strftime('%a, %-d %b %Y %T %z')}"
lines << "From: #{$email}"
lines << "To: "
cur = lines.count
lines << "Cc: "
lines << "Bcc: "
- lines << "Message-Id: #{generate_message_id}"
lines << "Subject: "
- lines << "Mime-Version: 1.0"
- lines << "Content-Type: text/plain; charset=utf-8"
- lines << "Content-Transfer-Encoding: 7bit"
lines << ""
lines << ""
lines << ""
def folders_render()
$curbuf.render do |b|
folders = VIM::evaluate('g:notmuch_folders')
- count_threads = VIM::evaluate('g:notmuch_folders_count_threads')
+ count_threads = VIM::evaluate('g:notmuch_folders_count_threads') == 1
$searches.clear
folders.each do |name, search|
q = $curbuf.query(search)
if mime_type != "text/html"
text = decoded
else
- IO.popen("elinks --dump", "w+") do |pipe|
+ IO.popen(VIM::evaluate('exists("g:notmuch_html_converter") ? ' +
+ 'g:notmuch_html_converter : "elinks --dump"'), "w+") do |pipe|
pipe.write(decode_body)
pipe.close_write
text = pipe.read
end
text
end
+
+ def present
+ buffer = ''
+ header.fields.each do |f|
+ buffer << "%s: %s\r\n" % [f.name, f.to_s]
+ end
+ buffer << "\r\n"
+ buffer << body.to_s
+ buffer
+ end
end
end