/bindings/python-cffi/_notmuch_config.py
TAGS
tags
+__pycache__
+Notmuch 0.38.3 (2024-03-09)
+===========================
+
+CLI
+---
+
+Fix a bug in configuration code that caused the notmuch command to
+erroneously report "Error: could not locate database" under some
+circumstances.
+
+Notmuch 0.38.2 (2023-12-01)
+===========================
+
+Library
+-------
+
+Make sorting of string maps lexicographic on (key,value) pairs. This
+avoids some test failures due to variation in message property output
+order.
+
+Emacs
+-----
+
+Avoid extra separators after the last address in `notmuch-emacs-mua`.
+
+
+Notmuch 0.38.1 (2023-10-26)
+===========================
+
+CLI
+---
+
+Report parse errors in config files.
+
+Emacs
+-----
+
+Fix image toggling for Emacs >= 29.1.
+
+notmuch-mutt
+------------
+
+Fix syntax error in script.
+
+Notmuch 0.38 (2023-09-12)
+=========================
+
+General
+-------
+
+Support relative lastmod queries (see notmuch-sexp-queries(7) and
+notmuch-search-terms(7) for details).
+
+Support indexing of designated attachments as text (see
+notmuch-config(1) for details).
+
+CLI
+---
+
+Add options --offset and --limit to notmuch-show(1).
+
+Emacs
+-----
+
+New commands notmuch-search-edit-search and notmuch-tree-edit-search.
+
+Introduce notmuch-tree-outline-mode.
+
+Some compatibility fixes for Emacs 29. At least one issue (hiding
+images) remains in 0.38.
+
+Support completion when piping to external command.
+
+Fix regression in updating tag display introduced by 0.37.
+
+Library
+-------
+
+Fix bug creating database when database.path is not set.
+
+Incremental performance improvements for message deletion.
+
+Catch Xapian exceptions when deleting messages.
+
+Sync removed message properties to the database.
+
+Replace use of thread-unsafe Query::MatchAll in the infix query
+parser.
+
+Notmuch-Mutt
+------------
+
+Be more careful when clearing the results directory.
+
+Ruby
+----
+
+Use `database_open_with_config`, and provide compatible path search
+semantics.
+
+Bugfix for query.get_sort
+
+Test Suite
+----------
+
+Support testing installed version of notmuch.
+
+Adapt to some breaking changes in glib handling of init files.
+
+Replace OpenPGP key used in test suite.
+
+Performance Tests
+-----------------
+
+Update signatures for performance test corpus.
+
Notmuch 0.37 (2022-08-21)
=========================
Add the `sexp` prefix to the infix (traditional) query parser. This
allows specific subqueries to be parsed by the sexp parser (with
-appropropriate quoting). See `notmuch-search-terms(7)` for details.
+appropriate quoting). See `notmuch-search-terms(7)` for details.
Add another heuristic to regexp fields to prevent phrase parsing of
bracketed sub-expressions.
Documentation
-------------
-Reorganize documention for `notmuch-config`. Add a few links from
+Reorganize documentation for `notmuch-config`. Add a few links from
other man pages.
Emacs
CLI
---
-Improve handling of leading/trailing punctation and space for
+Improve handling of leading/trailing punctuation and space for
configuration lists.
Only ignore `.notmuch` at the top level in `notmuch new`.
Don't add space to completion candidates, improves compatibility with
third party completion frameworks.
-Make citation formating more robust against whitespace.
+Make citation formatting more robust against whitespace.
Use `--excludes=false` when generating the 'All tags' section.
Build
-----
-Catch one more occurence of "version" in the build system, which
+Catch one more occurrence of "version" in the build system, which
caused the file to be regenerated in the release tarball.
Notmuch 0.31.1 (2020-11-08)
CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
CLEAN += bindings/python-cffi/build $(dir)/python-cffi.stamp
+CLEAN += bindings/python-cffi/__pycache__
+
+DISTCLEAN += bindings/python-cffi/_notmuch_config.py \
+ bindings/python-cffi/notmuch2.egg-info
return value
else:
- from configparser import SafeConfigParser
+ from configparser import ConfigParser as SafeConfigParser
+
+ if not hasattr(SafeConfigParser, 'readfp'): # py >= 3.12
+ SafeConfigParser.readfp = SafeConfigParser.read_file
class Python3StringMixIn(object):
def __str__(self):
# this file should be kept in sync with ../../../version
-__VERSION__ = '0.37'
+__VERSION__ = '0.38.3'
SOVERSION = '5'
notmuch_database_t *database;
notmuch_status_t ret;
+ path = NULL;
+ create = 0;
+ mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
+
/* Check arguments */
- rb_scan_args (argc, argv, "11", &pathv, &hashv);
+ rb_scan_args (argc, argv, "02", &pathv, &hashv);
- SafeStringValue (pathv);
- path = RSTRING_PTR (pathv);
+ if (!NIL_P (pathv)) {
+ SafeStringValue (pathv);
+ path = RSTRING_PTR (pathv);
+ }
if (!NIL_P (hashv)) {
- Check_Type (hashv, T_HASH);
- create = RTEST (rb_hash_aref (hashv, ID2SYM (ID_db_create)));
- modev = rb_hash_aref (hashv, ID2SYM (ID_db_mode));
- if (NIL_P (modev))
- mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
- else if (!FIXNUM_P (modev))
- rb_raise (rb_eTypeError, ":mode isn't a Fixnum");
- else {
- mode = FIX2INT (modev);
- switch (mode) {
- case NOTMUCH_DATABASE_MODE_READ_ONLY:
- case NOTMUCH_DATABASE_MODE_READ_WRITE:
- break;
- default:
- rb_raise ( rb_eTypeError, "Invalid mode");
+ VALUE rmode, rcreate;
+ VALUE kwargs[2];
+ static ID keyword_ids[2];
+
+ if (!keyword_ids[0]) {
+ keyword_ids[0] = rb_intern_const ("mode");
+ keyword_ids[1] = rb_intern_const ("create");
+ }
+
+ rb_get_kwargs (hashv, keyword_ids, 0, 2, kwargs);
+
+ rmode = kwargs[0];
+ rcreate = kwargs[1];
+
+ if (rmode != Qundef) {
+ if (!FIXNUM_P (rmode))
+ rb_raise (rb_eTypeError, ":mode isn't a Fixnum");
+ else {
+ mode = FIX2INT (rmode);
+ switch (mode) {
+ case NOTMUCH_DATABASE_MODE_READ_ONLY:
+ case NOTMUCH_DATABASE_MODE_READ_WRITE:
+ break;
+ default:
+ rb_raise ( rb_eTypeError, "Invalid mode");
+ }
}
}
- } else {
- create = 0;
- mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
+ if (rcreate != Qundef)
+ create = RTEST (rcreate);
}
rb_check_typeddata (self, ¬much_rb_database_type);
if (create)
ret = notmuch_database_create (path, &database);
else
- ret = notmuch_database_open (path, mode, &database);
+ ret = notmuch_database_open_with_config (path, mode, NULL, NULL, &database, NULL);
notmuch_rb_status_raise (ret);
DATA_PTR (self) = notmuch_rb_object_create (database, "notmuch_rb_database");
rb_raise (notmuch_rb_eBaseError, "%s", msg);
}
- return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, ¬much_rb_tags_type, tags);
+ return notmuch_rb_tags_get (tags);
}
/*
extern VALUE notmuch_rb_cThread;
extern VALUE notmuch_rb_cMessages;
extern VALUE notmuch_rb_cMessage;
-extern VALUE notmuch_rb_cTags;
extern VALUE notmuch_rb_eBaseError;
extern VALUE notmuch_rb_eDatabaseError;
extern VALUE notmuch_rb_eUnbalancedAtomicError;
extern ID ID_call;
-extern ID ID_db_create;
-extern ID ID_db_mode;
/* RSTRING_PTR() is new in ruby-1.9 */
#if !defined(RSTRING_PTR)
extern const rb_data_type_t notmuch_rb_object_type;
extern const rb_data_type_t notmuch_rb_database_type;
extern const rb_data_type_t notmuch_rb_directory_type;
-extern const rb_data_type_t notmuch_rb_filenames_type;
extern const rb_data_type_t notmuch_rb_query_type;
extern const rb_data_type_t notmuch_rb_threads_type;
extern const rb_data_type_t notmuch_rb_thread_type;
#define Data_Get_Notmuch_Directory(obj, ptr) \
Data_Get_Notmuch_Object ((obj), ¬much_rb_directory_type, (ptr))
-#define Data_Get_Notmuch_FileNames(obj, ptr) \
- Data_Get_Notmuch_Object ((obj), ¬much_rb_filenames_type, (ptr))
-
#define Data_Get_Notmuch_Query(obj, ptr) \
Data_Get_Notmuch_Object ((obj), ¬much_rb_query_type, (ptr))
/* filenames.c */
VALUE
-notmuch_rb_filenames_destroy (VALUE self);
-
-VALUE
-notmuch_rb_filenames_each (VALUE self);
+notmuch_rb_filenames_get (notmuch_filenames_t *fnames);
/* query.c */
VALUE
/* tags.c */
VALUE
-notmuch_rb_tags_destroy (VALUE self);
-
-VALUE
-notmuch_rb_tags_each (VALUE self);
+notmuch_rb_tags_get (notmuch_tags_t *tags);
/* init.c */
void
fnames = notmuch_directory_get_child_files (dir);
- return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
+ return notmuch_rb_filenames_get (fnames);
}
/*
fnames = notmuch_directory_get_child_directories (dir);
- return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
+ return notmuch_rb_filenames_get (fnames);
}
-/* The Ruby interface to the notmuch mail library
- *
- * Copyright © 2010 Ali Polatel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see https://www.gnu.org/licenses/ .
- *
- * Author: Ali Polatel <alip@exherbo.org>
- */
-
#include "defs.h"
-/*
- * call-seq: FILENAMES.destroy! => nil
- *
- * Destroys the filenames, freeing all resources allocated for it.
- */
-VALUE
-notmuch_rb_filenames_destroy (VALUE self)
-{
- notmuch_rb_object_destroy (self, ¬much_rb_filenames_type);
-
- return Qnil;
-}
-
-/*
- * call-seq: FILENAMES.each {|item| block } => FILENAMES
- *
- * Calls +block+ once for each element in +self+, passing that element as a
- * parameter.
- */
VALUE
-notmuch_rb_filenames_each (VALUE self)
+notmuch_rb_filenames_get (notmuch_filenames_t *fnames)
{
- notmuch_filenames_t *fnames;
-
- Data_Get_Notmuch_FileNames (self, fnames);
+ VALUE rb_array = rb_ary_new ();
for (; notmuch_filenames_valid (fnames); notmuch_filenames_move_to_next (fnames))
- rb_yield (rb_str_new2 (notmuch_filenames_get (fnames)));
-
- return self;
+ rb_ary_push (rb_array, rb_str_new2 (notmuch_filenames_get (fnames)));
+ return rb_array;
}
VALUE notmuch_rb_cDatabase;
VALUE notmuch_rb_cDirectory;
-VALUE notmuch_rb_cFileNames;
VALUE notmuch_rb_cQuery;
VALUE notmuch_rb_cThreads;
VALUE notmuch_rb_cThread;
VALUE notmuch_rb_cMessages;
VALUE notmuch_rb_cMessage;
-VALUE notmuch_rb_cTags;
VALUE notmuch_rb_eBaseError;
VALUE notmuch_rb_eDatabaseError;
VALUE notmuch_rb_eUnbalancedAtomicError;
ID ID_call;
-ID ID_db_create;
-ID ID_db_mode;
const rb_data_type_t notmuch_rb_object_type = {
.wrap_struct_name = "notmuch_object",
define_type (database);
define_type (directory);
-define_type (filenames);
define_type (query);
define_type (threads);
define_type (thread);
define_type (messages);
define_type (message);
-define_type (tags);
/*
* Document-module: Notmuch
* the user:
*
* - Notmuch::Database
- * - Notmuch::FileNames
* - Notmuch::Query
* - Notmuch::Threads
* - Notmuch::Messages
* - Notmuch::Thread
* - Notmuch::Message
- * - Notmuch::Tags
*/
void
VALUE mod;
ID_call = rb_intern ("call");
- ID_db_create = rb_intern ("create");
- ID_db_mode = rb_intern ("mode");
mod = rb_define_module ("Notmuch");
rb_define_method (notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); /* in directory.c */
rb_define_method (notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); /* in directory.c */
- /*
- * Document-class: Notmuch::FileNames
- *
- * Notmuch file names
- */
- notmuch_rb_cFileNames = rb_define_class_under (mod, "FileNames", rb_cObject);
- rb_undef_method (notmuch_rb_cFileNames, "initialize");
- rb_define_method (notmuch_rb_cFileNames, "destroy!", notmuch_rb_filenames_destroy, 0); /* in filenames.c */
- rb_define_method (notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); /* in filenames.c */
- rb_include_module (notmuch_rb_cFileNames, rb_mEnumerable);
-
/*
* Document-class: Notmuch::Query
*
rb_define_method (notmuch_rb_cMessage, "tags_to_maildir_flags", notmuch_rb_message_tags_to_maildir_flags, 0); /* in message.c */
rb_define_method (notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); /* in message.c */
rb_define_method (notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); /* in message.c */
-
- /*
- * Document-class: Notmuch::Tags
- *
- * Notmuch tags
- */
- notmuch_rb_cTags = rb_define_class_under (mod, "Tags", rb_cObject);
- rb_undef_method (notmuch_rb_cTags, "initialize");
- rb_define_method (notmuch_rb_cTags, "destroy!", notmuch_rb_tags_destroy, 0); /* in tags.c */
- rb_define_method (notmuch_rb_cTags, "each", notmuch_rb_tags_each, 0); /* in tags.c */
- rb_include_module (notmuch_rb_cTags, rb_mEnumerable);
}
fnames = notmuch_message_get_filenames (message);
- return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
+ return notmuch_rb_filenames_get (fnames);
}
/*
if (!tags)
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
- return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, ¬much_rb_tags_type, tags);
+ return notmuch_rb_tags_get (tags);
}
/*
if (!tags)
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
- return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, ¬much_rb_tags_type, tags);
+ return notmuch_rb_tags_get (tags);
}
Data_Get_Notmuch_Query (self, query);
- return FIX2INT (notmuch_query_get_sort (query));
+ return INT2FIX (notmuch_query_get_sort (query));
}
/*
-/* The Ruby interface to the notmuch mail library
- *
- * Copyright © 2010, 2011 Ali Polatel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see https://www.gnu.org/licenses/ .
- *
- * Author: Ali Polatel <alip@exherbo.org>
- */
-
#include "defs.h"
-/*
- * call-seq: TAGS.destroy! => nil
- *
- * Destroys the tags, freeing all resources allocated for it.
- */
-VALUE
-notmuch_rb_tags_destroy (VALUE self)
-{
- notmuch_rb_object_destroy (self, ¬much_rb_tags_type);
-
- return Qnil;
-}
-
-/*
- * call-seq: TAGS.each {|item| block } => TAGS
- *
- * Calls +block+ once for each element in +self+, passing that element as a
- * parameter.
- */
VALUE
-notmuch_rb_tags_each (VALUE self)
+notmuch_rb_tags_get (notmuch_tags_t *tags)
{
- const char *tag;
- notmuch_tags_t *tags;
-
- Data_Get_Notmuch_Tags (self, tags);
+ VALUE rb_array = rb_ary_new ();
for (; notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) {
- tag = notmuch_tags_get (tags);
- rb_yield (rb_str_new2 (tag));
+ const char *tag = notmuch_tags_get (tags);
+ rb_ary_push (rb_array, rb_str_new2 (tag));
}
-
- return self;
+ return rb_array;
}
if (!tags)
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
- return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, ¬much_rb_tags_type, tags);
+ return notmuch_rb_tags_get (tags);
}
#define _GNU_SOURCE
-#include <strings.h>
+#include <strings.h> /* strcasecmp() in POSIX */
+#include <string.h> /* strcasecmp() in *BSD */
int
main ()
! $split &&
case "${cur}" in
-*)
- local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html ${_notmuch_shared_options}"
+ local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html --limit= --offset= ${_notmuch_shared_options}"
compopt -o nospace
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
;;
'--exclude=[respect excluded tags setting]:exclude tags:(true false)' \
'--body=[output body]:output body content:(true false)' \
'--include-html[include text/html parts in the output]' \
+ '--limit=[limit the number of displayed results]:limit: ' \
+ '--offset=[skip displaying the first N results]:offset: ' \
'*::search term:_notmuch_search_term'
}
fi
unset test_cmdline
+printf "C compiler supports thread sanitizer... "
+test_cmdline="${CC} ${CFLAGS} ${CPPFLAGS} -fsanitize=thread minimal.c ${LDFLAGS} -o minimal"
+if ${test_cmdline} >/dev/null 2>&1 && ./minimal
+then
+ printf "Yes.\n"
+ have_tsan=1
+else
+ printf "Nope, skipping those tests.\n"
+ have_tsan=0
+fi
+unset test_cmdline
+
printf "Reading libnotmuch version from source... "
cat > _libversion.c <<EOF
#include <stdio.h>
Please try to rebuild your version of GMime against a more recent
version of GPGME (at least GPGME 1.8.0).
EOF
- if command -v gpgme-config >/dev/null; then
- printf 'Your current GPGME development version is: %s\n' "$(gpgme-config --version)"
+ if GPGME_VERS="$(pkg-config --modversion gpgme || gpgme-config --version)"; then
+ printf 'Your current GPGME development version is: %s\n' "$GPGME_VERS"
else
printf 'You do not have the GPGME development libraries installed.\n'
fi
NOTMUCH_ZLIB_CFLAGS="${zlib_cflags}"
NOTMUCH_ZLIB_LDFLAGS="${zlib_ldflags}"
-# Does the C compiler support the address sanitizer
+# Does the C compiler support the sanitizers
NOTMUCH_HAVE_ASAN=${have_asan}
+NOTMUCH_HAVE_TSAN=${have_tsan}
# do we have man pages?
NOTMUCH_HAVE_MAN=$((have_sphinx))
(Debian package: libmail-box-perl)
- Mail::Header <https://metacpan.org/pod/Mail::Header>
(Debian package: libmailtools-perl)
-- String::ShellQuote <https://metacpan.org/pod/String::ShellQuote>
- (Debian package: libstring-shellquote-perl)
- Term::ReadLine::Gnu <https://metacpan.org/pod/Term::ReadLine::Gnu>
(Debian package: libterm-readline-gnu-perl)
#
# notmuch-mutt - notmuch (of a) helper for Mutt
#
-# Copyright: © 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
+# Copyright: © 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
# License: GNU General Public License (GPL), version 3 or above
#
# See the bottom of this file for more documentation.
use File::Path;
use File::Basename;
+use File::Find;
use Getopt::Long qw(:config no_getopt_compat);
use Mail::Header;
use Mail::Box::Maildir;
use Pod::Usage;
-use String::ShellQuote;
use Term::ReadLine;
use Digest::SHA;
$xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
my $cache_dir = "$xdg_cache_dir/notmuch/mutt";
+sub die_dir($$) {
+ my ($maildir, $error) = @_;
+ die "notmuch-mutt: search cache maildir $maildir $error\n".
+ "Please ensure that the notmuch-mutt search cache Maildir\n".
+ "contains no subfolders or real mail data, only symlinks to mail\n";
+}
+
+sub die_subdir($$$) {
+ my ($maildir, $subdir, $error) = @_;
+ die_dir($maildir, "subdir $subdir $error");
+}
-# create an empty maildir (if missing) or empty an existing maildir"
-sub empty_maildir($) {
+# check that the search cache maildir is that and not a real maildir
+# otherwise there could be data loss when the search cache is emptied
+sub check_search_cache_maildir($) {
+ my ($maildir) = (@_);
+
+ return unless -e $maildir;
+
+ -d $maildir or die_dir($maildir, 'is not a directory');
+
+ opendir(my $mdh, $maildir) or die_dir($maildir, "cannot be opened: $!");
+ my @contents = grep { !/^\.\.?$/ } readdir $mdh;
+ closedir $mdh;
+
+ my @required = ('cur', 'new', 'tmp');
+ foreach my $d (@required) {
+ -l "$maildir/$d" and die_dir($maildir, "contains symlink $d");
+ -e "$maildir/$d" or die_subdir($maildir, $d, 'is missing');
+ -d "$maildir/$d" or die_subdir($maildir, $d, 'is not a directory');
+ find(sub {
+ $_ eq '.' and return;
+ $_ eq '..' and return;
+ -l $_ or die_subdir($maildir, $d, "contains non-symlink $_");
+ }, "$maildir/$d");
+ }
+
+ my %required = map { $_ => 1 } @required;
+ foreach my $d (@contents) {
+ -l "$maildir/$d" and die_dir( $maildir, "contains symlink $d");
+ -d "$maildir/$d" or die_dir( $maildir, "contains non-directory $d");
+ exists($required{$d}) or die_dir( $maildir, "contains directory $d");
+ }
+}
+
+# create an empty search cache maildir (if missing) or empty existing one
+sub empty_search_cache_maildir($) {
my ($maildir) = (@_);
rmtree($maildir) if (-d $maildir);
my $folder = new Mail::Box::Maildir(folder => $maildir,
push @args, "--duplicate=1" if $remove_dups;
push @args, $query;
- empty_maildir($maildir);
+ check_search_cache_maildir($maildir);
+ empty_search_cache_maildir($maildir);
open my $pipe, '-|', @args or die "Running @args failed: $!\n";
while (<$pipe>) {
chomp;
my $mid = get_message_id();
if (! defined $mid) {
- empty_maildir($results_dir);
die "notmuch-mutt: cannot find Message-Id, abort.\n";
}
- my $search_cmd = 'notmuch search --output=threads ' . shell_quote("id:$mid");
- my $tid = `$search_cmd`; # get thread id
- chomp($tid);
- search($results_dir, $remove_dups, $tid);
+ $mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
+ $mid =~ s/"/""""/g; # escape all double quote characters twice
+
+ search($results_dir, $remove_dups, qq{thread:"{id:""$mid""}"});
}
sub tag_action(@) {
my $mid = get_message_id();
defined $mid or die "notmuch-mutt: cannot find Message-Id, abort.\n";
- system("notmuch", "tag", @_, "--", "id:$mid");
+ $mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
+ $mid =~ s/"/""/g; # escape all double quote characters
+
+ system("notmuch", "tag", @_, "--", qq{id:"$mid"});
}
sub die_usage() {
+notmuch (0.38.3-1) unstable; urgency=medium
+
+ * New upstream bugfix release
+ * Bug fix: "Recommends transitional package gnupg-agent instead of
+ gpg-agent", thanks to Andreas Metzler (Closes: #1064114).
+
+ -- David Bremner <bremner@debian.org> Sat, 09 Mar 2024 23:13:07 -0400
+
+notmuch (0.38.2-1.1) unstable; urgency=medium
+
+ * Non-maintainer upload.
+ * Rename libraries for 64-bit time_t transition. Closes: #1063205
+
+ -- Benjamin Drung <bdrung@debian.org> Wed, 28 Feb 2024 23:56:48 +0000
+
+notmuch (0.38.2-1) unstable; urgency=medium
+
+ * New upstream bugfix release
+
+ -- David Bremner <bremner@debian.org> Fri, 01 Dec 2023 07:51:09 -0400
+
+notmuch (0.38.1-1) unstable; urgency=medium
+
+ * New upstream bugfix release
+
+ -- David Bremner <bremner@debian.org> Thu, 26 Oct 2023 19:58:42 -0300
+
+notmuch (0.38.1~rc1-1) experimental; urgency=medium
+
+ * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org> Thu, 12 Oct 2023 19:53:10 -0300
+
+notmuch (0.38.1~pre0-1) experimental; urgency=medium
+
+ * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org> Sun, 01 Oct 2023 08:14:17 -0300
+
+notmuch (0.38-2) unstable; urgency=medium
+
+ * Restrict autopkgtests to amd64 and aarch64. There are failures in
+ remaining architectures, but the same tests pass at build time, so any
+ bugs are probably related to either the autopkgtest environment, or
+ the (new) upstream test runner for installed notmuch.
+
+ -- David Bremner <bremner@debian.org> Wed, 13 Sep 2023 19:55:00 -0300
+
+notmuch (0.38-1) unstable; urgency=medium
+
+ * New upstream release
+ * Bug fix: "FTBFS: 6 tests failed.", thanks to Aurelien Jarno (Closes:
+ #1051111).
+ * Run most of upstream test suite as autopkgtests
+
+ -- David Bremner <bremner@debian.org> Tue, 12 Sep 2023 08:33:24 -0300
+
+notmuch (0.38~rc2-1) experimental; urgency=medium
+
+ * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org> Sun, 03 Sep 2023 09:10:24 -0300
+
+notmuch (0.38~rc1-1) experimental; urgency=medium
+
+ * New upstream release candidate
+ * Hopefully reduce/eliminate intermittent failures of T460 by
+ controlling Emacs native compilation.
+ * Disable T810-tsan on ppc64el
+
+ -- David Bremner <bremner@debian.org> Sat, 26 Aug 2023 08:31:21 -0300
+
+notmuch (0.38~rc0-1) experimental; urgency=medium
+
+ * New upstream release candidate
+
+ -- David Bremner <bremner@debian.org> Thu, 24 Aug 2023 10:56:06 -0300
+
notmuch (0.37-1) unstable; urgency=medium
* New upstream release.
gdb [ia64 mips mips64el hppa],
gdb-minimal,
ruby1.8,
-Build-Depends:
+Build-Depends: dpkg-dev (>= 1.22.5),
bash-completion (>=1.9.0~),
debhelper-compat (= 13),
dh-elpa (>= 1.3),
Package: notmuch
Architecture: any
Depends:
- libnotmuch5 (= ${binary:Version}),
+ libnotmuch5t64 (= ${binary:Version}),
${misc:Depends},
${shlibs:Depends},
Recommends:
elpa-notmuch | notmuch-vim | notmuch-mutt | alot,
- gnupg-agent,
+ gpg-agent,
gpgsm,
Suggests:
mailscripts,
.
This package contains the HTML documentation
-Package: libnotmuch5
+Package: libnotmuch5t64
+Provides: ${t64:Provides}
+Replaces: libnotmuch5
+Breaks: libnotmuch5 (<< ${source:Version})
Section: libs
Architecture: any
Depends:
Section: libdevel
Architecture: any
Depends:
- libnotmuch5 (= ${binary:Version}),
+ libnotmuch5t64 (= ${binary:Version}),
${misc:Depends},
Description: thread-based email index, search and tagging (development)
Notmuch is a system for indexing, searching, reading, and tagging
Architecture: all
Section: python
Depends:
- libnotmuch5 (>= ${source:Version}),
+ libnotmuch5t64 (>= ${source:Version}),
${misc:Depends},
${python3:Depends},
Description: Python 3 legacy interface to the notmuch mail search and index library
Architecture: any
Section: python
Depends:
- libnotmuch5 (>= ${source:Version}),
+ libnotmuch5t64 (>= ${source:Version}),
${misc:Depends},
${python3:Depends},
${shlibs:Depends},
Depends:
libmail-box-perl,
libmailtools-perl,
- libstring-shellquote-perl,
libterm-readline-gnu-perl,
notmuch (>= 0.4),
${misc:Depends},
+++ /dev/null
-usr/lib/*/libnotmuch.so.*
+++ /dev/null
-libnotmuch.so.5 libnotmuch5 #MINVER#
-* Build-Depends-Package: libnotmuch-dev
- notmuch_built_with@Base 0.23~rc0
- notmuch_config_get@Base 0.32~rc0
- notmuch_config_get_bool@Base 0.32~rc0
- notmuch_config_get_pairs@Base 0.32~rc0
- notmuch_config_get_values@Base 0.32~rc0
- notmuch_config_get_values_string@Base 0.32~rc0
- notmuch_config_list_destroy@Base 0.23~rc0
- notmuch_config_list_key@Base 0.23~rc0
- notmuch_config_list_move_to_next@Base 0.23~rc0
- notmuch_config_list_valid@Base 0.23~rc0
- notmuch_config_list_value@Base 0.23~rc0
- notmuch_config_pairs_destroy@Base 0.32~rc0
- notmuch_config_pairs_key@Base 0.32~rc0
- notmuch_config_pairs_move_to_next@Base 0.32~rc0
- notmuch_config_pairs_valid@Base 0.32~rc0
- notmuch_config_pairs_value@Base 0.32~rc0
- notmuch_config_path@Base 0.32~rc0
- notmuch_config_set@Base 0.32~rc0
- notmuch_config_values_destroy@Base 0.32~rc0
- notmuch_config_values_get@Base 0.32~rc0
- notmuch_config_values_move_to_next@Base 0.32~rc0
- notmuch_config_values_start@Base 0.32~rc0
- notmuch_config_values_valid@Base 0.32~rc0
- notmuch_database_add_message@Base 0.3
- notmuch_database_begin_atomic@Base 0.9~rc1
- notmuch_database_close@Base 0.13~rc1
- notmuch_database_compact@Base 0.17~rc1
- notmuch_database_compact_db@Base 0.32~rc0
- notmuch_database_create@Base 0.3
- notmuch_database_create_verbose@Base 0.20~rc1
- notmuch_database_create_with_config@Base 0.32~rc0
- notmuch_database_destroy@Base 0.13~rc1
- notmuch_database_end_atomic@Base 0.9~rc1
- notmuch_database_find_message@Base 0.9~rc2
- notmuch_database_find_message_by_filename@Base 0.9~rc2
- notmuch_database_get_all_tags@Base 0.3
- notmuch_database_get_config@Base 0.23~rc0
- notmuch_database_get_config_list@Base 0.23~rc0
- notmuch_database_get_default_indexopts@Base 0.26~rc0
- notmuch_database_get_directory@Base 0.3
- notmuch_database_get_path@Base 0.3
- notmuch_database_get_revision@Base 0.21~rc1
- notmuch_database_get_version@Base 0.3
- notmuch_database_index_file@Base 0.26~rc0
- notmuch_database_load_config@Base 0.32~rc0
- notmuch_database_needs_upgrade@Base 0.3
- notmuch_database_open@Base 0.3
- notmuch_database_open_verbose@Base 0.20~rc1
- notmuch_database_open_with_config@Base 0.32~rc0
- notmuch_database_remove_message@Base 0.3
- notmuch_database_reopen@Base 0.32~rc0
- notmuch_database_set_config@Base 0.23~rc0
- notmuch_database_status_string@Base 0.20~rc1
- notmuch_database_upgrade@Base 0.3
- notmuch_directory_delete@Base 0.21~rc1
- notmuch_directory_destroy@Base 0.3
- notmuch_directory_get_child_directories@Base 0.3
- notmuch_directory_get_child_files@Base 0.3
- notmuch_directory_get_mtime@Base 0.3
- notmuch_directory_set_mtime@Base 0.3
- notmuch_filenames_destroy@Base 0.3
- notmuch_filenames_get@Base 0.3
- notmuch_filenames_move_to_next@Base 0.3
- notmuch_filenames_valid@Base 0.3
- notmuch_indexopts_destroy@Base 0.26~rc0
- notmuch_indexopts_get_decrypt_policy@Base 0.26~rc0
- notmuch_indexopts_set_decrypt_policy@Base 0.26~rc0
- notmuch_message_add_property@Base 0.23~rc0
- notmuch_message_add_tag@Base 0.3
- notmuch_message_count_files@Base 0.26~rc0
- notmuch_message_count_properties@Base 0.27~rc0
- notmuch_message_destroy@Base 0.3
- notmuch_message_freeze@Base 0.3
- notmuch_message_get_database@Base 0.27~rc0
- notmuch_message_get_date@Base 0.3
- notmuch_message_get_filename@Base 0.3
- notmuch_message_get_filenames@Base 0.5
- notmuch_message_get_flag@Base 0.3
- notmuch_message_get_flag_st@Base 0.31~rc0
- notmuch_message_get_header@Base 0.3
- notmuch_message_get_message_id@Base 0.3
- notmuch_message_get_properties@Base 0.23~rc0
- notmuch_message_get_property@Base 0.23~rc0
- notmuch_message_get_replies@Base 0.3
- notmuch_message_get_tags@Base 0.3
- notmuch_message_get_thread_id@Base 0.3
- notmuch_message_has_maildir_flag@Base 0.26~rc0
- notmuch_message_has_maildir_flag_st@Base 0.31~rc0
- notmuch_message_maildir_flags_to_tags@Base 0.5
- notmuch_message_properties_destroy@Base 0.23~rc0
- notmuch_message_properties_key@Base 0.23~rc0
- notmuch_message_properties_move_to_next@Base 0.23~rc0
- notmuch_message_properties_valid@Base 0.23~rc0
- notmuch_message_properties_value@Base 0.23~rc0
- notmuch_message_reindex@Base 0.26~rc0
- notmuch_message_remove_all_properties@Base 0.23~rc0
- notmuch_message_remove_all_properties_with_prefix@Base 0.26~rc0
- notmuch_message_remove_all_tags@Base 0.3
- notmuch_message_remove_property@Base 0.23~rc0
- notmuch_message_remove_tag@Base 0.3
- notmuch_message_set_flag@Base 0.3
- notmuch_message_tags_to_maildir_flags@Base 0.5
- notmuch_message_thaw@Base 0.3
- notmuch_messages_collect_tags@Base 0.3
- notmuch_messages_destroy@Base 0.3
- notmuch_messages_get@Base 0.3
- notmuch_messages_move_to_next@Base 0.3
- notmuch_messages_valid@Base 0.3
- notmuch_query_add_tag_exclude@Base 0.12~rc1
- notmuch_query_count_messages@Base 0.3
- notmuch_query_count_messages_st@Base 0.21~rc1
- notmuch_query_count_threads@Base 0.10~rc1
- notmuch_query_count_threads_st@Base 0.21~rc1
- notmuch_query_create@Base 0.3
- notmuch_query_create_with_syntax@Base 0.34~rc0
- notmuch_query_destroy@Base 0.3
- notmuch_query_get_database@Base 0.21~rc1
- notmuch_query_get_query_string@Base 0.4
- notmuch_query_get_sort@Base 0.4
- notmuch_query_search_messages@Base 0.3
- notmuch_query_search_messages_st@Base 0.20~rc1
- notmuch_query_search_threads@Base 0.3
- notmuch_query_search_threads_st@Base 0.20~rc1
- notmuch_query_set_omit_excluded@Base 0.13~rc1
- notmuch_query_set_sort@Base 0.3
- notmuch_status_to_string@Base 0.3
- notmuch_tags_destroy@Base 0.3
- notmuch_tags_get@Base 0.3
- notmuch_tags_move_to_next@Base 0.3
- notmuch_tags_valid@Base 0.3
- notmuch_thread_destroy@Base 0.3
- notmuch_thread_get_authors@Base 0.3
- notmuch_thread_get_matched_messages@Base 0.3
- notmuch_thread_get_messages@Base 0.16
- notmuch_thread_get_newest_date@Base 0.3
- notmuch_thread_get_oldest_date@Base 0.3
- notmuch_thread_get_subject@Base 0.3
- notmuch_thread_get_tags@Base 0.3
- notmuch_thread_get_thread_id@Base 0.3
- notmuch_thread_get_toplevel_messages@Base 0.3
- notmuch_thread_get_total_files@Base 0.26~rc0
- notmuch_thread_get_total_messages@Base 0.3
- notmuch_threads_destroy@Base 0.3
- notmuch_threads_get@Base 0.3
- notmuch_threads_move_to_next@Base 0.3
- notmuch_threads_valid@Base 0.3
- (c++)"typeinfo for Xapian::LogicError@Base" 0.6.1
- (c++)"typeinfo for Xapian::RuntimeError@Base" 0.6.1
- (c++)"typeinfo for Xapian::DocNotFoundError@Base" 0.6.1
- (c++)"typeinfo for Xapian::InvalidArgumentError@Base" 0.6.1
- (c++)"typeinfo for Xapian::Error@Base" 0.6.1
- (c++)"typeinfo for Xapian::DatabaseError@Base" 0.24~rc0
- (c++)"typeinfo for Xapian::DatabaseModifiedError@Base" 0.24~rc0
- (c++)"typeinfo for Xapian::DatabaseOpeningError@Base" 0.32~rc0
- (c++|optional=present with Xapian 1.4)"typeinfo for Xapian::QueryParserError@Base" 0.23~rc0
- (c++)"typeinfo name for Xapian::LogicError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::RuntimeError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::DocNotFoundError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::InvalidArgumentError@Base" 0.6.1
- (c++)"typeinfo name for Xapian::Error@Base" 0.6.1
- (c++)"typeinfo name for Xapian::DatabaseError@Base" 0.24~rc0
- (c++)"typeinfo name for Xapian::DatabaseModifiedError@Base" 0.24~rc0
- (c++)"typeinfo name for Xapian::DatabaseOpeningError@Base" 0.32~rc0
- (c++|optional=present with Xapian 1.4)"typeinfo name for Xapian::QueryParserError@Base" 0.23~rc0
--- /dev/null
+usr/lib/*/libnotmuch.so.*
--- /dev/null
+libnotmuch5t64: package-name-doesnt-match-sonames libnotmuch5
--- /dev/null
+libnotmuch.so.5 libnotmuch5t64 #MINVER#
+* Build-Depends-Package: libnotmuch-dev
+ notmuch_built_with@Base 0.23~rc0
+ notmuch_config_get@Base 0.32~rc0
+ notmuch_config_get_bool@Base 0.32~rc0
+ notmuch_config_get_pairs@Base 0.32~rc0
+ notmuch_config_get_values@Base 0.32~rc0
+ notmuch_config_get_values_string@Base 0.32~rc0
+ notmuch_config_list_destroy@Base 0.23~rc0
+ notmuch_config_list_key@Base 0.23~rc0
+ notmuch_config_list_move_to_next@Base 0.23~rc0
+ notmuch_config_list_valid@Base 0.23~rc0
+ notmuch_config_list_value@Base 0.23~rc0
+ notmuch_config_pairs_destroy@Base 0.32~rc0
+ notmuch_config_pairs_key@Base 0.32~rc0
+ notmuch_config_pairs_move_to_next@Base 0.32~rc0
+ notmuch_config_pairs_valid@Base 0.32~rc0
+ notmuch_config_pairs_value@Base 0.32~rc0
+ notmuch_config_path@Base 0.32~rc0
+ notmuch_config_set@Base 0.32~rc0
+ notmuch_config_values_destroy@Base 0.32~rc0
+ notmuch_config_values_get@Base 0.32~rc0
+ notmuch_config_values_move_to_next@Base 0.32~rc0
+ notmuch_config_values_start@Base 0.32~rc0
+ notmuch_config_values_valid@Base 0.32~rc0
+ notmuch_database_add_message@Base 0.3
+ notmuch_database_begin_atomic@Base 0.9~rc1
+ notmuch_database_close@Base 0.13~rc1
+ notmuch_database_compact@Base 0.17~rc1
+ notmuch_database_compact_db@Base 0.32~rc0
+ notmuch_database_create@Base 0.3
+ notmuch_database_create_verbose@Base 0.20~rc1
+ notmuch_database_create_with_config@Base 0.32~rc0
+ notmuch_database_destroy@Base 0.13~rc1
+ notmuch_database_end_atomic@Base 0.9~rc1
+ notmuch_database_find_message@Base 0.9~rc2
+ notmuch_database_find_message_by_filename@Base 0.9~rc2
+ notmuch_database_get_all_tags@Base 0.3
+ notmuch_database_get_config@Base 0.23~rc0
+ notmuch_database_get_config_list@Base 0.23~rc0
+ notmuch_database_get_default_indexopts@Base 0.26~rc0
+ notmuch_database_get_directory@Base 0.3
+ notmuch_database_get_path@Base 0.3
+ notmuch_database_get_revision@Base 0.21~rc1
+ notmuch_database_get_version@Base 0.3
+ notmuch_database_index_file@Base 0.26~rc0
+ notmuch_database_load_config@Base 0.32~rc0
+ notmuch_database_needs_upgrade@Base 0.3
+ notmuch_database_open@Base 0.3
+ notmuch_database_open_verbose@Base 0.20~rc1
+ notmuch_database_open_with_config@Base 0.32~rc0
+ notmuch_database_remove_message@Base 0.3
+ notmuch_database_reopen@Base 0.32~rc0
+ notmuch_database_set_config@Base 0.23~rc0
+ notmuch_database_status_string@Base 0.20~rc1
+ notmuch_database_upgrade@Base 0.3
+ notmuch_directory_delete@Base 0.21~rc1
+ notmuch_directory_destroy@Base 0.3
+ notmuch_directory_get_child_directories@Base 0.3
+ notmuch_directory_get_child_files@Base 0.3
+ notmuch_directory_get_mtime@Base 0.3
+ notmuch_directory_set_mtime@Base 0.3
+ notmuch_filenames_destroy@Base 0.3
+ notmuch_filenames_get@Base 0.3
+ notmuch_filenames_move_to_next@Base 0.3
+ notmuch_filenames_valid@Base 0.3
+ notmuch_indexopts_destroy@Base 0.26~rc0
+ notmuch_indexopts_get_decrypt_policy@Base 0.26~rc0
+ notmuch_indexopts_set_decrypt_policy@Base 0.26~rc0
+ notmuch_message_add_property@Base 0.23~rc0
+ notmuch_message_add_tag@Base 0.3
+ notmuch_message_count_files@Base 0.26~rc0
+ notmuch_message_count_properties@Base 0.27~rc0
+ notmuch_message_destroy@Base 0.3
+ notmuch_message_freeze@Base 0.3
+ notmuch_message_get_database@Base 0.27~rc0
+ notmuch_message_get_date@Base 0.3
+ notmuch_message_get_filename@Base 0.3
+ notmuch_message_get_filenames@Base 0.5
+ notmuch_message_get_flag@Base 0.3
+ notmuch_message_get_flag_st@Base 0.31~rc0
+ notmuch_message_get_header@Base 0.3
+ notmuch_message_get_message_id@Base 0.3
+ notmuch_message_get_properties@Base 0.23~rc0
+ notmuch_message_get_property@Base 0.23~rc0
+ notmuch_message_get_replies@Base 0.3
+ notmuch_message_get_tags@Base 0.3
+ notmuch_message_get_thread_id@Base 0.3
+ notmuch_message_has_maildir_flag@Base 0.26~rc0
+ notmuch_message_has_maildir_flag_st@Base 0.31~rc0
+ notmuch_message_maildir_flags_to_tags@Base 0.5
+ notmuch_message_properties_destroy@Base 0.23~rc0
+ notmuch_message_properties_key@Base 0.23~rc0
+ notmuch_message_properties_move_to_next@Base 0.23~rc0
+ notmuch_message_properties_valid@Base 0.23~rc0
+ notmuch_message_properties_value@Base 0.23~rc0
+ notmuch_message_reindex@Base 0.26~rc0
+ notmuch_message_remove_all_properties@Base 0.23~rc0
+ notmuch_message_remove_all_properties_with_prefix@Base 0.26~rc0
+ notmuch_message_remove_all_tags@Base 0.3
+ notmuch_message_remove_property@Base 0.23~rc0
+ notmuch_message_remove_tag@Base 0.3
+ notmuch_message_set_flag@Base 0.3
+ notmuch_message_tags_to_maildir_flags@Base 0.5
+ notmuch_message_thaw@Base 0.3
+ notmuch_messages_collect_tags@Base 0.3
+ notmuch_messages_destroy@Base 0.3
+ notmuch_messages_get@Base 0.3
+ notmuch_messages_move_to_next@Base 0.3
+ notmuch_messages_valid@Base 0.3
+ notmuch_query_add_tag_exclude@Base 0.12~rc1
+ notmuch_query_count_messages@Base 0.3
+ notmuch_query_count_messages_st@Base 0.21~rc1
+ notmuch_query_count_threads@Base 0.10~rc1
+ notmuch_query_count_threads_st@Base 0.21~rc1
+ notmuch_query_create@Base 0.3
+ notmuch_query_create_with_syntax@Base 0.34~rc0
+ notmuch_query_destroy@Base 0.3
+ notmuch_query_get_database@Base 0.21~rc1
+ notmuch_query_get_query_string@Base 0.4
+ notmuch_query_get_sort@Base 0.4
+ notmuch_query_search_messages@Base 0.3
+ notmuch_query_search_messages_st@Base 0.20~rc1
+ notmuch_query_search_threads@Base 0.3
+ notmuch_query_search_threads_st@Base 0.20~rc1
+ notmuch_query_set_omit_excluded@Base 0.13~rc1
+ notmuch_query_set_sort@Base 0.3
+ notmuch_status_to_string@Base 0.3
+ notmuch_tags_destroy@Base 0.3
+ notmuch_tags_get@Base 0.3
+ notmuch_tags_move_to_next@Base 0.3
+ notmuch_tags_valid@Base 0.3
+ notmuch_thread_destroy@Base 0.3
+ notmuch_thread_get_authors@Base 0.3
+ notmuch_thread_get_matched_messages@Base 0.3
+ notmuch_thread_get_messages@Base 0.16
+ notmuch_thread_get_newest_date@Base 0.3
+ notmuch_thread_get_oldest_date@Base 0.3
+ notmuch_thread_get_subject@Base 0.3
+ notmuch_thread_get_tags@Base 0.3
+ notmuch_thread_get_thread_id@Base 0.3
+ notmuch_thread_get_toplevel_messages@Base 0.3
+ notmuch_thread_get_total_files@Base 0.26~rc0
+ notmuch_thread_get_total_messages@Base 0.3
+ notmuch_threads_destroy@Base 0.3
+ notmuch_threads_get@Base 0.3
+ notmuch_threads_move_to_next@Base 0.3
+ notmuch_threads_valid@Base 0.3
+ (c++)"typeinfo for Xapian::LogicError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::RuntimeError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::DocNotFoundError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::InvalidArgumentError@Base" 0.6.1
+ (c++)"typeinfo for Xapian::Error@Base" 0.6.1
+ (c++)"typeinfo for Xapian::DatabaseError@Base" 0.24~rc0
+ (c++)"typeinfo for Xapian::DatabaseModifiedError@Base" 0.24~rc0
+ (c++)"typeinfo for Xapian::DatabaseOpeningError@Base" 0.32~rc0
+ (c++|optional=present with Xapian 1.4)"typeinfo for Xapian::QueryParserError@Base" 0.23~rc0
+ (c++)"typeinfo name for Xapian::LogicError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::RuntimeError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::DocNotFoundError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::InvalidArgumentError@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::Error@Base" 0.6.1
+ (c++)"typeinfo name for Xapian::DatabaseError@Base" 0.24~rc0
+ (c++)"typeinfo name for Xapian::DatabaseModifiedError@Base" 0.24~rc0
+ (c++)"typeinfo name for Xapian::DatabaseOpeningError@Base" 0.32~rc0
+ (c++|optional=present with Xapian 1.4)"typeinfo name for Xapian::QueryParserError@Base" 0.23~rc0
#!/usr/bin/make -f
+include /usr/share/dpkg/architecture.mk
+
+ifeq ($(DEB_HOST_ARCH),ppc64el)
+ export NOTMUCH_SKIP_TESTS = T810-tsan
+endif
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
override_dh_auto_configure:
BASHCMD=/bin/bash ./configure --prefix=/usr \
- --libdir=/usr/lib/$$(dpkg-architecture -q DEB_TARGET_MULTIARCH) \
+ --libdir=/usr/lib/${DEB_TARGET_MULTIARCH} \
--includedir=/usr/include \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
override_dh_auto_clean:
dh_auto_clean
PYBUILD_NAME=notmuch dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python
- PYBUILD_NAME=notmuch2 dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python-cffi
dh_auto_clean --sourcedirectory bindings/ruby
$(MAKE) -C contrib/notmuch-mutt clean
--- /dev/null
+Test-command: env NOTMUCH_TEST_INSTALLED=1 TERM=dumb
+ NOTMUCH_HAVE_MAN=1 NOTMUCH_HAVE_SFSEXP=1 NOTMUCH_HAVE_XAPIAN_DB_RETRY_LOCK=1
+ NOTMUCH_HAVE_PYTHON3_CFFI=1 NOTMUCH_HAVE_PYTHON3_PYTEST=1
+ NOTMUCH_HAVE_ASAN=1 NOTMUCH_HAVE_TSAN=1
+ ./test/notmuch-test
+Restrictions: allow-stderr
+Architecture: amd64, arm64
+Depends: @,
+ build-essential,
+ dtach,
+ emacs-nox,
+ gdb,
+ git,
+ gnupg,
+ gpgsm,
+ libtalloc-dev,
+ man,
+ xapian-tools
| f | | notmuch-show-forward-message | notmuch-show-forward-message |
| g | | | |
| h | | notmuch-show-toggle-visibility-headers | |
-| i | | | |
+| i | notmuch-search-toggle-hide-excluded | | notmuch-tree-toggle-hide-excluded |
| j | notmuch-jump-search | notmuch-jump-search | notmuch-jump-search |
| k | notmuch-tag-jump | notmuch-tag-jump | notmuch-tag-jump |
| l | notmuch-search-filter | notmuch-show-filter-thread | notmuch-tree-filter |
return ''
frm = email.utils.getaddresses([hdr])
- return ','.join(['<a href="mailto:%s">%s</a> ' % ((l, p) if p else (l, l)) for (p, l) in frm])
+ return ', '.join(['<a href="mailto:%s">%s</a>' % ((l, p) if p else (l, l)) for (p, l) in frm])
env.globals['mailto_addrs'] = mailto_addrs
def link_msg(msg):
def format_message(nm_msg, mid):
fn = list(nm_msg.filenames())[0]
- msg = MaildirMessage(open(fn))
+ msg = MaildirMessage(open(fn, 'rb'))
return format_message_walk(msg, mid)
def decodeAnyway(txt, charset='ascii'):
{% set headers = ['Subject', 'Date'] %}
{% set addr_headers = ['To', 'Cc', 'From'] %}
{% for header in headers: %}
-<p><b>{{header}}:</b>{{m.header(header)|e}}</p>
+<p><b>{{header}}:</b> {{m.header(header)|e}}</p>
{% endfor %}
{% for header in addr_headers: %}
-<p><b>{{header}}:</b>{{mailto_addrs(m,header)|safe}}</p>
+<p><b>{{header}}:</b> {{mailto_addrs(m,header)|safe}}</p>
{% endfor %}
<hr>
{% for part in format_message(m,mid): %}{{ part|safe }}{% endfor %}
# (format_message_sprinter)
id: messageid,
match: bool,
+ excluded: bool,
filename: [string*],
timestamp: unix_time, # date header as unix time
date_relative: string, # user-friendly timestamp
CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.stamp
CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
+
+CLEAN := $(CLEAN) $(dir)/__pycache__
# General information about the project.
project = u'notmuch'
-copyright = u'2009-2022, Carl Worth and many others'
+copyright = u'2009-2024, Carl Worth and many others'
location = os.path.dirname(__file__)
Default tag prefix (filter) for :any:`notmuch-git`.
+.. nmconfig:: index.as_text
+
+ List of regular expressions (without delimiters) for MIME types to
+ be indexed as text. Currently this applies only to attachments. By
+ default the regex matches anywhere in the content type; if the
+ user wants an anchored match, they should include anchors in their
+ regexes.
+
+ History: This configuration value was introduced in notmuch 0.38.
+
.. nmconfig:: index.decrypt
Policy for decrypting encrypted messages during indexing. Must be
.. envvar:: NOTMUCH_GIT_DIR
- Default location of git repository. Overriden by :option:`--git-dir`.
+ Default location of git repository. Overridden by :option:`--git-dir`.
.. envvar:: NOTMUCH_GIT_PREFIX
- Default tag prefix (filter). Overriden by :option:`--tag-prefix`.
+ Default tag prefix (filter). Overridden by :option:`--tag-prefix`.
SEE ALSO
========
.. option:: --output=(summary|threads|messages|files|tags)
- summary
+ summary (default)
Output a summary of each thread with any message matching the
search terms. The summary includes the thread ID, date, the
number of messages in the thread (both the number matched and
By default, results will be displayed in reverse chronological
order, (that is, the newest results will be displayed first).
+.. option:: --offset=[-]N
+
+ Skip displaying the first N results. With the leading '-', start
+ at the Nth result from the end.
+
+.. option:: --limit=N
+
+ Limit the number of displayed results to N.
+
.. option:: --verify
Compute and report the validity of any MIME cryptographic
Matches any word starting with "prelim", inside a message subject.
-``(subject (starts-wih quick) "brown fox")``
+``(subject (starts-with quick) "brown fox")``
Match messages whose subject contains "quick brown fox", but also
"brown fox quicksand".
NOTES
=====
-.. [#macro-details] Technically macros impliment lazy evaluation and
+.. [#macro-details] Technically macros implement lazy evaluation and
lexical scope. There is one top level scope
containing all macro definitions, but all
parameter definitions are local to a given macro.
.. [#aka-bool] a.k.a. boolean prefixes
-.. [#not-phrase] Due to the implemention of phrase fields in Xapian,
+.. [#not-phrase] Due to the implementation of phrase fields in Xapian,
regex queries could only match individual words.
-.. [#not-body] Due the the way ``body`` is implemented in notmuch,
+.. [#not-body] Due to the way ``body`` is implemented in notmuch,
this modifier is not supported in the ``body`` field.
.. [#not-path] Due to the way recursive ``path`` queries are implemented
is important, we’ll refer to the Emacs interface as
*notmuch-emacs*.
-Notmuch-emacs is highly customizable via the the Emacs customization
+Notmuch-emacs is highly customizable via the Emacs customization
framework (or just by setting the appropriate variables). We try to
point out relevant variables in this manual, but in order to avoid
duplication of information, you can usually find the most detailed
Refresh the buffer
+.. el:define-key:: i
+
+ Toggle whether to show messages with excluded tags in search results.
+
.. el:define-key:: ?
Display full set of key bindings
Dealing with duplicates
-----------------------
-If there are are multiple files with the same :mailheader:`Message-ID`
+If there are multiple files with the same :mailheader:`Message-ID`
(see :any:`duplicate-files`), then :any:`notmuch-show` displays the
number of duplicates and identifies the current duplicate. In the
following example duplicate 3 of 5 is displayed.
Filter the current search results based on an additional tag
+.. el:define-key:: i
+
+ Toggle whether to show messages with excluded tags in search results.
.. el:define-key:: g
=
See also :el:defcustom:`notmuch-search-result-format` and
:el:defcustom:`notmuch-unthreaded-result-format`.
+.. _notmuch-tree-outline:
+
+notmuch-tree-outline
+--------------------
+
+When this mode is set, each thread and subthread in the results
+list is treated as a foldable section, with its first message as
+its header.
+
+The mode just makes available in the tree buffer all the
+keybindings in info:emacs#Outline_Mode, and binds the following
+additional keys:
+
+.. el:define-key:: <tab>
+
+ Cycle visibility state of the current message's tree.
+
+.. el:define-key:: <M-tab>
+
+ Cycle visibility state of all trees in the buffer.
+
+The behaviour of this minor mode is affected by the following
+customizable variables:
+
+.. el:defcustom:: notmuch-tree-outline-enabled
+
+ |docstring::notmuch-tree-outline-enabled|
+
+.. el:defcustom:: notmuch-tree-outline-visibility
+
+ |docstring::notmuch-tree-outline-visibility|
+
+.. el:defcustom:: notmuch-tree-outline-auto-close
+
+ |docstring::notmuch-tree-outline-auto-close|
+
+.. el:defcustom:: notmuch-tree-outline-open-on-next
+
+ |docstring::notmuch-tree-outline-open-on-next|
.. _notmuch-unthreaded:
notmuch-tag-undo
----------------
-Each notmuch buffer supporting tagging operations (i.e buffers in
+Each notmuch buffer supporting tagging operations (i.e. buffers in
:any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
:any:`notmuch-unthreaded` mode) keeps a local stack of tagging
operations. These can be undone via :any:`notmuch-tag-undo`. By default
;;; Setup
(defun notmuch-address-selection-function (prompt collection initial-input)
- "Call (`completing-read'
- PROMPT COLLECTION nil nil INITIAL-INPUT 'notmuch-address-history)"
+ "Default address selection function: delegate to completing read."
(completing-read
prompt collection nil nil initial-input 'notmuch-address-history))
ELISP=
MAILTO=
HELLO=
+TO_SEP=
+CC_SEP=
+BCC_SEP=
# Short options compatible with mutt(1).
while getopts :s:c:b:i:h opt; do
ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")"
;;
--to)
- ELISP="${ELISP} (message-goto-to) (insert \"${OPTARG}, \")"
+ ELISP="${ELISP} (message-goto-to) (insert \"${TO_SEP}${OPTARG}\")"
+ TO_SEP=", "
;;
--cc|c)
- ELISP="${ELISP} (message-goto-cc) (insert \"${OPTARG}, \")"
+ ELISP="${ELISP} (message-goto-cc) (insert \"${CC_SEP}${OPTARG}\")"
+ CC_SEP=", "
;;
--bcc|b)
- ELISP="${ELISP} (message-goto-bcc) (insert \"${OPTARG}, \")"
+ ELISP="${ELISP} (message-goto-bcc) (insert \"${BCC_SEP}${OPTARG}\")"
+ BCC_SEP=", "
;;
--body|i)
ELISP="${ELISP} (message-goto-body) (insert-file \"${OPTARG}\")"
(declare-function notmuch-poll "notmuch-lib" ())
(declare-function notmuch-tree "notmuch-tree"
(&optional query query-context target buffer-name
- open-target unthreaded parent-buffer oldest-first))
+ open-target unthreaded parent-buffer
+ oldest-first hide-excluded))
(declare-function notmuch-unthreaded "notmuch-tree"
(&optional query query-context target buffer-name
- open-target))
+ open-target oldest-first hide-excluded))
;;; Options
:sort-order Specify the sort order to be used for the search.
Possible values are `oldest-first', `newest-first'
or nil. Nil means use the default sort order.
+ :excluded Whether to show mail with excluded tags in the
+ search. Possible values are `hide', `show',
+ or nil. Nil means use the default value of
+ `notmuch-search-hide-excluded'.
:search-type Specify whether to run the search in search-mode,
tree mode or unthreaded mode. Set to `tree' to
- specify tree mode, 'unthreaded to specify
+ specify tree mode, \\='unthreaded to specify
unthreaded mode, and set to nil (or anything
except tree and unthreaded) to specify search
mode.
append (notmuch-hello-reflect-generate-row ncols nrows row list))))
(defun notmuch-hello-widget-search (widget &rest _ignore)
- (cl-case (widget-get widget :notmuch-search-type)
- (tree
- (let ((n (notmuch-search-format-buffer-name (widget-value widget) "tree" t)))
- (notmuch-tree (widget-get widget :notmuch-search-terms)
- nil nil n nil nil nil
- (widget-get widget :notmuch-search-oldest-first))))
- (unthreaded
- (let ((n (notmuch-search-format-buffer-name (widget-value widget)
- "unthreaded" t)))
- (notmuch-unthreaded (widget-get widget :notmuch-search-terms) nil nil n)))
- (t
- (notmuch-search (widget-get widget :notmuch-search-terms)
- (widget-get widget :notmuch-search-oldest-first)))))
+ (let ((search-terms (widget-get widget :notmuch-search-terms))
+ (oldest-first (widget-get widget :notmuch-search-oldest-first))
+ (exclude (widget-get widget :notmuch-search-hide-excluded)))
+ (cl-case (widget-get widget :notmuch-search-type)
+ (tree
+ (let ((n (notmuch-search-format-buffer-name (widget-value widget) "tree" t)))
+ (notmuch-tree search-terms nil nil n nil nil nil oldest-first exclude)))
+ (unthreaded
+ (let ((n (notmuch-search-format-buffer-name (widget-value widget)
+ "unthreaded" t)))
+ (notmuch-unthreaded search-terms nil nil n nil oldest-first exclude)))
+ (t
+ (notmuch-search search-terms oldest-first exclude)))))
(defun notmuch-saved-search-count (search)
(car (notmuch--process-lines notmuch-command "count" search)))
(newest-first nil)
(oldest-first t)
(otherwise notmuch-search-oldest-first)))
+ (exclude (cl-case (plist-get elem :excluded)
+ (hide t)
+ (show nil)
+ (otherwise notmuch-search-hide-excluded)))
(search-type (plist-get elem :search-type))
(msg-count (plist-get elem :count)))
(widget-insert (format "%8s "
:notmuch-search-terms query
:notmuch-search-oldest-first oldest-first
:notmuch-search-type search-type
+ :notmuch-search-hide-excluded exclude
name)
(setq column-indent
(1+ (max 0 (- column-width (length name)))))))
"Keymap for \"notmuch hello\" buffers.")
(define-derived-mode notmuch-hello-mode fundamental-mode "notmuch-hello"
- "Major mode for convenient notmuch navigation. This is your entry portal into notmuch.
+ "Major mode for convenient notmuch navigation. This is your entry
+portal into notmuch.
Saved searches are \"bookmarks\" for arbitrary queries. Hit RET
or click on a saved search to view matching threads. Edit saved
(widget-create 'notmuch-search-item :value search :size width)))))
(defun notmuch-hello-insert-searches (title query-list &rest options)
- "Insert a section with TITLE showing a list of buttons made from QUERY-LIST.
+ "Insert a section with TITLE showing a list of buttons made from
+QUERY-LIST.
QUERY-LIST should ideally be a plist but for backwards
compatibility other forms are also accepted (see
:show-empty-searches - show buttons with no matching messages
:hide-if-empty - hide if no buttons would be shown
(only makes sense without :show-empty-searches)
-:filter - This can be a function that takes the search query as its argument and
- returns a filter to be used in conjunction with the query for that search or nil
- to hide the element. This can also be a string that is used as a combined with
- each query using \"and\".
-:filter-count - Separate filter to generate the count displayed each search. Accepts
- the same values as :filter. If :filter and :filter-count are specified, this
- will be used instead of :filter, not in conjunction with it."
+:filter - This can be a function that takes the search query as
+ its argument and returns a filter to be used in conjunction
+ with the query for that search or nil to hide the
+ element. This can also be a string that is used as a combined
+ with each query using \"and\".
+:filter-count - Separate filter to generate the count displayed
+ each search. Accepts the same values as :filter. If :filter
+ and :filter-count are specified, this will be used instead of
+ :filter, not in conjunction with it."
+
(widget-insert title ": ")
(when (and notmuch-hello-first-run (plist-get options :initially-hidden))
(add-to-list 'notmuch-hello-hidden-sections title))
(cl-case (plist-get saved-search :sort-order)
(newest-first nil)
(oldest-first t)
- (otherwise (default-value 'notmuch-search-oldest-first)))))
+ (otherwise (default-value 'notmuch-search-oldest-first))))
+ (exclude (cl-case (plist-get saved-search :excluded)
+ (hide t)
+ (show nil)
+ (otherwise notmuch-search-hide-excluded))))
(push (list key name
(cond
((eq (plist-get saved-search :search-type) 'tree)
- (lambda () (notmuch-tree query)))
+ (lambda () (notmuch-tree query nil nil nil nil nil nil
+ oldest-first exclude)))
((eq (plist-get saved-search :search-type) 'unthreaded)
- (lambda () (notmuch-unthreaded query)))
+ (lambda () (notmuch-unthreaded query nil nil nil nil
+ oldest-first exclude)))
(t
- (lambda () (notmuch-search query oldest-first)))))
+ (lambda () (notmuch-search query oldest-first exclude)))))
action-map)))))
(setq action-map (nreverse action-map))
(if action-map
:group 'notmuch-search)
(make-variable-buffer-local 'notmuch-search-oldest-first)
+(defcustom notmuch-search-hide-excluded t
+ "Hide mail tagged with a excluded tag.
+
+Excluded tags are defined in the users configuration file under
+the search section. When this variable is true, any mail with
+such a tag will not be shown in the search output."
+ :type 'boolean
+ :group 'notmuch-search)
+(make-variable-buffer-local 'notmuch-search-hide-excluded)
+
(defcustom notmuch-poll-script nil
"[Deprecated] Command to run to incorporate new mail into the notmuch database.
mode, but bindings tables are shown with documentation strings
rather than command names. By default, this uses the first line
of each command's documentation string. A command can override
-this by setting the 'notmuch-doc property of its command symbol.
+this by setting the \\='notmuch-doc property of its command symbol.
A command that supports a prefix argument can explicitly document
-its prefixed behavior by setting the 'notmuch-prefix-doc property
+its prefixed behavior by setting the \\='notmuch-prefix-doc property
of its command symbol."
(interactive)
(let ((doc (substitute-command-keys
(when (mm-inlinable-p handle)
(set-buffer display-buffer)
(mm-display-part handle)
+ (plist-put part :undisplayer (mm-handle-undisplayer handle))
t))))))
;;; Generic Utilities
(list face)))
(defun notmuch-apply-face (object face &optional below start end)
- "Combine FACE into the 'face text property of OBJECT between START and END.
+ "Combine FACE into the \\='face text property of OBJECT between START and END.
This function combines FACE with any existing faces between START
and END in OBJECT. Attributes specified by FACE take precedence
(addr (and good-tokens (mapconcat #'identity good-tokens ", "))))
(message-replace-header header addr))))))
+;;;#autoload
(defun notmuch-mua-mail (&optional to subject other-headers _continue
switch-function yank-action send-actions
- return-action &rest ignored)
+ return-action &rest _ignored)
"Invoke the notmuch mail composition window.
The position of point when the function returns differs depending
(let ((user-agent (funcall notmuch-mua-user-agent-function)))
(unless (string-empty-p user-agent)
(push (cons 'User-Agent user-agent) other-headers))))
- (unless (assq 'From other-headers)
- (push (cons 'From (message-make-from
- (notmuch-user-name)
- (notmuch-user-primary-email)))
- other-headers))
(notmuch-mua-pop-to-buffer (message-buffer-name "mail" to)
(or switch-function
(notmuch-mua-get-switch-function)))
;; Cause `message-setup-1' to do things relevant for mail,
;; such as observe `message-default-mail-headers'.
(message-this-is-mail t))
+ (unless (assq 'From headers)
+ (push (cons 'From (message-make-from
+ (notmuch-user-name)
+ (notmuch-user-primary-email)))
+ headers))
(message-setup-1 headers yank-action send-actions return-action))
(notmuch-fcc-header-setup)
(notmuch-mua--remove-dont-reply-to-names)
(message-send-and-exit arg)
(message-send arg)))))
+;;;#autoload
(defun notmuch-mua-send-and-exit (&optional arg)
(interactive "P")
(notmuch-mua-send-common arg t))
+;;;#autoload
(defun notmuch-mua-send (&optional arg)
(interactive "P")
(notmuch-mua-send-common arg))
+;;;#autoload
(defun notmuch-mua-kill-buffer ()
(interactive)
(message-kill-buffer))
;;; _
+;;;#autoload
(define-mail-user-agent 'notmuch-user-agent
'notmuch-mua-mail
'notmuch-mua-send-and-exit
with an additional function that requires the next value in the
input to be a list and descends into it, allowing its elements to
be read one at a time or further descended into. Both functions
-can return 'retry to indicate that not enough input is available.
+can return \\='retry to indicate that not enough input is available.
The parser always consumes input from point in the current
buffer. Hence, the caller is allowed to delete any data before
(defun notmuch-sexp-read (sp)
"Consume and return the value at point in the current buffer.
-Returns 'retry if there is insufficient input to parse a complete
+Returns \\='retry if there is insufficient input to parse a complete
value (though it may still move point over whitespace). If the
parser is currently inside a list and the next token ends the
-list, this moves point just past the terminator and returns 'end.
+list, this moves point just past the terminator and returns \\='end.
Otherwise, this moves point to just past the end of the value and
returns the value."
(skip-chars-forward " \n\r\t")
(defun notmuch-sexp-begin-list (sp)
"Parse the beginning of a list value and enter the list.
-Returns 'retry if there is insufficient input to parse the
+Returns \\='retry if there is insufficient input to parse the
beginning of the list. If this is able to parse the beginning of
a list, it moves point past the token that opens the list and
returns t. Later calls to `notmuch-sexp-read' will return the
;;; Utility functions
(defun notmuch-print-run-evince (file)
- "View FILE using 'evince'."
+ "View FILE using `evince'."
(start-process "evince" nil "evince" file))
(defun notmuch-print-run-muttprint (&optional output)
- "Pass the contents of the current buffer to 'muttprint'.
+ "Pass the contents of the current buffer to `muttprint'.
Optional OUTPUT allows passing a list of flags to muttprint."
(apply #'notmuch--call-process-region (point-min) (point-max)
(defun notmuch-show-update-tags (tags)
"Update the displayed tags of the current message."
(save-excursion
- (goto-char (notmuch-show-message-top))
- (when (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
- (let ((inhibit-read-only t))
- (replace-match (concat "("
- (notmuch-tag-format-tags
- tags
- (notmuch-show-get-prop :orig-tags))
- ")"))))))
+ (let ((inhibit-read-only t)
+ (start (notmuch-show-message-top))
+ (depth (notmuch-show-get-prop :depth))
+ (orig-tags (notmuch-show-get-prop :orig-tags))
+ (props (notmuch-show-get-message-properties))
+ (extent (notmuch-show-message-extent)))
+ (goto-char start)
+ (notmuch-show-insert-headerline props depth tags orig-tags)
+ (put-text-property start (1+ start)
+ :notmuch-message-properties props)
+ (put-text-property (car extent) (cdr extent) :notmuch-message-extent extent)
+ ;; delete original headerline, but do not save to kill ring
+ (delete-region (point) (1+ (line-end-position))))))
(defun notmuch-clean-address (address)
"Try to clean a single email ADDRESS for display. Return a cons
(plist-put msg :height height)
height))))
-(defun notmuch-show-insert-headerline (headers date tags depth duplicate file-count)
+(defun notmuch-show-insert-headerline (msg-plist depth tags &optional orig-tags)
"Insert a notmuch style headerline based on HEADERS for a
message at DEPTH in the current thread."
- (let ((start (point))
- (from (notmuch-sanitize
+ (let* ((start (point))
+ (headers (plist-get msg-plist :headers))
+ (duplicate (or (plist-get msg-plist :duplicate) 0))
+ (file-count (length (plist-get msg-plist :filename)))
+ (date (or (and notmuch-show-relative-dates
+ (plist-get msg-plist :date_relative))
+ (plist-get headers :Date)))
+ (from (notmuch-sanitize
(notmuch-show-clean-address (plist-get headers :From)))))
(when (string-match "\\cR" from)
;; If the From header has a right-to-left character add
" ("
date
") ("
- (notmuch-tag-format-tags tags tags)
+ (notmuch-tag-format-tags tags (or orig-tags tags))
")")
(insert
(if (> file-count 1)
(when show
(button-put button :notmuch-lazy-part nil)
(notmuch-show-lazy-part lazy-part button))
- ;; else there must be an overlay.
- (overlay-put overlay 'invisible (not show))
+ (let* ((part (plist-get properties :notmuch-part))
+ (undisplayer (plist-get part :undisplayer))
+ (mime-type (plist-get part :computed-type))
+ (redisplay-data (button-get button
+ :notmuch-redisplay-data))
+ (imagep (string-match "^image/" mime-type)))
+ (cond
+ ((and imagep (not show) undisplayer)
+ ;; call undisplayer thunk created by gnus.
+ (funcall undisplayer)
+ ;; there is an extra newline left
+ (delete-region
+ (+ 1 (button-end button))
+ (+ 2 (button-end button))))
+ ((and imagep show redisplay-data)
+ (notmuch-show-lazy-part redisplay-data button))
+ (t
+ (overlay-put overlay 'invisible (not show)))))
t)))))))
;;; Part content ID handling
(part-end (copy-marker (point) t))
;; We have to save the depth as we can't find the depth
;; when narrowed.
- (depth (notmuch-show-get-depth)))
+ (depth (notmuch-show-get-depth))
+ (mime-type (plist-get (cadr part-args) :computed-type)))
(save-restriction
(narrow-to-region part-beg part-end)
(delete-region part-beg part-end)
+ (when (and mime-type (string-match "^image/" mime-type))
+ (button-put button :notmuch-redisplay-data part-args))
(apply #'notmuch-show-insert-bodypart-internal part-args)
(indent-rigidly part-beg
part-end
(and deep button)
(and high button)
(and long button))))
- (content-beg (point)))
+ (content-beg (point))
+ (part-data (list msg part mime-type nth depth button)))
;; Store the computed mime-type for later use (e.g. by attachment handlers).
(plist-put part :computed-type mime-type)
- (if show-part
- (notmuch-show-insert-bodypart-internal msg part mime-type nth depth button)
+ (cond
+ (show-part
+ (apply #'notmuch-show-insert-bodypart-internal part-data)
+ (when (and button (string-match "^image/" mime-type))
+ (button-put button :notmuch-redisplay-data part-data)))
+ (t
(when button
- (button-put button :notmuch-lazy-part
- (list msg part mime-type nth depth button))))
+ (button-put button :notmuch-lazy-part part-data))))
;; Some of the body part handlers leave point somewhere up in the
;; part, so we make sure that we're down at the end.
(goto-char (point-max))
(defun notmuch-show-insert-msg (msg depth)
"Insert the message MSG at depth DEPTH in the current thread."
(let* ((headers (plist-get msg :headers))
- (duplicate (or (plist-get msg :duplicate) 0))
- (files (length (plist-get msg :filename)))
;; Indentation causes the buffer offset of the start/end
;; points to move, so we must use markers.
message-start message-end
headers-start headers-end
(bare-subject (notmuch-show-strip-re (plist-get headers :Subject))))
(setq message-start (point-marker))
- (notmuch-show-insert-headerline headers
- (or (and notmuch-show-relative-dates
- (plist-get msg :date_relative))
- (plist-get headers :Date))
- (plist-get msg :tags) depth duplicate files)
+ (notmuch-show-insert-headerline msg depth (plist-get msg :tags))
(setq content-start (point-marker))
;; Set `headers-start' to point after the 'Subject:' header to be
;; compatible with the existing implementation. This just sets it
(defun notmuch-show-stash-mlarchive-link (&optional mla)
"Copy an ML Archive URI for the current message to the kill-ring.
-This presumes that the message is available at the selected Mailing List Archive.
+This presumes that the message is available at the selected
+Mailing List Archive.
-If optional argument MLA is non-nil, use the provided key instead of prompting
-the user (see `notmuch-show-stash-mlarchive-link-alist')."
+If optional argument MLA is non-nil, use the provided key instead
+of prompting the user (see
+`notmuch-show-stash-mlarchive-link-alist')."
(interactive)
(let ((url (cdr (assoc
(or mla
(concat url (notmuch-show-get-message-id t))))))
(defun notmuch-show-stash-mlarchive-link-and-go (&optional mla)
- "Copy an ML Archive URI for the current message to the kill-ring and visit it.
+ "Copy an ML Archive URI for the current message to the
+ kill-ring and visit it.
-This presumes that the message is available at the selected Mailing List Archive.
+This presumes that the message is available at the selected
+Mailing List Archive.
-If optional argument MLA is non-nil, use the provided key instead of prompting
-the user (see `notmuch-show-stash-mlarchive-link-alist')."
+If optional argument MLA is non-nil, use the provided key instead
+of prompting the user (see
+`notmuch-show-stash-mlarchive-link-alist')."
(interactive)
(notmuch-show-stash-mlarchive-link mla)
(browse-url (current-kill 0 t)))
For example, to replace a tag with another string, simply use
that string as a formatting expression. To change the foreground
of a tag to red, use the expression
- (propertize tag 'face '(:foreground \"red\"))
+ (propertize tag \\='face \\='(:foreground \"red\"))
See also `notmuch-tag-format-image', which can help replace tags
with images."
unless strike-through is not available (e.g., emacs is running in
a terminal) in which case it uses inverse video. To hide deleted
tags completely set this to
- '((\".*\" nil))
+ \\='((\".*\" nil))
See `notmuch-tag-formats' for full documentation."
:group 'notmuch-show
(defcustom notmuch-before-tag-hook nil
"Hooks that are run before tags of a message are modified.
-'tag-changes' will contain the tags that are about to be added or removed as
+`tag-changes' will contain the tags that are about to be added or removed as
a list of strings of the form \"+TAG\" or \"-TAG\".
-'query' will be a string containing the search query that determines
+`query' will be a string containing the search query that determines
the messages that are about to be tagged."
:type 'hook
:options '(notmuch-hl-line-mode)
(defcustom notmuch-after-tag-hook nil
"Hooks that are run after tags of a message are modified.
-'tag-changes' will contain the tags that were added or removed as
+`tag-changes' will contain the tags that were added or removed as
a list of strings of the form \"+TAG\" or \"-TAG\".
-'query' will be a string containing the search query that determines
+`query' will be a string containing the search query that determines
the messages that were tagged."
:type 'hook
:options '(notmuch-hl-line-mode)
(declare-function notmuch-search-previous-thread "notmuch" ())
(declare-function notmuch-tree-from-search-thread "notmuch" ())
-;; the following variable is defined in notmuch.el
-(defvar notmuch-search-query-string)
-
;; this variable distinguishes the unthreaded display from the normal tree display
(defvar-local notmuch-tree-unthreaded nil
"A buffer local copy of argument unthreaded to the function notmuch-tree.")
(defface notmuch-tree-match-tree-face
nil
- "Face used in tree mode for the thread tree block graphics in messages matching the query."
+ "Face used in tree mode for the thread tree block graphics in
+messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
(defface notmuch-tree-no-match-tree-face
nil
- "Face used in tree mode for the thread tree block graphics in messages matching the query."
+ "Face used in tree mode for the thread tree block graphics in
+messages matching the query."
:group 'notmuch-tree
:group 'notmuch-faces)
(define-key map [remap notmuch-jump-search] 'notmuch-tree-jump-search)
(define-key map "o" 'notmuch-tree-toggle-order)
+ (define-key map "i" 'notmuch-tree-toggle-hide-excluded)
(define-key map "S" 'notmuch-search-from-tree-current-query)
(define-key map "U" 'notmuch-unthreaded-from-tree-current-query)
(define-key map "Z" 'notmuch-tree-from-unthreaded-current-query)
(define-key map "V" 'notmuch-tree-view-raw-message)
(define-key map "l" 'notmuch-tree-filter)
(define-key map "t" 'notmuch-tree-filter-by-tag)
+ (define-key map "E" 'notmuch-tree-edit-search)
;; The main tree view bindings
(define-key map (kbd "RET") 'notmuch-tree-show-message)
"Call notmuch search with the current query."
(interactive)
(notmuch-tree-close-message-window)
- (notmuch-search (notmuch-tree-get-query)))
+ (notmuch-search (notmuch-tree-get-query)
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded))
(defun notmuch-tree-message-window-kill-hook ()
"Close the message pane when exiting the show buffer."
target
nil
unthreaded
- notmuch-search-oldest-first)))
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded)))
(defun notmuch-tree-thread-top ()
(when (notmuch-tree-get-message-properties)
A message tree is another name for a single sub-thread: i.e., a
message together with all its descendents."
(let ((msg (car tree))
- (replies (cadr tree)))
+ (replies (cadr tree))
+ ;; outline level, computed from the message's depth and
+ ;; whether or not it's the first message in the tree.
+ (level (1+ (if (and (eq 0 depth) (not first)) 1 depth))))
(cond
((and (< 0 depth) (not last))
(push (alist-get 'vertical-tee notmuch-tree-thread-symbols) tree-status))
(setq msg (plist-put msg :first (and first (eq 0 depth))))
(setq msg (plist-put msg :tree-status tree-status))
(setq msg (plist-put msg :orig-tags (plist-get msg :tags)))
+ (setq msg (plist-put msg :level level))
(notmuch-tree-goto-and-insert-msg msg)
(pop tree-status)
(pop tree-status)
(notmuch-tree-insert-thread replies (1+ depth) tree-status)))
(defun notmuch-tree-insert-thread (thread depth tree-status)
- "Insert the collection of sibling sub-threads THREAD at depth DEPTH in the current forest."
+ "Insert the collection of sibling sub-threads THREAD at depth
+DEPTH in the current forest."
(let ((n (length thread)))
(cl-loop for tree in thread
for count from 1 to n
(setq notmuch-buffer-refresh-function #'notmuch-tree-refresh-view)
(hl-line-mode 1)
(setq buffer-read-only t)
- (setq truncate-lines t))
+ (setq truncate-lines t)
+ (when notmuch-tree-outline-enabled (notmuch-tree-outline-mode 1)))
(defvar notmuch-tree-process-exit-functions nil
"Functions called when the process inserting a tree of results finishes.
results-buf)))))
(defun notmuch-tree-worker (basic-query &optional query-context target
- open-target unthreaded oldest-first)
+ open-target unthreaded oldest-first
+ exclude)
"Insert the tree view of the search in the current buffer.
This is is a helper function for notmuch-tree. The arguments are
(notmuch-tree-mode)
(add-hook 'post-command-hook #'notmuch-tree-command-hook t t)
(setq notmuch-search-oldest-first oldest-first)
+ (setq notmuch-search-hide-excluded exclude)
(setq notmuch-tree-unthreaded unthreaded)
(setq notmuch-tree-basic-query basic-query)
(setq notmuch-tree-query-context (if (or (string= query-context "")
(and query-context
(concat " and (" query-context ")"))))
(sort-arg (if oldest-first "--sort=oldest-first" "--sort=newest-first"))
- (message-arg (if unthreaded "--unthreaded" "--entire-thread")))
+ (message-arg (if unthreaded "--unthreaded" "--entire-thread"))
+ (exclude-arg (if exclude "--exclude=true" "--exclude=false")))
(when (equal (car (notmuch--process-lines notmuch-command "count" search-args)) "0")
(setq search-args basic-query))
(notmuch-tag-clear-cache)
(let ((proc (notmuch-start-notmuch
"notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
"show" "--body=false" "--format=sexp" "--format-version=5"
- sort-arg message-arg search-args))
+ sort-arg message-arg exclude-arg search-args))
;; Use a scratch buffer to accumulate partial output.
;; This buffer will be killed by the sentinel, which
;; should be called no matter how the process dies.
(setq notmuch-search-oldest-first (not notmuch-search-oldest-first))
(notmuch-tree-refresh-view))
+(defun notmuch-tree-toggle-hide-excluded ()
+ "Toggle whether to hide excluded messages.
+
+This command toggles whether to hide excluded messages for the current
+search. The default value for this is defined by `notmuch-search-hide-excluded'."
+ (interactive)
+ (setq notmuch-search-hide-excluded (not notmuch-search-hide-excluded))
+ (notmuch-tree-refresh-view))
+
+;;;###autoload
(defun notmuch-tree (&optional query query-context target buffer-name
- open-target unthreaded parent-buffer oldest-first)
+ open-target unthreaded parent-buffer
+ oldest-first hide-excluded)
"Display threads matching QUERY in tree view.
The arguments are:
it is nil \"*notmuch-tree\" followed by QUERY is used.
OPEN-TARGET: If TRUE open the target message in the message pane.
UNTHREADED: If TRUE only show matching messages in an unthreaded view."
- (interactive)
+ (interactive
+ (list
+ ;; Prompt for a query
+ nil
+ ;; Fill other args with nil.
+ nil nil nil nil nil nil
+ ;; Populate these from the default value of these options.
+ (default-value 'notmuch-search-oldest-first)
+ (default-value 'notmuch-search-hide-excluded)))
(unless query
(setq query (notmuch-read-query (concat "Notmuch "
(if unthreaded "unthreaded " "tree ")
(pop-to-buffer-same-window buffer))
;; Don't track undo information for this buffer
(setq buffer-undo-list t)
- (notmuch-tree-worker query query-context target open-target unthreaded oldest-first)
+ (notmuch-tree-worker query query-context target open-target
+ unthreaded oldest-first hide-excluded)
(setq notmuch-tree-parent-buffer parent-buffer)
(setq truncate-lines t))
(defun notmuch-unthreaded (&optional query query-context target buffer-name
- open-target)
+ open-target oldest-first hide-excluded)
"Display threads matching QUERY in unthreaded view.
See function NOTMUCH-TREE for documentation of the arguments"
- (interactive)
- (notmuch-tree query query-context target buffer-name open-target t))
+ (interactive
+ (list
+ ;; Prompt for a query
+ nil
+ ;; Fill other args with nil.
+ nil nil nil nil
+ ;; Populate these from the default value of these options.
+ (default-value 'notmuch-search-oldest-first)
+ (default-value 'notmuch-search-hide-excluded)))
+ (notmuch-tree query query-context target buffer-name open-target
+ t nil oldest-first hide-excluded))
(defun notmuch-tree-filter (query)
"Filter or LIMIT the current search results based on an additional query string.
(let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
(notmuch-tree-close-message-window)
(notmuch-tree (concat notmuch-tree-basic-query " and tag:" tag)
+ notmuch-tree-query-context
+ nil
+ nil
+ nil
+ notmuch-tree-unthreaded
+ nil
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded)))
+
+(defun notmuch-tree-edit-search (query)
+ "Edit the current search"
+ (interactive (list (read-from-minibuffer "Edit search: "
+ notmuch-tree-basic-query)))
+ (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
+ (notmuch-tree-close-message-window)
+ (notmuch-tree query
notmuch-tree-query-context
nil
nil
nil
notmuch-search-oldest-first)))
+;;; Tree outline mode
+;;;; Custom variables
+(defcustom notmuch-tree-outline-enabled nil
+ "Whether to automatically activate `notmuch-tree-outline-mode' in tree views."
+ :type 'boolean)
+
+(defcustom notmuch-tree-outline-visibility 'hide-others
+ "Default state of the forest outline for `notmuch-tree-outline-mode'.
+
+This variable controls the state of a forest initially and after
+a movement command. If set to nil, all trees are displayed while
+the symbol hide-all indicates that all trees in the forest should
+be folded and hide-other that only the first one should be
+unfolded."
+ :type '(choice (const :tag "Show all" nil)
+ (const :tag "Hide others" hide-others)
+ (const :tag "Hide all" hide-all)))
+
+(defcustom notmuch-tree-outline-auto-close nil
+ "Close message and tree windows when moving past the last message."
+ :type 'boolean)
+
+(defcustom notmuch-tree-outline-open-on-next nil
+ "Open new messages under point if they are closed when moving to next one.
+
+When this flag is set, using the command
+`notmuch-tree-outline-next' with point on a header for a new
+message that is not shown will open its `notmuch-show' buffer
+instead of moving point to next matching message."
+ :type 'boolean)
+
+;;;; Helper functions
+(defsubst notmuch-tree-outline--pop-at-end (pop-at-end)
+ (if notmuch-tree-outline-auto-close (not pop-at-end) pop-at-end))
+
+(defun notmuch-tree-outline--set-visibility ()
+ (when (and notmuch-tree-outline-mode (> (point-max) (point-min)))
+ (cl-case notmuch-tree-outline-visibility
+ (hide-others (notmuch-tree-outline-hide-others))
+ (hide-all (outline-hide-body)))))
+
+(defun notmuch-tree-outline--on-exit (proc)
+ (when (eq (process-status proc) 'exit)
+ (notmuch-tree-outline--set-visibility)))
+
+(add-hook 'notmuch-tree-process-exit-functions #'notmuch-tree-outline--on-exit)
+
+(defsubst notmuch-tree-outline--level (&optional props)
+ (or (plist-get (or props (notmuch-tree-get-message-properties)) :level) 0))
+
+(defsubst notmuch-tree-outline--message-open-p ()
+ (and (buffer-live-p notmuch-tree-message-buffer)
+ (get-buffer-window notmuch-tree-message-buffer)
+ (let ((id (notmuch-tree-get-message-id)))
+ (and id
+ (with-current-buffer notmuch-tree-message-buffer
+ (string= (notmuch-show-get-message-id) id))))))
+
+(defsubst notmuch-tree-outline--at-original-match-p ()
+ (and (notmuch-tree-get-prop :match)
+ (equal (notmuch-tree-get-prop :orig-tags)
+ (notmuch-tree-get-prop :tags))))
+
+(defun notmuch-tree-outline--next (prev thread pop-at-end &optional open-new)
+ (cond (thread
+ (notmuch-tree-thread-top)
+ (if prev
+ (outline-backward-same-level 1)
+ (outline-forward-same-level 1))
+ (when (> (notmuch-tree-outline--level) 0) (outline-show-branches))
+ (notmuch-tree-outline--next nil nil pop-at-end t))
+ ((and (or open-new notmuch-tree-outline-open-on-next)
+ (notmuch-tree-outline--at-original-match-p)
+ (not (notmuch-tree-outline--message-open-p)))
+ (notmuch-tree-outline-hide-others t))
+ (t (outline-next-visible-heading (if prev -1 1))
+ (unless (notmuch-tree-get-prop :match)
+ (notmuch-tree-matching-message prev pop-at-end))
+ (notmuch-tree-outline-hide-others t))))
+
+;;;; User commands
+(defun notmuch-tree-outline-hide-others (&optional and-show)
+ "Fold all threads except the one around point.
+If AND-SHOW is t, make the current message visible if it's not."
+ (interactive)
+ (save-excursion
+ (while (and (not (bobp)) (> (notmuch-tree-outline--level) 1))
+ (outline-previous-heading))
+ (outline-hide-sublevels 1))
+ (when (> (notmuch-tree-outline--level) 0)
+ (outline-show-subtree)
+ (when and-show (notmuch-tree-show-message nil))))
+
+(defun notmuch-tree-outline-next (&optional pop-at-end)
+ "Next matching message in a forest, taking care of thread visibility.
+A prefix argument reverses the meaning of `notmuch-tree-outline-auto-close'."
+ (interactive "P")
+ (let ((pop (notmuch-tree-outline--pop-at-end pop-at-end)))
+ (if (null notmuch-tree-outline-visibility)
+ (notmuch-tree-matching-message nil pop)
+ (notmuch-tree-outline--next nil nil pop))))
+
+(defun notmuch-tree-outline-previous (&optional pop-at-end)
+ "Previous matching message in forest, taking care of thread visibility.
+With prefix, quit the tree view if there is no previous message."
+ (interactive "P")
+ (if (null notmuch-tree-outline-visibility)
+ (notmuch-tree-prev-matching-message pop-at-end)
+ (notmuch-tree-outline--next t nil pop-at-end)))
+
+(defun notmuch-tree-outline-next-thread ()
+ "Next matching thread in forest, taking care of thread visibility."
+ (interactive)
+ (if (null notmuch-tree-outline-visibility)
+ (notmuch-tree-next-thread)
+ (notmuch-tree-outline--next nil t nil)))
+
+(defun notmuch-tree-outline-previous-thread ()
+ "Previous matching thread in forest, taking care of thread visibility."
+ (interactive)
+ (if (null notmuch-tree-outline-visibility)
+ (notmuch-tree-prev-thread)
+ (notmuch-tree-outline--next t t nil)))
+
+;;;; Mode definition
+(defvar notmuch-tree-outline-mode-lighter nil
+ "The lighter mark for notmuch-tree-outline mode.
+Usually empty since outline-minor-mode's lighter will be active.")
+
+(define-minor-mode notmuch-tree-outline-mode
+ "Minor mode allowing message trees to be folded as outlines.
+
+When this mode is set, each thread and subthread in the results
+list is treated as a foldable section, with its first message as
+its header.
+
+The mode just makes available in the tree buffer all the
+keybindings in `outline-minor-mode', and binds the following
+additional keys:
+
+\\{notmuch-tree-outline-mode-map}
+
+The customizable variable `notmuch-tree-outline-visibility'
+controls how navigation in the buffer is affected by this mode:
+
+ - If it is set to nil, `notmuch-tree-outline-previous',
+ `notmuch-tree-outline-next', and their thread counterparts
+ behave just as the corresponding notmuch-tree navigation keys
+ when this mode is not enabled.
+
+ - If, on the other hand, `notmuch-tree-outline-visibility' is
+ set to a non-nil value, these commands hiding the outlines of
+ the trees you are not reading as you move to new messages.
+
+To enable notmuch-tree-outline-mode by default in all
+notmuch-tree buffers, just set
+`notmuch-tree-outline-mode-enabled' to t."
+ :lighter notmuch-tree-outline-mode-lighter
+ :keymap `((,(kbd "TAB") . outline-cycle)
+ (,(kbd "M-TAB") . outline-cycle-buffer)
+ ("n" . notmuch-tree-outline-next)
+ ("p" . notmuch-tree-outline-previous)
+ (,(kbd "M-n") . notmuch-tree-outline-next-thread)
+ (,(kbd "M-p") . notmuch-tree-outline-previous-thread))
+ (outline-minor-mode notmuch-tree-outline-mode)
+ (unless (derived-mode-p 'notmuch-tree-mode)
+ (user-error "notmuch-tree-outline-mode is only meaningful for notmuch trees!"))
+ (if notmuch-tree-outline-mode
+ (progn (setq-local outline-regexp "^[^\n]+")
+ (setq-local outline-level #'notmuch-tree-outline--level)
+ (notmuch-tree-outline--set-visibility))
+ (setq-local outline-regexp (default-value 'outline-regexp))
+ (setq-local outline-level (default-value 'outline-level))))
+
;;; _
(provide 'notmuch-tree)
(notmuch-wash-subject-to-filename subject 52)))
(defun notmuch-wash-convert-inline-patch-to-part (msg depth)
- "Convert an inline patch into a fake 'text/x-diff' attachment.
+ "Convert an inline patch into a fake `text/x-diff' attachment.
Given that this function guesses whether a buffer includes a
patch and then guesses the extent of the patch, there is scope
(define-key map "r" 'notmuch-search-reply-to-thread-sender)
(define-key map "R" 'notmuch-search-reply-to-thread)
(define-key map "o" 'notmuch-search-toggle-order)
+ (define-key map "i" 'notmuch-search-toggle-hide-excluded)
(define-key map "c" 'notmuch-search-stash-map)
(define-key map "t" 'notmuch-search-filter-by-tag)
(define-key map "l" 'notmuch-search-filter)
+ (define-key map "E" 'notmuch-search-edit-search)
(define-key map [mouse-1] 'notmuch-search-show-thread)
(define-key map "k" 'notmuch-tag-jump)
(define-key map "*" 'notmuch-search-tag-all)
(defun notmuch-tree-from-search-current-query ()
"Tree view of current query."
(interactive)
- (notmuch-tree notmuch-search-query-string))
+ (notmuch-tree notmuch-search-query-string
+ nil nil nil nil nil nil
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded))
(defun notmuch-unthreaded-from-search-current-query ()
"Unthreaded view of current query."
(interactive)
- (notmuch-unthreaded notmuch-search-query-string))
+ (notmuch-unthreaded notmuch-search-query-string
+ nil nil nil nil
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded))
(defun notmuch-tree-from-search-thread ()
"Show the selected thread with notmuch-tree."
notmuch-search-query-string
nil
(notmuch-prettify-subject (notmuch-search-find-subject))
- t nil (current-buffer)))
+ t nil (current-buffer)
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded))
(defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
"Begin composing a reply-all to the entire current thread in a new buffer."
overlay)
(insert invisible-string)
(setq overlay (make-overlay start (point)))
+ (overlay-put overlay 'evaporate t)
(overlay-put overlay 'invisible 'ellipsis)
(overlay-put overlay 'isearch-open-invisible #'delete-overlay)))
(insert padding))))
(put 'notmuch-search 'notmuch-doc "Search for messages.")
;;;###autoload
-(defun notmuch-search (&optional query oldest-first target-thread target-line
- no-display)
+(defun notmuch-search (&optional query oldest-first hide-excluded target-thread
+ target-line no-display)
"Display threads matching QUERY in a notmuch-search buffer.
If QUERY is nil, it is read interactively from the minibuffer.
Other optional parameters are used as follows:
OLDEST-FIRST: A Boolean controlling the sort order of returned threads
+ HIDE-EXCLUDED: A boolean controlling whether to omit threads with excluded
+ tags.
TARGET-THREAD: A thread ID (without the thread: prefix) that will be made
current if it appears in the search results.
TARGET-LINE: The line number to move to if the target thread does not
(list
;; Prompt for a query
nil
- ;; Use the default search order (if we're doing a search from a
- ;; search buffer, ignore any buffer-local overrides)
- (default-value 'notmuch-search-oldest-first)))
+ ;; Use the default search order and exclude value (if we're doing a
+ ;; search from a search buffer, ignore any buffer-local overrides)
+ (default-value 'notmuch-search-oldest-first)
+ (default-value 'notmuch-search-hide-excluded)))
(let* ((query (or query (notmuch-read-query "Notmuch search: ")))
(buffer (get-buffer-create (notmuch-search-buffer-title query))))
(setq notmuch-search-oldest-first oldest-first)
(setq notmuch-search-target-thread target-thread)
(setq notmuch-search-target-line target-line)
+ (setq notmuch-search-hide-excluded hide-excluded)
(notmuch-tag-clear-cache)
(when (get-buffer-process buffer)
(error "notmuch search process already running for query `%s'" query))
(if oldest-first
"--sort=oldest-first"
"--sort=newest-first")
+ (if hide-excluded
+ "--exclude=true"
+ "--exclude=false")
query)))
;; Use a scratch buffer to accumulate partial output.
;; This buffer will be killed by the sentinel, which
(interactive)
(notmuch-search notmuch-search-query-string
notmuch-search-oldest-first
+ notmuch-search-hide-excluded
(notmuch-search-find-thread-id 'bare)
(line-number-at-pos)
t)
(goto-char (point-min)))
+(defun notmuch-search-toggle-hide-excluded ()
+ "Toggle whether to hide excluded messages.
+
+This command toggles whether to hide excluded messages for the current
+search. The default value for this is defined by `notmuch-search-hide-excluded'."
+ (interactive)
+ (setq notmuch-search-hide-excluded (not notmuch-search-hide-excluded))
+ (notmuch-search-refresh-view))
+
(defun notmuch-search-toggle-order ()
"Toggle the current search order.
(notmuch-search (if (string= grouped-original-query "*")
grouped-query
(concat grouped-original-query " and " grouped-query))
- notmuch-search-oldest-first)))
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded)))
(defun notmuch-search-filter-by-tag (tag)
"Filter the current search results based on a single TAG.
(list (notmuch-select-tag-with-completion "Filter by tag: "
notmuch-search-query-string)))
(notmuch-search (concat notmuch-search-query-string " and tag:" tag)
- notmuch-search-oldest-first))
+ notmuch-search-oldest-first
+ notmuch-search-hide-excluded))
(defun notmuch-search-by-tag (tag)
"Display threads matching TAG in a notmuch-search buffer."
(interactive
(list (notmuch-select-tag-with-completion "Notmuch search tag: ")))
- (notmuch-search (concat "tag:" tag)))
+ (notmuch-search (concat "tag:" tag)
+ (default-value 'notmuch-search-oldest-first)
+ (default-value 'notmuch-search-hide-excluded)))
+
+(defun notmuch-search-edit-search (query)
+ "Edit the current search"
+ (interactive (list (read-from-minibuffer "Edit search: "
+ notmuch-search-query-string)))
+ (notmuch-search query notmuch-search-oldest-first))
;;;###autoload
(defun notmuch ()
notmuch_status_t
_notmuch_config_load_from_file (notmuch_database_t *notmuch,
- GKeyFile *file)
+ GKeyFile *file,
+ char **status_string)
{
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
gchar **groups = NULL, **keys, *val;
for (gchar **keys_p = keys; *keys_p; keys_p++) {
char *absolute_key = talloc_asprintf (notmuch, "%s.%s", *grp, *keys_p);
char *normalized_val;
+ GError *gerr = NULL;
/* If we opened from a given path, do not overwrite it */
if (strcmp (absolute_key, "database.path") == 0 &&
notmuch->xapian_db)
continue;
- val = g_key_file_get_string (file, *grp, *keys_p, NULL);
+ val = g_key_file_get_string (file, *grp, *keys_p, &gerr);
+ if (gerr) {
+ if (status_string)
+ IGNORE_RESULT (asprintf (status_string,
+ "GLib: %s\n",
+ gerr->message));
+ g_error_free (gerr);
+ }
if (! val) {
status = NOTMUCH_STATUS_FILE_ERROR;
goto DONE;
return "database.autocommit";
case NOTMUCH_CONFIG_EXTRA_HEADERS:
return "show.extra_headers";
+ case NOTMUCH_CONFIG_INDEX_AS_TEXT:
+ return "index.as_text";
default:
return NULL;
}
else
email = _get_email_from_passwd_file (notmuch);
return email;
+ case NOTMUCH_CONFIG_INDEX_AS_TEXT:
case NOTMUCH_CONFIG_NEW_IGNORE:
return "";
case NOTMUCH_CONFIG_AUTOCOMMIT:
/* Track what parameters were specified when opening */
notmuch_open_param_t params;
+
+ /* list of regular expressions to check for text indexing */
+ regex_t *index_as_text;
+ size_t index_as_text_length;
};
/* Prior to database version 3, features were implied by the database
&message);
if (status == NOTMUCH_STATUS_SUCCESS && message) {
- status = _notmuch_message_remove_filename (message, filename);
+ if (notmuch_message_count_files (message) > 1) {
+ status = _notmuch_message_remove_filename (message, filename);
+ }
if (status == NOTMUCH_STATUS_SUCCESS)
- _notmuch_message_delete (message);
+ status = _notmuch_message_delete (message);
else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
_notmuch_message_sync (message);
{
return notmuch->status_string;
}
+
+bool
+_notmuch_database_indexable_as_text (notmuch_database_t *notmuch, const char *mime_string)
+{
+ for (size_t i = 0; i < notmuch->index_as_text_length; i++) {
+ if (regexec (¬much->index_as_text[i], mime_string, 0, NULL, 0) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
GMimeObject *part,
_notmuch_message_crypto_t *msg_crypto);
+static bool
+_indexable_as_text (notmuch_message_t *message, GMimeObject *part)
+{
+ GMimeContentType *content_type = g_mime_object_get_content_type (part);
+ notmuch_database_t *notmuch = notmuch_message_get_database (message);
+
+ if (content_type) {
+ char *mime_string = g_mime_content_type_get_mime_type (content_type);
+ if (mime_string) {
+ bool ret = _notmuch_database_indexable_as_text (notmuch, mime_string);
+ g_free (mime_string);
+ return ret;
+ }
+ }
+ return false;
+}
+
/* Callback to generate terms for each mime part of a message. */
static void
_index_mime_part (notmuch_message_t *message,
_notmuch_message_add_term (message, "tag", "attachment");
_notmuch_message_gen_terms (message, "attachment", filename);
- /* XXX: Would be nice to call out to something here to parse
- * the attachment into text and then index that. */
- goto DONE;
+ if (! _indexable_as_text (message, part)) {
+ /* XXX: Would be nice to call out to something here to parse
+ * the attachment into text and then index that. */
+ goto DONE;
+ }
}
byte_array = g_byte_array_new ();
#include "database-private.h"
#include "message-private.h"
+#define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error)
+
+static void
+_log_xapian_exception (const char *where, notmuch_message_t *message, const Xapian::Error error)
+{
+ notmuch_database_t *notmuch = notmuch_message_get_database (message);
+
+ _notmuch_database_log (notmuch,
+ "A Xapian exception occurred at %s: %s\n",
+ where,
+ error.get_msg ().c_str ());
+ notmuch->exception_reported = true;
+}
+
notmuch_status_t
notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
{
term = talloc_asprintf (message, "%s=%s", key, value);
- if (delete_it)
- private_status = _notmuch_message_remove_term (message, "property", term);
- else
- private_status = _notmuch_message_add_term (message, "property", term);
+ try {
+ if (delete_it)
+ private_status = _notmuch_message_remove_term (message, "property", term);
+ else
+ private_status = _notmuch_message_add_term (message, "property", term);
+ } catch (Xapian::Error &error) {
+ LOG_XAPIAN_EXCEPTION (message, error);
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
if (private_status)
return COERCE_STATUS (private_status,
if (status)
return status;
- _notmuch_message_invalidate_metadata (message, "property");
if (key)
term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
prefix ? "" : "=");
else
term_prefix = _find_prefix ("property");
- /* XXX better error reporting ? */
- _notmuch_message_remove_terms (message, term_prefix);
+ try {
+ /* XXX better error reporting ? */
+ _notmuch_message_remove_terms (message, term_prefix);
+ } catch (Xapian::Error &error) {
+ LOG_XAPIAN_EXCEPTION (message, error);
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
+
+ if (! _notmuch_message_frozen (message))
+ _notmuch_message_sync (message);
return NOTMUCH_STATUS_SUCCESS;
}
/* Ignore failure to remove non-existent term. */
}
}
+
+ _notmuch_message_invalidate_metadata (message, "property");
}
{
const char *relative, *directory;
notmuch_status_t status;
+ notmuch_private_status_t private_status;
void *local = talloc_new (message);
char *direntry;
/* New file-direntry allows navigating to this message with
* notmuch_directory_get_child_files() . */
- status = COERCE_STATUS (_notmuch_message_add_term (message, "file-direntry", direntry),
- "adding file-direntry term");
- if (status)
- return status;
+ private_status = _notmuch_message_add_term (message, "file-direntry", direntry);
+ switch (private_status) {
+ case NOTMUCH_PRIVATE_STATUS_SUCCESS:
+ break;
+ case NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG:
+ _notmuch_database_log (message->notmuch, "filename too long for file-direntry term: %s\n",
+ filename);
+ return NOTMUCH_STATUS_PATH_ERROR;
+ default:
+ return COERCE_STATUS (private_status, "adding file-direntry term");
+ }
status = _notmuch_message_add_folder_terms (message, directory);
if (status)
if (status)
return status;
- message->notmuch->writable_xapian_db->delete_document (message->doc_id);
-
- /* if this was a ghost to begin with, we are done */
- private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
- if (private_status)
- return COERCE_STATUS (private_status,
- "Error trying to determine whether message was a ghost");
- if (is_ghost)
- return NOTMUCH_STATUS_SUCCESS;
-
- /* look for a non-ghost message in the same thread */
try {
Xapian::PostingIterator thread_doc, thread_doc_end;
Xapian::PostingIterator mail_doc, mail_doc_end;
+ /* look for a non-ghost message in the same thread */
+ /* if this was a ghost to begin with, we are done */
+ private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
+ if (private_status)
+ return COERCE_STATUS (private_status,
+ "Error trying to determine whether message was a ghost");
+
+ message->notmuch->writable_xapian_db->delete_document (message->doc_id);
+
+ if (is_ghost)
+ return NOTMUCH_STATUS_SUCCESS;
+
_notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
&thread_doc_end);
_notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
notmuch_find_flags_t flags,
char **direntry);
+bool
+_notmuch_database_indexable_as_text (notmuch_database_t *notmuch,
+ const char *mime_string);
+
/* directory.cc */
notmuch_directory_t *
_notmuch_config_load_from_database (notmuch_database_t *db);
notmuch_status_t
-_notmuch_config_load_from_file (notmuch_database_t *db, GKeyFile *file);
+_notmuch_config_load_from_file (notmuch_database_t *db, GKeyFile *file, char **status_string);
notmuch_status_t
_notmuch_config_load_defaults (notmuch_database_t *db);
*
* NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
*
+ * NOTMUCH_STATUS_PATH_ERROR: filename is too long
+ *
* NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the
* database file (such as permission denied, or file not found,
* etc.), or the database already exists.
*
* The UUID is a NUL-terminated opaque string that uniquely identifies
* this database. Two revision numbers are only comparable if they
- * have the same database UUID.
+ * have the same database UUID. The string 'uuid' is owned by notmuch
+ * and should not be freed or modified by the user.
*/
unsigned long
notmuch_database_get_revision (notmuch_database_t *notmuch,
*
* query = notmuch_query_create (database, query_string);
*
- * for (messages = notmuch_query_search_messages (query);
+ * if (notmuch_query_search_messages (query, &messages) != NOTMUCH_STATUS_SUCCESS)
+ * return EXIT_FAILURE;
+ *
+ * for (;
* notmuch_messages_valid (messages);
* notmuch_messages_move_to_next (messages))
* {
NOTMUCH_CONFIG_USER_NAME,
NOTMUCH_CONFIG_AUTOCOMMIT,
NOTMUCH_CONFIG_EXTRA_HEADERS,
+ NOTMUCH_CONFIG_INDEX_AS_TEXT,
NOTMUCH_CONFIG_LAST
} notmuch_config_key_t;
return NOTMUCH_STATUS_NO_DATABASE;
}
+ if (*message) {
+ free (*message);
+ *message = NULL;
+ }
+
return NOTMUCH_STATUS_SUCCESS;
}
notmuch->transaction_count = 0;
notmuch->transaction_threshold = 0;
notmuch->view = 1;
+ notmuch->index_as_text = NULL;
+ notmuch->index_as_text_length = 0;
notmuch->params = NOTMUCH_PARAM_NONE;
if (database_path)
notmuch, notmuch->xapian_db->get_uuid ().c_str ());
}
+/* XXX This should really be done lazily, but the error reporting path in the indexing code
+ * would need to be redone to report any errors.
+ */
+notmuch_status_t
+_ensure_index_as_text (notmuch_database_t *notmuch, char **message)
+{
+ int nregex = 0;
+ regex_t *regexv = NULL;
+
+ if (notmuch->index_as_text)
+ return NOTMUCH_STATUS_SUCCESS;
+
+ for (notmuch_config_values_t *list = notmuch_config_get_values (notmuch,
+ NOTMUCH_CONFIG_INDEX_AS_TEXT);
+ notmuch_config_values_valid (list);
+ notmuch_config_values_move_to_next (list)) {
+ regex_t *new_regex;
+ int rerr;
+ const char *str = notmuch_config_values_get (list);
+ size_t len = strlen (str);
+
+ /* str must be non-empty, because n_c_get_values skips empty
+ * strings */
+ assert (len > 0);
+
+ regexv = talloc_realloc (notmuch, regexv, regex_t, nregex + 1);
+ new_regex = ®exv[nregex];
+
+ rerr = regcomp (new_regex, str, REG_EXTENDED | REG_NOSUB);
+ if (rerr) {
+ size_t error_size = regerror (rerr, new_regex, NULL, 0);
+ char *error = (char *) talloc_size (str, error_size);
+
+ regerror (rerr, new_regex, error, error_size);
+ IGNORE_RESULT (asprintf (message, "Error in index.as_text: %s: %s\n", error, str));
+
+ return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
+ }
+ nregex++;
+ }
+
+ notmuch->index_as_text = regexv;
+ notmuch->index_as_text_length = nregex;
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
static notmuch_status_t
_finish_open (notmuch_database_t *notmuch,
const char *profile,
goto DONE;
if (key_file)
- status = _notmuch_config_load_from_file (notmuch, key_file);
+ status = _notmuch_config_load_from_file (notmuch, key_file, &message);
if (status)
goto DONE;
if (status)
goto DONE;
+ status = _ensure_index_as_text (notmuch, &message);
+ if (status)
+ goto DONE;
+
autocommit_str = notmuch_config_get (notmuch, NOTMUCH_CONFIG_AUTOCOMMIT);
if (unlikely (! autocommit_str)) {
INTERNAL_ERROR ("missing configuration for autocommit");
}
if (key_file) {
- status = _notmuch_config_load_from_file (notmuch, key_file);
+ status = _notmuch_config_load_from_file (notmuch, key_file, &message);
if (status)
goto DONE;
}
#include "notmuch-private.h"
#include "database-private.h"
+#include "xapian-extra.h"
#include <glib.h> /* GHashTable, GPtrArray */
{
try {
if (query_string == "" || query_string == "*") {
- output = Xapian::Query::MatchAll;
+ output = xapian_query_match_all ();
} else {
output =
notmuch->query_parser->
#include "regexp-fields.h"
#include "notmuch-private.h"
#include "database-private.h"
+#include "xapian-extra.h"
notmuch_status_t
compile_regex (regex_t ®exp, const char *str, std::string &msg)
if (str.empty ()) {
if (options & NOTMUCH_FIELD_PROBABILISTIC) {
return Xapian::Query (Xapian::Query::OP_AND_NOT,
- Xapian::Query::MatchAll,
+ xapian_query_match_all (),
Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
} else {
return Xapian::Query (term_prefix);
static int
cmppair (const void *pa, const void *pb)
{
+ int cmp = 0;
notmuch_string_pair_t *a = (notmuch_string_pair_t *) pa;
notmuch_string_pair_t *b = (notmuch_string_pair_t *) pb;
- return strcmp (a->key, b->key);
+ cmp = strcmp (a->key, b->key);
+ if (cmp == 0)
+ cmp = strcmp (a->value, b->value);
+ return cmp;
}
static void
bool output_body;
int duplicate;
int part;
+ int offset;
+ int limit;
_notmuch_crypto_t crypto;
bool include_html;
GMimeStream *out_stream;
return NULL;
}
- if (config->is_new)
- g_key_file_set_comment (config->key_file, NULL, NULL,
- toplevel_config_comment, NULL);
-
for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
const char *name = group_comment_table[i].group_name;
if (! g_key_file_has_group (config->key_file, name)) {
/* Force group to exist before adding comment */
g_key_file_set_value (config->key_file, name, "dummy_key", "dummy_val");
g_key_file_remove_key (config->key_file, name, "dummy_key", NULL);
- g_key_file_set_comment (config->key_file, name, NULL,
- group_comment_table[i].comment, NULL);
+ if (config->is_new && (i == 0) ) {
+ const char *comment;
+
+ comment = talloc_asprintf (config, "%s\n%s",
+ toplevel_config_comment,
+ group_comment_table[i].comment);
+ g_key_file_set_comment (config->key_file, name, NULL, comment,
+ NULL);
+ } else {
+ g_key_file_set_comment (config->key_file, name, NULL,
+ group_comment_table[i].comment, NULL);
+ }
}
}
return config;
import logging as _logging
import os as _os
import re as _re
-import shutil as _shutil
import subprocess as _subprocess
import sys as _sys
import tempfile as _tempfile
stdout=_subprocess.PIPE, wait=True)
if status != 0:
_LOG.error("failed to run notmuch config")
- sys.exit(1)
+ _sys.exit(1)
return int(stdout.rstrip())
def get_tags(prefix=None):
"Get a list of tags with a given prefix."
(status, stdout, stderr) = _spawn(
- args=['notmuch', 'search', '--query=sexp', '--output=tags', _tag_query(prefix)],
+ args=['notmuch', 'search', '--exclude=false', '--query=sexp', '--output=tags', _tag_query(prefix)],
stdout=_subprocess.PIPE, wait=True)
return [tag for tag in stdout.splitlines()]
total = count_messages (TAG_PREFIX)
if total == 0:
- _LOG.error('No existing tags with given prefix, stopping.'.format(safe))
+ _LOG.error('No existing tags with given prefix, stopping.')
_LOG.error('Use --force to override.')
exit(1)
change = len(status['added'])+len(status['deleted'])
self._known[id] = False
else:
(_, stdout, stderr) = _spawn(
- args=['notmuch', 'search', '--output=files', 'id:{0}'.format(id)],
+ args=['notmuch', 'search', '--exclude=false', '--output=files', 'id:{0}'.format(id)],
stdout=_subprocess.PIPE,
wait=True)
self._known[id] = stdout != None
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
break;
+ case NOTMUCH_STATUS_PATH_ERROR:
+ fprintf (stderr, "Note: Ignoring non-indexable path: %s\n", filename);
+ (void) print_status_database ("add_file", notmuch, status);
+ break;
case NOTMUCH_STATUS_FILE_ERROR:
/* Someone renamed/removed the file between scandir and now. */
state->vanished_files++;
notmuch_thread_t *thread;
notmuch_messages_t *messages;
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
+ int i;
+
+ if (params->offset < 0) {
+ unsigned count;
+ notmuch_status_t s = notmuch_query_count_threads (query, &count);
+ if (print_status_query ("notmuch show", query, s))
+ return 1;
+
+ params->offset += count;
+ if (params->offset < 0)
+ params->offset = 0;
+ }
status = notmuch_query_search_threads (query, &threads);
if (print_status_query ("notmuch show", query, status))
sp->begin_list (sp);
- for (;
- notmuch_threads_valid (threads);
- notmuch_threads_move_to_next (threads)) {
+ for (i = 0;
+ notmuch_threads_valid (threads) && (params->limit < 0 || i < params->offset + params->limit);
+ notmuch_threads_move_to_next (threads), i++) {
thread = notmuch_threads_get (threads);
+ if (i < params->offset) {
+ notmuch_thread_destroy (thread);
+ continue;
+ }
+
messages = notmuch_thread_get_toplevel_messages (thread);
if (messages == NULL)
notmuch_message_t *message;
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
notmuch_bool_t excluded;
+ int i;
+
+ if (params->offset < 0) {
+ unsigned count;
+ notmuch_status_t s = notmuch_query_count_messages (query, &count);
+ if (print_status_query ("notmuch show", query, s))
+ return 1;
+
+ params->offset += count;
+ if (params->offset < 0)
+ params->offset = 0;
+ }
status = notmuch_query_search_messages (query, &messages);
if (print_status_query ("notmuch show", query, status))
sp->begin_list (sp);
- for (;
- notmuch_messages_valid (messages);
- notmuch_messages_move_to_next (messages)) {
+ for (i = 0;
+ notmuch_messages_valid (messages) && (params->limit < 0 || i < params->offset + params->limit);
+ notmuch_messages_move_to_next (messages), i++) {
+ if (i < params->offset) {
+ continue;
+ }
+
sp->begin_list (sp);
sp->begin_list (sp);
notmuch_show_params_t params = {
.part = -1,
.duplicate = 0,
+ .offset = 0,
+ .limit = -1, /* unlimited */
.omit_excluded = true,
.output_body = true,
.crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
{ .opt_bool = ¶ms.output_body, .name = "body" },
{ .opt_bool = ¶ms.include_html, .name = "include-html" },
{ .opt_int = ¶ms.duplicate, .name = "duplicate" },
+ { .opt_int = ¶ms.limit, .name = "limit" },
+ { .opt_int = ¶ms.offset, .name = "offset" },
{ .opt_inherit = notmuch_shared_options },
{ }
};
NULL,
¬much,
&status_string);
+ if (status_string) {
+ fputs (status_string, stderr);
+ free (status_string);
+ status_string = NULL;
+ }
+
switch (status) {
case NOTMUCH_STATUS_NO_CONFIG:
if (! (command->mode & NOTMUCH_COMMAND_CONFIG_CREATE)) {
case NOTMUCH_STATUS_SUCCESS:
break;
default:
+ fputs ("Error: unable to load config file.\n", stderr);
+ ret = 1;
goto DONE;
}
First, you need to get the corpus. If you don't already have the gpg
key for David Bremner, run
- % gpg --search 'david@tethera.net'
+ % gpg --locate-external-key 'david@tethera.net'
This should get you a key with fingerprint
- 815B 6398 2A79 F8E7 C727 86C4 762B 57BB 7842 06AD
+ 7A18 807F 100A 4570 C596 8420 7E4E 65C8 720B 706B
(the last 8 digits are printed as the "key id").
time_run 'tag * -existing_tag' "notmuch tag -new_tag '*'"
time_run 'tag * -missing_tag' "notmuch tag -new_tag '*'"
+time_run 'tag * +maildir_flag F' "notmuch tag +flagged '*'"
+time_run 'tag * -maildir_flag F' "notmuch tag -flagged '*'"
+time_run 'tag * +maildir_flag P' "notmuch tag +passed '*'"
+time_run 'tag * -maildir_flag P' "notmuch tag -passed '*'"
+time_run 'tag * +maildir_flag D' "notmuch tag +draft '*'"
+time_run 'tag * -maildir_flag D' "notmuch tag -draft '*'"
+time_run 'tag * +maildir_flag S' "notmuch tag -unread '*'"
+time_run 'tag * -maildir_flag S' "notmuch tag +unread '*'"
+
time_done
--- /dev/null
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEkiyHYXwaY0SiY6fqA0U5G1WqFSEFAmR119gACgkQA0U5G1Wq
+FSHlSQ/+NSRj27PEZjaP2I+3j+rsMG3pnVckNcuOQyfgjJ+zEagMZyRu3vaIA/pX
+xtBrNIX4l4CQIkqwyNjsuqJdzh6S3DeCWSEr1Q+GSBki+wQCBiRuDYY2HQoDezEK
+4bMfniEWZpKJD8PfIabz0OOqMUsfXEYMd9kefew5/J4OGnDIv8E5pKfqvDNNO4rW
+MhZ9w9uR9wkvmfmpO66kAgTfLllwiyNHWoWnzQfNmqM8eULFn7XxM1PEZShUEqXf
+pTWCqqm5OyUcy8f+gy9Mb7DRRvnwLpHHRQlCzzH2c+ENQRpt1ErsgVKpHTVk4UsB
+EML+zwyWEaQg7xVKWXRJDuGCF47S1GCQNUtvtx57HJl6Ds6N2mlr2KEGaI7qtiz5
+5hdaTc0L/TVN0WS+uCdfdDDozFErf1kwhA6Jnpi0YNNdK+wpFzj7ISvA+DNHwJ75
+TLBuJIU/h3QfX3NDC5xDbsWAgpv7a84e7ePO6+kAVkHsNYDbFjiunr5fRbqDsJcJ
+B+aVGhKvFZbziC84Dn5Ae9Lpa40fQlxbdb+So2nDIiuR3P33vt7wr/e2ptVfrqkn
+a1DM96n03VWexwEDMye3b3rOTXsN5Ul87zucg9xWm5JT75NGuqJ1WDJN/wwNPDro
+ZXS1OHh7UKsU1tP2J9+gLiKYNBP4m4BQjEgYXpiYEoge9A1QplQ=
+=5/Ep
+-----END PGP SIGNATURE-----
# this should be both a valid Makefile fragment and valid POSIX(ish) shell.
-PERFTEST_VERSION=0.4
+PERFTEST_VERSION=0.5
unable to run because of missing prerequisites, but not explicitly
skipped by the user, as failures.
+Testing installed notmuch
+-------------------------
+
+Systems integrators (e.g. Linux distros) may wish to test an installed
+version of notmuch. This can be done be running
+
+ $ NOTMUCH_TEST_INSTALLED=1 ./test/notmuch-test
+
+In this scenario the test suite does not assume a built tree, and in
+particular cannot rely on the output of 'configure'. You may want to
+set certain feature environment variables ('NOTMUCH_HAVE_*') directly
+if you know those apply to your installed notmuch). Consider also
+setting TERM=dumb if the value of TERM cannot be used (e.g. in a
+chroot with missing terminfo). Note that having a built tree may cause
+surprising/broken results for NOTMUCH_TEST_INSTALLED, so consider
+cleaning first.
+
Writing Tests
-------------
The test script is written as a shell script. It is to be named as
test_expect_success 'test -f "${NOTMUCH_CONFIG}"'
test_begin_subtest 'PATH is set to build directory'
+test_subtest_broken_for_installed
test_expect_equal \
"$(dirname ${TEST_DIRECTORY})" \
"$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
test_begin_subtest 'notmuch --version'
test_expect_success 'notmuch --version'
-if [ $NOTMUCH_HAVE_MAN -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_MAN-0}" = "1" ]; then
test_begin_subtest 'notmuch --help tag'
test_expect_success 'notmuch --help tag'
test_begin_subtest 'notmuch help tag'
test_expect_success 'notmuch help tag'
else
+ if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+ fi
test_begin_subtest 'notmuch --help tag (man pages not available)'
test_expect_success 'test_must_fail notmuch --help tag >/dev/null'
test_description='"notmuch config"'
. $(dirname "$0")/test-lib.sh || exit 1
+cp notmuch-config initial-config
+
test_begin_subtest "Get string value"
test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
database.path=MAIL_DIR
foo.list=this;is another;list value;
foo.string=this is another string value
+index.as_text=
maildir.synchronize_flags=true
new.ignore=
new.tags=unread;inbox
output=$(notmuch config get built_with.nonexistent)
test_expect_equal "$output" "false"
+test_begin_subtest "Bad utf8 reported as error"
+cp initial-config bad-config
+printf '[query]\nq3=from:\xff\n' >>bad-config
+test_expect_code 1 "notmuch --config=./bad-config config list"
+
+test_begin_subtest "Specific error message about bad utf8"
+notmuch --config=./bad-config config list 2>ERRORS
+cat <<EOF > EXPECTED
+GLib: Key file contains key “q3” with value “from:�” which is not UTF-8
+Error: unable to load config file.
+EOF
+test_expect_equal_file EXPECTED ERRORS
+
test_done
EOF
expected_dir=$NOTMUCH_SRCDIR/test/setup.expected-output
-test_expect_equal_file ${expected_dir}/config-with-comments new-notmuch-config
+sed '/^$/d' < new-notmuch-config > filtered-config
+test_expect_equal_file ${expected_dir}/config-with-comments filtered-config
test_begin_subtest "setup consistent with config-set for single items"
# note this relies on the config state from the previous test.
EOF
test_expect_equal_file EXPECTED OUTPUT
+test_begin_subtest "Long file names have reasonable diagnostics"
+printf -v name 'f%.0s' {1..234}
+generate_message "[filename]=$name"
+notmuch new 2>&1 | notmuch_dir_sanitize >OUTPUT
+rm ${MAIL_DIR}/${name}
+cat <<EOF > EXPECTED
+Note: Ignoring non-indexable path: MAIL_DIR/$name
+add_file: Path supplied is illegal for this function
+filename too long for file-direntry term: MAIL_DIR/$name
+Processed 1 file in almost no time.
+No new mail.
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
test_begin_subtest "Xapian exception: read only files"
+test_subtest_broken_for_root
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
EOF
test_expect_equal_file EXPECTED OUTPUT
-add_email_corpus indexing
-
-test_begin_subtest "index text/* attachments"
-test_subtest_known_broken
-notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
-notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
-test_expect_equal_file_nonempty EXPECTED OUTPUT
-
test_done
database.hook_dir
database.mail_root=MAIL_DIR
database.path
+index.as_text=
maildir.synchronize_flags=true
new.ignore=
new.tags=unread;inbox
notmuch new
test_expect_equal "$(xapian-metadata get ${XAPIAN_PATH} version)" 3
;;
+ home_mail|maildir_env)
+ test_begin_subtest "No errors from config list ($config)"
+ notmuch config list 2>OUTPUT 1>/dev/null
+ test_expect_equal_file /dev/null OUTPUT
+ ;;
*)
backup_database
test_begin_subtest ".notmuch without xapian/ handled gracefully ($config)"
EOF
test_expect_equal_file EXPECTED OUTPUT
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_begin_subtest "and of exact terms (query=sexp)"
output=$(notmuch count --query=sexp '(and "wonderful" "wizard")')
output=$(notmuch search id:${gen_msg_id} | notmuch_search_sanitize)
test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)"
+test_begin_subtest "Message-Id with spaces"
+test_subtest_known_broken
+add_message '[id]="message id@example.com"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
+output=$(notmuch search --output=messages id:"message id@example.com")
+test_expect_equal "$output" "messageid@example.com"
+
test_begin_subtest "Search by mid:"
add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; Message-Id with spaces (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by mid (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)
test_description='"notmuch search" in several variations'
. $(dirname "$0")/test-lib.sh || exit 1
-if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" != "1" ]; then
printf "Skipping due to missing sfsexp library\n"
test_done
fi
EOF
test_expect_equal_file EXPECTED OUTPUT
-if [[ NOTMUCH_HAVE_SFSEXP = 1 ]]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_begin_subtest "sexpr query: all messages"
notmuch address '*' > EXPECTED
notmuch address --query=sexp '()' > OUTPUT
--- /dev/null
+#!/usr/bin/env bash
+test_description='"notmuch show" --offset and --limit parameters'
+. $(dirname "$0")/test-lib.sh || exit 1
+
+add_email_corpus
+
+show () {
+ local kind="$1"
+ shift
+ if [ "$kind" = messages ]; then
+ set -- --unthreaded "$@"
+ fi
+ notmuch show --body=false --format=text --entire-thread=false "$@" "*" |
+ sed -nre 's/^.message\{.*\<depth:0\>.*/&/p'
+}
+
+for outp in messages threads; do
+ test_begin_subtest "$outp: limit does the right thing"
+ show $outp | head -n 20 >expected
+ show $outp --limit=20 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: concatenation of limited shows"
+ show $outp | head -n 20 >expected
+ show $outp --limit=10 >output
+ show $outp --limit=10 --offset=10 >>output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: limit larger than result set"
+ N=$(notmuch count --output=$outp "*")
+ show $outp >expected
+ show $outp --limit=$((1 + N)) >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: limit = 0"
+ test_expect_equal "$(show $outp --limit=0)" ""
+
+ test_begin_subtest "$outp: offset does the right thing"
+ # note: tail -n +N is 1-based
+ show $outp | tail -n +21 >expected
+ show $outp --offset=20 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: offset = 0"
+ show $outp >expected
+ show $outp --offset=0 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset"
+ show $outp | tail -n 20 >expected
+ show $outp --offset=-20 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset"
+ show $outp | tail -n 1 >expected
+ show $outp --offset=-1 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset combined with limit"
+ show $outp | tail -n 20 | head -n 10 >expected
+ show $outp --offset=-20 --limit=10 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset combined with equal limit"
+ show $outp | tail -n 20 >expected
+ show $outp --offset=-20 --limit=20 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset combined with large limit"
+ show $outp | tail -n 20 >expected
+ show $outp --offset=-20 --limit=50 >output
+ test_expect_equal_file expected output
+
+ test_begin_subtest "$outp: negative offset larger than results"
+ N=$(notmuch count --output=$outp "*")
+ show $outp >expected
+ show $outp --offset=-$((1 + N)) >output
+ test_expect_equal_file expected output
+done
+
+test_done
test_expect_code 1 'notmuch tag +- One'
test_begin_subtest "Xapian exception: read only files"
+test_subtest_broken_for_root
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
add_email_corpus
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
test_query_syntax '(or "php" "wizard")' 'php or wizard'
\"tags\": [\"inbox\",
\"unread\"]}]"
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
test_begin_subtest "Search message: json, 64-bit timestamp"
-if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
test_subtest_known_broken
fi
add_message "[subject]=\"json-search-64bit-timestamp-subject\"" "[date]=\"Tue, 01 Jan 2999 12:00:00 -0000\"" "[body]=\"json-search-64bit-timestamp-message\""
\"query\": [\"id:$gen_msg_id\", null],
\"tags\": [\"inbox\",
\"unread\"]}]"
+fi # NOTMUCH_TEST_INSTALLED undefined / empty
test_begin_subtest "Format version: too low"
test_expect_code 20 "notmuch search --format-version=0 \\*"
notmuch reply id:${gen_msg_id} >OUTPUT 2>&1 && echo OK >> OUTPUT
test_expect_equal_file basic.expected OUTPUT
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_begin_subtest "Basic reply (query=sexp)"
notmuch reply --query=sexp "(id ${gen_msg_id})" >OUTPUT 2>&1 && echo OK >> OUTPUT
test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_begin_subtest "dump --query=sexp -- '(from cworth)'"
notmuch dump --query=sexp -- '(from cworth)' > dump-dash-cworth.actual2
test_expect_equal_file dump-cworth.expected dump-outfile-dash-inbox.actual
test_begin_subtest "Check for a safe set of message-ids"
+test_subtest_broken_for_installed
notmuch search --output=messages from:cworth | sed s/^id:// > EXPECTED
notmuch search --output=messages from:cworth | sed s/^id:// |\
$TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT
test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
test_begin_subtest 'format=batch-tag, checking encoded output'
+test_subtest_broken_for_installed
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth |\
awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth > OUTPUT.$test_count
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
+test_subtest_broken_for_installed
notmuch new > /dev/null
output=$(notmuch search 'subject:"testing message sent via SMTP"' | notmuch_search_sanitize)
test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; Testing message sent via SMTP (inbox)"
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "Reply within emacs"
+test_subtest_broken_for_installed
test_emacs '(let ((message-hidden-headers ''()))
(notmuch-search "subject:\"testing message sent via SMTP\"")
(notmuch-test-wait)
YYY/notmuch_fail exited with status 1 (see *Notmuch errors* for more details)
=== ERROR ===
YYY/notmuch_fail exited with status 1
-command: YYY/notmuch_fail search --format\=sexp --format-version\=5 --sort\=newest-first tag\:inbox
+command: YYY/notmuch_fail search --format\=sexp --format-version\=5 --sort\=newest-first --exclude\=false tag\:inbox
exit status: 1"
test_begin_subtest "Search handles subprocess warnings"
test_expect_equal_message_body sent_message "$msg_file"
test_begin_subtest "signed part content-type indexing"
+test_subtest_broken_for_installed
notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize > OUTPUT
cat <<EOF >EXPECTED
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
test_valid_json "$output"
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
test_begin_subtest "Verify signature on PKCS#7 SignedData message"
-if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
test_subtest_known_broken
fi
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
'expires:[0][0][0]["crypto"]["signed"]["status"][0]["expires"]=2611032858' \
'fingerprint:[0][0][0]["crypto"]["signed"]["status"][0]["fingerprint"]="702BA4B157F1E2B7D16B0C6A5FFC8A7DE2057DEB"' \
'status:[0][0][0]["crypto"]["signed"]["status"][0]["status"]="good"'
+fi # NOTMUCH_TEST_INSTALLED undefined / empty
test_begin_subtest "Verify signature on PKCS#7 SignedData message signer User ID"
if [ $NOTMUCH_GMIME_X509_CERT_VALIDITY -ne 1 ]; then
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
test_begin_subtest 'running test' run_test
mkdir -p ${PWD}/fakedb/.notmuch
$TEST_DIRECTORY/symbol-test ${PWD}/fakedb ${PWD}/nonexistent 2>&1 \
test_require_external_prereq ${NOTMUCH_PYTHON}
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
add_email_corpus
add_gnupg_home
test_description="python bindings (pytest)"
. $(dirname "$0")/test-lib.sh || exit 1
-if [ $NOTMUCH_HAVE_PYTHON3_CFFI -eq 0 -o $NOTMUCH_HAVE_PYTHON3_PYTEST -eq 0 ]; then
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
test_done
fi
+if [ "${NOTMUCH_HAVE_PYTHON3_CFFI-0}" = "0" -o "${NOTMUCH_HAVE_PYTHON3_PYTEST-0}" = "0" ]; then
+ test_done
+fi
test_begin_subtest "python cffi tests (NOTMUCH_CONFIG set)"
pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
test_description="python bindings (notmuch test suite)"
. $(dirname "$0")/test-lib.sh || exit 1
-if [ $NOTMUCH_HAVE_PYTHON3_CFFI -eq 0 -o $NOTMUCH_HAVE_PYTHON3_PYTEST -eq 0 ]; then
+if [ "${NOTMUCH_HAVE_PYTHON3_CFFI-0}" = "0" -o "${NOTMUCH_HAVE_PYTHON3_PYTEST-0}" = "0" ]; then
test_done
fi
test_description="ruby bindings"
. $(dirname "$0")/test-lib.sh || exit 1
-if [ "${NOTMUCH_HAVE_RUBY_DEV}" = "0" ]; then
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" -a "${NOTMUCH_HAVE_RUBY_DEV-0}" = "0" ]; then
test_subtest_missing_external_prereq_["ruby development files"]=t
fi
(
cat <<-EOF
require 'notmuch'
- db = Notmuch::Database.new('$MAIL_DIR')
+ db = Notmuch::Database.new()
EOF
cat
- ) | $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"> OUTPUT
+ ) | if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ ruby
+ else
+ $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"
+ fi> OUTPUT
test_expect_equal_file EXPECTED OUTPUT
}
test_description="argument parsing"
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
test_begin_subtest "sanity check"
$TEST_DIRECTORY/arg-test pos1 --keyword=one --boolean --string=foo pos2 --int=7 --flag=one --flag=three > OUTPUT
cat <<EOF > EXPECTED
(notmuch-test-wait)
(test-output)
(delete-other-windows)'
-test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox OUTPUT
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-oldest-first OUTPUT
test_begin_subtest "Tree view of a single thread (from search)"
test_emacs '(notmuch-hello)
(notmuch-tree "*")))'
test_expect_equal "$(cat MESSAGES)" "COMPLETE"
+# reinitialize database for outline tests
+add_email_corpus
+
+test_begin_subtest "start in outline mode"
+test_emacs '(let ((notmuch-tree-outline-enabled t))
+ (notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (test-visible-output))'
+# folding all messages by height or depth should look the same
+test_expect_equal_file $EXPECTED/inbox-outline OUTPUT
+
+test_begin_subtest "outline-cycle-buffer"
+test_emacs '(let ((notmuch-tree-outline-enabled t))
+ (notmuch-tree "tag:inbox")
+ (notmuch-test-wait)
+ (outline-cycle-buffer)
+ (outline-cycle-buffer)
+ (notmuch-test-wait)
+ (test-visible-output))'
+# folding all messages by height or depth should look the same
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox OUTPUT
+
+test_done
+
add_email_corpus duplicate
ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="exclude options persist between Emacs search and tree modes"
+. $(dirname "$0")/test-lib.sh || exit 1
+. $NOTMUCH_SRCDIR/test/test-lib-emacs.sh || exit 1
+
+EXPECTED=$NOTMUCH_SRCDIR/test/emacs-exclude.expected-output
+
+test_require_emacs
+add_email_corpus
+notmuch config set search.exclude_tags deleted
+notmuch tag +deleted -- 'from:"Stewart Smith"' or 'from:"Chris Wilson"'
+
+# Basic test cases just asserting exclude option is working and consistent.
+
+test_begin_subtest "Search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in search will show excluded mail"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-search-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Tree search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-tree-from-search-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in tree search will show excluded mail"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-tree-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Unthreaded search doesn't contain excluded mail by default"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-search-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-without-excluded OUTPUT
+
+test_begin_subtest "Toggling exclude in unthreaded will show excluded mail"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+# Cycling from search to tree to unthreaded and vice versa will persist the current
+# value of notmuch-search-hide-excluded.
+
+test_begin_subtest "Value of hide-excluded from search persists into tree search"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-search-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-tree-from-search-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from search persists into unthreaded"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-search-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-search-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from tree persists into search"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-tree-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-search-from-tree-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from tree persists into unthreaded"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-tree-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-tree-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-unthreaded-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from unthreaded persists into tree"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-tree-from-unthreaded-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-tree-tag-inbox-with-excluded OUTPUT
+
+test_begin_subtest "Value of hide-excluded from unthreaded persists into search"
+test_emacs '(notmuch-hello)
+ (goto-char (point-min))
+ (re-search-forward "inbox")
+ (widget-button-press (1- (point)))
+ (notmuch-test-wait)
+ (notmuch-unthreaded-from-search-current-query)
+ (notmuch-test-wait)
+ (notmuch-tree-toggle-hide-excluded)
+ (notmuch-test-wait)
+ (notmuch-search-from-tree-current-query)
+ (notmuch-test-wait)
+ (test-output)
+ (delete-other-windows)'
+test_expect_equal_file $EXPECTED/notmuch-search-tag-inbox-with-excluded OUTPUT
+
+test_done
test_description="hex encoding and decoding"
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
test_begin_subtest "round trip"
find $NOTMUCH_SRCDIR/test/corpora/default -type f -print | sort | xargs cat > EXPECTED
$TEST_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
test_description="date/time parser module"
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
# Sanity/smoke tests for the date/time parser independent of notmuch
_date () {
test_expect_equal_file EXPECTED OUTPUT
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
test_query_syntax '(or "php" "wizard")' 'php or wizard'
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
test_begin_subtest "future database versions abort open"
${TEST_DIRECTORY}/make-db-version ${MAIL_DIR} 9999 ""
output=$(notmuch search x 2>&1 | sed 's/\(database at\) .*/\1 FILENAME/')
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED}" ]; then
+ test_done
+fi
+
add_email_corpus
test_begin_subtest "building database"
EOF
test_expect_equal_file EXPECTED OUTPUT
+TERMLIST_PATH=(${MAIL_DIR}/.notmuch/xapian/termlist.*)
+test_begin_subtest "remove message with corrupted db"
+backup_database
+cat c_head0 - c_tail <<'EOF' | test_private_C ${MAIL_DIR} ${TERMLIST_PATH}
+ {
+ notmuch_status_t status;
+
+ int fd = open(argv[2],O_WRONLY|O_TRUNC);
+ if (fd < 0) {
+ fprintf (stderr, "error opening %s\n", argv[1]);
+ exit (1);
+ }
+
+ stat = _notmuch_message_delete (message);
+ printf ("%d\n", stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION);
+ }
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+1
+== stderr ==
+A Xapian exception occurred at message.cc:XXX: EOF reading block YYY
+EOF
+sed 's/EOF reading block [0-9]*/EOF reading block YYY/' < OUTPUT > OUTPUT.clean
+test_expect_equal_file EXPECTED OUTPUT.clean
+restore_database
+
test_done
result=$(($subtotal == $total-1))
test_expect_equal 1 "$result"
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
test_begin_subtest 'exclude one message using negative lastmod (sexp)'
total=$(notmuch count '*')
notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
10: 'USER_FULL_NAME'
11: '8000'
12: 'NULL'
+13: ''
== stderr ==
EOF
unset MAILDIR
test_begin_subtest "list by keys (ndlc)"
notmuch config set search.exclude_tags "foo;bar;fub"
notmuch config set new.ignore "sekrit_junk"
+notmuch config set index.as_text "text/"
cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL%
{
notmuch_config_key_t key;
10: 'Notmuch Test Suite'
11: '8000'
12: 'NULL'
+13: 'text/'
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
10: 'USER_FULL_NAME'
11: '8000'
12: 'NULL'
+13: ''
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT.clean
database.hook_dir MAIL_DIR/.notmuch/hooks
database.mail_root MAIL_DIR
database.path MAIL_DIR
+index.as_text text/
key with spaces value, with, spaces!
maildir.synchronize_flags true
new.ignore sekrit_junk
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
message_a () {
mkdir -p ${MAIL_DIR}/cur
cat > ${MAIL_DIR}/cur/a <<EOF
notmuch_message_properties_t *list;
for (list = notmuch_message_get_properties (message, prefix, exact);
notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {
- printf("%s\n", notmuch_message_properties_value(list));
+ printf("%s = %s\n", notmuch_message_properties_key(list), notmuch_message_properties_value(list));
}
notmuch_message_properties_destroy (list);
}
EOF
test_expect_equal_file EXPECTED OUTPUT
-test_begin_subtest "notmuch_message_remove_all_properties"
-cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
-EXPECT0(notmuch_message_remove_all_properties (message, NULL));
-print_properties (message, "", FALSE);
-EOF
-cat <<'EOF' >EXPECTED
-== stdout ==
-== stderr ==
-EOF
-test_expect_equal_file EXPECTED OUTPUT
-
test_begin_subtest "testing string map binary search (via message properties)"
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-testvalue1
+testkey1 = testvalue1
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_remove_all_properties"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_remove_all_properties (message, NULL));
+EXPECT0(notmuch_database_destroy(db));
+EXPECT0(notmuch_database_open_with_config (argv[1],
+ NOTMUCH_DATABASE_MODE_READ_WRITE,
+ "", NULL, &db, &msg));
+if (msg) fputs (msg, stderr);
+EXPECT0(notmuch_database_find_message(db, "4EFC743A.3060609@april.org", &message));
+if (message == NULL) {
+ fprintf (stderr, "unable to find message");
+ exit (1);
+}
+print_properties (message, "", FALSE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-alice
-bob
-testvalue1
-testvalue2
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
print_properties (message, "testkey", FALSE);
EOF
-# expected: 4 values for testkey1, 3 values for testkey3
-# they are not guaranteed to be sorted, so sort them, leaving the first
-# line '== stdout ==' and the end ('== stderr ==' and whatever error
-# may have been printed) alone
-mv OUTPUT unsorted_OUTPUT
-awk ' NR == 1 { print; next } \
- NR < 6 { print | "sort"; next } \
- NR == 6 { close("sort") } \
- NR < 9 { print | "sort"; next } \
- NR == 9 { close("sort") } \
- { print }' unsorted_OUTPUT > OUTPUT
-rm unsorted_OUTPUT
cat <<'EOF' >EXPECTED
== stdout ==
-alice
-bob
-testvalue1
-testvalue2
-alice3
-bob3
-testvalue3
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
+testkey3 = alice3
+testkey3 = bob3
+testkey3 = testvalue3
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "dump message properties"
cat <<EOF > PROPERTIES
-#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue1 testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
+#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
EOF
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
EXPECT0(notmuch_message_add_property (message, "fancy key with áccènts", "import value with ="));
test_begin_subtest "dump _only_ message properties"
cat <<EOF > EXPECTED
#notmuch-dump batch-tag:3 properties
-#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue1 testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
+#= 4EFC743A.3060609@april.org fancy%20key%20with%20%c3%a1cc%c3%a8nts=import%20value%20with%20= testkey1=alice testkey1=bob testkey1=testvalue2 testkey3=alice3 testkey3=bob3 testkey3=testvalue3
EOF
notmuch dump --include=properties > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
cat <<'EOF' > EXPECTED
testkey1 = alice
testkey1 = bob
-testkey1 = testvalue1
testkey1 = testvalue2
EOF
test_expect_equal_file EXPECTED OUTPUT
cat <<'EOF' > EXPECTED
testkey1 = alice
testkey1 = bob
-testkey1 = testvalue1
testkey1 = testvalue2
testkey3 = alice3
testkey3 = bob3
EOF
test_expect_equal_file /dev/null OUTPUT
+test_begin_subtest "notmuch_message_remove_all_properties_with_prefix"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_remove_all_properties_with_prefix (message, "testkey3"));
+print_properties (message, "", FALSE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+fancy key with áccènts = import value with =
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue2
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "edit property on removed message without uncaught exception"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
+stat = notmuch_message_remove_property (message, "example", "example");
+if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
+ fprintf (stderr, "unable to remove properties on message");
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+== stderr ==
+unable to remove properties on message
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+add_email_corpus
+
+test_begin_subtest "remove all properties on removed message without uncaught exception"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
+stat = notmuch_message_remove_all_properties_with_prefix (message, "");
+if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
+ fprintf (stderr, "unable to remove properties on message");
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+== stderr ==
+unable to remove properties on message
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
test_done
add_email_corpus
-if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
count=$(notmuch count --lastmod '*' | cut -f 3)
for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
. $(dirname "$0")/test-lib.sh || exit 1
+if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_done
+fi
+
test_begin_subtest "good message ids"
${TEST_DIRECTORY}/message-id-parse <<EOF >OUTPUT
<018b1a8f2d1df62e804ce88b65401304832dfbbf.1346614915.git.jani@nikula.org>
--- /dev/null
+#!/usr/bin/env bash
+test_description='index attachments as text'
+. $(dirname "$0")/test-lib.sh || exit 1
+
+add_email_corpus indexing
+test_begin_subtest "empty as_text; skip text/x-diff"
+messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
+count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
+test_expect_equal "$messages,$count" "1,0"
+
+notmuch config set index.as_text "^text/"
+add_email_corpus indexing
+
+test_begin_subtest "as_index is text/; find text/x-diff"
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "reindex with empty as_text, skips text/x-diff"
+notmuch config set index.as_text
+notmuch reindex '*'
+messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
+count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "reindex with empty as_text; skips application/pdf"
+notmuch config set index.as_text
+notmuch reindex '*'
+gmessages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
+count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "reindex with as_text as text/; finds text/x-diff"
+notmuch config set index.as_text "^text/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "reindex with as_text as text/; skips application/pdf"
+notmuch config set index.as_text "^text/"
+notmuch config set index.as_text
+notmuch reindex '*'
+messages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
+count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
+test_expect_equal "$messages,$count" "1,0"
+
+test_begin_subtest "as_text has multiple regexes"
+notmuch config set index.as_text "blahblah;^text/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is non-anchored regex"
+notmuch config set index.as_text "e.t/"
+notmuch reindex '*'
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
+notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is 'application/pdf'"
+notmuch config set index.as_text "^application/pdf$"
+notmuch reindex '*'
+notmuch search id:871qo9p4tf.fsf@tethera.net > EXPECTED
+notmuch search id:871qo9p4tf.fsf@tethera.net and '"not really PDF"' > OUTPUT
+test_expect_equal_file_nonempty EXPECTED OUTPUT
+
+test_begin_subtest "as_text is bad regex"
+notmuch config set index.as_text '['
+notmuch reindex '*' >& OUTPUT
+cat<<EOF > EXPECTED
+Error in index.as_text: Invalid regular expression: [
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
test_description='run code with ASAN enabled against the library'
. $(dirname "$0")/test-lib.sh || exit 1
-if [ $NOTMUCH_HAVE_ASAN -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_ASAN-0}" != "1" ]; then
printf "Skipping due to missing ASAN support\n"
test_done
fi
+if [ -n "${LD_PRELOAD-}" ]; then
+ printf "Skipping due to ASAN LD_PRELOAD restrictions\n"
+ test_done
+fi
+
add_email_corpus
-TEST_CFLAGS="-fsanitize=address"
+TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=address"
test_begin_subtest "open and destroy"
test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} <<EOF
--- /dev/null
+#!/usr/bin/env bash
+
+test_directory=$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)
+
+test_description='run code with TSan enabled against the library'
+# Note it is hard to ensure race conditions are deterministic so this
+# only provides best effort detection.
+
+. "$test_directory"/test-lib.sh || exit 1
+
+if [ "${NOTMUCH_HAVE_TSAN-0}" != "1" ]; then
+ printf "Skipping due to missing TSan support\n"
+ test_done
+fi
+
+export TSAN_OPTIONS="suppressions=$test_directory/T810-tsan.suppressions"
+TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=thread"
+
+cp -r ${MAIL_DIR} ${MAIL_DIR}-2
+
+test_begin_subtest "create"
+test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
+#include <notmuch-test.h>
+#include <pthread.h>
+
+void *thread (void *arg) {
+ char *mail_dir = arg;
+ /*
+ * Calls into notmuch_query_search_messages which was using the thread-unsafe
+ * Xapian::Query::MatchAll.
+ */
+ EXPECT0(notmuch_database_create (mail_dir, NULL));
+ return NULL;
+}
+
+int main (int argc, char **argv) {
+ pthread_t t1, t2;
+ EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
+ EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
+ EXPECT0(pthread_join (t1, NULL));
+ EXPECT0(pthread_join (t2, NULL));
+ return 0;
+}
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+add_email_corpus
+rm -r ${MAIL_DIR}-2
+cp -r ${MAIL_DIR} ${MAIL_DIR}-2
+
+test_begin_subtest "query"
+test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
+#include <notmuch-test.h>
+#include <pthread.h>
+
+void *thread (void *arg) {
+ char *mail_dir = arg;
+ notmuch_database_t *db;
+ /*
+ * 'from' is NOTMUCH_FIELD_PROBABILISTIC | NOTMUCH_FIELD_PROCESSOR and an
+ * empty string gets us to RegexpFieldProcessor::operator which was using
+ * the tread-unsafe Xapian::Query::MatchAll.
+ */
+ EXPECT0(notmuch_database_open_with_config (mail_dir,
+ NOTMUCH_DATABASE_MODE_READ_ONLY,
+ NULL, NULL, &db, NULL));
+ notmuch_query_t *query = notmuch_query_create (db, "from:\"\"");
+ notmuch_messages_t *messages;
+ EXPECT0(notmuch_query_search_messages (query, &messages));
+ return NULL;
+}
+
+int main (int argc, char **argv) {
+ pthread_t t1, t2;
+ EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
+ EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
+ EXPECT0(pthread_join (t1, NULL));
+ EXPECT0(pthread_join (t2, NULL));
+ return 0;
+}
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
--- /dev/null
+# It's unclear how TSan-friendly GLib is:
+# https://gitlab.gnome.org/GNOME/glib/-/issues/1672
+called_from_lib:libglib*.so
test_description='"notmuch git" to save and restore tags'
. $(dirname "$0")/test-lib.sh || exit 1
-if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
+if [ "${NOTMUCH_HAVE_SFSEXP-0}" != "1" ]; then
printf "Skipping due to missing sfsexp library\n"
test_done
fi
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "invoke as nmbug sets defaults"
+test_subtest_broken_for_installed
"$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT
cat <<EOF > EXPECTED
prefix = notmuch::
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as nmbug"
+test_subtest_broken_for_installed
NOTMUCH_GIT_DIR=`pwd`/foo "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
cat <<EOF > EXPECTED
repository = CWD/foo
test_begin_subtest "env variable NOTMUCH_GIT_DIR overrides config when invoked as 'nmbug'"
+test_subtest_broken_for_installed
notmuch config set git.path `pwd`/bar
NOTMUCH_GIT_DIR=`pwd`/remote.git "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
notmuch config set git.path
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as 'nmbug'"
+test_subtest_broken_for_installed
NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
cat <<EOF > EXPECTED
prefix = env::
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as nmbug"
+test_subtest_broken_for_installed
NOTMUCH_GIT_PREFIX=foo:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
cat <<EOF > EXPECTED
prefix = foo::
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX overrides config when invoked as 'nmbug'"
+test_subtest_broken_for_installed
notmuch config set git.tag_prefix config::
NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
notmuch config set git.path
--- /dev/null
+From: David Bremner <david@tethera.net>
+To: example@example.com
+Subject: attachment content type
+Date: Thu, 05 Jan 2023 08:02:36 -0400
+Message-ID: <871qo9p4tf.fsf@tethera.net>
+MIME-Version: 1.0
+Content-Type: application/pdf
+Content-Disposition: attachment; filename=fake.pdf
+Content-Transfer-Encoding: base64
+
+dGhpcyBpcyBub3QgcmVhbGx5IFBERgo=
\ No newline at end of file
--- /dev/null
+ 2009-11-17 [5/5] Mikhail Gusarov, Carl Worth, Keith Packard [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth [notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 [1/1] Mikhail Gusarov [notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 [2/2] Keith Packard, Carl Worth [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 [2/2] Jan Janak, Carl Worth [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-17 [3/3] Jan Janak, Carl Worth [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 [3/3] Israel Herraiz, Keith Packard, Carl Worth [notmuch] New to the list (inbox unread)
+ 2009-11-17 [3/3] Adrian Perez de Castro, Keith Packard, Carl Worth [notmuch] Introducing myself (inbox signed unread)
+ 2009-11-17 [3/3] Aron Griffis, Keith Packard, Carl Worth [notmuch] archive (inbox unread)
+ 2009-11-17 [2/2] Ingmar Vanhassel, Carl Worth [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 [2/2] Alex Botero-Lowry, Carl Worth [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 [2/2] Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 [1/1] Stewart Smith [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (deleted inbox unread)
+ 2009-11-18 [1/1] Stewart Smith [notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+ 2009-11-18 [1/1] Stewart Smith [notmuch] [PATCH] count_files: sort directory in inode order before statting (deleted inbox unread)
+ 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 [1/1] Jan Janak [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 [1/1] Rolland Santimano [notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 [1/1] Alexander Botero-Lowry [notmuch] request for pull (inbox unread)
+ 2009-11-18 [2/2] Keith Packard, Alexander Botero-Lowry [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 [1/1] Chris Wilson [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+ 2010-12-16 [1/1] Olivier Berger Essai accentué (inbox unread)
+ 2010-12-29 [1/1] François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 [5/5] Mikhail Gusarov, Carl Worth, Keith Packard [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth [notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 [1/1] Mikhail Gusarov [notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 [2/2] Keith Packard, Carl Worth [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 [2/2] Jan Janak, Carl Worth [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-17 [3/3] Jan Janak, Carl Worth [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 [3/3] Israel Herraiz, Keith Packard, Carl Worth [notmuch] New to the list (inbox unread)
+ 2009-11-17 [3/3] Adrian Perez de Castro, Keith Packard, Carl Worth [notmuch] Introducing myself (inbox signed unread)
+ 2009-11-17 [3/3] Aron Griffis, Keith Packard, Carl Worth [notmuch] archive (inbox unread)
+ 2009-11-17 [2/2] Ingmar Vanhassel, Carl Worth [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 [2/2] Alex Botero-Lowry, Carl Worth [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 [2/2] Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 [1/1] Jan Janak [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 [1/1] Rolland Santimano [notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 [1/1] Alexander Botero-Lowry [notmuch] request for pull (inbox unread)
+ 2009-11-18 [2/2] Keith Packard, Alexander Botero-Lowry [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2010-12-16 [1/1] Olivier Berger Essai accentué (inbox unread)
+ 2010-12-29 [1/1] François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Mikhail Gusarov ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+ 2009-11-17 Carl Worth ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov ├┬► ... (inbox signed unread)
+ 2009-11-17 Lars Kellogg-Stedman │╰┬► ... (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov │ ├─► ... (inbox unread)
+ 2009-11-17 Keith Packard │ ╰┬► ... (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman │ ╰─► ... (inbox signed unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Alex Botero-Lowry ┬►[notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Mikhail Gusarov ─►[notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Keith Packard ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Israel Herraiz ┬►[notmuch] New to the list (inbox unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Adrian Perez de Cast ┬►[notmuch] Introducing myself (inbox signed unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Aron Griffis ┬►[notmuch] archive (inbox unread)
+ 2009-11-18 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-18 Alex Botero-Lowry ┬►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman ┬►[notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman ╰─► ... (attachment inbox signed unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (deleted inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] count_files: sort directory in inode order before statting (deleted inbox unread)
+ 2009-11-18 Jjgod Jiang ┬►[notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (inbox unread)
+ 2009-11-18 Jan Janak ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Rolland Santimano ─►[notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Alexander Botero-Low ─►[notmuch] request for pull (inbox unread)
+ 2009-11-18 Keith Packard ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Chris Wilson ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+ 2010-12-16 Olivier Berger ─►Essai accentué (inbox unread)
+ 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Mikhail Gusarov ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+ 2009-11-17 Carl Worth ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov ├┬► ... (inbox signed unread)
+ 2009-11-17 Lars Kellogg-Stedman │╰┬► ... (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov │ ├─► ... (inbox unread)
+ 2009-11-17 Keith Packard │ ╰┬► ... (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman │ ╰─► ... (inbox signed unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Alex Botero-Lowry ┬►[notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Mikhail Gusarov ─►[notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Keith Packard ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Israel Herraiz ┬►[notmuch] New to the list (inbox unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Adrian Perez de Cast ┬►[notmuch] Introducing myself (inbox signed unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Aron Griffis ┬►[notmuch] archive (inbox unread)
+ 2009-11-18 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-18 Alex Botero-Lowry ┬►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman ┬►[notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman ╰─► ... (attachment inbox signed unread)
+ 2009-11-18 Jjgod Jiang ┬►[notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (inbox unread)
+ 2009-11-18 Jan Janak ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Rolland Santimano ─►[notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Alexander Botero-Low ─►[notmuch] request for pull (inbox unread)
+ 2009-11-18 Keith Packard ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2010-12-16 Olivier Berger ─►Essai accentué (inbox unread)
+ 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+ 2009-11-17 Carl Worth [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Alex Botero-Lowry [notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 Carl Worth [notmuch] preliminary FreeBSD support (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Israel Herraiz [notmuch] New to the list (inbox unread)
+ 2009-11-17 Adrian Perez de Cast [notmuch] Introducing myself (inbox signed unread)
+ 2009-11-17 Aron Griffis [notmuch] archive (inbox unread)
+ 2009-11-17 Ingmar Vanhassel [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Alex Botero-Lowry [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Stewart Smith [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (deleted inbox unread)
+ 2009-11-18 Stewart Smith [notmuch] [PATCH 2/2] Read mail directory in inode number order (deleted inbox unread)
+ 2009-11-18 Keith Packard [notmuch] New to the list (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] Introducing myself (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] archive (inbox unread)
+ 2009-11-18 Stewart Smith [notmuch] [PATCH] count_files: sort directory in inode order before statting (deleted inbox unread)
+ 2009-11-18 Jjgod Jiang [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Jan Janak [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Rolland Santimano [notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Jjgod Jiang [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] request for pull (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] archive (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] What a great idea! (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] New to the list (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] Introducing myself (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+ 2009-11-18 Chris Wilson [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (deleted inbox unread)
+ 2010-12-16 Olivier Berger Essai accentué (inbox unread)
+ 2010-12-29 François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+ 2009-11-17 Carl Worth [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Alex Botero-Lowry [notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 Carl Worth [notmuch] preliminary FreeBSD support (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-17 Mikhail Gusarov [notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-17 Keith Packard [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak [notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Israel Herraiz [notmuch] New to the list (inbox unread)
+ 2009-11-17 Adrian Perez de Cast [notmuch] Introducing myself (inbox signed unread)
+ 2009-11-17 Aron Griffis [notmuch] archive (inbox unread)
+ 2009-11-17 Ingmar Vanhassel [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Alex Botero-Lowry [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Keith Packard [notmuch] New to the list (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] Introducing myself (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] archive (inbox unread)
+ 2009-11-18 Jjgod Jiang [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Jan Janak [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Rolland Santimano [notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Jjgod Jiang [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] request for pull (inbox unread)
+ 2009-11-18 Keith Packard [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] Working with Maildir storage? (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] archive (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] What a great idea! (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] New to the list (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] Introducing myself (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Carl Worth [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+ 2010-12-16 Olivier Berger Essai accentué (inbox unread)
+ 2010-12-29 François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
--- /dev/null
+ 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+ 2010-12-16 Olivier Berger ─►Essai accentué (inbox unread)
+ 2009-11-18 Chris Wilson ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+ 2009-11-18 Alex Botero-Lowry ┬►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-17 Adrian Perez de Cast ┬►[notmuch] Introducing myself (inbox signed unread)
+ 2009-11-17 Israel Herraiz ┬►[notmuch] New to the list (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-17 Aron Griffis ┬►[notmuch] archive (inbox unread)
+ 2009-11-17 Keith Packard ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-18 Keith Packard ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low ─►[notmuch] request for pull (inbox unread)
+ 2009-11-18 Jjgod Jiang ┬►[notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Rolland Santimano ─►[notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Jan Janak ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman ┬►[notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-17 Mikhail Gusarov ─►[notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Alex Botero-Lowry ┬►[notmuch] preliminary FreeBSD support (attachment inbox unread)
+End of search results.
--- /dev/null
+ 2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Mikhail Gusarov ├─►[notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
+ 2009-11-17 Carl Worth ╰┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
+ 2009-11-17 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov ├┬► ... (inbox signed unread)
+ 2009-11-17 Lars Kellogg-Stedman │╰┬► ... (inbox signed unread)
+ 2009-11-17 Mikhail Gusarov │ ├─► ... (inbox unread)
+ 2009-11-17 Keith Packard │ ╰┬► ... (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman │ ╰─► ... (inbox signed unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Alex Botero-Lowry ┬►[notmuch] preliminary FreeBSD support (attachment inbox unread)
+ 2009-11-17 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Mikhail Gusarov ─►[notmuch] [PATCH] Handle rename of message file (inbox unread)
+ 2009-11-17 Keith Packard ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Jan Janak ┬►[notmuch] What a great idea! (inbox unread)
+ 2009-11-17 Jan Janak ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Israel Herraiz ┬►[notmuch] New to the list (inbox unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Adrian Perez de Cast ┬►[notmuch] Introducing myself (inbox signed unread)
+ 2009-11-18 Keith Packard ├─► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Aron Griffis ┬►[notmuch] archive (inbox unread)
+ 2009-11-18 Keith Packard ╰┬► ... (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (inbox unread)
+ 2009-11-18 Carl Worth ╰─► ... (inbox unread)
+ 2009-11-18 Alex Botero-Lowry ┬►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
+ 2009-11-18 Carl Worth ╰─►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (inbox unread)
+ 2009-11-18 Lars Kellogg-Stedman ┬►[notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
+ 2009-11-18 Lars Kellogg-Stedman ╰─► ... (attachment inbox signed unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
+ 2009-11-18 Stewart Smith ─►[notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
+ 2009-11-18 Jjgod Jiang ┬►[notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰┬► ... (inbox unread)
+ 2009-11-18 Jjgod Jiang ╰┬► ... (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─► ... (inbox unread)
+ 2009-11-18 Jan Janak ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
+ 2009-11-18 Rolland Santimano ─►[notmuch] Link to mailing list archives ? (inbox unread)
+ 2009-11-18 Alexander Botero-Low ─►[notmuch] request for pull (inbox unread)
+ 2009-11-18 Keith Packard ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Alexander Botero-Low ╰─►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
+ 2009-11-18 Chris Wilson ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+ 2010-12-16 Olivier Berger ─►Essai accentué (inbox unread)
+ 2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+End of search results.
if [[ -z "${NOTMUCH_BUILDDIR}" ]]; then
export NOTMUCH_BUILDDIR="$(find_builddir "$(pwd)")"
- if [[ -z "${NOTMUCH_BUILDDIR}" ]]; then
+ if [ -z "${NOTMUCH_BUILDDIR}" -a "${NOTMUCH_TEST_INSTALLED-0}" = "0" ]; then
echo "Run tests in a subdir of built notmuch tree." >&2
exit 1
fi
set -eu
+# Where to run the tests
+# XXX FIXME this code is duplicated with test-lib.sh
+if [[ -n "${NOTMUCH_BUILDDIR}" ]]; then
+ TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+else
+ TEST_DIRECTORY=$NOTMUCH_SRCDIR/test
+fi
+
TESTS=
for test in ${NOTMUCH_TESTS-}; do
TESTS="$TESTS $NOTMUCH_SRCDIR/test/$test"
do
file=${file##*/} # drop leading path components
file=${file%.sh} # drop trailing '.sh'
- RESULT_FILES="$RESULT_FILES $NOTMUCH_BUILDDIR/test/test-results/$file"
+ RESULT_FILES="$RESULT_FILES $TEST_DIRECTORY/test-results/$file"
done
echo
fi
# Clean up
-rm -rf $NOTMUCH_BUILDDIR/test/test-results
+rm -rf $TEST_DIRECTORY/test-results
exit $ev
# .notmuch-config - Configuration file for the notmuch mail system
#
# For more information about notmuch, see https://notmuchmail.org
-
# Database configuration
#
# The only value supported here is 'path' which should be the top-level
#
[database]
path=/path/to/maildir
-
# User configuration
#
# Here is where you can let notmuch know how you would like to be
name=Test Suite
primary_email=test.suite@example.com
other_email=another.suite@example.com
-
# Configuration for "notmuch new"
#
# The following options are supported here:
#
[new]
tags=foo;bar;
-
# Search configuration
#
# The following option is supported here:
#
[search]
exclude_tags=baz
-
# Maildir compatibility configuration
#
# The following option is supported here:
#
type die >/dev/null 2>&1 || die () { echo "$@" >&2; exit 1; }
-if [[ -z "$NOTMUCH_SRCDIR" ]] || [[ -z "$NOTMUCH_BUILDDIR" ]]; then
+if [[ -z "$NOTMUCH_SRCDIR" ]] || [ -z "${NOTMUCH_TEST_INSTALLED-}" -a -z "$NOTMUCH_BUILDDIR" ]; then
echo "internal: srcdir or builddir not set" >&2
exit 1
fi
export LD_LIBRARY_PATH
# configure output
-. "$NOTMUCH_BUILDDIR/sh.config" || exit 1
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ . "$NOTMUCH_BUILDDIR/sh.config" || exit 1
+fi
# load OS specifics
if [[ -e "$NOTMUCH_SRCDIR/test/test-lib-$PLATFORM.sh" ]]; then
# Test repository
test="tmp.$(basename "$0" .sh)"
-TMP_DIRECTORY="$TEST_DIRECTORY/$test"
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ TMP_DIRECTORY="$TEST_DIRECTORY/$test"
+else
+ TMP_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}/notmuch-$test.XXXXXX")
+fi
+
test ! -z "$debug" || remove_tmp=$TMP_DIRECTORY
rm -rf "$TMP_DIRECTORY" || {
GIT_EXIT_OK=t
exit 1
}
+# Provide a guess at a usable Python, to support running tests without
+# running configure first.
+NOTMUCH_PYTHON=${NOTMUCH_PYTHON-python3}
+
# A temporary home directory is needed by at least:
# - emacs/"Sending a message via (fake) SMTP"
# - emacs/"Reply within emacs"
# to the message and encrypting/signing.
emacs_deliver_message () {
local subject body smtp_dummy_pid smtp_dummy_port
+ test_subtest_broken_for_installed
subject="$1"
body="$2"
shift 2
# Construct a little test script here for the benefit of the user,
# (who can easily run "run_emacs" to get the same emacs environment
# for investigating any failures).
+ if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ find_notmuch_el='--directory "$NOTMUCH_BUILDDIR/emacs"'
+ else
+ ### XXX FIXME: this should really use the installed emacs lisp files
+ find_notmuch_el='--directory "$NOTMUCH_SRCDIR/emacs"'
+ fi
+
cat <<EOF >"$TMP_DIRECTORY/run_emacs"
#!/bin/sh
export PATH=$PATH
#
# --load Force loading of notmuch.el and test-lib.el
-exec ${TEST_EMACS} --quick \
- --directory "$NOTMUCH_BUILDDIR/emacs" --load notmuch.el \
+exec ${TEST_EMACS} ${find_notmuch_el} --quick \
+ ${EXTRA_DIR} --load notmuch.el \
--directory "$NOTMUCH_SRCDIR/test" --load test-lib.el \
"\$@"
EOF
;;; Code:
+;; minimize impact of native compilation on the test suite.
+;; These are the Emacs 29.1 version of the variables.
+;; Leave trampolines enabled per Emacs upstream recommendations.
+;; It is important to set these variables before loading any
+;; .elc files.
+(setq native-comp-jit-compilation nil)
+(setq native-comp-speed -1)
+(setq native-comp-async-jobs-number 1)
+
(require 'cl-lib)
;; Ensure that the dynamic variables that are defined by this library
;; environments
(setq mm-text-html-renderer 'html2text)
+
+;; Set our own default for message-hidden-headers, to avoid tests
+;; breaking when the Emacs default changes.
+(setq message-hidden-headers
+ '("^References:" "^Face:" "^X-Face:" "^X-Draft-From:"))
# Ensure NOTMUCH_SRCDIR and NOTMUCH_BUILDDIR are set.
. $(dirname "$0")/export-dirs.sh || exit 1
-# It appears that people try to run tests without building...
-if [[ ! -x "$NOTMUCH_BUILDDIR/notmuch" ]]; then
+# We need either a built tree, or a promise of an installed notmuch
+if [ -z "${NOTMUCH_TEST_INSTALLED-}" -a ! -x "$NOTMUCH_BUILDDIR/notmuch" ]; then
echo >&2 'You do not seem to have built notmuch yet.'
exit 1
fi
test "$#" = 2 ||
error "bug in the test script: not 2 parameters to test_expect_equal_file"
+ for file in "$1" "$2"; do
+ if [ ! -s "$file" ]; then
+ test_failure_ "Missing or zero length file: $file"
+ inside_subtest=
+ return 1
+ fi
+ done
+
expected=$(sed '1,/^$/d' "$1")
output=$(sed '1,/^$/d' "$2")
test_expect_equal "$expected" "$output"
test_subtest_known_broken_=t
}
+test_subtest_broken_for_installed () {
+ if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ test_subtest_known_broken_=t
+ fi
+}
+
+test_subtest_broken_for_root () {
+ if [ "$EUID" = "0" ]; then
+ test_subtest_known_broken_=t
+ fi
+}
+
test_expect_success () {
exec 1>&6 2>&7 # Restore stdout and stderr
if [ -z "$inside_subtest" ]; then
}
notmuch_with_shim () {
- local base_name shim_file
- base_name="$1"
+ local base_name shim_file notmuch_cmd
+ if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
+ notmuch_cmd="notmuch"
+ else
+ notmuch_cmd="notmuch-shared"
+ fi
+ base_name=$1
shift
shim_file="${base_name}.so"
- LD_PRELOAD=${LD_PRELOAD:+:$LD_PRELOAD}:./${shim_file} notmuch-shared "$@"
+ LD_PRELOAD=${LD_PRELOAD:+:$LD_PRELOAD}:./${shim_file} $notmuch_cmd "$@"
}
# Creates a script that counts how much time it is executed and calls
# Where to run the tests
-TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+if [[ -n "${NOTMUCH_BUILDDIR}" ]]; then
+ TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
+else
+ TEST_DIRECTORY=$NOTMUCH_SRCDIR/test
+fi
. "$NOTMUCH_SRCDIR/test/test-lib-common.sh" || exit 1
--- /dev/null
+#ifndef _XAPIAN_EXTRA_H
+#define _XAPIAN_EXTRA_H
+
+#include <string>
+#include <xapian.h>
+
+inline Xapian::Query
+xapian_query_match_all (void)
+{
+ // Xapian::Query::MatchAll isn't thread safe (a static object with reference
+ // counting) so instead reconstruct the equivalent on demand.
+ return Xapian::Query (std::string ());
+}
+
+#endif
As an example to configure a key mapping to add the tag 'to-do' and archive,
this is what I use:
-let g:notmuch_rb_custom_search_maps = {
+let g:notmuch_custom_search_maps = {
\ 't': 'search_tag("+to-do -inbox")',
\ }
-let g:notmuch_rb_custom_show_maps = {
+let g:notmuch_custom_show_maps = {
\ 't': 'show_tag("+to-do -inbox")',
\ }
CONFIGURATION *notmuch-config*
You can add the following configurations to your `.vimrc`, or
-`~/.vim/plugin/notmuch.vim`.
+`~/.vim/after/plugin/notmuch.vim`.
*g:notmuch_folders*
If you want to count the threads instead of the messages in the folder view:
>
- let g:notmuch_folders_count_threads = 0
+ let g:notmuch_folders_count_threads = 1
<
*g:notmuch_reader*
*g:notmuch_sendmail*
-You can also configure your externail mail reader and sendemail program:
+You can also configure your external mail reader and sendmail program:
>
let g:notmuch_reader = 'mutt -f %s'
let g:notmuch_sendmail = 'sendmail'