mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-25 12:28:09 +01:00
Merge remote-tracking branch 'origin/master' into nmweb
This commit is contained in:
commit
1129cf890e
111 changed files with 1480 additions and 374 deletions
72
NEWS
72
NEWS
|
@ -1,3 +1,75 @@
|
||||||
|
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)
|
Notmuch 0.37 (2022-08-21)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
|
@ -34,3 +34,7 @@ CLEAN += $(patsubst %,$(dir)/ruby/%, \
|
||||||
CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
|
CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
|
||||||
|
|
||||||
CLEAN += bindings/python-cffi/build $(dir)/python-cffi.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
|
||||||
|
|
|
@ -47,7 +47,10 @@ if sys.version_info[0] == 2:
|
||||||
|
|
||||||
return value
|
return value
|
||||||
else:
|
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):
|
class Python3StringMixIn(object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# this file should be kept in sync with ../../../version
|
# this file should be kept in sync with ../../../version
|
||||||
__VERSION__ = '0.37'
|
__VERSION__ = '0.38'
|
||||||
SOVERSION = '5'
|
SOVERSION = '5'
|
||||||
|
|
|
@ -58,22 +58,38 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
|
||||||
notmuch_database_t *database;
|
notmuch_database_t *database;
|
||||||
notmuch_status_t ret;
|
notmuch_status_t ret;
|
||||||
|
|
||||||
/* Check arguments */
|
path = NULL;
|
||||||
rb_scan_args (argc, argv, "11", &pathv, &hashv);
|
create = 0;
|
||||||
|
mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
|
||||||
|
|
||||||
|
/* Check arguments */
|
||||||
|
rb_scan_args (argc, argv, "02", &pathv, &hashv);
|
||||||
|
|
||||||
|
if (!NIL_P (pathv)) {
|
||||||
SafeStringValue (pathv);
|
SafeStringValue (pathv);
|
||||||
path = RSTRING_PTR (pathv);
|
path = RSTRING_PTR (pathv);
|
||||||
|
}
|
||||||
|
|
||||||
if (!NIL_P (hashv)) {
|
if (!NIL_P (hashv)) {
|
||||||
Check_Type (hashv, T_HASH);
|
VALUE rmode, rcreate;
|
||||||
create = RTEST (rb_hash_aref (hashv, ID2SYM (ID_db_create)));
|
VALUE kwargs[2];
|
||||||
modev = rb_hash_aref (hashv, ID2SYM (ID_db_mode));
|
static ID keyword_ids[2];
|
||||||
if (NIL_P (modev))
|
|
||||||
mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
|
if (!keyword_ids[0]) {
|
||||||
else if (!FIXNUM_P (modev))
|
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");
|
rb_raise (rb_eTypeError, ":mode isn't a Fixnum");
|
||||||
else {
|
else {
|
||||||
mode = FIX2INT (modev);
|
mode = FIX2INT (rmode);
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case NOTMUCH_DATABASE_MODE_READ_ONLY:
|
case NOTMUCH_DATABASE_MODE_READ_ONLY:
|
||||||
case NOTMUCH_DATABASE_MODE_READ_WRITE:
|
case NOTMUCH_DATABASE_MODE_READ_WRITE:
|
||||||
|
@ -82,16 +98,16 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
|
||||||
rb_raise ( rb_eTypeError, "Invalid mode");
|
rb_raise ( rb_eTypeError, "Invalid mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
create = 0;
|
if (rcreate != Qundef)
|
||||||
mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
|
create = RTEST (rcreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_check_typeddata (self, ¬much_rb_database_type);
|
rb_check_typeddata (self, ¬much_rb_database_type);
|
||||||
if (create)
|
if (create)
|
||||||
ret = notmuch_database_create (path, &database);
|
ret = notmuch_database_create (path, &database);
|
||||||
else
|
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);
|
notmuch_rb_status_raise (ret);
|
||||||
|
|
||||||
DATA_PTR (self) = notmuch_rb_object_create (database, "notmuch_rb_database");
|
DATA_PTR (self) = notmuch_rb_object_create (database, "notmuch_rb_database");
|
||||||
|
@ -408,7 +424,7 @@ notmuch_rb_database_get_all_tags (VALUE self)
|
||||||
|
|
||||||
rb_raise (notmuch_rb_eBaseError, "%s", msg);
|
rb_raise (notmuch_rb_eBaseError, "%s", msg);
|
||||||
}
|
}
|
||||||
return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, ¬much_rb_tags_type, tags);
|
return notmuch_rb_tags_get (tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -33,7 +33,6 @@ extern VALUE notmuch_rb_cThreads;
|
||||||
extern VALUE notmuch_rb_cThread;
|
extern VALUE notmuch_rb_cThread;
|
||||||
extern VALUE notmuch_rb_cMessages;
|
extern VALUE notmuch_rb_cMessages;
|
||||||
extern VALUE notmuch_rb_cMessage;
|
extern VALUE notmuch_rb_cMessage;
|
||||||
extern VALUE notmuch_rb_cTags;
|
|
||||||
|
|
||||||
extern VALUE notmuch_rb_eBaseError;
|
extern VALUE notmuch_rb_eBaseError;
|
||||||
extern VALUE notmuch_rb_eDatabaseError;
|
extern VALUE notmuch_rb_eDatabaseError;
|
||||||
|
@ -48,8 +47,6 @@ extern VALUE notmuch_rb_eUnbalancedFreezeThawError;
|
||||||
extern VALUE notmuch_rb_eUnbalancedAtomicError;
|
extern VALUE notmuch_rb_eUnbalancedAtomicError;
|
||||||
|
|
||||||
extern ID ID_call;
|
extern ID ID_call;
|
||||||
extern ID ID_db_create;
|
|
||||||
extern ID ID_db_mode;
|
|
||||||
|
|
||||||
/* RSTRING_PTR() is new in ruby-1.9 */
|
/* RSTRING_PTR() is new in ruby-1.9 */
|
||||||
#if !defined(RSTRING_PTR)
|
#if !defined(RSTRING_PTR)
|
||||||
|
@ -59,7 +56,6 @@ extern ID ID_db_mode;
|
||||||
extern const rb_data_type_t notmuch_rb_object_type;
|
extern const rb_data_type_t notmuch_rb_object_type;
|
||||||
extern const rb_data_type_t notmuch_rb_database_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_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_query_type;
|
||||||
extern const rb_data_type_t notmuch_rb_threads_type;
|
extern const rb_data_type_t notmuch_rb_threads_type;
|
||||||
extern const rb_data_type_t notmuch_rb_thread_type;
|
extern const rb_data_type_t notmuch_rb_thread_type;
|
||||||
|
@ -92,9 +88,6 @@ extern const rb_data_type_t notmuch_rb_tags_type;
|
||||||
#define Data_Get_Notmuch_Directory(obj, ptr) \
|
#define Data_Get_Notmuch_Directory(obj, ptr) \
|
||||||
Data_Get_Notmuch_Object ((obj), ¬much_rb_directory_type, (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) \
|
#define Data_Get_Notmuch_Query(obj, ptr) \
|
||||||
Data_Get_Notmuch_Object ((obj), ¬much_rb_query_type, (ptr))
|
Data_Get_Notmuch_Object ((obj), ¬much_rb_query_type, (ptr))
|
||||||
|
|
||||||
|
@ -226,10 +219,7 @@ notmuch_rb_directory_get_child_directories (VALUE self);
|
||||||
|
|
||||||
/* filenames.c */
|
/* filenames.c */
|
||||||
VALUE
|
VALUE
|
||||||
notmuch_rb_filenames_destroy (VALUE self);
|
notmuch_rb_filenames_get (notmuch_filenames_t *fnames);
|
||||||
|
|
||||||
VALUE
|
|
||||||
notmuch_rb_filenames_each (VALUE self);
|
|
||||||
|
|
||||||
/* query.c */
|
/* query.c */
|
||||||
VALUE
|
VALUE
|
||||||
|
@ -370,10 +360,7 @@ notmuch_rb_message_thaw (VALUE self);
|
||||||
|
|
||||||
/* tags.c */
|
/* tags.c */
|
||||||
VALUE
|
VALUE
|
||||||
notmuch_rb_tags_destroy (VALUE self);
|
notmuch_rb_tags_get (notmuch_tags_t *tags);
|
||||||
|
|
||||||
VALUE
|
|
||||||
notmuch_rb_tags_each (VALUE self);
|
|
||||||
|
|
||||||
/* init.c */
|
/* init.c */
|
||||||
void
|
void
|
||||||
|
|
|
@ -87,7 +87,7 @@ notmuch_rb_directory_get_child_files (VALUE self)
|
||||||
|
|
||||||
fnames = notmuch_directory_get_child_files (dir);
|
fnames = notmuch_directory_get_child_files (dir);
|
||||||
|
|
||||||
return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
|
return notmuch_rb_filenames_get (fnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -106,5 +106,5 @@ notmuch_rb_directory_get_child_directories (VALUE self)
|
||||||
|
|
||||||
fnames = notmuch_directory_get_child_directories (dir);
|
fnames = notmuch_directory_get_child_directories (dir);
|
||||||
|
|
||||||
return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
|
return notmuch_rb_filenames_get (fnames);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +1,11 @@
|
||||||
/* The Ruby interface to the notmuch mail library
|
|
||||||
*
|
|
||||||
* Copyright © 2010 Ali Polatel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see https://www.gnu.org/licenses/ .
|
|
||||||
*
|
|
||||||
* Author: Ali Polatel <alip@exherbo.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq: FILENAMES.destroy! => nil
|
|
||||||
*
|
|
||||||
* Destroys the filenames, freeing all resources allocated for it.
|
|
||||||
*/
|
|
||||||
VALUE
|
VALUE
|
||||||
notmuch_rb_filenames_destroy (VALUE self)
|
notmuch_rb_filenames_get (notmuch_filenames_t *fnames)
|
||||||
{
|
{
|
||||||
notmuch_rb_object_destroy (self, ¬much_rb_filenames_type);
|
VALUE rb_array = rb_ary_new ();
|
||||||
|
|
||||||
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_filenames_t *fnames;
|
|
||||||
|
|
||||||
Data_Get_Notmuch_FileNames (self, fnames);
|
|
||||||
|
|
||||||
for (; notmuch_filenames_valid (fnames); notmuch_filenames_move_to_next (fnames))
|
for (; notmuch_filenames_valid (fnames); notmuch_filenames_move_to_next (fnames))
|
||||||
rb_yield (rb_str_new2 (notmuch_filenames_get (fnames)));
|
rb_ary_push (rb_array, rb_str_new2 (notmuch_filenames_get (fnames)));
|
||||||
|
return rb_array;
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,11 @@
|
||||||
|
|
||||||
VALUE notmuch_rb_cDatabase;
|
VALUE notmuch_rb_cDatabase;
|
||||||
VALUE notmuch_rb_cDirectory;
|
VALUE notmuch_rb_cDirectory;
|
||||||
VALUE notmuch_rb_cFileNames;
|
|
||||||
VALUE notmuch_rb_cQuery;
|
VALUE notmuch_rb_cQuery;
|
||||||
VALUE notmuch_rb_cThreads;
|
VALUE notmuch_rb_cThreads;
|
||||||
VALUE notmuch_rb_cThread;
|
VALUE notmuch_rb_cThread;
|
||||||
VALUE notmuch_rb_cMessages;
|
VALUE notmuch_rb_cMessages;
|
||||||
VALUE notmuch_rb_cMessage;
|
VALUE notmuch_rb_cMessage;
|
||||||
VALUE notmuch_rb_cTags;
|
|
||||||
|
|
||||||
VALUE notmuch_rb_eBaseError;
|
VALUE notmuch_rb_eBaseError;
|
||||||
VALUE notmuch_rb_eDatabaseError;
|
VALUE notmuch_rb_eDatabaseError;
|
||||||
|
@ -43,8 +41,6 @@ VALUE notmuch_rb_eUnbalancedFreezeThawError;
|
||||||
VALUE notmuch_rb_eUnbalancedAtomicError;
|
VALUE notmuch_rb_eUnbalancedAtomicError;
|
||||||
|
|
||||||
ID ID_call;
|
ID ID_call;
|
||||||
ID ID_db_create;
|
|
||||||
ID ID_db_mode;
|
|
||||||
|
|
||||||
const rb_data_type_t notmuch_rb_object_type = {
|
const rb_data_type_t notmuch_rb_object_type = {
|
||||||
.wrap_struct_name = "notmuch_object",
|
.wrap_struct_name = "notmuch_object",
|
||||||
|
@ -65,13 +61,11 @@ const rb_data_type_t notmuch_rb_object_type = {
|
||||||
|
|
||||||
define_type (database);
|
define_type (database);
|
||||||
define_type (directory);
|
define_type (directory);
|
||||||
define_type (filenames);
|
|
||||||
define_type (query);
|
define_type (query);
|
||||||
define_type (threads);
|
define_type (threads);
|
||||||
define_type (thread);
|
define_type (thread);
|
||||||
define_type (messages);
|
define_type (messages);
|
||||||
define_type (message);
|
define_type (message);
|
||||||
define_type (tags);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-module: Notmuch
|
* Document-module: Notmuch
|
||||||
|
@ -86,13 +80,11 @@ define_type (tags);
|
||||||
* the user:
|
* the user:
|
||||||
*
|
*
|
||||||
* - Notmuch::Database
|
* - Notmuch::Database
|
||||||
* - Notmuch::FileNames
|
|
||||||
* - Notmuch::Query
|
* - Notmuch::Query
|
||||||
* - Notmuch::Threads
|
* - Notmuch::Threads
|
||||||
* - Notmuch::Messages
|
* - Notmuch::Messages
|
||||||
* - Notmuch::Thread
|
* - Notmuch::Thread
|
||||||
* - Notmuch::Message
|
* - Notmuch::Message
|
||||||
* - Notmuch::Tags
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -101,8 +93,6 @@ Init_notmuch (void)
|
||||||
VALUE mod;
|
VALUE mod;
|
||||||
|
|
||||||
ID_call = rb_intern ("call");
|
ID_call = rb_intern ("call");
|
||||||
ID_db_create = rb_intern ("create");
|
|
||||||
ID_db_mode = rb_intern ("mode");
|
|
||||||
|
|
||||||
mod = rb_define_module ("Notmuch");
|
mod = rb_define_module ("Notmuch");
|
||||||
|
|
||||||
|
@ -297,17 +287,6 @@ Init_notmuch (void)
|
||||||
rb_define_method (notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); /* in directory.c */
|
rb_define_method (notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); /* in directory.c */
|
||||||
rb_define_method (notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); /* in directory.c */
|
rb_define_method (notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); /* in directory.c */
|
||||||
|
|
||||||
/*
|
|
||||||
* Document-class: Notmuch::FileNames
|
|
||||||
*
|
|
||||||
* Notmuch file names
|
|
||||||
*/
|
|
||||||
notmuch_rb_cFileNames = rb_define_class_under (mod, "FileNames", rb_cObject);
|
|
||||||
rb_undef_method (notmuch_rb_cFileNames, "initialize");
|
|
||||||
rb_define_method (notmuch_rb_cFileNames, "destroy!", notmuch_rb_filenames_destroy, 0); /* in filenames.c */
|
|
||||||
rb_define_method (notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); /* in filenames.c */
|
|
||||||
rb_include_module (notmuch_rb_cFileNames, rb_mEnumerable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-class: Notmuch::Query
|
* Document-class: Notmuch::Query
|
||||||
*
|
*
|
||||||
|
@ -395,15 +374,4 @@ Init_notmuch (void)
|
||||||
rb_define_method (notmuch_rb_cMessage, "tags_to_maildir_flags", notmuch_rb_message_tags_to_maildir_flags, 0); /* in message.c */
|
rb_define_method (notmuch_rb_cMessage, "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, "freeze", notmuch_rb_message_freeze, 0); /* in message.c */
|
||||||
rb_define_method (notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); /* in message.c */
|
rb_define_method (notmuch_rb_cMessage, "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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ notmuch_rb_message_get_filenames (VALUE self)
|
||||||
|
|
||||||
fnames = notmuch_message_get_filenames (message);
|
fnames = notmuch_message_get_filenames (message);
|
||||||
|
|
||||||
return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, ¬much_rb_filenames_type, fnames);
|
return notmuch_rb_filenames_get (fnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -221,7 +221,7 @@ notmuch_rb_message_get_tags (VALUE self)
|
||||||
if (!tags)
|
if (!tags)
|
||||||
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -71,5 +71,5 @@ notmuch_rb_messages_collect_tags (VALUE self)
|
||||||
if (!tags)
|
if (!tags)
|
||||||
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ notmuch_rb_query_get_sort (VALUE self)
|
||||||
|
|
||||||
Data_Get_Notmuch_Query (self, query);
|
Data_Get_Notmuch_Query (self, query);
|
||||||
|
|
||||||
return FIX2INT (notmuch_query_get_sort (query));
|
return INT2FIX (notmuch_query_get_sort (query));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,56 +1,13 @@
|
||||||
/* The Ruby interface to the notmuch mail library
|
|
||||||
*
|
|
||||||
* Copyright © 2010, 2011 Ali Polatel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see https://www.gnu.org/licenses/ .
|
|
||||||
*
|
|
||||||
* Author: Ali Polatel <alip@exherbo.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq: TAGS.destroy! => nil
|
|
||||||
*
|
|
||||||
* Destroys the tags, freeing all resources allocated for it.
|
|
||||||
*/
|
|
||||||
VALUE
|
VALUE
|
||||||
notmuch_rb_tags_destroy (VALUE self)
|
notmuch_rb_tags_get (notmuch_tags_t *tags)
|
||||||
{
|
{
|
||||||
notmuch_rb_object_destroy (self, ¬much_rb_tags_type);
|
VALUE rb_array = rb_ary_new ();
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
const char *tag;
|
|
||||||
notmuch_tags_t *tags;
|
|
||||||
|
|
||||||
Data_Get_Notmuch_Tags (self, tags);
|
|
||||||
|
|
||||||
for (; notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) {
|
for (; notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) {
|
||||||
tag = notmuch_tags_get (tags);
|
const char *tag = notmuch_tags_get (tags);
|
||||||
rb_yield (rb_str_new2 (tag));
|
rb_ary_push (rb_array, rb_str_new2 (tag));
|
||||||
}
|
}
|
||||||
|
return rb_array;
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,5 +204,5 @@ notmuch_rb_thread_get_tags (VALUE self)
|
||||||
if (!tags)
|
if (!tags)
|
||||||
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <strings.h>
|
#include <strings.h> /* strcasecmp() in POSIX */
|
||||||
|
#include <string.h> /* strcasecmp() in *BSD */
|
||||||
|
|
||||||
int
|
int
|
||||||
main ()
|
main ()
|
||||||
|
|
|
@ -530,7 +530,7 @@ _notmuch_show()
|
||||||
! $split &&
|
! $split &&
|
||||||
case "${cur}" in
|
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
|
compopt -o nospace
|
||||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -245,6 +245,8 @@ _notmuch_show() {
|
||||||
'--exclude=[respect excluded tags setting]:exclude tags:(true false)' \
|
'--exclude=[respect excluded tags setting]:exclude tags:(true false)' \
|
||||||
'--body=[output body]:output body content:(true false)' \
|
'--body=[output body]:output body content:(true false)' \
|
||||||
'--include-html[include text/html parts in the output]' \
|
'--include-html[include text/html parts in the output]' \
|
||||||
|
'--limit=[limit the number of displayed results]:limit: ' \
|
||||||
|
'--offset=[skip displaying the first N results]:offset: ' \
|
||||||
'*::search term:_notmuch_search_term'
|
'*::search term:_notmuch_search_term'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
configure
vendored
19
configure
vendored
|
@ -422,6 +422,18 @@ else
|
||||||
fi
|
fi
|
||||||
unset test_cmdline
|
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... "
|
printf "Reading libnotmuch version from source... "
|
||||||
cat > _libversion.c <<EOF
|
cat > _libversion.c <<EOF
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -541,8 +553,8 @@ version of GPGME.
|
||||||
Please try to rebuild your version of GMime against a more recent
|
Please try to rebuild your version of GMime against a more recent
|
||||||
version of GPGME (at least GPGME 1.8.0).
|
version of GPGME (at least GPGME 1.8.0).
|
||||||
EOF
|
EOF
|
||||||
if command -v gpgme-config >/dev/null; then
|
if GPGME_VERS="$(pkg-config --modversion gpgme || gpgme-config --version)"; then
|
||||||
printf 'Your current GPGME development version is: %s\n' "$(gpgme-config --version)"
|
printf 'Your current GPGME development version is: %s\n' "$GPGME_VERS"
|
||||||
else
|
else
|
||||||
printf 'You do not have the GPGME development libraries installed.\n'
|
printf 'You do not have the GPGME development libraries installed.\n'
|
||||||
fi
|
fi
|
||||||
|
@ -1590,8 +1602,9 @@ NOTMUCH_GMIME_VERIFY_WITH_SESSION_KEY=${gmime_verify_with_session_key}
|
||||||
NOTMUCH_ZLIB_CFLAGS="${zlib_cflags}"
|
NOTMUCH_ZLIB_CFLAGS="${zlib_cflags}"
|
||||||
NOTMUCH_ZLIB_LDFLAGS="${zlib_ldflags}"
|
NOTMUCH_ZLIB_LDFLAGS="${zlib_ldflags}"
|
||||||
|
|
||||||
# Does the C compiler support the address sanitizer
|
# Does the C compiler support the sanitizers
|
||||||
NOTMUCH_HAVE_ASAN=${have_asan}
|
NOTMUCH_HAVE_ASAN=${have_asan}
|
||||||
|
NOTMUCH_HAVE_TSAN=${have_tsan}
|
||||||
|
|
||||||
# do we have man pages?
|
# do we have man pages?
|
||||||
NOTMUCH_HAVE_MAN=$((have_sphinx))
|
NOTMUCH_HAVE_MAN=$((have_sphinx))
|
||||||
|
|
|
@ -39,8 +39,6 @@ To *run* notmuch-mutt you will need Perl with the following libraries:
|
||||||
(Debian package: libmail-box-perl)
|
(Debian package: libmail-box-perl)
|
||||||
- Mail::Header <https://metacpan.org/pod/Mail::Header>
|
- Mail::Header <https://metacpan.org/pod/Mail::Header>
|
||||||
(Debian package: libmailtools-perl)
|
(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>
|
- Term::ReadLine::Gnu <https://metacpan.org/pod/Term::ReadLine::Gnu>
|
||||||
(Debian package: libterm-readline-gnu-perl)
|
(Debian package: libterm-readline-gnu-perl)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# notmuch-mutt - notmuch (of a) helper for Mutt
|
# notmuch-mutt - notmuch (of a) helper for Mutt
|
||||||
#
|
#
|
||||||
# Copyright: © 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
|
# Copyright: © 2011-2015 Stefano Zacchiroli <zack@upsilon.cc>
|
||||||
# License: GNU General Public License (GPL), version 3 or above
|
# License: GNU General Public License (GPL), version 3 or above
|
||||||
#
|
#
|
||||||
# See the bottom of this file for more documentation.
|
# See the bottom of this file for more documentation.
|
||||||
|
@ -13,11 +13,11 @@ use warnings;
|
||||||
|
|
||||||
use File::Path;
|
use File::Path;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
|
use File::Find;
|
||||||
use Getopt::Long qw(:config no_getopt_compat);
|
use Getopt::Long qw(:config no_getopt_compat);
|
||||||
use Mail::Header;
|
use Mail::Header;
|
||||||
use Mail::Box::Maildir;
|
use Mail::Box::Maildir;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use String::ShellQuote;
|
|
||||||
use Term::ReadLine;
|
use Term::ReadLine;
|
||||||
use Digest::SHA;
|
use Digest::SHA;
|
||||||
|
|
||||||
|
@ -26,9 +26,53 @@ my $xdg_cache_dir = "$ENV{HOME}/.cache";
|
||||||
$xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
|
$xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
|
||||||
my $cache_dir = "$xdg_cache_dir/notmuch/mutt";
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
# create an empty maildir (if missing) or empty an existing maildir"
|
sub die_subdir($$$) {
|
||||||
sub empty_maildir($) {
|
my ($maildir, $subdir, $error) = @_;
|
||||||
|
die_dir($maildir, "subdir $subdir $error");
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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) = (@_);
|
my ($maildir) = (@_);
|
||||||
rmtree($maildir) if (-d $maildir);
|
rmtree($maildir) if (-d $maildir);
|
||||||
my $folder = new Mail::Box::Maildir(folder => $maildir,
|
my $folder = new Mail::Box::Maildir(folder => $maildir,
|
||||||
|
@ -46,7 +90,8 @@ sub search($$$) {
|
||||||
push @args, "--duplicate=1" if $remove_dups;
|
push @args, "--duplicate=1" if $remove_dups;
|
||||||
push @args, $query;
|
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";
|
open my $pipe, '-|', @args or die "Running @args failed: $!\n";
|
||||||
while (<$pipe>) {
|
while (<$pipe>) {
|
||||||
chomp;
|
chomp;
|
||||||
|
@ -121,21 +166,23 @@ sub thread_action($$@) {
|
||||||
|
|
||||||
my $mid = get_message_id();
|
my $mid = get_message_id();
|
||||||
if (! defined $mid) {
|
if (! defined $mid) {
|
||||||
empty_maildir($results_dir);
|
|
||||||
die "notmuch-mutt: cannot find Message-Id, abort.\n";
|
die "notmuch-mutt: cannot find Message-Id, abort.\n";
|
||||||
}
|
}
|
||||||
my $search_cmd = 'notmuch search --output=threads ' . shell_quote("id:$mid");
|
|
||||||
my $tid = `$search_cmd`; # get thread id
|
|
||||||
chomp($tid);
|
|
||||||
|
|
||||||
search($results_dir, $remove_dups, $tid);
|
$mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
|
||||||
|
$mid =~ s/"/""""/g; # escape all double quote characters twice
|
||||||
|
|
||||||
|
search($results_dir, $remove_dups, qq{thread:"{id:""$mid""}"});
|
||||||
}
|
}
|
||||||
|
|
||||||
sub tag_action(@) {
|
sub tag_action(@) {
|
||||||
my $mid = get_message_id();
|
my $mid = get_message_id();
|
||||||
defined $mid or die "notmuch-mutt: cannot find Message-Id, abort.\n";
|
defined $mid or die "notmuch-mutt: cannot find Message-Id, abort.\n";
|
||||||
|
|
||||||
system("notmuch", "tag", @_, "--", "id:$mid");
|
$mid =~ s/ //g; # notmuch strips spaces before storing Message-Id
|
||||||
|
$mid =~ s/"/""/g; # escape all double quote characters
|
||||||
|
|
||||||
|
system("notmuch", "tag", @_, "--", qq{id:"$mid"});
|
||||||
}
|
}
|
||||||
|
|
||||||
sub die_usage() {
|
sub die_usage() {
|
||||||
|
|
39
debian/changelog
vendored
39
debian/changelog
vendored
|
@ -1,3 +1,42 @@
|
||||||
|
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
|
notmuch (0.37-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream release.
|
* New upstream release.
|
||||||
|
|
1
debian/control
vendored
1
debian/control
vendored
|
@ -227,7 +227,6 @@ Architecture: all
|
||||||
Depends:
|
Depends:
|
||||||
libmail-box-perl,
|
libmail-box-perl,
|
||||||
libmailtools-perl,
|
libmailtools-perl,
|
||||||
libstring-shellquote-perl,
|
|
||||||
libterm-readline-gnu-perl,
|
libterm-readline-gnu-perl,
|
||||||
notmuch (>= 0.4),
|
notmuch (>= 0.4),
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
|
|
8
debian/rules
vendored
8
debian/rules
vendored
|
@ -1,4 +1,9 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
include /usr/share/dpkg/architecture.mk
|
||||||
|
|
||||||
|
ifeq ($(DEB_HOST_ARCH),ppc64el)
|
||||||
|
export NOTMUCH_SKIP_TESTS = T810-tsan
|
||||||
|
endif
|
||||||
|
|
||||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
|
@ -7,7 +12,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
override_dh_auto_configure:
|
override_dh_auto_configure:
|
||||||
BASHCMD=/bin/bash ./configure --prefix=/usr \
|
BASHCMD=/bin/bash ./configure --prefix=/usr \
|
||||||
--libdir=/usr/lib/$$(dpkg-architecture -q DEB_TARGET_MULTIARCH) \
|
--libdir=/usr/lib/${DEB_TARGET_MULTIARCH} \
|
||||||
--includedir=/usr/include \
|
--includedir=/usr/include \
|
||||||
--mandir=/usr/share/man \
|
--mandir=/usr/share/man \
|
||||||
--infodir=/usr/share/info \
|
--infodir=/usr/share/info \
|
||||||
|
@ -24,7 +29,6 @@ override_dh_auto_build:
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
dh_auto_clean
|
dh_auto_clean
|
||||||
PYBUILD_NAME=notmuch dh_auto_clean --buildsystem=pybuild --sourcedirectory bindings/python
|
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
|
dh_auto_clean --sourcedirectory bindings/ruby
|
||||||
$(MAKE) -C contrib/notmuch-mutt clean
|
$(MAKE) -C contrib/notmuch-mutt clean
|
||||||
|
|
||||||
|
|
18
debian/tests/control
vendored
Normal file
18
debian/tests/control
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Test-command: env NOTMUCH_TEST_INSTALLED=1 TERM=dumb
|
||||||
|
NOTMUCH_HAVE_MAN=1 NOTMUCH_HAVE_SFSEXP=1 NOTMUCH_HAVE_XAPIAN_DB_RETRY_LOCK=1
|
||||||
|
NOTMUCH_HAVE_PYTHON3_CFFI=1 NOTMUCH_HAVE_PYTHON3_PYTEST=1
|
||||||
|
NOTMUCH_HAVE_ASAN=1 NOTMUCH_HAVE_TSAN=1
|
||||||
|
./test/notmuch-test
|
||||||
|
Restrictions: allow-stderr
|
||||||
|
Architecture: amd64, arm64
|
||||||
|
Depends: @,
|
||||||
|
build-essential,
|
||||||
|
dtach,
|
||||||
|
emacs-nox,
|
||||||
|
gdb,
|
||||||
|
git,
|
||||||
|
gnupg,
|
||||||
|
gpgsm,
|
||||||
|
libtalloc-dev,
|
||||||
|
man,
|
||||||
|
xapian-tools
|
|
@ -76,6 +76,7 @@ message = {
|
||||||
# (format_message_sprinter)
|
# (format_message_sprinter)
|
||||||
id: messageid,
|
id: messageid,
|
||||||
match: bool,
|
match: bool,
|
||||||
|
excluded: bool,
|
||||||
filename: [string*],
|
filename: [string*],
|
||||||
timestamp: unix_time, # date header as unix time
|
timestamp: unix_time, # date header as unix time
|
||||||
date_relative: string, # user-friendly timestamp
|
date_relative: string, # user-friendly timestamp
|
||||||
|
|
|
@ -159,3 +159,5 @@ $(dir)/config.dox: version.stamp
|
||||||
CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
|
CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
|
||||||
CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.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) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
|
||||||
|
|
||||||
|
CLEAN := $(CLEAN) $(dir)/__pycache__
|
||||||
|
|
|
@ -16,7 +16,7 @@ master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'notmuch'
|
project = u'notmuch'
|
||||||
copyright = u'2009-2022, Carl Worth and many others'
|
copyright = u'2009-2023, Carl Worth and many others'
|
||||||
|
|
||||||
location = os.path.dirname(__file__)
|
location = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,16 @@ paths are presumed relative to `$HOME` for items in section
|
||||||
|
|
||||||
Default tag prefix (filter) for :any:`notmuch-git`.
|
Default tag prefix (filter) for :any:`notmuch-git`.
|
||||||
|
|
||||||
|
.. nmconfig:: index.as_text
|
||||||
|
|
||||||
|
List of regular expressions (without delimiters) for MIME types to
|
||||||
|
be indexed as text. Currently this applies only to attachments. By
|
||||||
|
default the regex matches anywhere in the content type; if the
|
||||||
|
user wants an anchored match, they should include anchors in their
|
||||||
|
regexes.
|
||||||
|
|
||||||
|
History: This configuration value was introduced in notmuch 0.38.
|
||||||
|
|
||||||
.. nmconfig:: index.decrypt
|
.. nmconfig:: index.decrypt
|
||||||
|
|
||||||
Policy for decrypting encrypted messages during indexing. Must be
|
Policy for decrypting encrypted messages during indexing. Must be
|
||||||
|
|
|
@ -325,11 +325,11 @@ If it is unset, 'default' is assumed.
|
||||||
|
|
||||||
.. envvar:: NOTMUCH_GIT_DIR
|
.. envvar:: NOTMUCH_GIT_DIR
|
||||||
|
|
||||||
Default location of git repository. Overriden by :option:`--git-dir`.
|
Default location of git repository. Overridden by :option:`--git-dir`.
|
||||||
|
|
||||||
.. envvar:: NOTMUCH_GIT_PREFIX
|
.. envvar:: NOTMUCH_GIT_PREFIX
|
||||||
|
|
||||||
Default tag prefix (filter). Overriden by :option:`--tag-prefix`.
|
Default tag prefix (filter). Overridden by :option:`--tag-prefix`.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
========
|
========
|
||||||
|
|
|
@ -43,7 +43,7 @@ Supported options for **search** include
|
||||||
|
|
||||||
.. option:: --output=(summary|threads|messages|files|tags)
|
.. option:: --output=(summary|threads|messages|files|tags)
|
||||||
|
|
||||||
summary
|
summary (default)
|
||||||
Output a summary of each thread with any message matching the
|
Output a summary of each thread with any message matching the
|
||||||
search terms. The summary includes the thread ID, date, the
|
search terms. The summary includes the thread ID, date, the
|
||||||
number of messages in the thread (both the number matched and
|
number of messages in the thread (both the number matched and
|
||||||
|
|
|
@ -130,6 +130,15 @@ Supported options for **show** include
|
||||||
By default, results will be displayed in reverse chronological
|
By default, results will be displayed in reverse chronological
|
||||||
order, (that is, the newest results will be displayed first).
|
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
|
.. option:: --verify
|
||||||
|
|
||||||
Compute and report the validity of any MIME cryptographic
|
Compute and report the validity of any MIME cryptographic
|
||||||
|
|
|
@ -274,7 +274,7 @@ EXAMPLES
|
||||||
|
|
||||||
Matches any word starting with "prelim", inside a message subject.
|
Matches any word starting with "prelim", inside a message subject.
|
||||||
|
|
||||||
``(subject (starts-wih quick) "brown fox")``
|
``(subject (starts-with quick) "brown fox")``
|
||||||
|
|
||||||
Match messages whose subject contains "quick brown fox", but also
|
Match messages whose subject contains "quick brown fox", but also
|
||||||
"brown fox quicksand".
|
"brown fox quicksand".
|
||||||
|
@ -336,7 +336,7 @@ user defined fields is permitted within a macro.
|
||||||
NOTES
|
NOTES
|
||||||
=====
|
=====
|
||||||
|
|
||||||
.. [#macro-details] Technically macros impliment lazy evaluation and
|
.. [#macro-details] Technically macros implement lazy evaluation and
|
||||||
lexical scope. There is one top level scope
|
lexical scope. There is one top level scope
|
||||||
containing all macro definitions, but all
|
containing all macro definitions, but all
|
||||||
parameter definitions are local to a given macro.
|
parameter definitions are local to a given macro.
|
||||||
|
@ -347,10 +347,10 @@ NOTES
|
||||||
|
|
||||||
.. [#aka-bool] a.k.a. boolean prefixes
|
.. [#aka-bool] a.k.a. boolean prefixes
|
||||||
|
|
||||||
.. [#not-phrase] Due to the implemention of phrase fields in Xapian,
|
.. [#not-phrase] Due to the implementation of phrase fields in Xapian,
|
||||||
regex queries could only match individual words.
|
regex queries could only match individual words.
|
||||||
|
|
||||||
.. [#not-body] Due the the way ``body`` is implemented in notmuch,
|
.. [#not-body] Due to the way ``body`` is implemented in notmuch,
|
||||||
this modifier is not supported in the ``body`` field.
|
this modifier is not supported in the ``body`` field.
|
||||||
|
|
||||||
.. [#not-path] Due to the way recursive ``path`` queries are implemented
|
.. [#not-path] Due to the way recursive ``path`` queries are implemented
|
||||||
|
|
|
@ -14,7 +14,7 @@ manual to refer to the Emacs interface to Notmuch. When this distinction
|
||||||
is important, we’ll refer to the Emacs interface as
|
is important, we’ll refer to the Emacs interface as
|
||||||
*notmuch-emacs*.
|
*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
|
framework (or just by setting the appropriate variables). We try to
|
||||||
point out relevant variables in this manual, but in order to avoid
|
point out relevant variables in this manual, but in order to avoid
|
||||||
duplication of information, you can usually find the most detailed
|
duplication of information, you can usually find the most detailed
|
||||||
|
@ -493,7 +493,7 @@ in :ref:`notmuch-search`.
|
||||||
Dealing with duplicates
|
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
|
(see :any:`duplicate-files`), then :any:`notmuch-show` displays the
|
||||||
number of duplicates and identifies the current duplicate. In the
|
number of duplicates and identifies the current duplicate. In the
|
||||||
following example duplicate 3 of 5 is displayed.
|
following example duplicate 3 of 5 is displayed.
|
||||||
|
@ -606,6 +606,45 @@ can be controlled by the variable ``notmuch-search-oldest-first``.
|
||||||
See also :el:defcustom:`notmuch-search-result-format` and
|
See also :el:defcustom:`notmuch-search-result-format` and
|
||||||
:el:defcustom:`notmuch-unthreaded-result-format`.
|
:el:defcustom:`notmuch-unthreaded-result-format`.
|
||||||
|
|
||||||
|
.. _notmuch-tree-outline:
|
||||||
|
|
||||||
|
notmuch-tree-outline
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
When this mode is set, each thread and subthread in the results
|
||||||
|
list is treated as a foldable section, with its first message as
|
||||||
|
its header.
|
||||||
|
|
||||||
|
The mode just makes available in the tree buffer all the
|
||||||
|
keybindings in info:emacs#Outline_Mode, and binds the following
|
||||||
|
additional keys:
|
||||||
|
|
||||||
|
.. el:define-key:: <tab>
|
||||||
|
|
||||||
|
Cycle visibility state of the current message's tree.
|
||||||
|
|
||||||
|
.. el:define-key:: <M-tab>
|
||||||
|
|
||||||
|
Cycle visibility state of all trees in the buffer.
|
||||||
|
|
||||||
|
The behaviour of this minor mode is affected by the following
|
||||||
|
customizable variables:
|
||||||
|
|
||||||
|
.. el:defcustom:: notmuch-tree-outline-enabled
|
||||||
|
|
||||||
|
|docstring::notmuch-tree-outline-enabled|
|
||||||
|
|
||||||
|
.. el:defcustom:: notmuch-tree-outline-visibility
|
||||||
|
|
||||||
|
|docstring::notmuch-tree-outline-visibility|
|
||||||
|
|
||||||
|
.. el:defcustom:: notmuch-tree-outline-auto-close
|
||||||
|
|
||||||
|
|docstring::notmuch-tree-outline-auto-close|
|
||||||
|
|
||||||
|
.. el:defcustom:: notmuch-tree-outline-open-on-next
|
||||||
|
|
||||||
|
|docstring::notmuch-tree-outline-open-on-next|
|
||||||
|
|
||||||
.. _notmuch-unthreaded:
|
.. _notmuch-unthreaded:
|
||||||
|
|
||||||
|
@ -678,7 +717,7 @@ operations specified in ``notmuch-tagging-keys``; i.e. each
|
||||||
notmuch-tag-undo
|
notmuch-tag-undo
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Each notmuch buffer supporting tagging operations (i.e buffers in
|
Each notmuch buffer supporting tagging operations (i.e. buffers in
|
||||||
:any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
|
:any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
|
||||||
:any:`notmuch-unthreaded` mode) keeps a local stack of tagging
|
:any:`notmuch-unthreaded` mode) keeps a local stack of tagging
|
||||||
operations. These can be undone via :any:`notmuch-tag-undo`. By default
|
operations. These can be undone via :any:`notmuch-tag-undo`. By default
|
||||||
|
|
|
@ -416,11 +416,6 @@ moved to the \"To:\" header."
|
||||||
(let ((user-agent (funcall notmuch-mua-user-agent-function)))
|
(let ((user-agent (funcall notmuch-mua-user-agent-function)))
|
||||||
(unless (string-empty-p user-agent)
|
(unless (string-empty-p user-agent)
|
||||||
(push (cons 'User-Agent user-agent) other-headers))))
|
(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)
|
(notmuch-mua-pop-to-buffer (message-buffer-name "mail" to)
|
||||||
(or switch-function
|
(or switch-function
|
||||||
(notmuch-mua-get-switch-function)))
|
(notmuch-mua-get-switch-function)))
|
||||||
|
@ -439,6 +434,11 @@ moved to the \"To:\" header."
|
||||||
;; Cause `message-setup-1' to do things relevant for mail,
|
;; Cause `message-setup-1' to do things relevant for mail,
|
||||||
;; such as observe `message-default-mail-headers'.
|
;; such as observe `message-default-mail-headers'.
|
||||||
(message-this-is-mail t))
|
(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))
|
(message-setup-1 headers yank-action send-actions return-action))
|
||||||
(notmuch-fcc-header-setup)
|
(notmuch-fcc-header-setup)
|
||||||
(notmuch-mua--remove-dont-reply-to-names)
|
(notmuch-mua--remove-dont-reply-to-names)
|
||||||
|
|
|
@ -452,14 +452,19 @@ operation on the contents of the current buffer."
|
||||||
(defun notmuch-show-update-tags (tags)
|
(defun notmuch-show-update-tags (tags)
|
||||||
"Update the displayed tags of the current message."
|
"Update the displayed tags of the current message."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (notmuch-show-message-top))
|
(let ((inhibit-read-only t)
|
||||||
(when (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
|
(start (notmuch-show-message-top))
|
||||||
(let ((inhibit-read-only t))
|
(depth (notmuch-show-get-prop :depth))
|
||||||
(replace-match (concat "("
|
(orig-tags (notmuch-show-get-prop :orig-tags))
|
||||||
(notmuch-tag-format-tags
|
(props (notmuch-show-get-message-properties))
|
||||||
tags
|
(extent (notmuch-show-message-extent)))
|
||||||
(notmuch-show-get-prop :orig-tags))
|
(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)
|
(defun notmuch-clean-address (address)
|
||||||
"Try to clean a single email ADDRESS for display. Return a cons
|
"Try to clean a single email ADDRESS for display. Return a cons
|
||||||
|
@ -530,10 +535,16 @@ Return unchanged ADDRESS if parsing fails."
|
||||||
(plist-put msg :height height)
|
(plist-put msg :height 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
|
"Insert a notmuch style headerline based on HEADERS for a
|
||||||
message at DEPTH in the current thread."
|
message at DEPTH in the current thread."
|
||||||
(let ((start (point))
|
(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
|
(from (notmuch-sanitize
|
||||||
(notmuch-show-clean-address (plist-get headers :From)))))
|
(notmuch-show-clean-address (plist-get headers :From)))))
|
||||||
(when (string-match "\\cR" from)
|
(when (string-match "\\cR" from)
|
||||||
|
@ -549,7 +560,7 @@ message at DEPTH in the current thread."
|
||||||
" ("
|
" ("
|
||||||
date
|
date
|
||||||
") ("
|
") ("
|
||||||
(notmuch-tag-format-tags tags tags)
|
(notmuch-tag-format-tags tags (or orig-tags tags))
|
||||||
")")
|
")")
|
||||||
(insert
|
(insert
|
||||||
(if (> file-count 1)
|
(if (> file-count 1)
|
||||||
|
@ -1171,8 +1182,6 @@ is out of range."
|
||||||
(defun notmuch-show-insert-msg (msg depth)
|
(defun notmuch-show-insert-msg (msg depth)
|
||||||
"Insert the message MSG at depth DEPTH in the current thread."
|
"Insert the message MSG at depth DEPTH in the current thread."
|
||||||
(let* ((headers (plist-get msg :headers))
|
(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
|
;; Indentation causes the buffer offset of the start/end
|
||||||
;; points to move, so we must use markers.
|
;; points to move, so we must use markers.
|
||||||
message-start message-end
|
message-start message-end
|
||||||
|
@ -1180,11 +1189,7 @@ is out of range."
|
||||||
headers-start headers-end
|
headers-start headers-end
|
||||||
(bare-subject (notmuch-show-strip-re (plist-get headers :Subject))))
|
(bare-subject (notmuch-show-strip-re (plist-get headers :Subject))))
|
||||||
(setq message-start (point-marker))
|
(setq message-start (point-marker))
|
||||||
(notmuch-show-insert-headerline headers
|
(notmuch-show-insert-headerline msg depth (plist-get msg :tags))
|
||||||
(or (and notmuch-show-relative-dates
|
|
||||||
(plist-get msg :date_relative))
|
|
||||||
(plist-get headers :Date))
|
|
||||||
(plist-get msg :tags) depth duplicate files)
|
|
||||||
(setq content-start (point-marker))
|
(setq content-start (point-marker))
|
||||||
;; Set `headers-start' to point after the 'Subject:' header to be
|
;; Set `headers-start' to point after the 'Subject:' header to be
|
||||||
;; compatible with the existing implementation. This just sets it
|
;; compatible with the existing implementation. This just sets it
|
||||||
|
|
|
@ -1014,7 +1014,10 @@ unchanged ADDRESS if parsing fails."
|
||||||
A message tree is another name for a single sub-thread: i.e., a
|
A message tree is another name for a single sub-thread: i.e., a
|
||||||
message together with all its descendents."
|
message together with all its descendents."
|
||||||
(let ((msg (car tree))
|
(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
|
(cond
|
||||||
((and (< 0 depth) (not last))
|
((and (< 0 depth) (not last))
|
||||||
(push (alist-get 'vertical-tee notmuch-tree-thread-symbols) tree-status))
|
(push (alist-get 'vertical-tee notmuch-tree-thread-symbols) tree-status))
|
||||||
|
@ -1034,6 +1037,7 @@ message together with all its descendents."
|
||||||
(setq msg (plist-put msg :first (and first (eq 0 depth))))
|
(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 :tree-status tree-status))
|
||||||
(setq msg (plist-put msg :orig-tags (plist-get msg :tags)))
|
(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)
|
(notmuch-tree-goto-and-insert-msg msg)
|
||||||
(pop tree-status)
|
(pop tree-status)
|
||||||
(pop tree-status)
|
(pop tree-status)
|
||||||
|
@ -1080,7 +1084,8 @@ Complete list of currently available key bindings:
|
||||||
(setq notmuch-buffer-refresh-function #'notmuch-tree-refresh-view)
|
(setq notmuch-buffer-refresh-function #'notmuch-tree-refresh-view)
|
||||||
(hl-line-mode 1)
|
(hl-line-mode 1)
|
||||||
(setq buffer-read-only t)
|
(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
|
(defvar notmuch-tree-process-exit-functions nil
|
||||||
"Functions called when the process inserting a tree of results finishes.
|
"Functions called when the process inserting a tree of results finishes.
|
||||||
|
@ -1278,6 +1283,180 @@ search results and that are also tagged with the given TAG."
|
||||||
nil
|
nil
|
||||||
notmuch-search-oldest-first)))
|
notmuch-search-oldest-first)))
|
||||||
|
|
||||||
|
;;; Tree outline mode
|
||||||
|
;;;; Custom variables
|
||||||
|
(defcustom notmuch-tree-outline-enabled nil
|
||||||
|
"Whether to automatically activate `notmuch-tree-outline-mode' in tree views."
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom notmuch-tree-outline-visibility 'hide-others
|
||||||
|
"Default state of the forest outline for `notmuch-tree-outline-mode'.
|
||||||
|
|
||||||
|
This variable controls the state of a forest initially and after
|
||||||
|
a movement command. If set to nil, all trees are displayed while
|
||||||
|
the symbol hide-all indicates that all trees in the forest should
|
||||||
|
be folded and hide-other that only the first one should be
|
||||||
|
unfolded."
|
||||||
|
:type '(choice (const :tag "Show all" nil)
|
||||||
|
(const :tag "Hide others" hide-others)
|
||||||
|
(const :tag "Hide all" hide-all)))
|
||||||
|
|
||||||
|
(defcustom notmuch-tree-outline-auto-close nil
|
||||||
|
"Close message and tree windows when moving past the last message."
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom notmuch-tree-outline-open-on-next nil
|
||||||
|
"Open new messages under point if they are closed when moving to next one.
|
||||||
|
|
||||||
|
When this flag is set, using the command
|
||||||
|
`notmuch-tree-outline-next' with point on a header for a new
|
||||||
|
message that is not shown will open its `notmuch-show' buffer
|
||||||
|
instead of moving point to next matching message."
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
;;;; Helper functions
|
||||||
|
(defsubst notmuch-tree-outline--pop-at-end (pop-at-end)
|
||||||
|
(if notmuch-tree-outline-auto-close (not pop-at-end) pop-at-end))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline--set-visibility ()
|
||||||
|
(when (and notmuch-tree-outline-mode (> (point-max) (point-min)))
|
||||||
|
(cl-case notmuch-tree-outline-visibility
|
||||||
|
(hide-others (notmuch-tree-outline-hide-others))
|
||||||
|
(hide-all (outline-hide-body)))))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline--on-exit (proc)
|
||||||
|
(when (eq (process-status proc) 'exit)
|
||||||
|
(notmuch-tree-outline--set-visibility)))
|
||||||
|
|
||||||
|
(add-hook 'notmuch-tree-process-exit-functions #'notmuch-tree-outline--on-exit)
|
||||||
|
|
||||||
|
(defsubst notmuch-tree-outline--level (&optional props)
|
||||||
|
(or (plist-get (or props (notmuch-tree-get-message-properties)) :level) 0))
|
||||||
|
|
||||||
|
(defsubst notmuch-tree-outline--message-open-p ()
|
||||||
|
(and (buffer-live-p notmuch-tree-message-buffer)
|
||||||
|
(get-buffer-window notmuch-tree-message-buffer)
|
||||||
|
(let ((id (notmuch-tree-get-message-id)))
|
||||||
|
(and id
|
||||||
|
(with-current-buffer notmuch-tree-message-buffer
|
||||||
|
(string= (notmuch-show-get-message-id) id))))))
|
||||||
|
|
||||||
|
(defsubst notmuch-tree-outline--at-original-match-p ()
|
||||||
|
(and (notmuch-tree-get-prop :match)
|
||||||
|
(equal (notmuch-tree-get-prop :orig-tags)
|
||||||
|
(notmuch-tree-get-prop :tags))))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline--next (prev thread pop-at-end &optional open-new)
|
||||||
|
(cond (thread
|
||||||
|
(notmuch-tree-thread-top)
|
||||||
|
(if prev
|
||||||
|
(outline-backward-same-level 1)
|
||||||
|
(outline-forward-same-level 1))
|
||||||
|
(when (> (notmuch-tree-outline--level) 0) (outline-show-branches))
|
||||||
|
(notmuch-tree-outline--next nil nil pop-at-end t))
|
||||||
|
((and (or open-new notmuch-tree-outline-open-on-next)
|
||||||
|
(notmuch-tree-outline--at-original-match-p)
|
||||||
|
(not (notmuch-tree-outline--message-open-p)))
|
||||||
|
(notmuch-tree-outline-hide-others t))
|
||||||
|
(t (outline-next-visible-heading (if prev -1 1))
|
||||||
|
(unless (notmuch-tree-get-prop :match)
|
||||||
|
(notmuch-tree-matching-message prev pop-at-end))
|
||||||
|
(notmuch-tree-outline-hide-others t))))
|
||||||
|
|
||||||
|
;;;; User commands
|
||||||
|
(defun notmuch-tree-outline-hide-others (&optional and-show)
|
||||||
|
"Fold all threads except the one around point.
|
||||||
|
If AND-SHOW is t, make the current message visible if it's not."
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(while (and (not (bobp)) (> (notmuch-tree-outline--level) 1))
|
||||||
|
(outline-previous-heading))
|
||||||
|
(outline-hide-sublevels 1))
|
||||||
|
(when (> (notmuch-tree-outline--level) 0)
|
||||||
|
(outline-show-subtree)
|
||||||
|
(when and-show (notmuch-tree-show-message nil))))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline-next (&optional pop-at-end)
|
||||||
|
"Next matching message in a forest, taking care of thread visibility.
|
||||||
|
A prefix argument reverses the meaning of `notmuch-tree-outline-auto-close'."
|
||||||
|
(interactive "P")
|
||||||
|
(let ((pop (notmuch-tree-outline--pop-at-end pop-at-end)))
|
||||||
|
(if (null notmuch-tree-outline-visibility)
|
||||||
|
(notmuch-tree-matching-message nil pop)
|
||||||
|
(notmuch-tree-outline--next nil nil pop))))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline-previous (&optional pop-at-end)
|
||||||
|
"Previous matching message in forest, taking care of thread visibility.
|
||||||
|
With prefix, quit the tree view if there is no previous message."
|
||||||
|
(interactive "P")
|
||||||
|
(if (null notmuch-tree-outline-visibility)
|
||||||
|
(notmuch-tree-prev-matching-message pop-at-end)
|
||||||
|
(notmuch-tree-outline--next t nil pop-at-end)))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline-next-thread ()
|
||||||
|
"Next matching thread in forest, taking care of thread visibility."
|
||||||
|
(interactive)
|
||||||
|
(if (null notmuch-tree-outline-visibility)
|
||||||
|
(notmuch-tree-next-thread)
|
||||||
|
(notmuch-tree-outline--next nil t nil)))
|
||||||
|
|
||||||
|
(defun notmuch-tree-outline-previous-thread ()
|
||||||
|
"Previous matching thread in forest, taking care of thread visibility."
|
||||||
|
(interactive)
|
||||||
|
(if (null notmuch-tree-outline-visibility)
|
||||||
|
(notmuch-tree-prev-thread)
|
||||||
|
(notmuch-tree-outline--next t t nil)))
|
||||||
|
|
||||||
|
;;;; Mode definition
|
||||||
|
(defvar notmuch-tree-outline-mode-lighter nil
|
||||||
|
"The lighter mark for notmuch-tree-outline mode.
|
||||||
|
Usually empty since outline-minor-mode's lighter will be active.")
|
||||||
|
|
||||||
|
(define-minor-mode notmuch-tree-outline-mode
|
||||||
|
"Minor mode allowing message trees to be folded as outlines.
|
||||||
|
|
||||||
|
When this mode is set, each thread and subthread in the results
|
||||||
|
list is treated as a foldable section, with its first message as
|
||||||
|
its header.
|
||||||
|
|
||||||
|
The mode just makes available in the tree buffer all the
|
||||||
|
keybindings in `outline-minor-mode', and binds the following
|
||||||
|
additional keys:
|
||||||
|
|
||||||
|
\\{notmuch-tree-outline-mode-map}
|
||||||
|
|
||||||
|
The customizable variable `notmuch-tree-outline-visibility'
|
||||||
|
controls how navigation in the buffer is affected by this mode:
|
||||||
|
|
||||||
|
- If it is set to nil, `notmuch-tree-outline-previous',
|
||||||
|
`notmuch-tree-outline-next', and their thread counterparts
|
||||||
|
behave just as the corresponding notmuch-tree navigation keys
|
||||||
|
when this mode is not enabled.
|
||||||
|
|
||||||
|
- If, on the other hand, `notmuch-tree-outline-visibility' is
|
||||||
|
set to a non-nil value, these commands hiding the outlines of
|
||||||
|
the trees you are not reading as you move to new messages.
|
||||||
|
|
||||||
|
To enable notmuch-tree-outline-mode by default in all
|
||||||
|
notmuch-tree buffers, just set
|
||||||
|
`notmuch-tree-outline-mode-enabled' to t."
|
||||||
|
:lighter notmuch-tree-outline-mode-lighter
|
||||||
|
:keymap `((,(kbd "TAB") . outline-cycle)
|
||||||
|
(,(kbd "M-TAB") . outline-cycle-buffer)
|
||||||
|
("n" . notmuch-tree-outline-next)
|
||||||
|
("p" . notmuch-tree-outline-previous)
|
||||||
|
(,(kbd "M-n") . notmuch-tree-outline-next-thread)
|
||||||
|
(,(kbd "M-p") . notmuch-tree-outline-previous-thread))
|
||||||
|
(outline-minor-mode notmuch-tree-outline-mode)
|
||||||
|
(unless (derived-mode-p 'notmuch-tree-mode)
|
||||||
|
(user-error "notmuch-tree-outline-mode is only meaningful for notmuch trees!"))
|
||||||
|
(if notmuch-tree-outline-mode
|
||||||
|
(progn (setq-local outline-regexp "^[^\n]+")
|
||||||
|
(setq-local outline-level #'notmuch-tree-outline--level)
|
||||||
|
(notmuch-tree-outline--set-visibility))
|
||||||
|
(setq-local outline-regexp (default-value 'outline-regexp))
|
||||||
|
(setq-local outline-level (default-value 'outline-level))))
|
||||||
|
|
||||||
;;; _
|
;;; _
|
||||||
|
|
||||||
(provide 'notmuch-tree)
|
(provide 'notmuch-tree)
|
||||||
|
|
|
@ -841,6 +841,7 @@ non-authors is found, assume that all of the authors match."
|
||||||
overlay)
|
overlay)
|
||||||
(insert invisible-string)
|
(insert invisible-string)
|
||||||
(setq overlay (make-overlay start (point)))
|
(setq overlay (make-overlay start (point)))
|
||||||
|
(overlay-put overlay 'evaporate t)
|
||||||
(overlay-put overlay 'invisible 'ellipsis)
|
(overlay-put overlay 'invisible 'ellipsis)
|
||||||
(overlay-put overlay 'isearch-open-invisible #'delete-overlay)))
|
(overlay-put overlay 'isearch-open-invisible #'delete-overlay)))
|
||||||
(insert padding))))
|
(insert padding))))
|
||||||
|
|
|
@ -599,6 +599,8 @@ _notmuch_config_key_to_string (notmuch_config_key_t key)
|
||||||
return "database.autocommit";
|
return "database.autocommit";
|
||||||
case NOTMUCH_CONFIG_EXTRA_HEADERS:
|
case NOTMUCH_CONFIG_EXTRA_HEADERS:
|
||||||
return "show.extra_headers";
|
return "show.extra_headers";
|
||||||
|
case NOTMUCH_CONFIG_INDEX_AS_TEXT:
|
||||||
|
return "index.as_text";
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -642,6 +644,7 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key)
|
||||||
else
|
else
|
||||||
email = _get_email_from_passwd_file (notmuch);
|
email = _get_email_from_passwd_file (notmuch);
|
||||||
return email;
|
return email;
|
||||||
|
case NOTMUCH_CONFIG_INDEX_AS_TEXT:
|
||||||
case NOTMUCH_CONFIG_NEW_IGNORE:
|
case NOTMUCH_CONFIG_NEW_IGNORE:
|
||||||
return "";
|
return "";
|
||||||
case NOTMUCH_CONFIG_AUTOCOMMIT:
|
case NOTMUCH_CONFIG_AUTOCOMMIT:
|
||||||
|
|
|
@ -291,6 +291,10 @@ struct _notmuch_database {
|
||||||
|
|
||||||
/* Track what parameters were specified when opening */
|
/* Track what parameters were specified when opening */
|
||||||
notmuch_open_param_t params;
|
notmuch_open_param_t params;
|
||||||
|
|
||||||
|
/* list of regular expressions to check for text indexing */
|
||||||
|
regex_t *index_as_text;
|
||||||
|
size_t index_as_text_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Prior to database version 3, features were implied by the database
|
/* Prior to database version 3, features were implied by the database
|
||||||
|
|
|
@ -1454,9 +1454,11 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
|
||||||
&message);
|
&message);
|
||||||
|
|
||||||
if (status == NOTMUCH_STATUS_SUCCESS && message) {
|
if (status == NOTMUCH_STATUS_SUCCESS && message) {
|
||||||
|
if (notmuch_message_count_files (message) > 1) {
|
||||||
status = _notmuch_message_remove_filename (message, filename);
|
status = _notmuch_message_remove_filename (message, filename);
|
||||||
|
}
|
||||||
if (status == NOTMUCH_STATUS_SUCCESS)
|
if (status == NOTMUCH_STATUS_SUCCESS)
|
||||||
_notmuch_message_delete (message);
|
status = _notmuch_message_delete (message);
|
||||||
else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
|
else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
|
||||||
_notmuch_message_sync (message);
|
_notmuch_message_sync (message);
|
||||||
|
|
||||||
|
@ -1573,3 +1575,15 @@ notmuch_database_status_string (const notmuch_database_t *notmuch)
|
||||||
{
|
{
|
||||||
return notmuch->status_string;
|
return notmuch->status_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
_notmuch_database_indexable_as_text (notmuch_database_t *notmuch, const char *mime_string)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < notmuch->index_as_text_length; i++) {
|
||||||
|
if (regexec (¬much->index_as_text[i], mime_string, 0, NULL, 0) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
19
lib/index.cc
19
lib/index.cc
|
@ -380,6 +380,23 @@ _index_pkcs7_part (notmuch_message_t *message,
|
||||||
GMimeObject *part,
|
GMimeObject *part,
|
||||||
_notmuch_message_crypto_t *msg_crypto);
|
_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. */
|
/* Callback to generate terms for each mime part of a message. */
|
||||||
static void
|
static void
|
||||||
_index_mime_part (notmuch_message_t *message,
|
_index_mime_part (notmuch_message_t *message,
|
||||||
|
@ -497,10 +514,12 @@ _index_mime_part (notmuch_message_t *message,
|
||||||
_notmuch_message_add_term (message, "tag", "attachment");
|
_notmuch_message_add_term (message, "tag", "attachment");
|
||||||
_notmuch_message_gen_terms (message, "attachment", filename);
|
_notmuch_message_gen_terms (message, "attachment", filename);
|
||||||
|
|
||||||
|
if (! _indexable_as_text (message, part)) {
|
||||||
/* XXX: Would be nice to call out to something here to parse
|
/* XXX: Would be nice to call out to something here to parse
|
||||||
* the attachment into text and then index that. */
|
* the attachment into text and then index that. */
|
||||||
goto DONE;
|
goto DONE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
byte_array = g_byte_array_new ();
|
byte_array = g_byte_array_new ();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,20 @@
|
||||||
#include "database-private.h"
|
#include "database-private.h"
|
||||||
#include "message-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_status_t
|
||||||
notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
|
notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
|
||||||
{
|
{
|
||||||
|
@ -83,10 +97,15 @@ _notmuch_message_modify_property (notmuch_message_t *message, const char *key, c
|
||||||
|
|
||||||
term = talloc_asprintf (message, "%s=%s", key, value);
|
term = talloc_asprintf (message, "%s=%s", key, value);
|
||||||
|
|
||||||
|
try {
|
||||||
if (delete_it)
|
if (delete_it)
|
||||||
private_status = _notmuch_message_remove_term (message, "property", term);
|
private_status = _notmuch_message_remove_term (message, "property", term);
|
||||||
else
|
else
|
||||||
private_status = _notmuch_message_add_term (message, "property", term);
|
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)
|
if (private_status)
|
||||||
return COERCE_STATUS (private_status,
|
return COERCE_STATUS (private_status,
|
||||||
|
@ -123,15 +142,22 @@ _notmuch_message_remove_all_properties (notmuch_message_t *message, const char *
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
_notmuch_message_invalidate_metadata (message, "property");
|
|
||||||
if (key)
|
if (key)
|
||||||
term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
|
term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
|
||||||
prefix ? "" : "=");
|
prefix ? "" : "=");
|
||||||
else
|
else
|
||||||
term_prefix = _find_prefix ("property");
|
term_prefix = _find_prefix ("property");
|
||||||
|
|
||||||
|
try {
|
||||||
/* XXX better error reporting ? */
|
/* XXX better error reporting ? */
|
||||||
_notmuch_message_remove_terms (message, term_prefix);
|
_notmuch_message_remove_terms (message, term_prefix);
|
||||||
|
} catch (Xapian::Error &error) {
|
||||||
|
LOG_XAPIAN_EXCEPTION (message, error);
|
||||||
|
return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! _notmuch_message_frozen (message))
|
||||||
|
_notmuch_message_sync (message);
|
||||||
|
|
||||||
return NOTMUCH_STATUS_SUCCESS;
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -719,6 +719,8 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
|
||||||
/* Ignore failure to remove non-existent term. */
|
/* Ignore failure to remove non-existent term. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_notmuch_message_invalidate_metadata (message, "property");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -941,6 +943,7 @@ _notmuch_message_add_filename (notmuch_message_t *message,
|
||||||
{
|
{
|
||||||
const char *relative, *directory;
|
const char *relative, *directory;
|
||||||
notmuch_status_t status;
|
notmuch_status_t status;
|
||||||
|
notmuch_private_status_t private_status;
|
||||||
void *local = talloc_new (message);
|
void *local = talloc_new (message);
|
||||||
char *direntry;
|
char *direntry;
|
||||||
|
|
||||||
|
@ -964,10 +967,17 @@ _notmuch_message_add_filename (notmuch_message_t *message,
|
||||||
|
|
||||||
/* New file-direntry allows navigating to this message with
|
/* New file-direntry allows navigating to this message with
|
||||||
* notmuch_directory_get_child_files() . */
|
* notmuch_directory_get_child_files() . */
|
||||||
status = COERCE_STATUS (_notmuch_message_add_term (message, "file-direntry", direntry),
|
private_status = _notmuch_message_add_term (message, "file-direntry", direntry);
|
||||||
"adding file-direntry term");
|
switch (private_status) {
|
||||||
if (status)
|
case NOTMUCH_PRIVATE_STATUS_SUCCESS:
|
||||||
return status;
|
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);
|
status = _notmuch_message_add_folder_terms (message, directory);
|
||||||
if (status)
|
if (status)
|
||||||
|
@ -1383,21 +1393,22 @@ _notmuch_message_delete (notmuch_message_t *message)
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
message->notmuch->writable_xapian_db->delete_document (message->doc_id);
|
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 */
|
/* if this was a ghost to begin with, we are done */
|
||||||
private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
|
private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
|
||||||
if (private_status)
|
if (private_status)
|
||||||
return COERCE_STATUS (private_status,
|
return COERCE_STATUS (private_status,
|
||||||
"Error trying to determine whether message was a ghost");
|
"Error trying to determine whether message was a ghost");
|
||||||
|
|
||||||
|
message->notmuch->writable_xapian_db->delete_document (message->doc_id);
|
||||||
|
|
||||||
if (is_ghost)
|
if (is_ghost)
|
||||||
return NOTMUCH_STATUS_SUCCESS;
|
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;
|
|
||||||
|
|
||||||
_notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
|
_notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
|
||||||
&thread_doc_end);
|
&thread_doc_end);
|
||||||
_notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
|
_notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
|
||||||
|
|
|
@ -259,6 +259,10 @@ _notmuch_database_filename_to_direntry (void *ctx,
|
||||||
notmuch_find_flags_t flags,
|
notmuch_find_flags_t flags,
|
||||||
char **direntry);
|
char **direntry);
|
||||||
|
|
||||||
|
bool
|
||||||
|
_notmuch_database_indexable_as_text (notmuch_database_t *notmuch,
|
||||||
|
const char *mime_string);
|
||||||
|
|
||||||
/* directory.cc */
|
/* directory.cc */
|
||||||
|
|
||||||
notmuch_directory_t *
|
notmuch_directory_t *
|
||||||
|
|
|
@ -293,6 +293,8 @@ typedef struct _notmuch_indexopts notmuch_indexopts_t;
|
||||||
*
|
*
|
||||||
* NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
|
* NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
|
||||||
*
|
*
|
||||||
|
* NOTMUCH_STATUS_PATH_ERROR: filename is too long
|
||||||
|
*
|
||||||
* NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the
|
* NOTMUCH_STATUS_FILE_ERROR: An error occurred trying to create the
|
||||||
* database file (such as permission denied, or file not found,
|
* database file (such as permission denied, or file not found,
|
||||||
* etc.), or the database already exists.
|
* etc.), or the database already exists.
|
||||||
|
@ -720,7 +722,8 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
|
||||||
*
|
*
|
||||||
* The UUID is a NUL-terminated opaque string that uniquely identifies
|
* The UUID is a NUL-terminated opaque string that uniquely identifies
|
||||||
* this database. Two revision numbers are only comparable if they
|
* 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
|
unsigned long
|
||||||
notmuch_database_get_revision (notmuch_database_t *notmuch,
|
notmuch_database_get_revision (notmuch_database_t *notmuch,
|
||||||
|
@ -1170,7 +1173,10 @@ notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out
|
||||||
*
|
*
|
||||||
* query = notmuch_query_create (database, query_string);
|
* query = notmuch_query_create (database, query_string);
|
||||||
*
|
*
|
||||||
* for (messages = notmuch_query_search_messages (query);
|
* if (notmuch_query_search_messages (query, &messages) != NOTMUCH_STATUS_SUCCESS)
|
||||||
|
* return EXIT_FAILURE;
|
||||||
|
*
|
||||||
|
* for (;
|
||||||
* notmuch_messages_valid (messages);
|
* notmuch_messages_valid (messages);
|
||||||
* notmuch_messages_move_to_next (messages))
|
* notmuch_messages_move_to_next (messages))
|
||||||
* {
|
* {
|
||||||
|
@ -2558,6 +2564,7 @@ typedef enum {
|
||||||
NOTMUCH_CONFIG_USER_NAME,
|
NOTMUCH_CONFIG_USER_NAME,
|
||||||
NOTMUCH_CONFIG_AUTOCOMMIT,
|
NOTMUCH_CONFIG_AUTOCOMMIT,
|
||||||
NOTMUCH_CONFIG_EXTRA_HEADERS,
|
NOTMUCH_CONFIG_EXTRA_HEADERS,
|
||||||
|
NOTMUCH_CONFIG_INDEX_AS_TEXT,
|
||||||
NOTMUCH_CONFIG_LAST
|
NOTMUCH_CONFIG_LAST
|
||||||
} notmuch_config_key_t;
|
} notmuch_config_key_t;
|
||||||
|
|
||||||
|
|
53
lib/open.cc
53
lib/open.cc
|
@ -320,6 +320,8 @@ _alloc_notmuch (const char *database_path, const char *config_path, const char *
|
||||||
notmuch->transaction_count = 0;
|
notmuch->transaction_count = 0;
|
||||||
notmuch->transaction_threshold = 0;
|
notmuch->transaction_threshold = 0;
|
||||||
notmuch->view = 1;
|
notmuch->view = 1;
|
||||||
|
notmuch->index_as_text = NULL;
|
||||||
|
notmuch->index_as_text_length = 0;
|
||||||
|
|
||||||
notmuch->params = NOTMUCH_PARAM_NONE;
|
notmuch->params = NOTMUCH_PARAM_NONE;
|
||||||
if (database_path)
|
if (database_path)
|
||||||
|
@ -427,6 +429,53 @@ _load_database_state (notmuch_database_t *notmuch)
|
||||||
notmuch, notmuch->xapian_db->get_uuid ().c_str ());
|
notmuch, notmuch->xapian_db->get_uuid ().c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX This should really be done lazily, but the error reporting path in the indexing code
|
||||||
|
* would need to be redone to report any errors.
|
||||||
|
*/
|
||||||
|
notmuch_status_t
|
||||||
|
_ensure_index_as_text (notmuch_database_t *notmuch, char **message)
|
||||||
|
{
|
||||||
|
int nregex = 0;
|
||||||
|
regex_t *regexv = NULL;
|
||||||
|
|
||||||
|
if (notmuch->index_as_text)
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
for (notmuch_config_values_t *list = notmuch_config_get_values (notmuch,
|
||||||
|
NOTMUCH_CONFIG_INDEX_AS_TEXT);
|
||||||
|
notmuch_config_values_valid (list);
|
||||||
|
notmuch_config_values_move_to_next (list)) {
|
||||||
|
regex_t *new_regex;
|
||||||
|
int rerr;
|
||||||
|
const char *str = notmuch_config_values_get (list);
|
||||||
|
size_t len = strlen (str);
|
||||||
|
|
||||||
|
/* str must be non-empty, because n_c_get_values skips empty
|
||||||
|
* strings */
|
||||||
|
assert (len > 0);
|
||||||
|
|
||||||
|
regexv = talloc_realloc (notmuch, regexv, regex_t, nregex + 1);
|
||||||
|
new_regex = ®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
|
static notmuch_status_t
|
||||||
_finish_open (notmuch_database_t *notmuch,
|
_finish_open (notmuch_database_t *notmuch,
|
||||||
const char *profile,
|
const char *profile,
|
||||||
|
@ -531,6 +580,10 @@ _finish_open (notmuch_database_t *notmuch,
|
||||||
if (status)
|
if (status)
|
||||||
goto DONE;
|
goto DONE;
|
||||||
|
|
||||||
|
status = _ensure_index_as_text (notmuch, &message);
|
||||||
|
if (status)
|
||||||
|
goto DONE;
|
||||||
|
|
||||||
autocommit_str = notmuch_config_get (notmuch, NOTMUCH_CONFIG_AUTOCOMMIT);
|
autocommit_str = notmuch_config_get (notmuch, NOTMUCH_CONFIG_AUTOCOMMIT);
|
||||||
if (unlikely (! autocommit_str)) {
|
if (unlikely (! autocommit_str)) {
|
||||||
INTERNAL_ERROR ("missing configuration for autocommit");
|
INTERNAL_ERROR ("missing configuration for autocommit");
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "notmuch-private.h"
|
#include "notmuch-private.h"
|
||||||
#include "database-private.h"
|
#include "database-private.h"
|
||||||
|
#include "xapian-extra.h"
|
||||||
|
|
||||||
#include <glib.h> /* GHashTable, GPtrArray */
|
#include <glib.h> /* GHashTable, GPtrArray */
|
||||||
|
|
||||||
|
@ -186,7 +187,7 @@ _notmuch_query_string_to_xapian_query (notmuch_database_t *notmuch,
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (query_string == "" || query_string == "*") {
|
if (query_string == "" || query_string == "*") {
|
||||||
output = Xapian::Query::MatchAll;
|
output = xapian_query_match_all ();
|
||||||
} else {
|
} else {
|
||||||
output =
|
output =
|
||||||
notmuch->query_parser->
|
notmuch->query_parser->
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "regexp-fields.h"
|
#include "regexp-fields.h"
|
||||||
#include "notmuch-private.h"
|
#include "notmuch-private.h"
|
||||||
#include "database-private.h"
|
#include "database-private.h"
|
||||||
|
#include "xapian-extra.h"
|
||||||
|
|
||||||
notmuch_status_t
|
notmuch_status_t
|
||||||
compile_regex (regex_t ®exp, const char *str, std::string &msg)
|
compile_regex (regex_t ®exp, const char *str, std::string &msg)
|
||||||
|
@ -200,7 +201,7 @@ RegexpFieldProcessor::operator() (const std::string & str)
|
||||||
if (str.empty ()) {
|
if (str.empty ()) {
|
||||||
if (options & NOTMUCH_FIELD_PROBABILISTIC) {
|
if (options & NOTMUCH_FIELD_PROBABILISTIC) {
|
||||||
return Xapian::Query (Xapian::Query::OP_AND_NOT,
|
return Xapian::Query (Xapian::Query::OP_AND_NOT,
|
||||||
Xapian::Query::MatchAll,
|
xapian_query_match_all (),
|
||||||
Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
|
Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
|
||||||
} else {
|
} else {
|
||||||
return Xapian::Query (term_prefix);
|
return Xapian::Query (term_prefix);
|
||||||
|
|
|
@ -77,6 +77,8 @@ typedef struct notmuch_show_params {
|
||||||
bool output_body;
|
bool output_body;
|
||||||
int duplicate;
|
int duplicate;
|
||||||
int part;
|
int part;
|
||||||
|
int offset;
|
||||||
|
int limit;
|
||||||
_notmuch_crypto_t crypto;
|
_notmuch_crypto_t crypto;
|
||||||
bool include_html;
|
bool include_html;
|
||||||
GMimeStream *out_stream;
|
GMimeStream *out_stream;
|
||||||
|
|
|
@ -278,20 +278,26 @@ notmuch_conffile_open (notmuch_database_t *notmuch,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->is_new)
|
|
||||||
g_key_file_set_comment (config->key_file, NULL, NULL,
|
|
||||||
toplevel_config_comment, NULL);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
|
||||||
const char *name = group_comment_table[i].group_name;
|
const char *name = group_comment_table[i].group_name;
|
||||||
if (! g_key_file_has_group (config->key_file, name)) {
|
if (! g_key_file_has_group (config->key_file, name)) {
|
||||||
/* Force group to exist before adding comment */
|
/* Force group to exist before adding comment */
|
||||||
g_key_file_set_value (config->key_file, name, "dummy_key", "dummy_val");
|
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_remove_key (config->key_file, name, "dummy_key", 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,
|
g_key_file_set_comment (config->key_file, name, NULL,
|
||||||
group_comment_table[i].comment, NULL);
|
group_comment_table[i].comment, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,7 +254,7 @@ def count_messages(prefix=None):
|
||||||
def get_tags(prefix=None):
|
def get_tags(prefix=None):
|
||||||
"Get a list of tags with a given prefix."
|
"Get a list of tags with a given prefix."
|
||||||
(status, stdout, stderr) = _spawn(
|
(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)
|
stdout=_subprocess.PIPE, wait=True)
|
||||||
return [tag for tag in stdout.splitlines()]
|
return [tag for tag in stdout.splitlines()]
|
||||||
|
|
||||||
|
@ -719,7 +719,7 @@ class DatabaseCache:
|
||||||
self._known[id] = False
|
self._known[id] = False
|
||||||
else:
|
else:
|
||||||
(_, stdout, stderr) = _spawn(
|
(_, 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,
|
stdout=_subprocess.PIPE,
|
||||||
wait=True)
|
wait=True)
|
||||||
self._known[id] = stdout != None
|
self._known[id] = stdout != None
|
||||||
|
|
|
@ -413,6 +413,10 @@ add_file (notmuch_database_t *notmuch, const char *filename,
|
||||||
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
|
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
|
||||||
fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
|
fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
|
||||||
break;
|
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:
|
case NOTMUCH_STATUS_FILE_ERROR:
|
||||||
/* Someone renamed/removed the file between scandir and now. */
|
/* Someone renamed/removed the file between scandir and now. */
|
||||||
state->vanished_files++;
|
state->vanished_files++;
|
||||||
|
|
|
@ -1159,6 +1159,18 @@ do_show_threaded (void *ctx,
|
||||||
notmuch_thread_t *thread;
|
notmuch_thread_t *thread;
|
||||||
notmuch_messages_t *messages;
|
notmuch_messages_t *messages;
|
||||||
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
|
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);
|
status = notmuch_query_search_threads (query, &threads);
|
||||||
if (print_status_query ("notmuch show", query, status))
|
if (print_status_query ("notmuch show", query, status))
|
||||||
|
@ -1166,11 +1178,16 @@ do_show_threaded (void *ctx,
|
||||||
|
|
||||||
sp->begin_list (sp);
|
sp->begin_list (sp);
|
||||||
|
|
||||||
for (;
|
for (i = 0;
|
||||||
notmuch_threads_valid (threads);
|
notmuch_threads_valid (threads) && (params->limit < 0 || i < params->offset + params->limit);
|
||||||
notmuch_threads_move_to_next (threads)) {
|
notmuch_threads_move_to_next (threads), i++) {
|
||||||
thread = notmuch_threads_get (threads);
|
thread = notmuch_threads_get (threads);
|
||||||
|
|
||||||
|
if (i < params->offset) {
|
||||||
|
notmuch_thread_destroy (thread);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
messages = notmuch_thread_get_toplevel_messages (thread);
|
messages = notmuch_thread_get_toplevel_messages (thread);
|
||||||
|
|
||||||
if (messages == NULL)
|
if (messages == NULL)
|
||||||
|
@ -1201,6 +1218,18 @@ do_show_unthreaded (void *ctx,
|
||||||
notmuch_message_t *message;
|
notmuch_message_t *message;
|
||||||
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
|
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
|
||||||
notmuch_bool_t excluded;
|
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);
|
status = notmuch_query_search_messages (query, &messages);
|
||||||
if (print_status_query ("notmuch show", query, status))
|
if (print_status_query ("notmuch show", query, status))
|
||||||
|
@ -1208,9 +1237,13 @@ do_show_unthreaded (void *ctx,
|
||||||
|
|
||||||
sp->begin_list (sp);
|
sp->begin_list (sp);
|
||||||
|
|
||||||
for (;
|
for (i = 0;
|
||||||
notmuch_messages_valid (messages);
|
notmuch_messages_valid (messages) && (params->limit < 0 || i < params->offset + params->limit);
|
||||||
notmuch_messages_move_to_next (messages)) {
|
notmuch_messages_move_to_next (messages), i++) {
|
||||||
|
if (i < params->offset) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
sp->begin_list (sp);
|
sp->begin_list (sp);
|
||||||
sp->begin_list (sp);
|
sp->begin_list (sp);
|
||||||
|
|
||||||
|
@ -1287,6 +1320,8 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
||||||
notmuch_show_params_t params = {
|
notmuch_show_params_t params = {
|
||||||
.part = -1,
|
.part = -1,
|
||||||
.duplicate = 0,
|
.duplicate = 0,
|
||||||
|
.offset = 0,
|
||||||
|
.limit = -1, /* unlimited */
|
||||||
.omit_excluded = true,
|
.omit_excluded = true,
|
||||||
.output_body = true,
|
.output_body = true,
|
||||||
.crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
|
.crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO },
|
||||||
|
@ -1328,6 +1363,8 @@ notmuch_show_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
||||||
{ .opt_bool = ¶ms.output_body, .name = "body" },
|
{ .opt_bool = ¶ms.output_body, .name = "body" },
|
||||||
{ .opt_bool = ¶ms.include_html, .name = "include-html" },
|
{ .opt_bool = ¶ms.include_html, .name = "include-html" },
|
||||||
{ .opt_int = ¶ms.duplicate, .name = "duplicate" },
|
{ .opt_int = ¶ms.duplicate, .name = "duplicate" },
|
||||||
|
{ .opt_int = ¶ms.limit, .name = "limit" },
|
||||||
|
{ .opt_int = ¶ms.offset, .name = "offset" },
|
||||||
{ .opt_inherit = notmuch_shared_options },
|
{ .opt_inherit = notmuch_shared_options },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,11 +24,11 @@ Getting set up to run tests:
|
||||||
First, you need to get the corpus. If you don't already have the gpg
|
First, you need to get the corpus. If you don't already have the gpg
|
||||||
key for David Bremner, run
|
key for David Bremner, run
|
||||||
|
|
||||||
% gpg --search 'david@tethera.net'
|
% gpg --locate-external-key 'david@tethera.net'
|
||||||
|
|
||||||
This should get you a key with fingerprint
|
This should get you a key with fingerprint
|
||||||
|
|
||||||
815B 6398 2A79 F8E7 C727 86C4 762B 57BB 7842 06AD
|
7A18 807F 100A 4570 C596 8420 7E4E 65C8 720B 706B
|
||||||
|
|
||||||
(the last 8 digits are printed as the "key id").
|
(the last 8 digits are printed as the "key id").
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIzBAABCAAdFiEEkiyHYXwaY0SiY6fqA0U5G1WqFSEFAmR119gACgkQA0U5G1Wq
|
||||||
|
FSHlSQ/+NSRj27PEZjaP2I+3j+rsMG3pnVckNcuOQyfgjJ+zEagMZyRu3vaIA/pX
|
||||||
|
xtBrNIX4l4CQIkqwyNjsuqJdzh6S3DeCWSEr1Q+GSBki+wQCBiRuDYY2HQoDezEK
|
||||||
|
4bMfniEWZpKJD8PfIabz0OOqMUsfXEYMd9kefew5/J4OGnDIv8E5pKfqvDNNO4rW
|
||||||
|
MhZ9w9uR9wkvmfmpO66kAgTfLllwiyNHWoWnzQfNmqM8eULFn7XxM1PEZShUEqXf
|
||||||
|
pTWCqqm5OyUcy8f+gy9Mb7DRRvnwLpHHRQlCzzH2c+ENQRpt1ErsgVKpHTVk4UsB
|
||||||
|
EML+zwyWEaQg7xVKWXRJDuGCF47S1GCQNUtvtx57HJl6Ds6N2mlr2KEGaI7qtiz5
|
||||||
|
5hdaTc0L/TVN0WS+uCdfdDDozFErf1kwhA6Jnpi0YNNdK+wpFzj7ISvA+DNHwJ75
|
||||||
|
TLBuJIU/h3QfX3NDC5xDbsWAgpv7a84e7ePO6+kAVkHsNYDbFjiunr5fRbqDsJcJ
|
||||||
|
B+aVGhKvFZbziC84Dn5Ae9Lpa40fQlxbdb+So2nDIiuR3P33vt7wr/e2ptVfrqkn
|
||||||
|
a1DM96n03VWexwEDMye3b3rOTXsN5Ul87zucg9xWm5JT75NGuqJ1WDJN/wwNPDro
|
||||||
|
ZXS1OHh7UKsU1tP2J9+gLiKYNBP4m4BQjEgYXpiYEoge9A1QplQ=
|
||||||
|
=5/Ep
|
||||||
|
-----END PGP SIGNATURE-----
|
|
@ -1,3 +1,3 @@
|
||||||
# this should be both a valid Makefile fragment and valid POSIX(ish) shell.
|
# this should be both a valid Makefile fragment and valid POSIX(ish) shell.
|
||||||
|
|
||||||
PERFTEST_VERSION=0.4
|
PERFTEST_VERSION=0.5
|
||||||
|
|
17
test/README
17
test/README
|
@ -137,6 +137,23 @@ detection of missing prerequisites. In the future we may treat tests
|
||||||
unable to run because of missing prerequisites, but not explicitly
|
unable to run because of missing prerequisites, but not explicitly
|
||||||
skipped by the user, as failures.
|
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
|
Writing Tests
|
||||||
-------------
|
-------------
|
||||||
The test script is written as a shell script. It is to be named as
|
The test script is written as a shell script. It is to be named as
|
||||||
|
|
|
@ -66,6 +66,7 @@ test_begin_subtest 'NOTMUCH_CONFIG is set and points to an existing file'
|
||||||
test_expect_success 'test -f "${NOTMUCH_CONFIG}"'
|
test_expect_success 'test -f "${NOTMUCH_CONFIG}"'
|
||||||
|
|
||||||
test_begin_subtest 'PATH is set to build directory'
|
test_begin_subtest 'PATH is set to build directory'
|
||||||
|
test_subtest_broken_for_installed
|
||||||
test_expect_equal \
|
test_expect_equal \
|
||||||
"$(dirname ${TEST_DIRECTORY})" \
|
"$(dirname ${TEST_DIRECTORY})" \
|
||||||
"$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
|
"$(echo $PATH|cut -f1 -d: | sed -e 's,/test/valgrind/bin$,,')"
|
||||||
|
|
|
@ -12,13 +12,16 @@ test_expect_success 'notmuch help'
|
||||||
test_begin_subtest 'notmuch --version'
|
test_begin_subtest 'notmuch --version'
|
||||||
test_expect_success '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_begin_subtest 'notmuch --help tag'
|
||||||
test_expect_success 'notmuch --help tag'
|
test_expect_success 'notmuch --help tag'
|
||||||
|
|
||||||
test_begin_subtest 'notmuch help tag'
|
test_begin_subtest 'notmuch help tag'
|
||||||
test_expect_success 'notmuch help tag'
|
test_expect_success 'notmuch help tag'
|
||||||
else
|
else
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
test_begin_subtest 'notmuch --help tag (man pages not available)'
|
test_begin_subtest 'notmuch --help tag (man pages not available)'
|
||||||
test_expect_success 'test_must_fail notmuch --help tag >/dev/null'
|
test_expect_success 'test_must_fail notmuch --help tag >/dev/null'
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ database.mail_root=MAIL_DIR
|
||||||
database.path=MAIL_DIR
|
database.path=MAIL_DIR
|
||||||
foo.list=this;is another;list value;
|
foo.list=this;is another;list value;
|
||||||
foo.string=this is another string value
|
foo.string=this is another string value
|
||||||
|
index.as_text=
|
||||||
maildir.synchronize_flags=true
|
maildir.synchronize_flags=true
|
||||||
new.ignore=
|
new.ignore=
|
||||||
new.tags=unread;inbox
|
new.tags=unread;inbox
|
||||||
|
|
|
@ -21,7 +21,8 @@ baz
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
expected_dir=$NOTMUCH_SRCDIR/test/setup.expected-output
|
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"
|
test_begin_subtest "setup consistent with config-set for single items"
|
||||||
# note this relies on the config state from the previous test.
|
# note this relies on the config state from the previous test.
|
||||||
|
|
|
@ -383,7 +383,22 @@ No new mail. Removed 1 message.
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "Long file names have reasonable diagnostics"
|
||||||
|
printf -v name 'f%.0s' {1..234}
|
||||||
|
generate_message "[filename]=$name"
|
||||||
|
notmuch new 2>&1 | notmuch_dir_sanitize >OUTPUT
|
||||||
|
rm ${MAIL_DIR}/${name}
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
Note: Ignoring non-indexable path: MAIL_DIR/$name
|
||||||
|
add_file: Path supplied is illegal for this function
|
||||||
|
filename too long for file-direntry term: MAIL_DIR/$name
|
||||||
|
Processed 1 file in almost no time.
|
||||||
|
No new mail.
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "Xapian exception: read only files"
|
test_begin_subtest "Xapian exception: read only files"
|
||||||
|
test_subtest_broken_for_root
|
||||||
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
|
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
|
||||||
output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
|
output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
|
||||||
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
|
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
|
||||||
|
@ -455,12 +470,4 @@ Date: Fri, 17 Jun 2016 22:14:41 -0400
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
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
|
test_done
|
||||||
|
|
|
@ -299,6 +299,7 @@ database.backup_dir
|
||||||
database.hook_dir
|
database.hook_dir
|
||||||
database.mail_root=MAIL_DIR
|
database.mail_root=MAIL_DIR
|
||||||
database.path
|
database.path
|
||||||
|
index.as_text=
|
||||||
maildir.synchronize_flags=true
|
maildir.synchronize_flags=true
|
||||||
new.ignore=
|
new.ignore=
|
||||||
new.tags=unread;inbox
|
new.tags=unread;inbox
|
||||||
|
|
|
@ -157,7 +157,7 @@ print("4: {} messages".format(query.count_messages()))
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
|
if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
|
||||||
|
|
||||||
test_begin_subtest "and of exact terms (query=sexp)"
|
test_begin_subtest "and of exact terms (query=sexp)"
|
||||||
output=$(notmuch count --query=sexp '(and "wonderful" "wizard")')
|
output=$(notmuch count --query=sexp '(and "wonderful" "wizard")')
|
||||||
|
|
|
@ -34,6 +34,12 @@ add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"
|
||||||
output=$(notmuch search id:${gen_msg_id} | notmuch_search_sanitize)
|
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_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:"
|
test_begin_subtest "Search by mid:"
|
||||||
add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
|
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)
|
output=$(notmuch search mid:${gen_msg_id} | notmuch_search_sanitize)
|
||||||
|
@ -132,6 +138,7 @@ thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)
|
||||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
|
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; 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; utf8-sübjéct (inbox unread)
|
||||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)
|
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by 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 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 tag (inbox searchbytag unread)
|
||||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)
|
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
test_description='"notmuch search" in several variations'
|
test_description='"notmuch search" in several variations'
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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"
|
printf "Skipping due to missing sfsexp library\n"
|
||||||
test_done
|
test_done
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -325,7 +325,7 @@ cat <<EOF >EXPECTED
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
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"
|
test_begin_subtest "sexpr query: all messages"
|
||||||
notmuch address '*' > EXPECTED
|
notmuch address '*' > EXPECTED
|
||||||
notmuch address --query=sexp '()' > OUTPUT
|
notmuch address --query=sexp '()' > OUTPUT
|
||||||
|
|
81
test/T131-show-limiting.sh
Executable file
81
test/T131-show-limiting.sh
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
test_description='"notmuch show" --offset and --limit parameters'
|
||||||
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
add_email_corpus
|
||||||
|
|
||||||
|
show () {
|
||||||
|
local kind="$1"
|
||||||
|
shift
|
||||||
|
if [ "$kind" = messages ]; then
|
||||||
|
set -- --unthreaded "$@"
|
||||||
|
fi
|
||||||
|
notmuch show --body=false --format=text --entire-thread=false "$@" "*" |
|
||||||
|
sed -nre 's/^.message\{.*\<depth:0\>.*/&/p'
|
||||||
|
}
|
||||||
|
|
||||||
|
for outp in messages threads; do
|
||||||
|
test_begin_subtest "$outp: limit does the right thing"
|
||||||
|
show $outp | head -n 20 >expected
|
||||||
|
show $outp --limit=20 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: concatenation of limited shows"
|
||||||
|
show $outp | head -n 20 >expected
|
||||||
|
show $outp --limit=10 >output
|
||||||
|
show $outp --limit=10 --offset=10 >>output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: limit larger than result set"
|
||||||
|
N=$(notmuch count --output=$outp "*")
|
||||||
|
show $outp >expected
|
||||||
|
show $outp --limit=$((1 + N)) >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: limit = 0"
|
||||||
|
test_expect_equal "$(show $outp --limit=0)" ""
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: offset does the right thing"
|
||||||
|
# note: tail -n +N is 1-based
|
||||||
|
show $outp | tail -n +21 >expected
|
||||||
|
show $outp --offset=20 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: offset = 0"
|
||||||
|
show $outp >expected
|
||||||
|
show $outp --offset=0 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset"
|
||||||
|
show $outp | tail -n 20 >expected
|
||||||
|
show $outp --offset=-20 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset"
|
||||||
|
show $outp | tail -n 1 >expected
|
||||||
|
show $outp --offset=-1 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset combined with limit"
|
||||||
|
show $outp | tail -n 20 | head -n 10 >expected
|
||||||
|
show $outp --offset=-20 --limit=10 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset combined with equal limit"
|
||||||
|
show $outp | tail -n 20 >expected
|
||||||
|
show $outp --offset=-20 --limit=20 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset combined with large limit"
|
||||||
|
show $outp | tail -n 20 >expected
|
||||||
|
show $outp --offset=-20 --limit=50 >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
|
||||||
|
test_begin_subtest "$outp: negative offset larger than results"
|
||||||
|
N=$(notmuch count --output=$outp "*")
|
||||||
|
show $outp >expected
|
||||||
|
show $outp --offset=-$((1 + N)) >output
|
||||||
|
test_expect_equal_file expected output
|
||||||
|
done
|
||||||
|
|
||||||
|
test_done
|
|
@ -320,6 +320,7 @@ test_begin_subtest "Tag name beginning with -"
|
||||||
test_expect_code 1 'notmuch tag +- One'
|
test_expect_code 1 'notmuch tag +- One'
|
||||||
|
|
||||||
test_begin_subtest "Xapian exception: read only files"
|
test_begin_subtest "Xapian exception: read only files"
|
||||||
|
test_subtest_broken_for_root
|
||||||
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
|
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.*
|
||||||
output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
|
output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
|
||||||
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
|
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
|
||||||
|
@ -327,7 +328,7 @@ test_expect_equal "$output" "A Xapian exception occurred opening database"
|
||||||
|
|
||||||
add_email_corpus
|
add_email_corpus
|
||||||
|
|
||||||
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
|
if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
|
||||||
|
|
||||||
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
|
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
|
||||||
test_query_syntax '(or "php" "wizard")' 'php or wizard'
|
test_query_syntax '(or "php" "wizard")' 'php or wizard'
|
||||||
|
|
|
@ -65,8 +65,9 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
|
||||||
\"tags\": [\"inbox\",
|
\"tags\": [\"inbox\",
|
||||||
\"unread\"]}]"
|
\"unread\"]}]"
|
||||||
|
|
||||||
|
if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
test_begin_subtest "Search message: json, 64-bit timestamp"
|
test_begin_subtest "Search message: json, 64-bit timestamp"
|
||||||
if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
|
if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
|
||||||
test_subtest_known_broken
|
test_subtest_known_broken
|
||||||
fi
|
fi
|
||||||
add_message "[subject]=\"json-search-64bit-timestamp-subject\"" "[date]=\"Tue, 01 Jan 2999 12:00:00 -0000\"" "[body]=\"json-search-64bit-timestamp-message\""
|
add_message "[subject]=\"json-search-64bit-timestamp-subject\"" "[date]=\"Tue, 01 Jan 2999 12:00:00 -0000\"" "[body]=\"json-search-64bit-timestamp-message\""
|
||||||
|
@ -81,6 +82,7 @@ test_expect_equal_json "$output" "[{\"thread\": \"XXX\",
|
||||||
\"query\": [\"id:$gen_msg_id\", null],
|
\"query\": [\"id:$gen_msg_id\", null],
|
||||||
\"tags\": [\"inbox\",
|
\"tags\": [\"inbox\",
|
||||||
\"unread\"]}]"
|
\"unread\"]}]"
|
||||||
|
fi # NOTMUCH_TEST_INSTALLED undefined / empty
|
||||||
|
|
||||||
test_begin_subtest "Format version: too low"
|
test_begin_subtest "Format version: too low"
|
||||||
test_expect_code 20 "notmuch search --format-version=0 \\*"
|
test_expect_code 20 "notmuch search --format-version=0 \\*"
|
||||||
|
|
|
@ -24,7 +24,7 @@ test_begin_subtest "Basic reply"
|
||||||
notmuch reply id:${gen_msg_id} >OUTPUT 2>&1 && echo OK >> OUTPUT
|
notmuch reply id:${gen_msg_id} >OUTPUT 2>&1 && echo OK >> OUTPUT
|
||||||
test_expect_equal_file basic.expected 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)"
|
test_begin_subtest "Basic reply (query=sexp)"
|
||||||
notmuch reply --query=sexp "(id ${gen_msg_id})" >OUTPUT 2>&1 && echo OK >> OUTPUT
|
notmuch reply --query=sexp "(id ${gen_msg_id})" >OUTPUT 2>&1 && echo OK >> OUTPUT
|
||||||
|
|
|
@ -118,7 +118,7 @@ notmuch dump -- from:cworth > dump-dash-cworth.actual
|
||||||
test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
|
test_expect_equal_file dump-cworth.expected dump-dash-cworth.actual
|
||||||
|
|
||||||
|
|
||||||
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
|
if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
|
||||||
|
|
||||||
test_begin_subtest "dump --query=sexp -- '(from cworth)'"
|
test_begin_subtest "dump --query=sexp -- '(from cworth)'"
|
||||||
notmuch dump --query=sexp -- '(from cworth)' > dump-dash-cworth.actual2
|
notmuch dump --query=sexp -- '(from cworth)' > dump-dash-cworth.actual2
|
||||||
|
@ -139,6 +139,7 @@ notmuch dump --output=dump-outfile-dash-inbox.actual -- from:cworth
|
||||||
test_expect_equal_file dump-cworth.expected dump-outfile-dash-inbox.actual
|
test_expect_equal_file dump-cworth.expected dump-outfile-dash-inbox.actual
|
||||||
|
|
||||||
test_begin_subtest "Check for a safe set of message-ids"
|
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:// > EXPECTED
|
||||||
notmuch search --output=messages from:cworth | sed s/^id:// |\
|
notmuch search --output=messages from:cworth | sed s/^id:// |\
|
||||||
$TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT
|
$TEST_DIRECTORY/hex-xcode --direction=encode > OUTPUT
|
||||||
|
@ -246,6 +247,7 @@ notmuch dump --format=batch-tag > OUTPUT.$test_count
|
||||||
test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
|
test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
|
||||||
|
|
||||||
test_begin_subtest 'format=batch-tag, checking encoded output'
|
test_begin_subtest 'format=batch-tag, checking encoded output'
|
||||||
|
test_subtest_broken_for_installed
|
||||||
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth |\
|
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth |\
|
||||||
awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
|
awk "{ print \"+$enc1 +$enc2 +$enc3 -- \" \$5 }" > EXPECTED.$test_count
|
||||||
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth > OUTPUT.$test_count
|
NOTMUCH_DUMP_TAGS --format=batch-tag -- from:cworth > OUTPUT.$test_count
|
||||||
|
|
|
@ -258,6 +258,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
|
test_begin_subtest "Verify that sent messages are saved/searchable (via FCC)"
|
||||||
|
test_subtest_broken_for_installed
|
||||||
notmuch new > /dev/null
|
notmuch new > /dev/null
|
||||||
output=$(notmuch search 'subject:"testing message sent via SMTP"' | notmuch_search_sanitize)
|
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 "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; Testing message sent via SMTP (inbox)"
|
||||||
|
@ -350,6 +351,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "Reply within emacs"
|
test_begin_subtest "Reply within emacs"
|
||||||
|
test_subtest_broken_for_installed
|
||||||
test_emacs '(let ((message-hidden-headers ''()))
|
test_emacs '(let ((message-hidden-headers ''()))
|
||||||
(notmuch-search "subject:\"testing message sent via SMTP\"")
|
(notmuch-search "subject:\"testing message sent via SMTP\"")
|
||||||
(notmuch-test-wait)
|
(notmuch-test-wait)
|
||||||
|
|
|
@ -30,6 +30,7 @@ msg_file=$(notmuch search --output=files subject:signed-message-sent-via-SMTP)
|
||||||
test_expect_equal_message_body sent_message "$msg_file"
|
test_expect_equal_message_body sent_message "$msg_file"
|
||||||
|
|
||||||
test_begin_subtest "signed part content-type indexing"
|
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
|
notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize > OUTPUT
|
||||||
cat <<EOF >EXPECTED
|
cat <<EOF >EXPECTED
|
||||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
|
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
|
||||||
|
|
|
@ -183,8 +183,9 @@ test_begin_subtest "show PKCS#7 SignedData outputs valid JSON"
|
||||||
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
|
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
|
||||||
test_valid_json "$output"
|
test_valid_json "$output"
|
||||||
|
|
||||||
|
if [ -z "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
test_begin_subtest "Verify signature on PKCS#7 SignedData message"
|
test_begin_subtest "Verify signature on PKCS#7 SignedData message"
|
||||||
if [ $NOTMUCH_HAVE_64BIT_TIME_T -ne 1 ]; then
|
if [ "${NOTMUCH_HAVE_64BIT_TIME_T-0}" != "1" ]; then
|
||||||
test_subtest_known_broken
|
test_subtest_known_broken
|
||||||
fi
|
fi
|
||||||
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
|
output=$(notmuch show --format=json id:smime-onepart-signed@protected-headers.example)
|
||||||
|
@ -194,6 +195,7 @@ test_json_nodes <<<"$output" \
|
||||||
'expires:[0][0][0]["crypto"]["signed"]["status"][0]["expires"]=2611032858' \
|
'expires:[0][0][0]["crypto"]["signed"]["status"][0]["expires"]=2611032858' \
|
||||||
'fingerprint:[0][0][0]["crypto"]["signed"]["status"][0]["fingerprint"]="702BA4B157F1E2B7D16B0C6A5FFC8A7DE2057DEB"' \
|
'fingerprint:[0][0][0]["crypto"]["signed"]["status"][0]["fingerprint"]="702BA4B157F1E2B7D16B0C6A5FFC8A7DE2057DEB"' \
|
||||||
'status:[0][0][0]["crypto"]["signed"]["status"][0]["status"]="good"'
|
'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"
|
test_begin_subtest "Verify signature on PKCS#7 SignedData message signer User ID"
|
||||||
if [ $NOTMUCH_GMIME_X509_CERT_VALIDITY -ne 1 ]; then
|
if [ $NOTMUCH_GMIME_X509_CERT_VALIDITY -ne 1 ]; then
|
||||||
|
|
|
@ -11,6 +11,10 @@ test_description='exception symbol hiding'
|
||||||
|
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
test_begin_subtest 'running test' run_test
|
test_begin_subtest 'running test' run_test
|
||||||
mkdir -p ${PWD}/fakedb/.notmuch
|
mkdir -p ${PWD}/fakedb/.notmuch
|
||||||
$TEST_DIRECTORY/symbol-test ${PWD}/fakedb ${PWD}/nonexistent 2>&1 \
|
$TEST_DIRECTORY/symbol-test ${PWD}/fakedb ${PWD}/nonexistent 2>&1 \
|
||||||
|
|
|
@ -4,6 +4,10 @@ test_description="python bindings"
|
||||||
|
|
||||||
test_require_external_prereq ${NOTMUCH_PYTHON}
|
test_require_external_prereq ${NOTMUCH_PYTHON}
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
add_email_corpus
|
add_email_corpus
|
||||||
add_gnupg_home
|
add_gnupg_home
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,13 @@
|
||||||
test_description="python bindings (pytest)"
|
test_description="python bindings (pytest)"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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
|
test_done
|
||||||
fi
|
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)"
|
test_begin_subtest "python cffi tests (NOTMUCH_CONFIG set)"
|
||||||
pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
|
pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
test_description="python bindings (notmuch test suite)"
|
test_description="python bindings (notmuch test suite)"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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
|
test_done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
test_description="ruby bindings"
|
test_description="ruby bindings"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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
|
test_subtest_missing_external_prereq_["ruby development files"]=t
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -12,10 +12,14 @@ test_ruby() {
|
||||||
(
|
(
|
||||||
cat <<-EOF
|
cat <<-EOF
|
||||||
require 'notmuch'
|
require 'notmuch'
|
||||||
db = Notmuch::Database.new('$MAIL_DIR')
|
db = Notmuch::Database.new()
|
||||||
EOF
|
EOF
|
||||||
cat
|
cat
|
||||||
) | $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"> OUTPUT
|
) | if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
ruby
|
||||||
|
else
|
||||||
|
$NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"
|
||||||
|
fi> OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
test_description="argument parsing"
|
test_description="argument parsing"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
test_begin_subtest "sanity check"
|
test_begin_subtest "sanity check"
|
||||||
$TEST_DIRECTORY/arg-test pos1 --keyword=one --boolean --string=foo pos2 --int=7 --flag=one --flag=three > OUTPUT
|
$TEST_DIRECTORY/arg-test pos1 --keyword=one --boolean --string=foo pos2 --int=7 --flag=one --flag=three > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
|
|
|
@ -200,6 +200,30 @@ test_emacs '(test-log-error
|
||||||
(notmuch-tree "*")))'
|
(notmuch-tree "*")))'
|
||||||
test_expect_equal "$(cat MESSAGES)" "COMPLETE"
|
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
|
add_email_corpus duplicate
|
||||||
|
|
||||||
ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
|
ID3=87r2ecrr6x.fsf@zephyr.silentflame.com
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
test_description="hex encoding and decoding"
|
test_description="hex encoding and decoding"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
test_begin_subtest "round trip"
|
test_begin_subtest "round trip"
|
||||||
find $NOTMUCH_SRCDIR/test/corpora/default -type f -print | sort | xargs cat > EXPECTED
|
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_DIRECTORY/hex-xcode --direction=encode < EXPECTED | $TEST_DIRECTORY/hex-xcode --direction=decode > OUTPUT
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
test_description="date/time parser module"
|
test_description="date/time parser module"
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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
|
# Sanity/smoke tests for the date/time parser independent of notmuch
|
||||||
|
|
||||||
_date () {
|
_date () {
|
||||||
|
|
|
@ -35,7 +35,7 @@ notmuch show --entire-thread=true --sort=oldest-first $QUERY > OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
|
||||||
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
|
if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
|
||||||
|
|
||||||
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
|
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
|
||||||
test_query_syntax '(or "php" "wizard")' 'php or wizard'
|
test_query_syntax '(or "php" "wizard")' 'php or wizard'
|
||||||
|
|
|
@ -3,6 +3,10 @@ test_description="database version and feature compatibility"
|
||||||
|
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
test_begin_subtest "future database versions abort open"
|
test_begin_subtest "future database versions abort open"
|
||||||
${TEST_DIRECTORY}/make-db-version ${MAIL_DIR} 9999 ""
|
${TEST_DIRECTORY}/make-db-version ${MAIL_DIR} 9999 ""
|
||||||
output=$(notmuch search x 2>&1 | sed 's/\(database at\) .*/\1 FILENAME/')
|
output=$(notmuch search x 2>&1 | sed 's/\(database at\) .*/\1 FILENAME/')
|
||||||
|
|
|
@ -3,6 +3,10 @@ test_description="API tests for notmuch_message_*"
|
||||||
|
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
add_email_corpus
|
add_email_corpus
|
||||||
|
|
||||||
test_begin_subtest "building database"
|
test_begin_subtest "building database"
|
||||||
|
@ -516,4 +520,31 @@ cat <<EOF > EXPECTED
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
TERMLIST_PATH=(${MAIL_DIR}/.notmuch/xapian/termlist.*)
|
||||||
|
test_begin_subtest "remove message with corrupted db"
|
||||||
|
backup_database
|
||||||
|
cat c_head0 - c_tail <<'EOF' | test_private_C ${MAIL_DIR} ${TERMLIST_PATH}
|
||||||
|
{
|
||||||
|
notmuch_status_t status;
|
||||||
|
|
||||||
|
int fd = open(argv[2],O_WRONLY|O_TRUNC);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf (stderr, "error opening %s\n", argv[1]);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stat = _notmuch_message_delete (message);
|
||||||
|
printf ("%d\n", stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
1
|
||||||
|
== stderr ==
|
||||||
|
A Xapian exception occurred at message.cc:XXX: EOF reading block YYY
|
||||||
|
EOF
|
||||||
|
sed 's/EOF reading block [0-9]*/EOF reading block YYY/' < OUTPUT > OUTPUT.clean
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT.clean
|
||||||
|
restore_database
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -95,7 +95,7 @@ subtotal=$(notmuch count lastmod:..$lastmod)
|
||||||
result=$(($subtotal == $total-1))
|
result=$(($subtotal == $total-1))
|
||||||
test_expect_equal 1 "$result"
|
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)'
|
test_begin_subtest 'exclude one message using negative lastmod (sexp)'
|
||||||
total=$(notmuch count '*')
|
total=$(notmuch count '*')
|
||||||
notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
|
notmuch tag +${RANDOM} id:4EFC743A.3060609@april.org
|
||||||
|
|
|
@ -440,6 +440,7 @@ cat <<'EOF' >EXPECTED
|
||||||
10: 'USER_FULL_NAME'
|
10: 'USER_FULL_NAME'
|
||||||
11: '8000'
|
11: '8000'
|
||||||
12: 'NULL'
|
12: 'NULL'
|
||||||
|
13: ''
|
||||||
== stderr ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
unset MAILDIR
|
unset MAILDIR
|
||||||
|
@ -725,6 +726,7 @@ test_expect_equal_file EXPECTED OUTPUT
|
||||||
test_begin_subtest "list by keys (ndlc)"
|
test_begin_subtest "list by keys (ndlc)"
|
||||||
notmuch config set search.exclude_tags "foo;bar;fub"
|
notmuch config set search.exclude_tags "foo;bar;fub"
|
||||||
notmuch config set new.ignore "sekrit_junk"
|
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%
|
cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL%
|
||||||
{
|
{
|
||||||
notmuch_config_key_t key;
|
notmuch_config_key_t key;
|
||||||
|
@ -751,6 +753,7 @@ cat <<'EOF' >EXPECTED
|
||||||
10: 'Notmuch Test Suite'
|
10: 'Notmuch Test Suite'
|
||||||
11: '8000'
|
11: '8000'
|
||||||
12: 'NULL'
|
12: 'NULL'
|
||||||
|
13: 'text/'
|
||||||
== stderr ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -785,6 +788,7 @@ cat <<'EOF' >EXPECTED
|
||||||
10: 'USER_FULL_NAME'
|
10: 'USER_FULL_NAME'
|
||||||
11: '8000'
|
11: '8000'
|
||||||
12: 'NULL'
|
12: 'NULL'
|
||||||
|
13: ''
|
||||||
== stderr ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT.clean
|
test_expect_equal_file EXPECTED OUTPUT.clean
|
||||||
|
@ -856,6 +860,7 @@ database.backup_dir MAIL_DIR/.notmuch/backups
|
||||||
database.hook_dir MAIL_DIR/.notmuch/hooks
|
database.hook_dir MAIL_DIR/.notmuch/hooks
|
||||||
database.mail_root MAIL_DIR
|
database.mail_root MAIL_DIR
|
||||||
database.path MAIL_DIR
|
database.path MAIL_DIR
|
||||||
|
index.as_text text/
|
||||||
key with spaces value, with, spaces!
|
key with spaces value, with, spaces!
|
||||||
maildir.synchronize_flags true
|
maildir.synchronize_flags true
|
||||||
new.ignore sekrit_junk
|
new.ignore sekrit_junk
|
||||||
|
|
|
@ -21,6 +21,10 @@ test_description='thread breakage during reindexing'
|
||||||
|
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
message_a () {
|
message_a () {
|
||||||
mkdir -p ${MAIL_DIR}/cur
|
mkdir -p ${MAIL_DIR}/cur
|
||||||
cat > ${MAIL_DIR}/cur/a <<EOF
|
cat > ${MAIL_DIR}/cur/a <<EOF
|
||||||
|
|
|
@ -12,7 +12,7 @@ void print_properties (notmuch_message_t *message, const char *prefix, notmuch_b
|
||||||
notmuch_message_properties_t *list;
|
notmuch_message_properties_t *list;
|
||||||
for (list = notmuch_message_get_properties (message, prefix, exact);
|
for (list = notmuch_message_get_properties (message, prefix, exact);
|
||||||
notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {
|
notmuch_message_properties_valid (list); notmuch_message_properties_move_to_next (list)) {
|
||||||
printf("%s\n", notmuch_message_properties_value(list));
|
printf("%s = %s\n", notmuch_message_properties_key(list), notmuch_message_properties_value(list));
|
||||||
}
|
}
|
||||||
notmuch_message_properties_destroy (list);
|
notmuch_message_properties_destroy (list);
|
||||||
}
|
}
|
||||||
|
@ -89,17 +89,6 @@ testkey2 = NULL
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
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)"
|
test_begin_subtest "testing string map binary search (via message properties)"
|
||||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||||
{
|
{
|
||||||
|
@ -157,7 +146,28 @@ print_properties (message, "testkey1", TRUE);
|
||||||
EOF
|
EOF
|
||||||
cat <<'EOF' >EXPECTED
|
cat <<'EOF' >EXPECTED
|
||||||
== stdout ==
|
== 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 ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -171,10 +181,9 @@ print_properties (message, "testkey1", TRUE);
|
||||||
EOF
|
EOF
|
||||||
cat <<'EOF' >EXPECTED
|
cat <<'EOF' >EXPECTED
|
||||||
== stdout ==
|
== stdout ==
|
||||||
alice
|
testkey1 = alice
|
||||||
bob
|
testkey1 = bob
|
||||||
testvalue1
|
testkey1 = testvalue2
|
||||||
testvalue2
|
|
||||||
== stderr ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -186,27 +195,14 @@ EXPECT0(notmuch_message_add_property (message, "testkey3", "testvalue3"));
|
||||||
EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
|
EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
|
||||||
print_properties (message, "testkey", FALSE);
|
print_properties (message, "testkey", FALSE);
|
||||||
EOF
|
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
|
cat <<'EOF' >EXPECTED
|
||||||
== stdout ==
|
== stdout ==
|
||||||
alice
|
testkey1 = alice
|
||||||
bob
|
testkey1 = bob
|
||||||
testvalue1
|
testkey1 = testvalue2
|
||||||
testvalue2
|
testkey3 = alice3
|
||||||
alice3
|
testkey3 = bob3
|
||||||
bob3
|
testkey3 = testvalue3
|
||||||
testvalue3
|
|
||||||
== stderr ==
|
== stderr ==
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -248,7 +244,7 @@ test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "dump message properties"
|
test_begin_subtest "dump message properties"
|
||||||
cat <<EOF > 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
|
EOF
|
||||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||||
EXPECT0(notmuch_message_add_property (message, "fancy key with áccènts", "import value with ="));
|
EXPECT0(notmuch_message_add_property (message, "fancy key with áccènts", "import value with ="));
|
||||||
|
@ -259,7 +255,7 @@ test_expect_equal_file PROPERTIES OUTPUT
|
||||||
test_begin_subtest "dump _only_ message properties"
|
test_begin_subtest "dump _only_ message properties"
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
#notmuch-dump batch-tag:3 properties
|
#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
|
EOF
|
||||||
notmuch dump --include=properties > OUTPUT
|
notmuch dump --include=properties > OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -328,7 +324,6 @@ EOF
|
||||||
cat <<'EOF' > EXPECTED
|
cat <<'EOF' > EXPECTED
|
||||||
testkey1 = alice
|
testkey1 = alice
|
||||||
testkey1 = bob
|
testkey1 = bob
|
||||||
testkey1 = testvalue1
|
|
||||||
testkey1 = testvalue2
|
testkey1 = testvalue2
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
@ -344,7 +339,6 @@ EOF
|
||||||
cat <<'EOF' > EXPECTED
|
cat <<'EOF' > EXPECTED
|
||||||
testkey1 = alice
|
testkey1 = alice
|
||||||
testkey1 = bob
|
testkey1 = bob
|
||||||
testkey1 = testvalue1
|
|
||||||
testkey1 = testvalue2
|
testkey1 = testvalue2
|
||||||
testkey3 = alice3
|
testkey3 = alice3
|
||||||
testkey3 = bob3
|
testkey3 = bob3
|
||||||
|
@ -362,4 +356,49 @@ for (key,val) in msg.get_properties("testkey",True):
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file /dev/null OUTPUT
|
test_expect_equal_file /dev/null OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "notmuch_message_remove_all_properties_with_prefix"
|
||||||
|
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||||
|
EXPECT0(notmuch_message_remove_all_properties_with_prefix (message, "testkey3"));
|
||||||
|
print_properties (message, "", FALSE);
|
||||||
|
EOF
|
||||||
|
cat <<'EOF' >EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
fancy key with áccènts = import value with =
|
||||||
|
testkey1 = alice
|
||||||
|
testkey1 = bob
|
||||||
|
testkey1 = testvalue2
|
||||||
|
== stderr ==
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "edit property on removed message without uncaught exception"
|
||||||
|
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||||
|
EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
|
||||||
|
stat = notmuch_message_remove_property (message, "example", "example");
|
||||||
|
if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
|
||||||
|
fprintf (stderr, "unable to remove properties on message");
|
||||||
|
EOF
|
||||||
|
cat <<'EOF' >EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
== stderr ==
|
||||||
|
unable to remove properties on message
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
add_email_corpus
|
||||||
|
|
||||||
|
test_begin_subtest "remove all properties on removed message without uncaught exception"
|
||||||
|
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||||
|
EXPECT0(notmuch_database_remove_message (db, notmuch_message_get_filename (message)));
|
||||||
|
stat = notmuch_message_remove_all_properties_with_prefix (message, "");
|
||||||
|
if (stat == NOTMUCH_STATUS_XAPIAN_EXCEPTION)
|
||||||
|
fprintf (stderr, "unable to remove properties on message");
|
||||||
|
EOF
|
||||||
|
cat <<'EOF' >EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
== stderr ==
|
||||||
|
unable to remove properties on message
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -5,7 +5,7 @@ test_description='reindexing messages'
|
||||||
add_email_corpus
|
add_email_corpus
|
||||||
|
|
||||||
|
|
||||||
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
|
if [ "${NOTMUCH_HAVE_SFSEXP-0}" = "1" ]; then
|
||||||
|
|
||||||
count=$(notmuch count --lastmod '*' | cut -f 3)
|
count=$(notmuch count --lastmod '*' | cut -f 3)
|
||||||
for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
|
for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
|
||||||
|
|
|
@ -3,6 +3,10 @@ test_description="message id parsing"
|
||||||
|
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ -n "${NOTMUCH_TEST_INSTALLED-}" ]; then
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
test_begin_subtest "good message ids"
|
test_begin_subtest "good message ids"
|
||||||
${TEST_DIRECTORY}/message-id-parse <<EOF >OUTPUT
|
${TEST_DIRECTORY}/message-id-parse <<EOF >OUTPUT
|
||||||
<018b1a8f2d1df62e804ce88b65401304832dfbbf.1346614915.git.jani@nikula.org>
|
<018b1a8f2d1df62e804ce88b65401304832dfbbf.1346614915.git.jani@nikula.org>
|
||||||
|
|
77
test/T760-as-text.sh
Executable file
77
test/T760-as-text.sh
Executable file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
test_description='index attachments as text'
|
||||||
|
. $(dirname "$0")/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
add_email_corpus indexing
|
||||||
|
test_begin_subtest "empty as_text; skip text/x-diff"
|
||||||
|
messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
|
||||||
|
count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
|
||||||
|
test_expect_equal "$messages,$count" "1,0"
|
||||||
|
|
||||||
|
notmuch config set index.as_text "^text/"
|
||||||
|
add_email_corpus indexing
|
||||||
|
|
||||||
|
test_begin_subtest "as_index is text/; find text/x-diff"
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
|
||||||
|
test_expect_equal_file_nonempty EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "reindex with empty as_text, skips text/x-diff"
|
||||||
|
notmuch config set index.as_text
|
||||||
|
notmuch reindex '*'
|
||||||
|
messages=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain)
|
||||||
|
count=$(notmuch count id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz)
|
||||||
|
test_expect_equal "$messages,$count" "1,0"
|
||||||
|
|
||||||
|
test_begin_subtest "reindex with empty as_text; skips application/pdf"
|
||||||
|
notmuch config set index.as_text
|
||||||
|
notmuch reindex '*'
|
||||||
|
gmessages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
|
||||||
|
count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
|
||||||
|
test_expect_equal "$messages,$count" "1,0"
|
||||||
|
|
||||||
|
test_begin_subtest "reindex with as_text as text/; finds text/x-diff"
|
||||||
|
notmuch config set index.as_text "^text/"
|
||||||
|
notmuch reindex '*'
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
|
||||||
|
test_expect_equal_file_nonempty EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "reindex with as_text as text/; skips application/pdf"
|
||||||
|
notmuch config set index.as_text "^text/"
|
||||||
|
notmuch config set index.as_text
|
||||||
|
notmuch reindex '*'
|
||||||
|
messages=$(notmuch count id:871qo9p4tf.fsf@tethera.net)
|
||||||
|
count=$(notmuch count id:871qo9p4tf.fsf@tethera.net and body:not-really-PDF)
|
||||||
|
test_expect_equal "$messages,$count" "1,0"
|
||||||
|
|
||||||
|
test_begin_subtest "as_text has multiple regexes"
|
||||||
|
notmuch config set index.as_text "blahblah;^text/"
|
||||||
|
notmuch reindex '*'
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
|
||||||
|
test_expect_equal_file_nonempty EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "as_text is non-anchored regex"
|
||||||
|
notmuch config set index.as_text "e.t/"
|
||||||
|
notmuch reindex '*'
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain > EXPECTED
|
||||||
|
notmuch search id:20200930101213.2m2pt3jrspvcrxfx@localhost.localdomain and ersatz > OUTPUT
|
||||||
|
test_expect_equal_file_nonempty EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "as_text is 'application/pdf'"
|
||||||
|
notmuch config set index.as_text "^application/pdf$"
|
||||||
|
notmuch reindex '*'
|
||||||
|
notmuch search id:871qo9p4tf.fsf@tethera.net > EXPECTED
|
||||||
|
notmuch search id:871qo9p4tf.fsf@tethera.net and '"not really PDF"' > OUTPUT
|
||||||
|
test_expect_equal_file_nonempty EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "as_text is bad regex"
|
||||||
|
notmuch config set index.as_text '['
|
||||||
|
notmuch reindex '*' >& OUTPUT
|
||||||
|
cat<<EOF > EXPECTED
|
||||||
|
Error in index.as_text: Invalid regular expression: [
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_done
|
|
@ -2,14 +2,19 @@
|
||||||
test_description='run code with ASAN enabled against the library'
|
test_description='run code with ASAN enabled against the library'
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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"
|
printf "Skipping due to missing ASAN support\n"
|
||||||
test_done
|
test_done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${LD_PRELOAD-}" ]; then
|
||||||
|
printf "Skipping due to ASAN LD_PRELOAD restrictions\n"
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
add_email_corpus
|
add_email_corpus
|
||||||
|
|
||||||
TEST_CFLAGS="-fsanitize=address"
|
TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=address"
|
||||||
|
|
||||||
test_begin_subtest "open and destroy"
|
test_begin_subtest "open and destroy"
|
||||||
test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} <<EOF
|
test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} <<EOF
|
||||||
|
|
92
test/T810-tsan.sh
Executable file
92
test/T810-tsan.sh
Executable file
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
test_directory=$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)
|
||||||
|
|
||||||
|
test_description='run code with TSan enabled against the library'
|
||||||
|
# Note it is hard to ensure race conditions are deterministic so this
|
||||||
|
# only provides best effort detection.
|
||||||
|
|
||||||
|
. "$test_directory"/test-lib.sh || exit 1
|
||||||
|
|
||||||
|
if [ "${NOTMUCH_HAVE_TSAN-0}" != "1" ]; then
|
||||||
|
printf "Skipping due to missing TSan support\n"
|
||||||
|
test_done
|
||||||
|
fi
|
||||||
|
|
||||||
|
export TSAN_OPTIONS="suppressions=$test_directory/T810-tsan.suppressions"
|
||||||
|
TEST_CFLAGS="${TEST_CFLAGS:-} -fsanitize=thread"
|
||||||
|
|
||||||
|
cp -r ${MAIL_DIR} ${MAIL_DIR}-2
|
||||||
|
|
||||||
|
test_begin_subtest "create"
|
||||||
|
test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
|
||||||
|
#include <notmuch-test.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void *thread (void *arg) {
|
||||||
|
char *mail_dir = arg;
|
||||||
|
/*
|
||||||
|
* Calls into notmuch_query_search_messages which was using the thread-unsafe
|
||||||
|
* Xapian::Query::MatchAll.
|
||||||
|
*/
|
||||||
|
EXPECT0(notmuch_database_create (mail_dir, NULL));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
pthread_t t1, t2;
|
||||||
|
EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
|
||||||
|
EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
|
||||||
|
EXPECT0(pthread_join (t1, NULL));
|
||||||
|
EXPECT0(pthread_join (t2, NULL));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
== stderr ==
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
add_email_corpus
|
||||||
|
rm -r ${MAIL_DIR}-2
|
||||||
|
cp -r ${MAIL_DIR} ${MAIL_DIR}-2
|
||||||
|
|
||||||
|
test_begin_subtest "query"
|
||||||
|
test_C ${MAIL_DIR} ${MAIL_DIR}-2 <<EOF
|
||||||
|
#include <notmuch-test.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void *thread (void *arg) {
|
||||||
|
char *mail_dir = arg;
|
||||||
|
notmuch_database_t *db;
|
||||||
|
/*
|
||||||
|
* 'from' is NOTMUCH_FIELD_PROBABILISTIC | NOTMUCH_FIELD_PROCESSOR and an
|
||||||
|
* empty string gets us to RegexpFieldProcessor::operator which was using
|
||||||
|
* the tread-unsafe Xapian::Query::MatchAll.
|
||||||
|
*/
|
||||||
|
EXPECT0(notmuch_database_open_with_config (mail_dir,
|
||||||
|
NOTMUCH_DATABASE_MODE_READ_ONLY,
|
||||||
|
NULL, NULL, &db, NULL));
|
||||||
|
notmuch_query_t *query = notmuch_query_create (db, "from:\"\"");
|
||||||
|
notmuch_messages_t *messages;
|
||||||
|
EXPECT0(notmuch_query_search_messages (query, &messages));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
pthread_t t1, t2;
|
||||||
|
EXPECT0(pthread_create (&t1, NULL, thread, argv[1]));
|
||||||
|
EXPECT0(pthread_create (&t2, NULL, thread, argv[2]));
|
||||||
|
EXPECT0(pthread_join (t1, NULL));
|
||||||
|
EXPECT0(pthread_join (t2, NULL));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
== stdout ==
|
||||||
|
== stderr ==
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_done
|
3
test/T810-tsan.suppressions
Normal file
3
test/T810-tsan.suppressions
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# It's unclear how TSan-friendly GLib is:
|
||||||
|
# https://gitlab.gnome.org/GNOME/glib/-/issues/1672
|
||||||
|
called_from_lib:libglib*.so
|
|
@ -2,7 +2,7 @@
|
||||||
test_description='"notmuch git" to save and restore tags'
|
test_description='"notmuch git" to save and restore tags'
|
||||||
. $(dirname "$0")/test-lib.sh || exit 1
|
. $(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"
|
printf "Skipping due to missing sfsexp library\n"
|
||||||
test_done
|
test_done
|
||||||
fi
|
fi
|
||||||
|
@ -233,6 +233,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "invoke as nmbug sets defaults"
|
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
|
"$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
prefix = notmuch::
|
prefix = notmuch::
|
||||||
|
@ -241,6 +242,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as nmbug"
|
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
|
NOTMUCH_GIT_DIR=`pwd`/foo "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
repository = CWD/foo
|
repository = CWD/foo
|
||||||
|
@ -256,6 +258,7 @@ test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
|
||||||
test_begin_subtest "env variable NOTMUCH_GIT_DIR overrides config when invoked as 'nmbug'"
|
test_begin_subtest "env variable NOTMUCH_GIT_DIR overrides config when invoked as 'nmbug'"
|
||||||
|
test_subtest_broken_for_installed
|
||||||
notmuch config set git.path `pwd`/bar
|
notmuch config set git.path `pwd`/bar
|
||||||
NOTMUCH_GIT_DIR=`pwd`/remote.git "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
|
NOTMUCH_GIT_DIR=`pwd`/remote.git "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT
|
||||||
notmuch config set git.path
|
notmuch config set git.path
|
||||||
|
@ -274,6 +277,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as 'nmbug'"
|
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
|
NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
prefix = env::
|
prefix = env::
|
||||||
|
@ -281,6 +285,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as nmbug"
|
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
|
NOTMUCH_GIT_PREFIX=foo:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
prefix = foo::
|
prefix = foo::
|
||||||
|
@ -288,6 +293,7 @@ EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "env variable NOTMUCH_GIT_PREFIX overrides config when invoked as 'nmbug'"
|
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 config set git.tag_prefix config::
|
||||||
NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
|
NOTMUCH_GIT_PREFIX=env:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT
|
||||||
notmuch config set git.path
|
notmuch config set git.path
|
||||||
|
|
11
test/corpora/indexing/fake-pdf:2,S
Normal file
11
test/corpora/indexing/fake-pdf:2,S
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
From: David Bremner <david@tethera.net>
|
||||||
|
To: example@example.com
|
||||||
|
Subject: attachment content type
|
||||||
|
Date: Thu, 05 Jan 2023 08:02:36 -0400
|
||||||
|
Message-ID: <871qo9p4tf.fsf@tethera.net>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: application/pdf
|
||||||
|
Content-Disposition: attachment; filename=fake.pdf
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
dGhpcyBpcyBub3QgcmVhbGx5IFBERgo=
|
25
test/emacs-tree.expected-output/inbox-outline
Normal file
25
test/emacs-tree.expected-output/inbox-outline
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
2010-12-29 François Boulogne ─►[aur-general] Guidelines: cp, mkdir vs install (inbox unread)
|
||||||
|
2010-12-16 Olivier Berger ─►Essai accentué (inbox unread)
|
||||||
|
2009-11-18 Chris Wilson ─►[notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
|
||||||
|
2009-11-18 Alex Botero-Lowry ┬►[notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
|
||||||
|
2009-11-17 Ingmar Vanhassel ┬►[notmuch] [PATCH] Typsos (inbox unread)
|
||||||
|
2009-11-17 Adrian Perez de Cast ┬►[notmuch] Introducing myself (inbox signed unread)
|
||||||
|
2009-11-17 Israel Herraiz ┬►[notmuch] New to the list (inbox unread)
|
||||||
|
2009-11-17 Jan Janak ┬►[notmuch] What a great idea! (inbox unread)
|
||||||
|
2009-11-17 Jan Janak ┬►[notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)
|
||||||
|
2009-11-17 Aron Griffis ┬►[notmuch] archive (inbox unread)
|
||||||
|
2009-11-17 Keith Packard ┬►[notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)
|
||||||
|
2009-11-17 Lars Kellogg-Stedman ┬►[notmuch] Working with Maildir storage? (inbox signed unread)
|
||||||
|
2009-11-17 Mikhail Gusarov ┬►[notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)
|
||||||
|
2009-11-18 Keith Packard ┬►[notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
|
||||||
|
2009-11-18 Alexander Botero-Low ─►[notmuch] request for pull (inbox unread)
|
||||||
|
2009-11-18 Jjgod Jiang ┬►[notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
|
||||||
|
2009-11-18 Rolland Santimano ─►[notmuch] Link to mailing list archives ? (inbox unread)
|
||||||
|
2009-11-18 Jan Janak ─►[notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (inbox unread)
|
||||||
|
2009-11-18 Stewart Smith ─►[notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
|
||||||
|
2009-11-18 Stewart Smith ─►[notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
|
||||||
|
2009-11-18 Stewart Smith ─►[notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
|
||||||
|
2009-11-18 Lars Kellogg-Stedman ┬►[notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
|
||||||
|
2009-11-17 Mikhail Gusarov ─►[notmuch] [PATCH] Handle rename of message file (inbox unread)
|
||||||
|
2009-11-17 Alex Botero-Lowry ┬►[notmuch] preliminary FreeBSD support (attachment inbox unread)
|
||||||
|
End of search results.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue