mirror of
https://git.notmuchmail.org/git/notmuch
synced 2025-01-21 18:55:58 +01:00
uploaded to unstable
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQGcBAABCAAGBQJWTbNFAAoJEPIClx2kp54sJiYL/imjoqg0scajZ4p8D0Rkmjc8 WVSxfKbbbZKbZJuYzBpMtOAl8GaqjwAHLtc3MhFgSXmK//JDT8yMlpHNodk08w91 u7nuKpZTtgdv1dAD6Pj0fu9FL8t/gC0+0D4ikI+U4EXNlXYiaXZQJ8hNeTlnMj2a ppUA3sK/1OYFsxkpxAVM2+WIjDty6uTu1vqOiQe23EZLRz7uFd1SyR9iq6B/o5tK wF54B6uneAiVtLCTaSoBIevinGkCegZKSyZDHoECkU/C0wHn9Pd9I+AJhoogjVCb FP2P5ehln1ZpaaST2WVBAHUfG9k3mxlCtQlYqLNRbG153SVHbsKIeJ59K5zGIUKA 7wgzJgOgO6VPu+ZIJWWwp727mTrjlWHLXrSDjMjwqRFANfm2fbYGGremDFcJIvzq i3DCsMvuRla8ZQMy57bl64byCW3IV3osg8TFv+pwwY093QhJwt9fc6ITHjM6swNU sF08cxT0KTIjtlL6zBIczmiOpgX1uk/TK1ReErl9iA== =TQWy -----END PGP SIGNATURE----- Merge tag 'debian/0.21-3' into jessie-backports uploaded to unstable
This commit is contained in:
commit
e3cd357fdd
147 changed files with 2319 additions and 818 deletions
6
INSTALL
6
INSTALL
|
@ -20,7 +20,7 @@ configure stage.
|
|||
|
||||
Dependencies
|
||||
------------
|
||||
Notmuch depends on four libraries: Xapian, GMime 2.4 or 2.6,
|
||||
Notmuch depends on four libraries: Xapian, GMime 2.6,
|
||||
Talloc, and zlib which are each described below:
|
||||
|
||||
Xapian
|
||||
|
@ -39,8 +39,8 @@ Talloc, and zlib which are each described below:
|
|||
reading mail while notmuch would wait for Xapian when removing
|
||||
the "inbox" and "unread" tags from messages in a thread.
|
||||
|
||||
GMime 2.4 or 2.6
|
||||
----------------
|
||||
GMime 2.6
|
||||
----------
|
||||
GMime provides decoding of MIME email messages for Notmuch.
|
||||
|
||||
Without GMime, Notmuch would not be able to extract and index
|
||||
|
|
|
@ -59,7 +59,7 @@ endif
|
|||
FINAL_LIBNOTMUCH_LDFLAGS = $(LDFLAGS) $(AS_NEEDED_LDFLAGS) $(CONFIGURE_LDFLAGS)
|
||||
|
||||
.PHONY: all
|
||||
all: notmuch notmuch-shared build-man
|
||||
all: notmuch notmuch-shared build-man ruby-bindings
|
||||
ifeq ($(MAKECMDGOALS),)
|
||||
ifeq ($(shell cat .first-build-message 2>/dev/null),)
|
||||
@NOTMUCH_FIRST_BUILD=1 $(MAKE) --no-print-directory all
|
||||
|
@ -224,7 +224,7 @@ release-checks:
|
|||
.PHONY: verify-newer
|
||||
verify-newer:
|
||||
@echo -n "Checking that no $(VERSION) release already exists..."
|
||||
@wget -q -O /dev/null $(RELEASE_URL)/$(TAR_FILE) ; \
|
||||
@wget -q --no-check-certificate -O /dev/null $(RELEASE_URL)/$(TAR_FILE) ; \
|
||||
case $$? in \
|
||||
8) echo "Good." ;; \
|
||||
0) echo "Ouch."; \
|
||||
|
@ -271,6 +271,7 @@ dataclean: distclean
|
|||
notmuch_client_srcs = \
|
||||
command-line-arguments.c\
|
||||
debugger.c \
|
||||
status.c \
|
||||
gmime-filter-reply.c \
|
||||
hooks.c \
|
||||
notmuch.c \
|
||||
|
|
147
NEWS
147
NEWS
|
@ -1,3 +1,146 @@
|
|||
Notmuch 0.21 (2015-10-29)
|
||||
=========================
|
||||
|
||||
General
|
||||
-------
|
||||
|
||||
Notmuch now requires gmime >= 2.6.7. The gmime 2.4 series is no longer
|
||||
supported.
|
||||
|
||||
Database revision tracking: `lastmod:` queries
|
||||
|
||||
Each message now has a metadata revision number that increases with
|
||||
every tagging operation. See the discussion of `lastmod:` in
|
||||
`notmuch-search-terms(7)` for more information.
|
||||
|
||||
Date queries now support `date:<expr>..!` shorthand for
|
||||
`date:<expr>..<expr>`
|
||||
|
||||
You can use, for example, `date:yesterday..!` to match from the
|
||||
beginning of yesterday to the end of yesterday. For further details,
|
||||
please refer to the `notmuch-search-terms` manual page.
|
||||
|
||||
Notmuch database upgrade to support `lastmod:` queries
|
||||
|
||||
The above mentioned `lastmod:` prefix. This will be done
|
||||
automatically, without prompting on the next time `notmuch new` is
|
||||
run after the upgrade. The upgrade is not reversible, and the
|
||||
upgraded database will not be readable by older versions of
|
||||
Notmuch. As a safeguard, a database dump will be created in the
|
||||
`.notmuch` directory before upgrading.
|
||||
|
||||
Build System
|
||||
------------
|
||||
|
||||
The ruby bindings are now built as part of the main notmuch build
|
||||
process. This can be disabled with the `--without-ruby` option to
|
||||
configure.
|
||||
|
||||
Building the documentation can be disabled with the `--without-docs`
|
||||
option to configure.
|
||||
|
||||
Skipped individual tests are no longer considered as failures.
|
||||
|
||||
Command Line Interface
|
||||
----------------------
|
||||
|
||||
Database revision tracking
|
||||
|
||||
Two new options were added to support revision tracking. A global
|
||||
option "--uuid" (`notmuch(1)`) was added for to detect counter
|
||||
rollover and reinitialization, and `notmuch-count(1)` gained a
|
||||
`--lastmod` option to query database revision tracking data.
|
||||
|
||||
The `notmuch address` command supports new deduplication schemes
|
||||
|
||||
`notmuch address` has gained a new `--deduplicate` option to specify
|
||||
how the results should be deduplicated, if at all. The alternatives
|
||||
are `no` (do not deduplicate, useful for processing the results with
|
||||
external tools), `mailbox` (deduplicate based on the full, case
|
||||
sensitive name and email address), and `address` (deduplicate based
|
||||
on the case insensitive address part). See the `notmuch-address`
|
||||
manual page for further information.
|
||||
|
||||
Emacs Interface
|
||||
---------------
|
||||
|
||||
`notmuch-emacs-version` is used in `User-Agent` header
|
||||
|
||||
The value of recently introduced variable `notmuch-emacs-version` is
|
||||
now used as a part of `User-Agent` header when sending emails.
|
||||
|
||||
Removed `notmuch-version` function by renaming it to `notmuch-cli-version`
|
||||
|
||||
With existing variable `notmuch-emacs-version` the accompanied
|
||||
function which retrieves the version of `notmuch-command` is
|
||||
better named as `notmuch-cli-version`.
|
||||
|
||||
Query input now supports completion for "is:<tag>"
|
||||
|
||||
New message composition mode: `notmuch-compose-mode`
|
||||
|
||||
This is mainly to fix fcc handling, but may be useful for user
|
||||
customization as well.
|
||||
|
||||
Allow filtering of search results in `notmuch-show`
|
||||
|
||||
Add function to rerun current tree-view search in search mode
|
||||
|
||||
Bug fix for replying to encrypted messages in `notmuch-tree` mode
|
||||
|
||||
Allow saved searched to specify tree view rather than search view
|
||||
|
||||
Applies to saved searches run from `notmuch-hello`, or by a keyboard
|
||||
shortcut (`notmuch-jump`). Can be set in the customize interface, or
|
||||
by adding :search-type tree to the appropriate saved search plist in
|
||||
`notmuch-saved-searches`.
|
||||
|
||||
Increase maximum size of rendered text parts
|
||||
|
||||
The variable `notmuch-show-max-text-part-size` controls the maximum
|
||||
size (in bytes) which is automatically rendered. This may make
|
||||
rendering large threads slower. To get the previous behaviour set
|
||||
this variable to 10000.
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
The use of absolute paths is now enforced when calling
|
||||
`notmuch_database_{open, create}`
|
||||
|
||||
New function `notmuch_directory_delete` to delete directory documents
|
||||
|
||||
Previously there was no way to delete directory documents from the
|
||||
database, leading to confusing results when the "ghost" directory
|
||||
document of a renamed or deleted filesystem directory was
|
||||
encountered every time the parent directory was being scanned by
|
||||
`notmuch new`. The mtime of the old directory document was also used
|
||||
if a directory by the same name was added again in the filesystem,
|
||||
potentially bypassing the scan for the directory. The issues are
|
||||
fixed by providing a library call to delete directory documents, and
|
||||
deleting the old documents in `notmuch new` on filesystem directory
|
||||
removal or rename.
|
||||
|
||||
Database revision tracking
|
||||
|
||||
Revision tracking is supported via a new prefix "lastmod:" in the
|
||||
query parser and the new function
|
||||
`notmuch_database_get_revision`. For the latter, see `notmuch(3)`.
|
||||
|
||||
New status code returning API for n_query_count_{messages,threads}
|
||||
|
||||
Deprecated functions
|
||||
|
||||
`notmuch_query_search_threads`, `notmuch_query_search_messages`,
|
||||
`notmuch_query_count_messages`, and `notmuch_query_count_threads`
|
||||
are all deprecated as of this release. Clients are encouraged to
|
||||
transition to the `_st` variants supporting better error reporting.
|
||||
|
||||
nmbug-status
|
||||
------------
|
||||
|
||||
`nmbug-status` now supports specifying the sort order for each view.
|
||||
|
||||
Notmuch 0.20.2 (2015-06-27)
|
||||
===========================
|
||||
|
||||
|
@ -12,7 +155,7 @@ Notmuch 0.20.1 (2015-06-01)
|
|||
Test Suite
|
||||
----------
|
||||
|
||||
Work around apparent gdb bug on arm64
|
||||
Work around apparent gdb bug on arm64.
|
||||
|
||||
Notmuch 0.20 (2015-05-31)
|
||||
=========================
|
||||
|
@ -2767,7 +2910,7 @@ New 'G' key binding to trigger mail refresh (G == "Get new mail")
|
|||
|
||||
The 'G' key works wherever '=' works. Before refreshing the screen
|
||||
it calls an external program that can be used to poll email servers,
|
||||
run notmuch new and setup specific tags for the new emails. The
|
||||
run notmuch new and set up specific tags for the new emails. The
|
||||
script to be called should be configured with the "Notmuch Poll
|
||||
Script" setting in the customize interface. This script will
|
||||
typically invoke "notmuch new" and then perhaps several "notmuch
|
||||
|
|
7
bindings/Makefile
Normal file
7
bindings/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
# See Makefile.local for the list of files to be compiled in this
|
||||
# directory.
|
||||
all:
|
||||
$(MAKE) -C .. all
|
||||
|
||||
.DEFAULT:
|
||||
$(MAKE) -C .. $@
|
21
bindings/Makefile.local
Normal file
21
bindings/Makefile.local
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- makefile -*-
|
||||
|
||||
dir := bindings
|
||||
|
||||
# force the shared library to be built
|
||||
ruby-bindings: lib/$(LINKER_NAME)
|
||||
ifeq ($(HAVE_RUBY_DEV),1)
|
||||
cd $(dir)/ruby && \
|
||||
EXTRA_LDFLAGS="$(NO_UNDEFINED_LDFLAGS)" \
|
||||
LIBNOTMUCH="../../lib/$(LINKER_NAME)" \
|
||||
ruby extconf.rb --vendor
|
||||
$(MAKE) -C $(dir)/ruby
|
||||
else
|
||||
@echo Missing dependency, skipping ruby bindings
|
||||
endif
|
||||
|
||||
CLEAN += $(patsubst %,$(dir)/ruby/%, \
|
||||
.RUBYARCHDIR.time \
|
||||
Makefile database.o directory.o filenames.o\
|
||||
init.o message.o messages.o mkmf.log notmuch.so query.o \
|
||||
status.o tags.o thread.o threads.o)
|
|
@ -17,7 +17,7 @@ along with notmuch. If not, see <http://www.gnu.org/licenses/>.
|
|||
Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
|
||||
"""
|
||||
|
||||
from ctypes import c_char_p, c_uint
|
||||
from ctypes import c_char_p, c_uint, POINTER, byref
|
||||
from .globals import (
|
||||
nmlib,
|
||||
Enum,
|
||||
|
@ -178,8 +178,8 @@ class Query(object):
|
|||
raise NullPointerError
|
||||
return Messages(msgs_p, self)
|
||||
|
||||
_count_messages = nmlib.notmuch_query_count_messages
|
||||
_count_messages.argtypes = [NotmuchQueryP]
|
||||
_count_messages = nmlib.notmuch_query_count_messages_st
|
||||
_count_messages.argtypes = [NotmuchQueryP, POINTER(c_uint)]
|
||||
_count_messages.restype = c_uint
|
||||
|
||||
def count_messages(self):
|
||||
|
@ -191,10 +191,14 @@ class Query(object):
|
|||
:rtype: int
|
||||
'''
|
||||
self._assert_query_is_initialized()
|
||||
return Query._count_messages(self._query)
|
||||
count = c_uint(0)
|
||||
status = Query._count_messages(self._query, byref(count))
|
||||
if status != 0:
|
||||
raise NotmuchError(status)
|
||||
return count.value
|
||||
|
||||
_count_threads = nmlib.notmuch_query_count_threads
|
||||
_count_threads.argtypes = [NotmuchQueryP]
|
||||
_count_threads = nmlib.notmuch_query_count_threads_st
|
||||
_count_threads.argtypes = [NotmuchQueryP, POINTER(c_uint)]
|
||||
_count_threads.restype = c_uint
|
||||
|
||||
def count_threads(self):
|
||||
|
@ -210,7 +214,11 @@ class Query(object):
|
|||
:rtype: int
|
||||
'''
|
||||
self._assert_query_is_initialized()
|
||||
return Query._count_threads(self._query)
|
||||
count = c_uint(0)
|
||||
status = Query._count_threads(self._query, byref(count))
|
||||
if status != 0:
|
||||
raise NotmuchError(status)
|
||||
return count.value
|
||||
|
||||
_destroy = nmlib.notmuch_query_destroy
|
||||
_destroy.argtypes = [NotmuchQueryP]
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# this file should be kept in sync with ../../../version
|
||||
__VERSION__ = '0.20.2'
|
||||
__VERSION__ = '0.21'
|
||||
SOVERSION = '4'
|
||||
|
|
7
bindings/ruby/README
Normal file
7
bindings/ruby/README
Normal file
|
@ -0,0 +1,7 @@
|
|||
To build the the notmuch ruby extension, run the following commands
|
||||
from the *top level* notmuch source directory:
|
||||
|
||||
% ./configure
|
||||
% make ruby-bindings
|
||||
|
||||
The generic documentation about building notmuch also applies.
|
|
@ -10,22 +10,16 @@ dir = File.join('..', '..', 'lib')
|
|||
# includes
|
||||
$INCFLAGS = "-I#{dir} #{$INCFLAGS}"
|
||||
|
||||
# make sure there are no undefined symbols
|
||||
$LDFLAGS += ' -Wl,--no-undefined'
|
||||
|
||||
def have_local_library(lib, path, func, headers = nil)
|
||||
checking_for checking_message(func, lib) do
|
||||
lib = File.join(path, lib)
|
||||
if try_func(func, lib, headers)
|
||||
$LOCAL_LIBS += lib
|
||||
end
|
||||
end
|
||||
if ENV['EXTRA_LDFLAGS']
|
||||
$LDFLAGS += " " + ENV['EXTRA_LDFLAGS']
|
||||
end
|
||||
|
||||
if not have_local_library('libnotmuch.so', dir, 'notmuch_database_create', 'notmuch.h')
|
||||
if not ENV['LIBNOTMUCH']
|
||||
exit 1
|
||||
end
|
||||
|
||||
$LOCAL_LIBS += ENV['LIBNOTMUCH']
|
||||
|
||||
# Create Makefile
|
||||
dir_config('notmuch')
|
||||
create_makefile('notmuch')
|
||||
|
|
|
@ -134,12 +134,13 @@ notmuch_rb_query_search_threads (VALUE self)
|
|||
{
|
||||
notmuch_query_t *query;
|
||||
notmuch_threads_t *threads;
|
||||
notmuch_status_t status;
|
||||
|
||||
Data_Get_Notmuch_Query (self, query);
|
||||
|
||||
threads = notmuch_query_search_threads (query);
|
||||
if (!threads)
|
||||
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
|
||||
status = notmuch_query_search_threads_st (query, &threads);
|
||||
if (status)
|
||||
notmuch_rb_status_raise (status);
|
||||
|
||||
return Data_Wrap_Struct (notmuch_rb_cThreads, NULL, NULL, threads);
|
||||
}
|
||||
|
@ -154,12 +155,13 @@ notmuch_rb_query_search_messages (VALUE self)
|
|||
{
|
||||
notmuch_query_t *query;
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_status_t status;
|
||||
|
||||
Data_Get_Notmuch_Query (self, query);
|
||||
|
||||
messages = notmuch_query_search_messages (query);
|
||||
if (!messages)
|
||||
rb_raise (notmuch_rb_eMemoryError, "Out of memory");
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (status)
|
||||
notmuch_rb_status_raise (status);
|
||||
|
||||
return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
|
||||
}
|
||||
|
@ -173,14 +175,16 @@ VALUE
|
|||
notmuch_rb_query_count_messages (VALUE self)
|
||||
{
|
||||
notmuch_query_t *query;
|
||||
notmuch_status_t status;
|
||||
unsigned int count;
|
||||
|
||||
Data_Get_Notmuch_Query (self, query);
|
||||
|
||||
/* Xapian exceptions are not handled properly.
|
||||
* (function may return 0 after printing a message)
|
||||
* Thus there is nothing we can do here...
|
||||
*/
|
||||
return UINT2NUM(notmuch_query_count_messages(query));
|
||||
status = notmuch_query_count_messages_st (query, &count);
|
||||
if (status)
|
||||
notmuch_rb_status_raise (status);
|
||||
|
||||
return UINT2NUM(count);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -192,12 +196,14 @@ VALUE
|
|||
notmuch_rb_query_count_threads (VALUE self)
|
||||
{
|
||||
notmuch_query_t *query;
|
||||
notmuch_status_t status;
|
||||
unsigned int count;
|
||||
|
||||
Data_Get_Notmuch_Query (self, query);
|
||||
|
||||
/* Xapian exceptions are not handled properly.
|
||||
* (function may return 0 after printing a message)
|
||||
* Thus there is nothing we can do here...
|
||||
*/
|
||||
return UINT2NUM(notmuch_query_count_threads(query));
|
||||
status = notmuch_query_count_threads_st (query, &count);
|
||||
if (status)
|
||||
notmuch_rb_status_raise (status);
|
||||
|
||||
return UINT2NUM(count);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
# on completion.
|
||||
#
|
||||
|
||||
_notmuch_shared_options="--help --uuid= --version"
|
||||
|
||||
# $1: current input of the form prefix:partialinput, where prefix is
|
||||
# to or from.
|
||||
_notmuch_email()
|
||||
|
@ -84,7 +86,7 @@ _notmuch_search_terms()
|
|||
sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
|
||||
;;
|
||||
*)
|
||||
local search_terms="from: to: subject: attachment: mimetype: tag: id: thread: folder: path: date:"
|
||||
local search_terms="from: to: subject: attachment: mimetype: tag: id: thread: folder: path: date: lastmod:"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "${search_terms}" -- ${cur}) )
|
||||
;;
|
||||
|
@ -109,7 +111,7 @@ _notmuch_compact()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--backup= --quiet"
|
||||
local options="--backup= --quiet ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -162,7 +164,7 @@ _notmuch_count()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--output= --exclude= --batch --input="
|
||||
local options="--output= --exclude= --batch --input= --lastmod ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -192,7 +194,7 @@ _notmuch_dump()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--gzip --format= --output="
|
||||
local options="--gzip --format= --output= ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -222,7 +224,7 @@ _notmuch_insert()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
--*)
|
||||
local options="--create-folder --folder= --keep --no-hooks"
|
||||
local options="--create-folder --folder= --keep --no-hooks ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
return
|
||||
|
@ -245,7 +247,8 @@ _notmuch_new()
|
|||
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--no-hooks --quiet"
|
||||
local options="--no-hooks --quiet ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
|
||||
;;
|
||||
esac
|
||||
|
@ -271,7 +274,7 @@ _notmuch_reply()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--format= --format-version= --reply-to= --decrypt"
|
||||
local options="--format= --format-version= --reply-to= --decrypt ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -301,7 +304,7 @@ _notmuch_restore()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--format= --accumulate --input="
|
||||
local options="--format= --accumulate --input= ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -336,7 +339,7 @@ _notmuch_search()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate="
|
||||
local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate= ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -369,12 +372,16 @@ _notmuch_address()
|
|||
COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
|
||||
return
|
||||
;;
|
||||
--deduplicate)
|
||||
COMPREPLY=( $( compgen -W "no mailbox address" -- "${cur}" ) )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--format= --output= --sort= --exclude="
|
||||
local options="--format= --output= --sort= --exclude= --deduplicate= ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -408,7 +415,7 @@ _notmuch_show()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
-*)
|
||||
local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt --include-html"
|
||||
local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt --include-html ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
;;
|
||||
|
@ -435,7 +442,7 @@ _notmuch_tag()
|
|||
! $split &&
|
||||
case "${cur}" in
|
||||
--*)
|
||||
local options="--batch --input= --remove-all"
|
||||
local options="--batch --input= --remove-all ${_notmuch_shared_options}"
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
|
||||
return
|
||||
|
@ -477,10 +484,15 @@ _notmuch()
|
|||
|
||||
if [ -z "${arg}" ]; then
|
||||
# top level completion
|
||||
local top_options="--help --version"
|
||||
case "${cur}" in
|
||||
-*) COMPREPLY=( $(compgen -W "${top_options}" -- ${cur}) ) ;;
|
||||
*) COMPREPLY=( $(compgen -W "${_notmuch_commands}" -- ${cur}) ) ;;
|
||||
-*)
|
||||
# XXX: handle ${_notmuch_shared_options} and --config=
|
||||
local options="--help --version"
|
||||
COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $(compgen -W "${_notmuch_commands}" -- ${cur}) )
|
||||
;;
|
||||
esac
|
||||
elif [ "${arg}" = "help" ]; then
|
||||
# handle help command specially due to _notmuch_commands usage
|
||||
|
|
244
configure
vendored
244
configure
vendored
|
@ -21,6 +21,7 @@ srcdir=$(dirname "$0")
|
|||
|
||||
subdirs="util compat lib parse-time-string completion doc emacs"
|
||||
subdirs="${subdirs} performance-test test test/test-databases"
|
||||
subdirs="${subdirs} bindings"
|
||||
|
||||
# For a non-srcdir configure invocation (such as ../configure), create
|
||||
# the directory structure and copy Makefiles.
|
||||
|
@ -37,7 +38,7 @@ if [ "$srcdir" != "." ]; then
|
|||
cp -a "$srcdir"/test/* test
|
||||
|
||||
# Emacs only likes to generate compiled files next to the .el files
|
||||
# by default so copy these as well (which is not ideal0.
|
||||
# by default so copy these as well (which is not ideal).
|
||||
cp -a "$srcdir"/emacs/*.el emacs
|
||||
fi
|
||||
|
||||
|
@ -47,9 +48,11 @@ CC=${CC:-cc}
|
|||
CXX=${CXX:-c++}
|
||||
CFLAGS=${CFLAGS:--g -O2}
|
||||
CPPFLAGS=${CPPFLAGS:-}
|
||||
CXXFLAGS_for_sh=${CXXFLAGS:-${CFLAGS}}
|
||||
CXXFLAGS=${CXXFLAGS:-\$(CFLAGS)}
|
||||
LDFLAGS=${LDFLAGS:-}
|
||||
XAPIAN_CONFIG=${XAPIAN_CONFIG:-xapian-config}
|
||||
PYTHON=${PYTHON:-}
|
||||
|
||||
# We don't allow the EMACS or GZIP Makefile variables inherit values
|
||||
# from the environment as we do with CC and CXX above. The reason is
|
||||
|
@ -62,20 +65,12 @@ XAPIAN_CONFIG=${XAPIAN_CONFIG:-xapian-config}
|
|||
# options.
|
||||
PREFIX=/usr/local
|
||||
LIBDIR=
|
||||
WITH_DOCS=1
|
||||
WITH_EMACS=1
|
||||
WITH_BASH=1
|
||||
WITH_RUBY=1
|
||||
WITH_ZSH=1
|
||||
|
||||
# Compatible GMime versions (with constraints).
|
||||
# If using GMime 2.6, we need to have a version >= 2.6.5 to avoid a
|
||||
# crypto bug. We need 2.6.7 for permissive "From " header handling.
|
||||
GMIME_24_VERSION_CTR=''
|
||||
GMIME_24_VERSION="gmime-2.4 $GMIME_24_VERSION_CTR"
|
||||
GMIME_26_VERSION_CTR='>= 2.6.7'
|
||||
GMIME_26_VERSION="gmime-2.6 $GMIME_26_VERSION_CTR"
|
||||
|
||||
WITH_GMIME_VERSIONS="$GMIME_26_VERSION;$GMIME_24_VERSION"
|
||||
|
||||
usage ()
|
||||
{
|
||||
cat <<EOF
|
||||
|
@ -95,7 +90,7 @@ First, some common variables can specified via environment variables:
|
|||
|
||||
CC The C compiler to use
|
||||
CFLAGS Flags to pass to the C compiler
|
||||
CPPFLAGS Flags to pass to the C preprocessor
|
||||
CPPFLAGS Flags to pass to the C preprocessor
|
||||
CXX The C++ compiler to use
|
||||
CXXFLAGS Flags to pass to the C compiler
|
||||
LDFLAGS Flags to pass when linking
|
||||
|
@ -109,6 +104,8 @@ Other environment variables can be used to control configure itself,
|
|||
XAPIAN_CONFIG The program to use to determine flags for
|
||||
compiling and linking against the Xapian
|
||||
library. [$XAPIAN_CONFIG]
|
||||
PYTHON Name of python command to use in
|
||||
configure and the test suite.
|
||||
|
||||
Additionally, various options can be specified on the configure
|
||||
command line.
|
||||
|
@ -133,15 +130,13 @@ Fine tuning of some installation directories is available:
|
|||
--bashcompletiondir=DIR Bash completions files [SYSCONFDIR/bash_completion.d]
|
||||
--zshcompletiondir=DIR Zsh completions files [PREFIX/share/zsh/functions/Completion/Unix]
|
||||
|
||||
Some specific library versions can be specified (auto-detected otherwise):
|
||||
|
||||
--with-gmime-version=VERS Specify GMIME version (2.4 or 2.6)
|
||||
|
||||
Some features can be disabled (--with-feature=no is equivalent to
|
||||
--without-feature) :
|
||||
|
||||
--without-emacs Do not install lisp file
|
||||
--without-bash-completion Do not install bash completions files
|
||||
--without-docs Do not install documentation and man pages
|
||||
--without-emacs Do not install lisp file
|
||||
--without-ruby Do not install ruby bindings
|
||||
--without-zsh-completion Do not install zsh completions files
|
||||
|
||||
Additional options are accepted for compatibility with other
|
||||
|
@ -182,6 +177,14 @@ for option; do
|
|||
BASHCOMPLETIONDIR="${option#*=}"
|
||||
elif [ "${option%%=*}" = '--zshcompletiondir' ] ; then
|
||||
ZSHCOMLETIONDIR="${option#*=}"
|
||||
elif [ "${option%%=*}" = '--with-docs' ]; then
|
||||
if [ "${option#*=}" = 'no' ]; then
|
||||
WITH_DOCS=0
|
||||
else
|
||||
WITH_DOCS=1
|
||||
fi
|
||||
elif [ "${option}" = '--without-docs' ] ; then
|
||||
WITH_DOCS=0
|
||||
elif [ "${option%%=*}" = '--with-emacs' ]; then
|
||||
if [ "${option#*=}" = 'no' ]; then
|
||||
WITH_EMACS=0
|
||||
|
@ -198,6 +201,14 @@ for option; do
|
|||
fi
|
||||
elif [ "${option}" = '--without-bash-completion' ] ; then
|
||||
WITH_BASH=0
|
||||
elif [ "${option%%=*}" = '--with-ruby' ]; then
|
||||
if [ "${option#*=}" = 'no' ]; then
|
||||
WITH_RUBY=0
|
||||
else
|
||||
WITH_RUBY=1
|
||||
fi
|
||||
elif [ "${option}" = '--without-ruby' ] ; then
|
||||
WITH_RUBY=0
|
||||
elif [ "${option%%=*}" = '--with-zsh-completion' ]; then
|
||||
if [ "${option#*=}" = 'no' ]; then
|
||||
WITH_ZSH=0
|
||||
|
@ -206,12 +217,6 @@ for option; do
|
|||
fi
|
||||
elif [ "${option}" = '--without-zsh-completion' ] ; then
|
||||
WITH_ZSH=0
|
||||
elif [ "${option%%=*}" = '--with-gmime-version' ] ; then
|
||||
if [ "${option#*=}" = '2.4' ]; then
|
||||
WITH_GMIME_VERSIONS=$GMIME_24_VERSION
|
||||
elif [ "${option#*=}" = '2.6' ]; then
|
||||
WITH_GMIME_VERSIONS=$GMIME_26_VERSION
|
||||
fi
|
||||
elif [ "${option%%=*}" = '--build' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--host' ] ; then
|
||||
|
@ -269,6 +274,64 @@ dependencies are available:
|
|||
EOF
|
||||
|
||||
errors=0
|
||||
printf "int main(void){return 0;}\n" > minimal.c
|
||||
|
||||
printf "Sanity checking C compilation environment... "
|
||||
if ${CC} ${CFLAGS} ${CPPFLAGS} minimal.c ${LDFLAGS} -o minimal > /dev/null 2>&1
|
||||
then
|
||||
printf "OK.\n"
|
||||
else
|
||||
printf "Fail.\n"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
printf "Sanity checking C++ compilation environment... "
|
||||
if ${CXX} ${CXXFLAGS_for_sh} ${CPPFLAGS} minimal.c ${LDFLAGS} -o minimal > /dev/null 2>&1
|
||||
then
|
||||
printf "OK.\n"
|
||||
else
|
||||
printf "Fail.\n"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
if [ $errors -gt 0 ]; then
|
||||
cat <<EOF
|
||||
*** Error: Initial sanity checking of environment failed. Please try
|
||||
running configure in a clean environment, and if the problem persists,
|
||||
report a bug.
|
||||
EOF
|
||||
rm -f minimal minimal.c
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf "Reading libnotmuch version from source... "
|
||||
cat > _libversion.c <<EOF
|
||||
#include <stdio.h>
|
||||
#include "lib/notmuch.h"
|
||||
int main(void) {
|
||||
printf("libnotmuch_version_major=%d\n",
|
||||
LIBNOTMUCH_MAJOR_VERSION);
|
||||
printf("libnotmuch_version_minor=%d\n",
|
||||
LIBNOTMUCH_MINOR_VERSION);
|
||||
printf("libnotmuch_version_release=%d\n",
|
||||
LIBNOTMUCH_MICRO_VERSION);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if ${CC} ${CFLAGS} _libversion.c -o _libversion > /dev/null 2>&1 && \
|
||||
./_libversion > _libversion.sh && . ./_libversion.sh
|
||||
then
|
||||
printf "OK.\n"
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
*** Error: Reading lib/notmuch.h failed.
|
||||
Please try running configure again in a clean environment, and if the
|
||||
problem persists, report a bug.
|
||||
EOF
|
||||
rm -f _libversion _libversion.c _libversion.sh
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if pkg-config --version > /dev/null 2>&1; then
|
||||
have_pkg_config=1
|
||||
|
@ -298,30 +361,29 @@ have_xapian_compact=0
|
|||
if [ ${have_xapian} = "1" ]; then
|
||||
printf "Checking for Xapian compaction support... "
|
||||
case "${xapian_version}" in
|
||||
0.*|1.[01].*|1.2.[0-5])
|
||||
printf "No (only available with Xapian > 1.2.6).\n" ;;
|
||||
[1-9]*.[0-9]*.[0-9]*)
|
||||
have_xapian_compact=1
|
||||
printf "Yes.\n" ;;
|
||||
*)
|
||||
printf "Unknown version.\n" ;;
|
||||
0.*|1.[01].*|1.2.[0-5])
|
||||
printf "No (only available with Xapian > 1.2.6).\n" ;;
|
||||
[1-9]*.[0-9]*.[0-9]*)
|
||||
have_xapian_compact=1
|
||||
printf "Yes.\n" ;;
|
||||
*)
|
||||
printf "Unknown version.\n" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
# we need to have a version >= 2.6.5 to avoid a crypto bug. We need
|
||||
# 2.6.7 for permissive "From " header handling.
|
||||
GMIME_MINVER=2.6.7
|
||||
|
||||
printf "Checking for GMime development files... "
|
||||
have_gmime=0
|
||||
IFS=';'
|
||||
for gmimepc in $WITH_GMIME_VERSIONS; do
|
||||
if pkg-config --exists $gmimepc; then
|
||||
printf "Yes ($gmimepc).\n"
|
||||
have_gmime=1
|
||||
gmime_cflags=$(pkg-config --cflags $gmimepc)
|
||||
gmime_ldflags=$(pkg-config --libs $gmimepc)
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$DEFAULT_IFS
|
||||
if [ "$have_gmime" = "0" ]; then
|
||||
if pkg-config --exists "gmime-2.6 >= $GMIME_MINVER"; then
|
||||
printf "Yes.\n"
|
||||
have_gmime=1
|
||||
gmime_cflags=$(pkg-config --cflags gmime-2.6)
|
||||
gmime_ldflags=$(pkg-config --libs gmime-2.6)
|
||||
else
|
||||
have_gmime=0
|
||||
printf "No.\n"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
@ -377,7 +439,7 @@ fi
|
|||
printf "Checking for python... "
|
||||
have_python=0
|
||||
|
||||
for name in python python2 python3; do
|
||||
for name in ${PYTHON} python python2 python3; do
|
||||
if command -v $name > /dev/null; then
|
||||
have_python=1
|
||||
python=$name
|
||||
|
@ -434,22 +496,37 @@ else
|
|||
have_emacs=0
|
||||
fi
|
||||
|
||||
printf "Checking if doxygen is available... "
|
||||
if command -v doxygen > /dev/null; then
|
||||
printf "Yes.\n"
|
||||
have_doxygen=1
|
||||
else
|
||||
printf "No (so will not install api docs)\n"
|
||||
have_doxygen=0
|
||||
have_doxygen=0
|
||||
if [ $WITH_DOCS = "1" ] ; then
|
||||
printf "Checking if doxygen is available... "
|
||||
if command -v doxygen > /dev/null; then
|
||||
printf "Yes.\n"
|
||||
have_doxygen=1
|
||||
else
|
||||
printf "No (so will not install api docs)\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "Checking if sphinx is available and supports nroff output... "
|
||||
if command -v sphinx-build > /dev/null && ${python} -m sphinx.writers.manpage > /dev/null 2>&1 ; then
|
||||
printf "Yes.\n"
|
||||
have_sphinx=1
|
||||
else
|
||||
printf "No (so will not install man pages).\n"
|
||||
have_sphinx=0
|
||||
have_ruby_dev=0
|
||||
if [ $WITH_RUBY = "1" ] ; then
|
||||
printf "Checking for ruby development files... "
|
||||
if ruby -e "require 'mkmf'"> /dev/null 2>&1; then
|
||||
printf "Yes.\n"
|
||||
have_ruby_dev=1
|
||||
else
|
||||
printf "No (skipping ruby bindings)\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
have_sphinx=0
|
||||
if [ $WITH_DOCS = "1" ] ; then
|
||||
printf "Checking if sphinx is available and supports nroff output... "
|
||||
if command -v sphinx-build > /dev/null && ${python} -m sphinx.writers.manpage > /dev/null 2>&1 ; then
|
||||
printf "Yes.\n"
|
||||
have_sphinx=1
|
||||
else
|
||||
printf "No (so will not install man pages).\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
libdir_in_ldconfig=0
|
||||
|
@ -542,7 +619,7 @@ EOF
|
|||
echo
|
||||
fi
|
||||
if [ $have_gmime -eq 0 ]; then
|
||||
echo " Either GMime 2.4 library" $GMIME_24_VERSION_CTR "or GMime 2.6 library" $GMIME_26_VERSION_CTR
|
||||
echo " GMime 2.6 library >= $GMIME_MINVER"
|
||||
echo " (including development files such as headers)"
|
||||
echo " http://spruce.sourceforge.net/gmime/"
|
||||
echo
|
||||
|
@ -690,8 +767,6 @@ else
|
|||
fi
|
||||
rm -f compat/check_asctime
|
||||
|
||||
printf "int main(void){return 0;}\n" > minimal.c
|
||||
|
||||
printf "Checking for rpath support... "
|
||||
if ${CC} -Wl,--enable-new-dtags -Wl,-rpath,/tmp/ -o minimal minimal.c >/dev/null 2>&1
|
||||
then
|
||||
|
@ -712,6 +787,16 @@ else
|
|||
as_needed_ldflags=""
|
||||
fi
|
||||
|
||||
printf "Checking for -Wl,--no-undefined... "
|
||||
if ${CC} -Wl,--no-undefined -o minimal minimal.c >/dev/null 2>&1
|
||||
then
|
||||
printf "Yes.\n"
|
||||
no_undefined_ldflags="-Wl,--no-undefined"
|
||||
else
|
||||
printf "No (nothing to worry about).\n"
|
||||
no_undefined_ldflags=""
|
||||
fi
|
||||
|
||||
WARN_CXXFLAGS=""
|
||||
printf "Checking for available C++ compiler warning flags... "
|
||||
for flag in -Wall -Wextra -Wwrite-strings; do
|
||||
|
@ -732,7 +817,7 @@ for flag in -Wmissing-declarations; do
|
|||
done
|
||||
printf "\n\t${WARN_CFLAGS}\n"
|
||||
|
||||
rm -f minimal minimal.c
|
||||
rm -f minimal minimal.c _libversion.c _libversion _libversion.sh
|
||||
|
||||
# construct the Makefile.config
|
||||
cat > Makefile.config <<EOF
|
||||
|
@ -770,6 +855,28 @@ vpath Makefile.% \$(srcdir)
|
|||
vpath %.py \$(srcdir)
|
||||
vpath %.rst \$(srcdir)
|
||||
|
||||
# Library versions (used to make SONAME)
|
||||
# The major version of the library interface. This will control the soname.
|
||||
# As such, this number must be incremented for any incompatible change to
|
||||
# the library interface, (such as the deletion of an API or a major
|
||||
# semantic change that breaks formerly functioning code).
|
||||
#
|
||||
LIBNOTMUCH_VERSION_MAJOR = ${libnotmuch_version_major}
|
||||
|
||||
# The minor version of the library interface. This should be incremented at
|
||||
# the time of release for any additions to the library interface,
|
||||
# (and when it is incremented, the release version of the library should
|
||||
# be reset to 0).
|
||||
LIBNOTMUCH_VERSION_MINOR = ${libnotmuch_version_minor}
|
||||
|
||||
# The release version the library interface. This should be incremented at
|
||||
# the time of release if there have been no changes to the interface, (but
|
||||
# simply compatible changes to the implementation).
|
||||
LIBNOTMUCH_VERSION_RELEASE = ${libnotmuch_version_release}
|
||||
|
||||
# These are derived from the VERSION macros in lib/notmuch.h so
|
||||
# if you have to change them, something is wrong.
|
||||
|
||||
# The C compiler to use
|
||||
CC = ${CC}
|
||||
|
||||
|
@ -858,6 +965,10 @@ HAVE_CANONICALIZE_FILE_NAME = ${have_canonicalize_file_name}
|
|||
# build its own version)
|
||||
HAVE_GETLINE = ${have_getline}
|
||||
|
||||
# Are the ruby development files (and ruby) available? If not skip
|
||||
# building/testing ruby bindings.
|
||||
HAVE_RUBY_DEV = ${have_ruby_dev}
|
||||
|
||||
# Whether the strcasestr function is available (if not, then notmuch will
|
||||
# build its own version)
|
||||
HAVE_STRCASESTR = ${have_strcasestr}
|
||||
|
@ -894,7 +1005,7 @@ LINKER_RESOLVES_LIBRARY_DEPENDENCIES = ${linker_resolves_library_dependencies}
|
|||
XAPIAN_CXXFLAGS = ${xapian_cxxflags}
|
||||
XAPIAN_LDFLAGS = ${xapian_ldflags}
|
||||
|
||||
# Flags needed to compile and link against GMime-2.4
|
||||
# Flags needed to compile and link against GMime
|
||||
GMIME_CFLAGS = ${gmime_cflags}
|
||||
GMIME_LDFLAGS = ${gmime_ldflags}
|
||||
|
||||
|
@ -912,6 +1023,9 @@ RPATH_LDFLAGS = ${rpath_ldflags}
|
|||
# Flags needed to have linker link only to necessary libraries
|
||||
AS_NEEDED_LDFLAGS = ${as_needed_ldflags}
|
||||
|
||||
# Flags to have the linker flag undefined symbols in object files
|
||||
NO_UNDEFINED_LDFLAGS = ${no_undefined_ldflags}
|
||||
|
||||
# Whether valgrind header files are available
|
||||
HAVE_VALGRIND = ${have_valgrind}
|
||||
|
||||
|
@ -970,6 +1084,10 @@ NOTMUCH_HAVE_MAN=$((have_sphinx))
|
|||
|
||||
# Name of python interpreter
|
||||
NOTMUCH_PYTHON=${python}
|
||||
|
||||
# Are the ruby development files (and ruby) available? If not skip
|
||||
# building/testing ruby bindings.
|
||||
NOTMUCH_HAVE_RUBY_DEV=${have_ruby_dev}
|
||||
EOF
|
||||
|
||||
# Finally, after everything configured, inform the user how to continue.
|
||||
|
|
25
crypto.c
25
crypto.c
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include "notmuch-client.h"
|
||||
|
||||
#ifdef GMIME_ATLEAST_26
|
||||
|
||||
/* Create a GPG context (GMime 2.6) */
|
||||
static notmuch_crypto_context_t *
|
||||
create_gpg_context (const char *gpgpath)
|
||||
|
@ -39,29 +37,6 @@ create_gpg_context (const char *gpgpath)
|
|||
return gpgctx;
|
||||
}
|
||||
|
||||
#else /* GMIME_ATLEAST_26 */
|
||||
|
||||
/* Create a GPG context (GMime 2.4) */
|
||||
static notmuch_crypto_context_t *
|
||||
create_gpg_context (const char* gpgpath)
|
||||
{
|
||||
GMimeSession *session;
|
||||
notmuch_crypto_context_t *gpgctx;
|
||||
|
||||
session = g_object_new (g_mime_session_get_type (), NULL);
|
||||
gpgctx = g_mime_gpg_context_new (session, gpgpath ? gpgpath : "gpg");
|
||||
g_object_unref (session);
|
||||
|
||||
if (! gpgctx)
|
||||
return NULL;
|
||||
|
||||
g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) gpgctx, FALSE);
|
||||
|
||||
return gpgctx;
|
||||
}
|
||||
|
||||
#endif /* GMIME_ATLEAST_26 */
|
||||
|
||||
/* for the specified protocol return the context pointer (initializing
|
||||
* if needed) */
|
||||
notmuch_crypto_context_t *
|
||||
|
|
10
debian/NEWS
vendored
10
debian/NEWS
vendored
|
@ -1,3 +1,13 @@
|
|||
notmuch (0.21~rc1-1) experimental; urgency=medium
|
||||
|
||||
* This release of notmuch requires a non-reversible database upgrade
|
||||
to support database revision tracking. This upgrade will happen on
|
||||
the first run of 'notmuch-new' after updating. Notmuch will backup
|
||||
your tags for your before doing the upgrade, but it never hurts to
|
||||
make your own backup with notmuch dump.
|
||||
|
||||
-- David Bremner <bremner@debian.org> Thu, 15 Oct 2015 08:13:04 -0300
|
||||
|
||||
notmuch (0.19-1) experimental; urgency=medium
|
||||
|
||||
* This release of notmuch again requires a non-reversable database
|
||||
|
|
64
debian/changelog
vendored
64
debian/changelog
vendored
|
@ -1,3 +1,67 @@
|
|||
notmuch (0.21-3) unstable; urgency=medium
|
||||
|
||||
* Add mips and mips64el to gdb build-dep blacklist
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sat, 14 Nov 2015 19:07:06 -0400
|
||||
|
||||
notmuch (0.21-2) unstable; urgency=medium
|
||||
|
||||
* Build-conflict with gdb on ppc64el and mipsel. Workaround gdb breakage on those
|
||||
architectures (Closes: #804792).
|
||||
|
||||
-- David Bremner <bremner@debian.org> Thu, 12 Nov 2015 08:54:23 -0400
|
||||
|
||||
notmuch (0.21-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release. Highlights include
|
||||
- revision tracking for metadata
|
||||
- new features and bug fixes for emacs interface
|
||||
See /usr/share/doc/notmuch/NEWS for more details.
|
||||
|
||||
-- David Bremner <bremner@debian.org> Thu, 29 Oct 2015 20:04:42 -0300
|
||||
|
||||
notmuch (0.21~rc3-3) experimental; urgency=medium
|
||||
|
||||
* Build-conflict with gdb-minimal. gdb python scripts are needed for
|
||||
the test suite
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sun, 25 Oct 2015 22:08:56 -0300
|
||||
|
||||
notmuch (0.21~rc3-2) experimental; urgency=medium
|
||||
|
||||
* Bug fix: "reply-to encrypted messages in tree view fails to quote
|
||||
and defaults to unencrypted message", thanks to Vagrant Cascadian
|
||||
(Closes: #795243).
|
||||
* Bug fix: "install/notmuch-emacs may interact with console, fail
|
||||
emacs24 upgrade", thanks to Hilko Bengen (Closes: #802952).
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sun, 25 Oct 2015 13:42:57 -0300
|
||||
|
||||
notmuch (0.21~rc3-1) experimental; urgency=medium
|
||||
|
||||
* New upstream release candidate
|
||||
|
||||
-- David Bremner <bremner@debian.org> Thu, 22 Oct 2015 09:19:02 -0300
|
||||
|
||||
notmuch (0.21~rc2-1) experimental; urgency=medium
|
||||
|
||||
* New upstream release candidate
|
||||
|
||||
-- David Bremner <bremner@debian.org> Mon, 19 Oct 2015 07:25:10 -0300
|
||||
|
||||
notmuch (0.21~rc1-1) experimental; urgency=medium
|
||||
|
||||
* New upstream release candidate
|
||||
|
||||
-- David Bremner <bremner@debian.org> Thu, 15 Oct 2015 08:08:17 -0300
|
||||
|
||||
notmuch (0.20.2-2) unstable; urgency=medium
|
||||
|
||||
* Fix linking in emacsen-install script. The previous version can
|
||||
break an emacs upgrade.
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sat, 26 Sep 2015 09:26:41 -0300
|
||||
|
||||
notmuch (0.20.2-1~bpo8+1) jessie-backports; urgency=medium
|
||||
|
||||
* Rebuild for jessie-backports.
|
||||
|
|
4
debian/control
vendored
4
debian/control
vendored
|
@ -5,7 +5,7 @@ Maintainer: Carl Worth <cworth@debian.org>
|
|||
Uploaders:
|
||||
Jameson Graef Rollins <jrollins@finestructure.net>,
|
||||
David Bremner <bremner@debian.org>
|
||||
Build-Conflicts: ruby1.8
|
||||
Build-Conflicts: ruby1.8, gdb-minimal, gdb [s390x ia64 armel ppc64el mips mipsel mips64el]
|
||||
Build-Depends:
|
||||
debhelper (>= 9),
|
||||
pkg-config,
|
||||
|
@ -20,7 +20,7 @@ Build-Depends:
|
|||
ruby, ruby-dev (>>1:1.9.3~),
|
||||
emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~) |
|
||||
emacs23-nox | emacs23 (>=23~) | emacs23-lucid (>=23~),
|
||||
gdb [!s390x !ia64 !armel],
|
||||
gdb [!s390x !ia64 !armel !ppc64el !mips !mipsel !mips64el],
|
||||
dtach (>= 0.8),
|
||||
bash-completion (>=1.9.0~)
|
||||
Standards-Version: 3.9.6
|
||||
|
|
5
debian/libnotmuch4.symbols
vendored
5
debian/libnotmuch4.symbols
vendored
|
@ -12,6 +12,7 @@ libnotmuch.so.4 libnotmuch4 #MINVER#
|
|||
notmuch_database_get_all_tags@Base 0.3
|
||||
notmuch_database_get_directory@Base 0.3
|
||||
notmuch_database_get_path@Base 0.3
|
||||
notmuch_database_get_revision@Base 0.21~rc1
|
||||
notmuch_database_get_version@Base 0.3
|
||||
notmuch_database_needs_upgrade@Base 0.3
|
||||
notmuch_database_open@Base 0.3
|
||||
|
@ -19,6 +20,7 @@ libnotmuch.so.4 libnotmuch4 #MINVER#
|
|||
notmuch_database_remove_message@Base 0.3
|
||||
notmuch_database_status_string@Base 0.20~rc1
|
||||
notmuch_database_upgrade@Base 0.3
|
||||
notmuch_directory_delete@Base 0.21~rc1
|
||||
notmuch_directory_destroy@Base 0.3
|
||||
notmuch_directory_get_child_directories@Base 0.3
|
||||
notmuch_directory_get_child_files@Base 0.3
|
||||
|
@ -53,9 +55,12 @@ libnotmuch.so.4 libnotmuch4 #MINVER#
|
|||
notmuch_messages_valid@Base 0.3
|
||||
notmuch_query_add_tag_exclude@Base 0.12~rc1
|
||||
notmuch_query_count_messages@Base 0.3
|
||||
notmuch_query_count_messages_st@Base 0.21~rc1
|
||||
notmuch_query_count_threads@Base 0.10~rc1
|
||||
notmuch_query_count_threads_st@Base 0.21~rc1
|
||||
notmuch_query_create@Base 0.3
|
||||
notmuch_query_destroy@Base 0.3
|
||||
notmuch_query_get_database@Base 0.21~rc1
|
||||
notmuch_query_get_query_string@Base 0.4
|
||||
notmuch_query_get_sort@Base 0.4
|
||||
notmuch_query_search_messages@Base 0.3
|
||||
|
|
4
debian/notmuch-emacs.emacsen-install
vendored
4
debian/notmuch-emacs.emacsen-install
vendored
|
@ -31,7 +31,7 @@ echo install/${PACKAGE}: byte-compiling for ${FLAVOR}
|
|||
# Create symlinks to the .el files (see section 6E in debian-emacs
|
||||
# polcy). This makes complation easy, and also allows find-function
|
||||
# and find-library to work properly.
|
||||
(cd ${elc_dir} && cp -s ${el_dir}/*.el .)
|
||||
(cd ${elc_dir} && ln -sf ${el_dir}/*.el .)
|
||||
|
||||
# Byte compile them
|
||||
(cd ${elc_dir}
|
||||
|
@ -43,6 +43,6 @@ echo install/${PACKAGE}: byte-compiling for ${FLAVOR}
|
|||
exit 1
|
||||
fi
|
||||
set -e
|
||||
gzip -9 Install.log)
|
||||
gzip -9f Install.log)
|
||||
|
||||
exit 0;
|
||||
|
|
1
debian/rules
vendored
1
debian/rules
vendored
|
@ -19,7 +19,6 @@ override_dh_auto_build:
|
|||
dh_auto_build -- V=1
|
||||
dh_auto_build --sourcedirectory bindings/python
|
||||
cd bindings/python && $(python3_all) setup.py build
|
||||
cd bindings/ruby && ruby extconf.rb --vendor && make
|
||||
$(MAKE) -C contrib/notmuch-mutt
|
||||
|
||||
override_dh_auto_clean:
|
||||
|
|
10
devel/STYLE
10
devel/STYLE
|
@ -93,3 +93,13 @@ libnotmuch conventions
|
|||
|
||||
* Code which needs to be accessed from both the CLI and from
|
||||
libnotmuch should be factored out into libutil (under util/).
|
||||
|
||||
* Deprecated functions should be marked with the NOTMUCH_DEPRECATED
|
||||
macro which generates run time warnings with gcc and clang. In order
|
||||
not to confuse doxygen this should go at the beginning of the
|
||||
declaration like:
|
||||
|
||||
NOTMUCH_DEPRECATED(major,minor) notmuch_status_t notmuch_dwim(void *arg);
|
||||
|
||||
The @deprecated doxygen command can be used to generate markup in
|
||||
the API docs.
|
||||
|
|
|
@ -79,7 +79,7 @@ while getopts v:c:s: opt; do
|
|||
done
|
||||
shift `expr $OPTIND - 1`
|
||||
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
SHORT_CORPUS=$(basename ${CORPUS:-database})
|
||||
DBNAME=${SHORT_CORPUS}${SUFFIX}
|
||||
|
|
|
@ -156,11 +156,20 @@ class Page (object):
|
|||
stream.write(self.footer)
|
||||
|
||||
def _write_view(self, database, view, stream):
|
||||
# sort order, default to oldest-first
|
||||
sort_key = view.get('sort', 'oldest-first')
|
||||
# dynamically accept all values in Query.SORT
|
||||
sort_attribute = sort_key.upper().replace('-', '_')
|
||||
try:
|
||||
sort = getattr(notmuch.Query.SORT, sort_attribute)
|
||||
except AttributeError:
|
||||
raise ConfigError('Invalid sort setting for {}: {!r}'.format(
|
||||
view['title'], sort_key))
|
||||
if 'query-string' not in view:
|
||||
query = view['query']
|
||||
view['query-string'] = ' and '.join(query)
|
||||
q = notmuch.Query(database, view['query-string'])
|
||||
q.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
|
||||
q.set_sort(sort)
|
||||
threads = self._get_threads(messages=q.search_messages())
|
||||
self._write_view_header(view=view, stream=stream)
|
||||
self._write_threads(threads=threads, stream=stream)
|
||||
|
@ -309,7 +318,7 @@ args = parser.parse_args()
|
|||
try:
|
||||
config = read_config(path=args.config)
|
||||
except ConfigError as e:
|
||||
print(e)
|
||||
print(e, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
header_template = config['meta'].get('header', '''<!DOCTYPE html>
|
||||
|
|
|
@ -59,6 +59,17 @@ readonly VERSION
|
|||
|
||||
# In the rest of this file, tests collect list of errors to be fixed
|
||||
|
||||
echo -n "Checking that git working directory is clean... "
|
||||
git_status=`git status --porcelain`
|
||||
if [ "$git_status" = '' ]
|
||||
then
|
||||
echo Yes.
|
||||
else
|
||||
echo No.
|
||||
append_emsg "Git working directory is not clean (git status --porcelain)."
|
||||
fi
|
||||
unset git_status
|
||||
|
||||
verfail ()
|
||||
{
|
||||
echo No.
|
||||
|
@ -77,38 +88,6 @@ case $VERSION in
|
|||
*) verfail "'$VERSION' is a single number" ;;
|
||||
esac
|
||||
|
||||
echo -n "Checking that LIBNOTMUCH version macros & variables match ... "
|
||||
# lib/notmuch.h
|
||||
LIBNOTMUCH_MAJOR_VERSION=broken
|
||||
LIBNOTMUCH_MINOR_VERSION=broken
|
||||
LIBNOTMUCH_MICRO_VERSION=broken
|
||||
# lib/Makefile.local
|
||||
LIBNOTMUCH_VERSION_MAJOR=borken
|
||||
LIBNOTMUCH_VERSION_MINOR=borken
|
||||
LIBNOTMUCH_VERSION_RELEASE=borken
|
||||
|
||||
eval `awk 'NF == 3 && $1 == "#define" && $2 ~ /^LIBNOTMUCH_[A-Z]+_VERSION$/ \
|
||||
&& $3 ~ /^[0-9]+$/ { print $2 "=" $3 }' lib/notmuch.h`
|
||||
|
||||
eval `awk 'NF == 3 && $1 ~ /^LIBNOTMUCH_VERSION_[A-Z]+$/ && $2 == "=" \
|
||||
&& $3 ~ /^[0-9]+$/ { print $1 "=" $3 }' lib/Makefile.local`
|
||||
|
||||
|
||||
check_version_component ()
|
||||
{
|
||||
eval local v1=\$LIBNOTMUCH_$1_VERSION
|
||||
eval local v2=\$LIBNOTMUCH_VERSION_$2
|
||||
if [ $v1 != $v2 ]
|
||||
then append_emsg "LIBNOTMUCH_$1_VERSION ($v1) does not equal LIBNOTMUCH_VERSION_$2 ($v2)"
|
||||
fi
|
||||
}
|
||||
|
||||
old_emsg_count=$emsg_count
|
||||
check_version_component MAJOR MAJOR
|
||||
check_version_component MINOR MINOR
|
||||
check_version_component MICRO RELEASE
|
||||
[ $old_emsg_count = $emsg_count ] && echo Yes. || echo No.
|
||||
|
||||
echo -n "Checking that this is Debian package for notmuch... "
|
||||
read deb_notmuch deb_version rest < debian/changelog
|
||||
if [ "$deb_notmuch" = 'notmuch' ]
|
||||
|
@ -130,7 +109,7 @@ else
|
|||
fi
|
||||
|
||||
echo -n "Checking that python bindings version is $VERSION... "
|
||||
py_version=`python -c "with open('$PV_FILE') as vf: exec(vf.read()); print __VERSION__"`
|
||||
py_version=`python -c "with open('$PV_FILE') as vf: exec(vf.read()); print(__VERSION__)"`
|
||||
if [ "$py_version" = "$VERSION" ]
|
||||
then
|
||||
echo Yes.
|
||||
|
|
|
@ -7,7 +7,7 @@ SPHINXOPTS := -q
|
|||
SPHINXBUILD = sphinx-build
|
||||
DOCBUILDDIR := $(dir)/_build
|
||||
|
||||
mkdocdeps := python $(srcdir)/$(dir)/mkdocdeps.py
|
||||
mkdocdeps := $(PYTHON) $(srcdir)/$(dir)/mkdocdeps.py
|
||||
|
||||
# Internal variables.
|
||||
ALLSPHINXOPTS := -d $(DOCBUILDDIR)/doctrees $(SPHINXOPTS) $(srcdir)/$(dir)
|
||||
|
|
|
@ -12,7 +12,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'notmuch'
|
||||
copyright = u'2014, Carl Worth and many others'
|
||||
copyright = u'2009-2015, Carl Worth and many others'
|
||||
|
||||
location = os.path.dirname(__file__)
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ STRICT_PROTO_MATCHING = NO
|
|||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = NO
|
||||
|
|
|
@ -55,6 +55,28 @@ Supported options for **address** include
|
|||
Note: With this option, addresses are printed only after
|
||||
the whole search is finished. This may take long time.
|
||||
|
||||
``--deduplicate=(no|mailbox|address)``
|
||||
|
||||
Control the deduplication of results.
|
||||
|
||||
**no**
|
||||
Output all occurences of addresses in the matching
|
||||
messages. This is not applicable with --output=count.
|
||||
|
||||
**mailbox**
|
||||
Deduplicate addresses based on the full, case sensitive
|
||||
name and email address, or mailbox. This is effectively
|
||||
the same as piping the --deduplicate=no output to **sort |
|
||||
uniq**, except for the order of results. This is the
|
||||
default.
|
||||
|
||||
**address**
|
||||
Deduplicate addresses based on the case insensitive
|
||||
address part of the mailbox. Of all the variants (with
|
||||
different name or case), print the one occurring most
|
||||
frequently among the matching messages. If --output=count
|
||||
is specified, include all variants in the count.
|
||||
|
||||
``--sort=``\ (**newest-first**\ \|\ **oldest-first**)
|
||||
This option can be used to present results in either
|
||||
chronological order (**oldest-first**) or reverse chronological
|
||||
|
@ -63,7 +85,9 @@ Supported options for **address** include
|
|||
By default, results will be displayed in reverse chronological
|
||||
order, (that is, the newest results will be displayed first).
|
||||
|
||||
This option is not supported with --output=count.
|
||||
However, if either --output=count or --deduplicate=address is
|
||||
specified, this option is ignored and the order of the results
|
||||
is unspecified.
|
||||
|
||||
``--exclude=(true|false)``
|
||||
A message is called "excluded" if it matches at least one tag in
|
||||
|
|
|
@ -47,6 +47,11 @@ Supported options for **count** include
|
|||
(or threads) in the database will be output. This option is not
|
||||
compatible with specifying search terms on the command line.
|
||||
|
||||
``--lastmod``
|
||||
Append lastmod (counter for number of database updates) and UUID
|
||||
to the output. lastmod values are only comparable between databases
|
||||
with the same UUID.
|
||||
|
||||
``--input=``\ <filename>
|
||||
Read input from given file, instead of from stdin. Implies
|
||||
``--batch``.
|
||||
|
|
|
@ -18,10 +18,6 @@ Supported options for **notmuch-emacs-mua** include
|
|||
``-h, --help``
|
||||
Display help.
|
||||
|
||||
``--client``
|
||||
Use emacsclient, rather than emacs. This will start
|
||||
an emacs daemon process if necessary.
|
||||
|
||||
``-s, --subject=``\ <subject>
|
||||
Specify the subject of the message.
|
||||
|
||||
|
@ -38,7 +34,23 @@ Supported options for **notmuch-emacs-mua** include
|
|||
Specify a file to include into the body of the message.
|
||||
|
||||
``--no-window-system``
|
||||
Even if a window system is available, use the current terminal
|
||||
Even if a window system is available, use the current terminal.
|
||||
|
||||
``--client``
|
||||
Use **emacsclient**, rather than **emacs**. For
|
||||
**emacsclient** to work, you need an already running Emacs
|
||||
with a server, or use ``--auto-daemon``.
|
||||
|
||||
``--auto-daemon``
|
||||
Automatically start Emacs in daemon mode, if the Emacs server
|
||||
is not running. Applicable with ``--client``. Implies
|
||||
``--create-frame``.
|
||||
|
||||
``--create-frame``
|
||||
Create a new frame instead of trying to use the current Emacs
|
||||
frame. Applicable with ``--client``. This will be required
|
||||
when Emacs is running (or automatically started with
|
||||
``--auto-daemon``) in daemon mode.
|
||||
|
||||
``--print``
|
||||
Output the resulting elisp to stdout instead of evaluating it.
|
||||
|
|
|
@ -39,15 +39,28 @@ OPTIONS
|
|||
|
||||
Supported global options for ``notmuch`` include
|
||||
|
||||
``--help``
|
||||
Print a synopsis of available commands and exit.
|
||||
``--help`` [command-name]
|
||||
Print a synopsis of available commands and exit.
|
||||
With an optional command name, show the man page
|
||||
for that subcommand.
|
||||
|
||||
``--version``
|
||||
Print the installed version of notmuch, and exit.
|
||||
Print the installed version of notmuch, and exit.
|
||||
|
||||
``--config=FILE``
|
||||
Specify the configuration file to use. This overrides any
|
||||
configuration file specified by ${NOTMUCH\_CONFIG}.
|
||||
Specify the configuration file to use. This overrides any
|
||||
configuration file specified by ${NOTMUCH\_CONFIG}.
|
||||
|
||||
``--uuid=HEX``
|
||||
Enforce that the database UUID (a unique identifier which
|
||||
persists until e.g. the database is compacted)
|
||||
is HEX; exit with an error if it is not. This is useful to
|
||||
detect rollover in modification counts on messages. You can
|
||||
find this UUID using e.g. ``notmuch count --lastmod``
|
||||
|
||||
All global options except ``--config`` can also be specified after the
|
||||
command. For example, ``notmuch subcommand --uuid=HEX`` is
|
||||
equivalent to ``notmuch --uuid=HEX subcommand``.
|
||||
|
||||
COMMANDS
|
||||
========
|
||||
|
|
|
@ -54,6 +54,8 @@ indicate user-supplied values):
|
|||
|
||||
- date:<since>..<until>
|
||||
|
||||
- lastmod:<initial-revision>..<final-revision>
|
||||
|
||||
The **from:** prefix is used to match the name or address of the sender
|
||||
of an email message.
|
||||
|
||||
|
@ -124,6 +126,12 @@ The time range can also be specified using timestamps with a syntax of:
|
|||
Each timestamp is a number representing the number of seconds since
|
||||
1970-01-01 00:00:00 UTC.
|
||||
|
||||
The **lastmod:** prefix can be used to restrict the result by the
|
||||
database revision number of when messages were last modified (tags
|
||||
were added/removed or filenames changed). This is usually used in
|
||||
conjunction with the **--uuid** argument to **notmuch search**
|
||||
to find messages that have changed since an earlier query.
|
||||
|
||||
Operators
|
||||
---------
|
||||
|
||||
|
@ -270,6 +278,13 @@ In this case, <since> is taken as the earliest time it could describe
|
|||
could describe (the end of yesterday). Similarly, date:january..february
|
||||
matches from the beginning of January to the end of February.
|
||||
|
||||
date:<expr>..! can be used as a shorthand for date:<expr>..<expr>. The
|
||||
expansion takes place before interpretation, and thus, for example,
|
||||
date:monday..! matches from the beginning of Monday until the end of
|
||||
Monday. (Note that entering date:<expr> without "..", for example
|
||||
date:yesterday, won't work, as it's not interpreted as a range
|
||||
expression at all. Again, use date:yesterday..!)
|
||||
|
||||
Currently, we do not support spaces in range expressions. You can
|
||||
replace the spaces with '\_', or (in most cases) '-', or (in some cases)
|
||||
leave the spaces out altogether. Examples in this man page use spaces
|
||||
|
@ -280,11 +295,6 @@ to specify date:..<until> or date:<since>.. to not limit the start or
|
|||
end time, respectively. Pre-1.2.1 Xapian does not report an error on
|
||||
open ended ranges, but it does not work as expected either.
|
||||
|
||||
Entering date:expr without ".." (for example date:yesterday) won't work,
|
||||
as it's not interpreted as a range expression at all. You can achieve
|
||||
the expected result by duplicating the expr both sides of ".." (for
|
||||
example date:yesterday..yesterday).
|
||||
|
||||
Relative date and time
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
(declare-function notmuch-search "notmuch" (&optional query oldest-first target-thread target-line continuation))
|
||||
(declare-function notmuch-poll "notmuch" ())
|
||||
(declare-function notmuch-tree "notmuch-tree"
|
||||
(&optional query query-context target buffer-name open-target))
|
||||
|
||||
(defun notmuch-saved-search-get (saved-search field)
|
||||
"Get FIELD from SAVED-SEARCH.
|
||||
|
@ -91,7 +93,11 @@ searches so they still work in customize."
|
|||
(choice :tag " Sort Order"
|
||||
(const :tag "Default" nil)
|
||||
(const :tag "Oldest-first" oldest-first)
|
||||
(const :tag "Newest-first" newest-first))))))
|
||||
(const :tag "Newest-first" newest-first)))
|
||||
(group :format "%v" :inline t (const :format "" :search-type)
|
||||
(choice :tag " Search Type"
|
||||
(const :tag "Search mode" nil)
|
||||
(const :tag "Tree mode" tree))))))
|
||||
|
||||
(defcustom notmuch-saved-searches
|
||||
`((:name "inbox" :query "tag:inbox" :key ,(kbd "i"))
|
||||
|
@ -114,6 +120,10 @@ a plist. Supported properties are
|
|||
:sort-order Specify the sort order to be used for the search.
|
||||
Possible values are 'oldest-first 'newest-first or
|
||||
nil. Nil means use the default sort order.
|
||||
:search-type Specify whether to run the search in search-mode
|
||||
or tree mode. Set to 'tree to specify tree
|
||||
mode, set to nil (or anything except tree) to
|
||||
specify search mode.
|
||||
|
||||
Other accepted forms are a cons cell of the form (NAME . QUERY)
|
||||
or a list of the form (NAME QUERY COUNT-QUERY)."
|
||||
|
@ -425,10 +435,13 @@ diagonal."
|
|||
append (notmuch-hello-reflect-generate-row ncols nrows row list))))
|
||||
|
||||
(defun notmuch-hello-widget-search (widget &rest ignore)
|
||||
(notmuch-search (widget-get widget
|
||||
:notmuch-search-terms)
|
||||
(widget-get widget
|
||||
:notmuch-search-oldest-first)))
|
||||
(if (widget-get widget :notmuch-search-type)
|
||||
(notmuch-tree (widget-get widget
|
||||
:notmuch-search-terms))
|
||||
(notmuch-search (widget-get widget
|
||||
:notmuch-search-terms)
|
||||
(widget-get widget
|
||||
:notmuch-search-oldest-first))))
|
||||
|
||||
(defun notmuch-saved-search-count (search)
|
||||
(car (process-lines notmuch-command "count" search)))
|
||||
|
@ -564,6 +577,7 @@ with `notmuch-hello-query-counts'."
|
|||
(newest-first nil)
|
||||
(oldest-first t)
|
||||
(otherwise notmuch-search-oldest-first)))
|
||||
(search-type (eq (plist-get elem :search-type) 'tree))
|
||||
(msg-count (plist-get elem :count)))
|
||||
(widget-insert (format "%8s "
|
||||
(notmuch-hello-nice-number msg-count)))
|
||||
|
@ -571,6 +585,7 @@ with `notmuch-hello-query-counts'."
|
|||
:notify #'notmuch-hello-widget-search
|
||||
:notmuch-search-terms query
|
||||
:notmuch-search-oldest-first oldest-first
|
||||
:notmuch-search-type search-type
|
||||
name)
|
||||
(setq column-indent
|
||||
(1+ (max 0 (- column-width (length name)))))))
|
||||
|
@ -628,7 +643,7 @@ with `notmuch-hello-query-counts'."
|
|||
(defun notmuch-hello-versions ()
|
||||
"Display the notmuch version(s)"
|
||||
(interactive)
|
||||
(let ((notmuch-cli-version (notmuch-version)))
|
||||
(let ((notmuch-cli-version (notmuch-cli-version)))
|
||||
(message "notmuch version %s"
|
||||
(if (string= notmuch-emacs-version notmuch-cli-version)
|
||||
notmuch-cli-version
|
||||
|
|
|
@ -54,7 +54,9 @@ fast way to jump to a saved search from anywhere in Notmuch."
|
|||
(oldest-first t)
|
||||
(otherwise (default-value 'notmuch-search-oldest-first)))))
|
||||
(push (list key name
|
||||
`(lambda () (notmuch-search ',query ',oldest-first)))
|
||||
(if (eq (plist-get saved-search :search-type) 'tree)
|
||||
`(lambda () (notmuch-tree ',query))
|
||||
`(lambda () (notmuch-search ',query ',oldest-first))))
|
||||
action-map)))))
|
||||
(setq action-map (nreverse action-map))
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
(require 'mm-decode)
|
||||
(require 'cl)
|
||||
|
||||
(unless (require 'notmuch-version nil t)
|
||||
(defconst notmuch-emacs-version "unknown"
|
||||
"Placeholder variable when notmuch-version.el[c] is not available."))
|
||||
|
||||
(autoload 'notmuch-jump-search "notmuch-jump"
|
||||
"Jump to a saved search by shortcut key." t)
|
||||
|
||||
|
@ -192,8 +196,8 @@ Otherwise the output will be returned"
|
|||
"Perhaps you haven't run \"notmuch setup\" yet? Try running this
|
||||
on the command line, and then retry your notmuch command")))
|
||||
|
||||
(defun notmuch-version ()
|
||||
"Return a string with the notmuch version number."
|
||||
(defun notmuch-cli-version ()
|
||||
"Return a string with the notmuch cli command version number."
|
||||
(let ((long-string
|
||||
;; Trim off the trailing newline.
|
||||
(substring (notmuch-command-to-string "--version") 0 -1)))
|
||||
|
|
|
@ -59,23 +59,19 @@ yet when sending a mail."
|
|||
:require 'notmuch-fcc-initialization
|
||||
:group 'notmuch-send)
|
||||
|
||||
(defun notmuch-fcc-initialization ()
|
||||
"If notmuch-fcc-directories is set,
|
||||
hook them into the message-fcc-handler-function"
|
||||
;; Set up the message-fcc-handler to move mails to the maildir in Fcc
|
||||
;; The parameter is set to mark messages as "seen"
|
||||
(setq message-fcc-handler-function
|
||||
(lambda (destdir)
|
||||
(notmuch-maildir-fcc-write-buffer-to-maildir destdir t)))
|
||||
;; add a hook to actually insert the Fcc header when sending
|
||||
(add-hook 'message-header-setup-hook 'notmuch-fcc-header-setup))
|
||||
(defun notmuch-fcc-handler (destdir)
|
||||
"Write buffer to `destdir', marking it as sent
|
||||
|
||||
Intended to be dynamically bound to `message-fcc-handler-function'"
|
||||
(notmuch-maildir-fcc-write-buffer-to-maildir destdir t))
|
||||
|
||||
(defun notmuch-fcc-header-setup ()
|
||||
"Add an Fcc header to the current message buffer.
|
||||
|
||||
Can be added to `message-send-hook' and will set the Fcc header
|
||||
based on the values of `notmuch-fcc-dirs'. An existing Fcc header
|
||||
will NOT be removed or replaced."
|
||||
Sets the Fcc header based on the values of `notmuch-fcc-dirs'.
|
||||
|
||||
Originally intended to be use a hook function, but now called directly
|
||||
by notmuch-mua-mail"
|
||||
|
||||
(let ((subdir
|
||||
(cond
|
||||
|
@ -213,6 +209,5 @@ return t if successful, and nil otherwise."
|
|||
(delete-file (concat destdir "/tmp/" msg-id))))
|
||||
t)))
|
||||
|
||||
(notmuch-fcc-initialization)
|
||||
(provide 'notmuch-maildir-fcc)
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ window/frame that will be destroyed when the buffer is killed.
|
|||
You may want to customize `message-kill-buffer-on-exit'
|
||||
accordingly."
|
||||
(when (< emacs-major-version 24)
|
||||
" Due to a known bug in Emacs 23, you should not set
|
||||
" Due to a known bug in Emacs 23, you should not set
|
||||
this to `new-window' if `message-kill-buffer-on-exit' is
|
||||
disabled: this would result in an incorrect behavior."))
|
||||
:group 'notmuch-send
|
||||
|
@ -118,7 +118,10 @@ Note that these functions use `mail-citation-hook' if that is non-nil."
|
|||
|
||||
(defun notmuch-mua-user-agent-notmuch ()
|
||||
"Generate a `User-Agent:' string suitable for notmuch."
|
||||
(concat "Notmuch/" (notmuch-version) " (http://notmuchmail.org)"))
|
||||
(let ((notmuch-version (if (string= notmuch-emacs-version "unknown")
|
||||
(notmuch-cli-version)
|
||||
notmuch-emacs-version)))
|
||||
(concat "Notmuch/" notmuch-version " (http://notmuchmail.org)")))
|
||||
|
||||
(defun notmuch-mua-user-agent-emacs ()
|
||||
"Generate a `User-Agent:' string suitable for notmuch."
|
||||
|
@ -265,6 +268,12 @@ Note that these functions use `mail-citation-hook' if that is non-nil."
|
|||
(message-goto-body)
|
||||
(set-buffer-modified-p nil))
|
||||
|
||||
(define-derived-mode notmuch-message-mode message-mode "Message[Notmuch]"
|
||||
"Notmuch message composition mode. Mostly like `message-mode'")
|
||||
|
||||
(define-key notmuch-message-mode-map (kbd "C-c C-c") #'notmuch-mua-send-and-exit)
|
||||
(define-key notmuch-message-mode-map (kbd "C-c C-s") #'notmuch-mua-send)
|
||||
|
||||
(defun notmuch-mua-mail (&optional to subject other-headers &rest other-args)
|
||||
"Invoke the notmuch mail composition window.
|
||||
|
||||
|
@ -281,6 +290,8 @@ OTHER-ARGS are passed through to `message-mail'."
|
|||
(notmuch-user-name) " <" (notmuch-user-primary-email) ">")) other-headers))
|
||||
|
||||
(apply #'message-mail to subject other-headers other-args)
|
||||
(notmuch-message-mode)
|
||||
(notmuch-fcc-header-setup)
|
||||
(message-sort-headers)
|
||||
(message-hide-headers)
|
||||
(set-buffer-modified-p nil)
|
||||
|
@ -394,7 +405,13 @@ will be addressed to all recipients of the source message."
|
|||
|
||||
(defun notmuch-mua-send-and-exit (&optional arg)
|
||||
(interactive "P")
|
||||
(message-send-and-exit arg))
|
||||
(let ((message-fcc-handler-function #'notmuch-fcc-handler))
|
||||
(message-send-and-exit arg)))
|
||||
|
||||
(defun notmuch-mua-send (&optional arg)
|
||||
(interactive "P")
|
||||
(let ((message-fcc-handler-function #'notmuch-fcc-handler))
|
||||
(message-send arg)))
|
||||
|
||||
(defun notmuch-mua-kill-buffer ()
|
||||
(interactive)
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
(declare-function notmuch-tree "notmuch-tree"
|
||||
(&optional query query-context target buffer-name open-target))
|
||||
(declare-function notmuch-tree-get-message-properties "notmuch-tree" nil)
|
||||
(declare-function notmuch-read-query "notmuch" (prompt))
|
||||
|
||||
(defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
|
||||
"Headers that should be shown in a message, in this order.
|
||||
|
@ -99,7 +100,7 @@ visible for any given message."
|
|||
:group 'notmuch-show
|
||||
:group 'notmuch-hooks)
|
||||
|
||||
(defcustom notmuch-show-max-text-part-size 10000
|
||||
(defcustom notmuch-show-max-text-part-size 100000
|
||||
"Maximum size of a text part to be shown by default in characters.
|
||||
|
||||
Set to 0 to show the part regardless of size."
|
||||
|
@ -1281,6 +1282,16 @@ This includes:
|
|||
")")
|
||||
notmuch-show-thread-id))
|
||||
|
||||
(defun notmuch-show-goto-message (msg-id)
|
||||
"Go to message with msg-id."
|
||||
(goto-char (point-min))
|
||||
(unless (loop if (string= msg-id (notmuch-show-get-message-id))
|
||||
return t
|
||||
until (not (notmuch-show-goto-message-next)))
|
||||
(goto-char (point-min))
|
||||
(message "Message-id not found."))
|
||||
(notmuch-show-message-adjust))
|
||||
|
||||
(defun notmuch-show-apply-state (state)
|
||||
"Apply STATE to the current buffer.
|
||||
|
||||
|
@ -1298,13 +1309,7 @@ This includes:
|
|||
until (not (notmuch-show-goto-message-next)))
|
||||
|
||||
;; Go to the previously open message.
|
||||
(goto-char (point-min))
|
||||
(unless (loop if (string= current (notmuch-show-get-message-id))
|
||||
return t
|
||||
until (not (notmuch-show-goto-message-next)))
|
||||
(goto-char (point-min))
|
||||
(message "Previously current message not found."))
|
||||
(notmuch-show-message-adjust)))
|
||||
(notmuch-show-goto-message current)))
|
||||
|
||||
(defun notmuch-show-refresh-view (&optional reset-state)
|
||||
"Refresh the current view.
|
||||
|
@ -1368,6 +1373,7 @@ reset based on the original query."
|
|||
(define-key map (kbd "<backtab>") 'notmuch-show-previous-button)
|
||||
(define-key map (kbd "TAB") 'notmuch-show-next-button)
|
||||
(define-key map "f" 'notmuch-show-forward-message)
|
||||
(define-key map "l" 'notmuch-show-filter-thread)
|
||||
(define-key map "r" 'notmuch-show-reply-sender)
|
||||
(define-key map "R" 'notmuch-show-reply)
|
||||
(define-key map "|" 'notmuch-show-pipe-message)
|
||||
|
@ -1656,6 +1662,16 @@ user decision and we should not override it."
|
|||
(save-excursion
|
||||
(funcall notmuch-show-mark-read-function (window-start) (window-end)))))
|
||||
|
||||
(defun notmuch-show-filter-thread (query)
|
||||
"Filter or LIMIT the current thread based on a new query string.
|
||||
|
||||
Reshows the current thread with matches defined by the new query-string."
|
||||
(interactive (list (notmuch-read-query "Filter thread: ")))
|
||||
(let ((msg-id (notmuch-show-get-message-id)))
|
||||
(setq notmuch-show-query-context (if (string= query "") nil query))
|
||||
(notmuch-show-refresh-view t)
|
||||
(notmuch-show-goto-message msg-id)))
|
||||
|
||||
;; Functions for getting attributes of several messages in the current
|
||||
;; thread.
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ changed (the normal case) are shown using formats from
|
|||
(defcustom notmuch-before-tag-hook nil
|
||||
"Hooks that are run before tags of a message are modified.
|
||||
|
||||
'tags' will contain the tags that are about to be added or removed as
|
||||
'tag-changes' will contain the tags that are about to be added or removed as
|
||||
a list of strings of the form \"+TAG\" or \"-TAG\".
|
||||
'query' will be a string containing the search query that determines
|
||||
the messages that are about to be tagged"
|
||||
|
@ -277,7 +277,7 @@ the messages that are about to be tagged"
|
|||
(defcustom notmuch-after-tag-hook nil
|
||||
"Hooks that are run after tags of a message are modified.
|
||||
|
||||
'tags' will contain the tags that were added or removed as
|
||||
'tag-changes' will contain the tags that were added or removed as
|
||||
a list of strings of the form \"+TAG\" or \"-TAG\".
|
||||
'query' will be a string containing the search query that determines
|
||||
the messages that were tagged"
|
||||
|
|
|
@ -240,6 +240,8 @@ FUNC."
|
|||
;; Override because we want to close message pane first.
|
||||
(define-key map [remap notmuch-mua-new-mail] (notmuch-tree-close-message-pane-and #'notmuch-mua-new-mail))
|
||||
|
||||
(define-key map "S" 'notmuch-search-from-tree-current-query)
|
||||
|
||||
;; these use notmuch-show functions directly
|
||||
(define-key map "|" 'notmuch-show-pipe-message)
|
||||
(define-key map "w" 'notmuch-show-save-attachments)
|
||||
|
@ -402,6 +404,12 @@ Does NOT change the database."
|
|||
(notmuch-tree-close-message-window)
|
||||
(notmuch-tree query)))
|
||||
|
||||
(defun notmuch-search-from-tree-current-query ()
|
||||
"Call notmuch search with the current query"
|
||||
(interactive)
|
||||
(notmuch-tree-close-message-window)
|
||||
(notmuch-search (notmuch-tree-get-query)))
|
||||
|
||||
(defun notmuch-tree-message-window-kill-hook ()
|
||||
"Close the message pane when exiting the show buffer."
|
||||
(let ((buffer (current-buffer)))
|
||||
|
@ -867,6 +875,11 @@ the same as for the function notmuch-tree."
|
|||
(setq notmuch-tree-query-context query-context)
|
||||
(setq notmuch-tree-target-msg target)
|
||||
(setq notmuch-tree-open-target open-target)
|
||||
;; Set the default value for `notmuch-show-process-crypto' in this
|
||||
;; buffer. Although we don't use this some of the functions we call
|
||||
;; (such as reply) do. It is a buffer local variable so setting it
|
||||
;; will not affect genuine show buffers.
|
||||
(setq notmuch-show-process-crypto notmuch-crypto-process-mime)
|
||||
|
||||
(erase-buffer)
|
||||
(goto-char (point-min))
|
||||
|
|
|
@ -61,10 +61,6 @@
|
|||
(require 'notmuch-message)
|
||||
(require 'notmuch-parser)
|
||||
|
||||
(unless (require 'notmuch-version nil t)
|
||||
(defconst notmuch-emacs-version "unknown"
|
||||
"Placeholder variable when notmuch-version.el[c] is not available."))
|
||||
|
||||
(defcustom notmuch-search-result-format
|
||||
`(("date" . "%12s ")
|
||||
("count" . "%-7s ")
|
||||
|
@ -181,6 +177,7 @@ there will be called at other points of notmuch execution."
|
|||
(defvar notmuch-search-stash-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "i" 'notmuch-search-stash-thread-id)
|
||||
(define-key map "q" 'notmuch-stash-query)
|
||||
(define-key map "?" 'notmuch-subkeymap-help)
|
||||
map)
|
||||
"Submap for stash commands")
|
||||
|
@ -191,6 +188,11 @@ there will be called at other points of notmuch execution."
|
|||
(interactive)
|
||||
(notmuch-common-do-stash (notmuch-search-find-thread-id)))
|
||||
|
||||
(defun notmuch-stash-query ()
|
||||
"Copy current query to kill-ring."
|
||||
(interactive)
|
||||
(notmuch-common-do-stash (notmuch-search-get-query)))
|
||||
|
||||
(defvar notmuch-search-query-string)
|
||||
(defvar notmuch-search-target-thread)
|
||||
(defvar notmuch-search-target-line)
|
||||
|
@ -855,13 +857,15 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
|
|||
"Read a notmuch-query from the minibuffer with completion.
|
||||
|
||||
PROMPT is the string to prompt with."
|
||||
(lexical-let
|
||||
((completions
|
||||
(append (list "folder:" "path:" "thread:" "id:" "date:" "from:" "to:"
|
||||
"subject:" "attachment:" "mimetype:")
|
||||
(mapcar (lambda (tag)
|
||||
(concat "tag:" (notmuch-escape-boolean-term tag)))
|
||||
(process-lines notmuch-command "search" "--output=tags" "*")))))
|
||||
(lexical-let*
|
||||
((all-tags
|
||||
(mapcar (lambda (tag) (notmuch-escape-boolean-term tag))
|
||||
(process-lines notmuch-command "search" "--output=tags" "*")))
|
||||
(completions
|
||||
(append (list "folder:" "path:" "thread:" "id:" "date:" "from:" "to:"
|
||||
"subject:" "attachment:" "mimetype:")
|
||||
(mapcar (lambda (tag) (concat "tag:" tag)) all-tags)
|
||||
(mapcar (lambda (tag) (concat "is:" tag)) all-tags))))
|
||||
(let ((keymap (copy-keymap minibuffer-local-map))
|
||||
(current-query (case major-mode
|
||||
(notmuch-search-mode (notmuch-search-get-query))
|
||||
|
@ -974,18 +978,28 @@ default sort order is defined by `notmuch-search-oldest-first'."
|
|||
(set 'notmuch-search-oldest-first (not notmuch-search-oldest-first))
|
||||
(notmuch-search-refresh-view))
|
||||
|
||||
(defun notmuch-group-disjunctive-query-string (query-string)
|
||||
"Group query if it contains a complex expression.
|
||||
|
||||
Enclose QUERY-STRING in parentheses if it matches
|
||||
`notmuch-search-disjunctive-regexp'."
|
||||
(if (string-match-p notmuch-search-disjunctive-regexp query-string)
|
||||
(concat "( " query-string " )")
|
||||
query-string))
|
||||
|
||||
(defun notmuch-search-filter (query)
|
||||
"Filter the current search results based on an additional query string.
|
||||
|
||||
Runs a new search matching only messages that match both the
|
||||
current search results AND the additional query string provided."
|
||||
(interactive (list (notmuch-read-query "Filter search: ")))
|
||||
(let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp query)
|
||||
(concat "( " query " )")
|
||||
query)))
|
||||
(notmuch-search (if (string= notmuch-search-query-string "*")
|
||||
(let ((grouped-query (notmuch-group-disjunctive-query-string query))
|
||||
(grouped-original-query (notmuch-group-disjunctive-query-string
|
||||
notmuch-search-query-string)))
|
||||
(notmuch-search (if (string= grouped-original-query "*")
|
||||
grouped-query
|
||||
(concat notmuch-search-query-string " and " grouped-query)) notmuch-search-oldest-first)))
|
||||
(concat grouped-original-query " and " grouped-query))
|
||||
notmuch-search-oldest-first)))
|
||||
|
||||
(defun notmuch-search-filter-by-tag (tag)
|
||||
"Filter the current search results based on a single tag.
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
# -*- makefile -*-
|
||||
|
||||
# The major version of the library interface. This will control the soname.
|
||||
# As such, this number must be incremented for any incompatible change to
|
||||
# the library interface, (such as the deletion of an API or a major
|
||||
# semantic change that breaks formerly functioning code).
|
||||
#
|
||||
LIBNOTMUCH_VERSION_MAJOR = 4
|
||||
|
||||
# The minor version of the library interface. This should be incremented at
|
||||
# the time of release for any additions to the library interface,
|
||||
# (and when it is incremented, the release version of the library should
|
||||
# be reset to 0).
|
||||
LIBNOTMUCH_VERSION_MINOR = 2
|
||||
|
||||
# The release version the library interface. This should be incremented at
|
||||
# the time of release if there have been no changes to the interface, (but
|
||||
# simply compatible changes to the implementation).
|
||||
LIBNOTMUCH_VERSION_RELEASE = 0
|
||||
|
||||
# Note: Don't forget to change the VERSION macros in notmuch.h when
|
||||
# any of the above change.
|
||||
|
||||
ifeq ($(PLATFORM),MACOSX)
|
||||
LIBRARY_SUFFIX = dylib
|
||||
# On OS X, library version numbers go before suffix.
|
||||
|
@ -33,7 +12,7 @@ LIBRARY_SUFFIX = so
|
|||
LINKER_NAME = libnotmuch.$(LIBRARY_SUFFIX)
|
||||
SONAME = $(LINKER_NAME).$(LIBNOTMUCH_VERSION_MAJOR)
|
||||
LIBNAME = $(SONAME).$(LIBNOTMUCH_VERSION_MINOR).$(LIBNOTMUCH_VERSION_RELEASE)
|
||||
LIBRARY_LINK_FLAG = -shared -Wl,--version-script=notmuch.sym,-soname=$(SONAME) -Wl,--no-undefined
|
||||
LIBRARY_LINK_FLAG = -shared -Wl,--version-script=notmuch.sym,-soname=$(SONAME) $(NO_UNDEFINED_LDFLAGS)
|
||||
ifeq ($(PLATFORM),OPENBSD)
|
||||
LIBRARY_LINK_FLAG += -lc
|
||||
endif
|
||||
|
|
|
@ -100,6 +100,12 @@ enum _notmuch_features {
|
|||
*
|
||||
* Introduced: version 3. */
|
||||
NOTMUCH_FEATURE_INDEXED_MIMETYPES = 1 << 5,
|
||||
|
||||
/* If set, messages store the revision number of the last
|
||||
* modification in NOTMUCH_VALUE_LAST_MOD.
|
||||
*
|
||||
* Introduced: version 3. */
|
||||
NOTMUCH_FEATURE_LAST_MOD = 1 << 6,
|
||||
};
|
||||
|
||||
/* In C++, a named enum is its own type, so define bitwise operators
|
||||
|
@ -145,6 +151,8 @@ struct _notmuch_database {
|
|||
|
||||
notmuch_database_mode_t mode;
|
||||
int atomic_nesting;
|
||||
/* TRUE if changes have been made in this atomic section */
|
||||
notmuch_bool_t atomic_dirty;
|
||||
Xapian::Database *xapian_db;
|
||||
|
||||
/* Bit mask of features used by this database. This is a
|
||||
|
@ -158,10 +166,17 @@ struct _notmuch_database {
|
|||
* next library call. May be NULL */
|
||||
char *status_string;
|
||||
|
||||
/* Highest committed revision number. Modifications are recorded
|
||||
* under a higher revision number, which can be generated with
|
||||
* notmuch_database_new_revision. */
|
||||
unsigned long revision;
|
||||
const char *uuid;
|
||||
|
||||
Xapian::QueryParser *query_parser;
|
||||
Xapian::TermGenerator *term_gen;
|
||||
Xapian::ValueRangeProcessor *value_range_processor;
|
||||
Xapian::ValueRangeProcessor *date_range_processor;
|
||||
Xapian::ValueRangeProcessor *last_mod_range_processor;
|
||||
};
|
||||
|
||||
/* Prior to database version 3, features were implied by the database
|
||||
|
@ -179,7 +194,8 @@ struct _notmuch_database {
|
|||
* will have it). */
|
||||
#define NOTMUCH_FEATURES_CURRENT \
|
||||
(NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_DIRECTORY_DOCS | \
|
||||
NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS)
|
||||
NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS | \
|
||||
NOTMUCH_FEATURE_LAST_MOD)
|
||||
|
||||
/* Return the list of terms from the given iterator matching a prefix.
|
||||
* The prefix will be stripped from the strings in the returned list.
|
||||
|
|
107
lib/database.cc
107
lib/database.cc
|
@ -101,6 +101,9 @@ typedef struct {
|
|||
*
|
||||
* SUBJECT: The value of the "Subject" header
|
||||
*
|
||||
* LAST_MOD: The revision number as of the last tag or
|
||||
* filename change.
|
||||
*
|
||||
* In addition, terms from the content of the message are added with
|
||||
* "from", "to", "attachment", and "subject" prefixes for use by the
|
||||
* user in searching. Similarly, terms from the path of the mail
|
||||
|
@ -310,6 +313,8 @@ static const struct {
|
|||
* them. */
|
||||
{ NOTMUCH_FEATURE_INDEXED_MIMETYPES,
|
||||
"indexed MIME types", "w"},
|
||||
{ NOTMUCH_FEATURE_LAST_MOD,
|
||||
"modification tracking", "w"},
|
||||
};
|
||||
|
||||
const char *
|
||||
|
@ -342,6 +347,8 @@ notmuch_status_to_string (notmuch_status_t status)
|
|||
return "Unsupported operation";
|
||||
case NOTMUCH_STATUS_UPGRADE_REQUIRED:
|
||||
return "Operation requires a database upgrade";
|
||||
case NOTMUCH_STATUS_PATH_ERROR:
|
||||
return "Path supplied is illegal for this function";
|
||||
default:
|
||||
case NOTMUCH_STATUS_LAST_STATUS:
|
||||
return "Unknown error status value";
|
||||
|
@ -657,6 +664,12 @@ notmuch_database_create_verbose (const char *path,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
if (path[0] != '/') {
|
||||
message = strdup ("Error: Database path must be absolute.\n");
|
||||
status = NOTMUCH_STATUS_PATH_ERROR;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
err = stat (path, &st);
|
||||
if (err) {
|
||||
IGNORE_RESULT (asprintf (&message, "Error: Cannot create database at %s: %s.\n",
|
||||
|
@ -729,6 +742,23 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)
|
|||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Allocate a revision number for the next change. */
|
||||
unsigned long
|
||||
_notmuch_database_new_revision (notmuch_database_t *notmuch)
|
||||
{
|
||||
unsigned long new_revision = notmuch->revision + 1;
|
||||
|
||||
/* If we're in an atomic section, hold off on updating the
|
||||
* committed revision number until we commit the atomic section.
|
||||
*/
|
||||
if (notmuch->atomic_nesting)
|
||||
notmuch->atomic_dirty = TRUE;
|
||||
else
|
||||
notmuch->revision = new_revision;
|
||||
|
||||
return new_revision;
|
||||
}
|
||||
|
||||
/* Parse a database features string from the given database version.
|
||||
* Returns the feature bit set.
|
||||
*
|
||||
|
@ -847,6 +877,12 @@ notmuch_database_open_verbose (const char *path,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
if (path[0] != '/') {
|
||||
message = strdup ("Error: Database path must be absolute.\n");
|
||||
status = NOTMUCH_STATUS_PATH_ERROR;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
|
||||
message = strdup ("Out of memory\n");
|
||||
status = NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||
|
@ -890,6 +926,7 @@ notmuch_database_open_verbose (const char *path,
|
|||
notmuch->atomic_nesting = 0;
|
||||
try {
|
||||
string last_thread_id;
|
||||
string last_mod;
|
||||
|
||||
if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) {
|
||||
notmuch->xapian_db = new Xapian::WritableDatabase (xapian_path,
|
||||
|
@ -948,11 +985,22 @@ notmuch_database_open_verbose (const char *path,
|
|||
INTERNAL_ERROR ("Malformed database last_thread_id: %s", str);
|
||||
}
|
||||
|
||||
/* Get current highest revision number. */
|
||||
last_mod = notmuch->xapian_db->get_value_upper_bound (
|
||||
NOTMUCH_VALUE_LAST_MOD);
|
||||
if (last_mod.empty ())
|
||||
notmuch->revision = 0;
|
||||
else
|
||||
notmuch->revision = Xapian::sortable_unserialise (last_mod);
|
||||
notmuch->uuid = talloc_strdup (
|
||||
notmuch, notmuch->xapian_db->get_uuid ().c_str ());
|
||||
|
||||
notmuch->query_parser = new Xapian::QueryParser;
|
||||
notmuch->term_gen = new Xapian::TermGenerator;
|
||||
notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
|
||||
notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
|
||||
notmuch->date_range_processor = new ParseTimeValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
|
||||
notmuch->last_mod_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
|
||||
|
||||
notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
|
||||
notmuch->query_parser->set_database (*notmuch->xapian_db);
|
||||
|
@ -960,6 +1008,7 @@ notmuch_database_open_verbose (const char *path,
|
|||
notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME);
|
||||
notmuch->query_parser->add_valuerangeprocessor (notmuch->value_range_processor);
|
||||
notmuch->query_parser->add_valuerangeprocessor (notmuch->date_range_processor);
|
||||
notmuch->query_parser->add_valuerangeprocessor (notmuch->last_mod_range_processor);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) {
|
||||
prefix_t *prefix = &BOOLEAN_PREFIX_EXTERNAL[i];
|
||||
|
@ -1038,6 +1087,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
|
|||
notmuch->value_range_processor = NULL;
|
||||
delete notmuch->date_range_processor;
|
||||
notmuch->date_range_processor = NULL;
|
||||
delete notmuch->last_mod_range_processor;
|
||||
notmuch->last_mod_range_processor = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -1321,6 +1372,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
enum _notmuch_features target_features, new_features;
|
||||
notmuch_status_t status;
|
||||
notmuch_private_status_t private_status;
|
||||
notmuch_query_t *query = NULL;
|
||||
unsigned int count = 0, total = 0;
|
||||
|
||||
status = _notmuch_database_ensure_writable (notmuch);
|
||||
|
@ -1336,7 +1388,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
return NOTMUCH_STATUS_SUCCESS;
|
||||
|
||||
if (progress_notify) {
|
||||
/* Setup our handler for SIGALRM */
|
||||
/* Set up our handler for SIGALRM */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
action.sa_handler = handle_sigalrm;
|
||||
sigemptyset (&action.sa_mask);
|
||||
|
@ -1355,10 +1407,18 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
|
||||
/* Figure out how much total work we need to do. */
|
||||
if (new_features &
|
||||
(NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER)) {
|
||||
notmuch_query_t *query = notmuch_query_create (notmuch, "");
|
||||
total += notmuch_query_count_messages (query);
|
||||
(NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER |
|
||||
NOTMUCH_FEATURE_LAST_MOD)) {
|
||||
query = notmuch_query_create (notmuch, "");
|
||||
unsigned msg_count;
|
||||
|
||||
status = notmuch_query_count_messages_st (query, &msg_count);
|
||||
if (status)
|
||||
goto DONE;
|
||||
|
||||
total += msg_count;
|
||||
notmuch_query_destroy (query);
|
||||
query = NULL;
|
||||
}
|
||||
if (new_features & NOTMUCH_FEATURE_DIRECTORY_DOCS) {
|
||||
t_end = db->allterms_end ("XTIMESTAMP");
|
||||
|
@ -1382,13 +1442,18 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
|
||||
/* Perform per-message upgrades. */
|
||||
if (new_features &
|
||||
(NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER)) {
|
||||
notmuch_query_t *query = notmuch_query_create (notmuch, "");
|
||||
(NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER |
|
||||
NOTMUCH_FEATURE_LAST_MOD)) {
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
char *filename;
|
||||
|
||||
for (messages = notmuch_query_search_messages (query);
|
||||
query = notmuch_query_create (notmuch, "");
|
||||
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (status)
|
||||
goto DONE;
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
notmuch_messages_move_to_next (messages))
|
||||
{
|
||||
|
@ -1419,6 +1484,14 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
if (new_features & NOTMUCH_FEATURE_BOOL_FOLDER)
|
||||
_notmuch_message_upgrade_folder (message);
|
||||
|
||||
/* Prior to NOTMUCH_FEATURE_LAST_MOD, messages did not
|
||||
* track modification revisions. Give all messages the
|
||||
* next available revision; since we just started tracking
|
||||
* revisions for this database, that will be 1.
|
||||
*/
|
||||
if (new_features & NOTMUCH_FEATURE_LAST_MOD)
|
||||
_notmuch_message_upgrade_last_mod (message);
|
||||
|
||||
_notmuch_message_sync (message);
|
||||
|
||||
notmuch_message_destroy (message);
|
||||
|
@ -1427,6 +1500,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
}
|
||||
|
||||
notmuch_query_destroy (query);
|
||||
query = NULL;
|
||||
}
|
||||
|
||||
/* Perform per-directory upgrades. */
|
||||
|
@ -1547,6 +1621,9 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
|
|||
sigaction (SIGALRM, &action, NULL);
|
||||
}
|
||||
|
||||
if (query)
|
||||
notmuch_query_destroy (query);
|
||||
|
||||
talloc_free (local);
|
||||
return status;
|
||||
}
|
||||
|
@ -1601,11 +1678,25 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch)
|
|||
return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||
}
|
||||
|
||||
if (notmuch->atomic_dirty) {
|
||||
++notmuch->revision;
|
||||
notmuch->atomic_dirty = FALSE;
|
||||
}
|
||||
|
||||
DONE:
|
||||
notmuch->atomic_nesting--;
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
notmuch_database_get_revision (notmuch_database_t *notmuch,
|
||||
const char **uuid)
|
||||
{
|
||||
if (uuid)
|
||||
*uuid = notmuch->uuid;
|
||||
return notmuch->revision;
|
||||
}
|
||||
|
||||
/* We allow the user to use arbitrarily long paths for directories. But
|
||||
* we have a term-length limit. So if we exceed that, we'll use the
|
||||
* SHA-1 of the path for the database term.
|
||||
|
@ -2576,7 +2667,7 @@ notmuch_database_get_all_tags (notmuch_database_t *db)
|
|||
}
|
||||
|
||||
const char *
|
||||
notmuch_database_status_string (notmuch_database_t *notmuch)
|
||||
notmuch_database_status_string (const notmuch_database_t *notmuch)
|
||||
{
|
||||
return notmuch->status_string;
|
||||
}
|
||||
|
|
|
@ -281,6 +281,31 @@ notmuch_directory_get_child_directories (notmuch_directory_t *directory)
|
|||
return child_directories;
|
||||
}
|
||||
|
||||
notmuch_status_t
|
||||
notmuch_directory_delete (notmuch_directory_t *directory)
|
||||
{
|
||||
notmuch_status_t status;
|
||||
Xapian::WritableDatabase *db;
|
||||
|
||||
status = _notmuch_database_ensure_writable (directory->notmuch);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
try {
|
||||
db = static_cast <Xapian::WritableDatabase *> (directory->notmuch->xapian_db);
|
||||
db->delete_document (directory->document_id);
|
||||
} catch (const Xapian::Error &error) {
|
||||
_notmuch_database_log (directory->notmuch,
|
||||
"A Xapian exception occurred deleting directory entry: %s.\n",
|
||||
error.get_msg().c_str());
|
||||
directory->notmuch->exception_reported = TRUE;
|
||||
status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||
}
|
||||
notmuch_directory_destroy (directory);
|
||||
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
notmuch_directory_destroy (notmuch_directory_t *directory)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
set -eu
|
||||
|
||||
# we go through a bit of work to get the unmangled names of the
|
||||
# typeinfo symbols because of
|
||||
|
|
|
@ -37,27 +37,6 @@ struct _notmuch_message_file {
|
|||
GMimeMessage *message;
|
||||
};
|
||||
|
||||
static int
|
||||
strcase_equal (const void *a, const void *b)
|
||||
{
|
||||
return strcasecmp (a, b) == 0;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
strcase_hash (const void *ptr)
|
||||
{
|
||||
const char *s = ptr;
|
||||
|
||||
/* This is the djb2 hash. */
|
||||
unsigned int hash = 5381;
|
||||
while (s && *s) {
|
||||
hash = ((hash << 5) + hash) + tolower (*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int
|
||||
_notmuch_message_file_destructor (notmuch_message_file_t *message)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,9 @@ struct visible _notmuch_message {
|
|||
* if each flag has been initialized. */
|
||||
unsigned long lazy_flags;
|
||||
|
||||
/* Message document modified since last sync */
|
||||
notmuch_bool_t modified;
|
||||
|
||||
Xapian::Document doc;
|
||||
Xapian::termcount termpos;
|
||||
};
|
||||
|
@ -539,6 +542,7 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
|
|||
|
||||
try {
|
||||
message->doc.remove_term ((*i));
|
||||
message->modified = TRUE;
|
||||
} catch (const Xapian::InvalidArgumentError) {
|
||||
/* Ignore failure to remove non-existent term. */
|
||||
}
|
||||
|
@ -793,6 +797,7 @@ void
|
|||
_notmuch_message_clear_data (notmuch_message_t *message)
|
||||
{
|
||||
message->doc.set_data ("");
|
||||
message->modified = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -990,6 +995,17 @@ _notmuch_message_set_header_values (notmuch_message_t *message,
|
|||
Xapian::sortable_serialise (time_value));
|
||||
message->doc.add_value (NOTMUCH_VALUE_FROM, from);
|
||||
message->doc.add_value (NOTMUCH_VALUE_SUBJECT, subject);
|
||||
message->modified = TRUE;
|
||||
}
|
||||
|
||||
/* Upgrade a message to support NOTMUCH_FEATURE_LAST_MOD. The caller
|
||||
* must call _notmuch_message_sync. */
|
||||
void
|
||||
_notmuch_message_upgrade_last_mod (notmuch_message_t *message)
|
||||
{
|
||||
/* _notmuch_message_sync will update the last modification
|
||||
* revision; we just have to ask it to. */
|
||||
message->modified = TRUE;
|
||||
}
|
||||
|
||||
/* Synchronize changes made to message->doc out into the database. */
|
||||
|
@ -1001,8 +1017,24 @@ _notmuch_message_sync (notmuch_message_t *message)
|
|||
if (message->notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)
|
||||
return;
|
||||
|
||||
if (! message->modified)
|
||||
return;
|
||||
|
||||
/* Update the last modification of this message. */
|
||||
if (message->notmuch->features & NOTMUCH_FEATURE_LAST_MOD)
|
||||
/* sortable_serialise gives a reasonably compact encoding,
|
||||
* which directly translates to reduced IO when scanning the
|
||||
* value stream. Since it's built for doubles, we only get 53
|
||||
* effective bits, but that's still enough for the database to
|
||||
* last a few centuries at 1 million revisions per second. */
|
||||
message->doc.add_value (NOTMUCH_VALUE_LAST_MOD,
|
||||
Xapian::sortable_serialise (
|
||||
_notmuch_database_new_revision (
|
||||
message->notmuch)));
|
||||
|
||||
db = static_cast <Xapian::WritableDatabase *> (message->notmuch->xapian_db);
|
||||
db->replace_document (message->doc_id, message->doc);
|
||||
message->modified = FALSE;
|
||||
}
|
||||
|
||||
/* Delete a message document from the database. */
|
||||
|
@ -1077,6 +1109,7 @@ _notmuch_message_add_term (notmuch_message_t *message,
|
|||
return NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG;
|
||||
|
||||
message->doc.add_term (term, 0);
|
||||
message->modified = TRUE;
|
||||
|
||||
talloc_free (term);
|
||||
|
||||
|
@ -1145,6 +1178,7 @@ _notmuch_message_remove_term (notmuch_message_t *message,
|
|||
|
||||
try {
|
||||
message->doc.remove_term (term);
|
||||
message->modified = TRUE;
|
||||
} catch (const Xapian::InvalidArgumentError) {
|
||||
/* We'll let the philosopher's try to wrestle with the
|
||||
* question of whether failing to remove that which was not
|
||||
|
|
|
@ -50,6 +50,7 @@ NOTMUCH_BEGIN_DECLS
|
|||
|
||||
#include "xutil.h"
|
||||
#include "error_util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#pragma GCC visibility push(hidden)
|
||||
|
||||
|
@ -107,7 +108,8 @@ typedef enum {
|
|||
NOTMUCH_VALUE_TIMESTAMP = 0,
|
||||
NOTMUCH_VALUE_MESSAGE_ID,
|
||||
NOTMUCH_VALUE_FROM,
|
||||
NOTMUCH_VALUE_SUBJECT
|
||||
NOTMUCH_VALUE_SUBJECT,
|
||||
NOTMUCH_VALUE_LAST_MOD,
|
||||
} notmuch_value_t;
|
||||
|
||||
/* Xapian (with flint backend) complains if we provide a term longer
|
||||
|
@ -194,6 +196,9 @@ void
|
|||
_notmuch_database_log (notmuch_database_t *notmuch,
|
||||
const char *format, ...);
|
||||
|
||||
unsigned long
|
||||
_notmuch_database_new_revision (notmuch_database_t *notmuch);
|
||||
|
||||
const char *
|
||||
_notmuch_database_relative_path (notmuch_database_t *notmuch,
|
||||
const char *path);
|
||||
|
@ -305,6 +310,10 @@ _notmuch_message_set_header_values (notmuch_message_t *message,
|
|||
const char *date,
|
||||
const char *from,
|
||||
const char *subject);
|
||||
|
||||
void
|
||||
_notmuch_message_upgrade_last_mod (notmuch_message_t *message);
|
||||
|
||||
void
|
||||
_notmuch_message_sync (notmuch_message_t *message);
|
||||
|
||||
|
|
144
lib/notmuch.h
144
lib/notmuch.h
|
@ -56,9 +56,11 @@ NOTMUCH_BEGIN_DECLS
|
|||
* version in Makefile.local.
|
||||
*/
|
||||
#define LIBNOTMUCH_MAJOR_VERSION 4
|
||||
#define LIBNOTMUCH_MINOR_VERSION 2
|
||||
#define LIBNOTMUCH_MINOR_VERSION 3
|
||||
#define LIBNOTMUCH_MICRO_VERSION 0
|
||||
|
||||
#define NOTMUCH_DEPRECATED(major,minor) \
|
||||
__attribute__ ((deprecated ("function deprecated as of libnotmuch " #major "." #minor)))
|
||||
#endif /* __DOXYGEN__ */
|
||||
|
||||
/**
|
||||
|
@ -163,6 +165,11 @@ typedef enum _notmuch_status {
|
|||
* The operation requires a database upgrade.
|
||||
*/
|
||||
NOTMUCH_STATUS_UPGRADE_REQUIRED,
|
||||
/**
|
||||
* There is a problem with the proposed path, e.g. a relative path
|
||||
* passed to a function expecting an absolute path.
|
||||
*/
|
||||
NOTMUCH_STATUS_PATH_ERROR,
|
||||
/**
|
||||
* Not an actual status value. Just a way to find out how many
|
||||
* valid status values there are.
|
||||
|
@ -306,7 +313,7 @@ notmuch_database_open_verbose (const char *path,
|
|||
*
|
||||
*/
|
||||
const char *
|
||||
notmuch_database_status_string (notmuch_database_t *notmuch);
|
||||
notmuch_database_status_string (const notmuch_database_t *notmuch);
|
||||
|
||||
/**
|
||||
* Commit changes and close the given notmuch database.
|
||||
|
@ -460,6 +467,24 @@ notmuch_database_begin_atomic (notmuch_database_t *notmuch);
|
|||
notmuch_status_t
|
||||
notmuch_database_end_atomic (notmuch_database_t *notmuch);
|
||||
|
||||
/**
|
||||
* Return the committed database revision and UUID.
|
||||
*
|
||||
* The database revision number increases monotonically with each
|
||||
* commit to the database. Hence, all messages and message changes
|
||||
* committed to the database (that is, visible to readers) have a last
|
||||
* modification revision <= the committed database revision. Any
|
||||
* messages committed in the future will be assigned a modification
|
||||
* revision > the committed database revision.
|
||||
*
|
||||
* The UUID is a NUL-terminated opaque string that uniquely identifies
|
||||
* this database. Two revision numbers are only comparable if they
|
||||
* have the same database UUID.
|
||||
*/
|
||||
unsigned long
|
||||
notmuch_database_get_revision (notmuch_database_t *notmuch,
|
||||
const char **uuid);
|
||||
|
||||
/**
|
||||
* Retrieve a directory object from the database for 'path'.
|
||||
*
|
||||
|
@ -703,7 +728,13 @@ typedef enum {
|
|||
* Return the query_string of this query. See notmuch_query_create.
|
||||
*/
|
||||
const char *
|
||||
notmuch_query_get_query_string (notmuch_query_t *query);
|
||||
notmuch_query_get_query_string (const notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Return the notmuch database of this query. See notmuch_query_create.
|
||||
*/
|
||||
notmuch_database_t *
|
||||
notmuch_query_get_database (const notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Exclude values for notmuch_query_set_omit_excluded. The strange
|
||||
|
@ -760,7 +791,7 @@ notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort);
|
|||
* notmuch_query_set_sort.
|
||||
*/
|
||||
notmuch_sort_t
|
||||
notmuch_query_get_sort (notmuch_query_t *query);
|
||||
notmuch_query_get_sort (const notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Add a tag that will be excluded from the query results by default.
|
||||
|
@ -807,19 +838,25 @@ notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag);
|
|||
* notmuch_threads_destroy function, but there's no good reason
|
||||
* to call it if the query is about to be destroyed).
|
||||
*
|
||||
* If a Xapian exception occurs this function will return NULL.
|
||||
* For better error reporting, use the _st variant.
|
||||
*/
|
||||
notmuch_threads_t *
|
||||
notmuch_query_search_threads (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Like notmuch_query_search_threads, but with a status return.
|
||||
* @since libnotmuch 4.2 (notmuch 0.20)
|
||||
*/
|
||||
notmuch_status_t
|
||||
notmuch_query_search_threads_st (notmuch_query_t *query,
|
||||
notmuch_threads_t **out);
|
||||
|
||||
/**
|
||||
* Like notmuch_query_search_threads_st, but without a status return.
|
||||
*
|
||||
* If a Xapian exception occurs this function will return NULL.
|
||||
*
|
||||
* @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please
|
||||
* use notmuch_query_search_threads_st instead.
|
||||
*
|
||||
*/
|
||||
NOTMUCH_DEPRECATED(4,3)
|
||||
notmuch_threads_t *
|
||||
notmuch_query_search_threads (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Execute a query for messages, returning a notmuch_messages_t object
|
||||
* which can be used to iterate over the results. The returned
|
||||
|
@ -858,17 +895,24 @@ notmuch_query_search_threads_st (notmuch_query_t *query,
|
|||
* reason to call it if the query is about to be destroyed).
|
||||
*
|
||||
* If a Xapian exception occurs this function will return NULL.
|
||||
* For better error reporting, use the _st variant.
|
||||
*/
|
||||
notmuch_messages_t *
|
||||
notmuch_query_search_messages (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Like notmuch_query_search_messages, but with a status return.
|
||||
*
|
||||
* @since libnotmuch 4.2 (notmuch 0.20)
|
||||
*/
|
||||
notmuch_status_t
|
||||
notmuch_query_search_messages_st (notmuch_query_t *query,
|
||||
notmuch_messages_t **out);
|
||||
/**
|
||||
* Like notmuch_query_search_messages, but without a status return.
|
||||
*
|
||||
* If a Xapian exception occurs this function will return NULL.
|
||||
*
|
||||
* @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please use
|
||||
* notmuch_query_search_messages_st instead.
|
||||
*
|
||||
*/
|
||||
NOTMUCH_DEPRECATED(4,3)
|
||||
notmuch_messages_t *
|
||||
notmuch_query_search_messages (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
* Destroy a notmuch_query_t along with any associated resources.
|
||||
|
@ -942,10 +986,28 @@ notmuch_threads_destroy (notmuch_threads_t *threads);
|
|||
* This function performs a search and returns the number of matching
|
||||
* messages.
|
||||
*
|
||||
* If a Xapian exception occurs, this function may return 0 (after
|
||||
* printing a message).
|
||||
* @returns
|
||||
*
|
||||
* NOTMUCH_STATUS_SUCCESS: query completed successfully.
|
||||
*
|
||||
* NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The
|
||||
* value of *count is not defined.
|
||||
*
|
||||
* @since libnotmuch 4.3 (notmuch 0.21)
|
||||
*/
|
||||
unsigned
|
||||
notmuch_status_t
|
||||
notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count);
|
||||
|
||||
/**
|
||||
* like notmuch_query_count_messages_st, but without a status return.
|
||||
*
|
||||
* May return 0 in the case of errors.
|
||||
*
|
||||
* @deprecated Deprecated since libnotmuch 4.3 (notmuch 0.21). Please
|
||||
* use notmuch_query_count_messages_st instead.
|
||||
*/
|
||||
NOTMUCH_DEPRECATED(4,3)
|
||||
unsigned int
|
||||
notmuch_query_count_messages (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
|
@ -956,11 +1018,33 @@ notmuch_query_count_messages (notmuch_query_t *query);
|
|||
* search.
|
||||
*
|
||||
* Note that this is a significantly heavier operation than
|
||||
* notmuch_query_count_messages().
|
||||
* notmuch_query_count_messages{_st}().
|
||||
*
|
||||
* If an error occurs, this function may return 0.
|
||||
* @returns
|
||||
*
|
||||
* NOTMUCH_STATUS_OUT_OF_MEMORY: Memory allocation failed. The value
|
||||
* of *count is not defined
|
||||
|
||||
* NOTMUCH_STATUS_SUCCESS: query completed successfully.
|
||||
*
|
||||
* NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The
|
||||
* value of *count is not defined.
|
||||
*
|
||||
* @since libnotmuch 4.3 (notmuch 0.21)
|
||||
*/
|
||||
unsigned
|
||||
notmuch_status_t
|
||||
notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count);
|
||||
|
||||
/**
|
||||
* like notmuch_query_count_threads, but without a status return.
|
||||
*
|
||||
* May return 0 in case of errors.
|
||||
*
|
||||
* @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please
|
||||
* use notmuch_query_count_threads_st instead.
|
||||
*/
|
||||
NOTMUCH_DEPRECATED(4,3)
|
||||
unsigned int
|
||||
notmuch_query_count_threads (notmuch_query_t *query);
|
||||
|
||||
/**
|
||||
|
@ -1677,6 +1761,16 @@ notmuch_directory_get_child_files (notmuch_directory_t *directory);
|
|||
notmuch_filenames_t *
|
||||
notmuch_directory_get_child_directories (notmuch_directory_t *directory);
|
||||
|
||||
/**
|
||||
* Delete directory document from the database, and destroy the
|
||||
* notmuch_directory_t object. Assumes any child directories and files
|
||||
* have been deleted by the caller.
|
||||
*
|
||||
* @since libnotmuch 4.3 (notmuch 0.21)
|
||||
*/
|
||||
notmuch_status_t
|
||||
notmuch_directory_delete (notmuch_directory_t *directory);
|
||||
|
||||
/**
|
||||
* Destroy a notmuch_directory_t object.
|
||||
*/
|
||||
|
|
|
@ -31,6 +31,7 @@ Xapian::valueno
|
|||
ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end)
|
||||
{
|
||||
time_t t, now;
|
||||
std::string b;
|
||||
|
||||
/* Require date: prefix in start of the range... */
|
||||
if (STRNCMP_LITERAL (begin.c_str (), PREFIX))
|
||||
|
@ -38,6 +39,7 @@ ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end)
|
|||
|
||||
/* ...and remove it. */
|
||||
begin.erase (0, sizeof (PREFIX) - 1);
|
||||
b = begin;
|
||||
|
||||
/* Use the same 'now' for begin and end. */
|
||||
if (time (&now) == (time_t) -1)
|
||||
|
@ -51,6 +53,9 @@ ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end)
|
|||
}
|
||||
|
||||
if (!end.empty ()) {
|
||||
if (end == "!" && ! b.empty ())
|
||||
end = b;
|
||||
|
||||
if (parse_time_string (end.c_str (), &t, &now, PARSE_TIME_ROUND_UP_INCLUSIVE))
|
||||
return Xapian::BAD_VALUENO;
|
||||
|
||||
|
|
53
lib/query.cc
53
lib/query.cc
|
@ -98,7 +98,7 @@ notmuch_query_create (notmuch_database_t *notmuch,
|
|||
}
|
||||
|
||||
const char *
|
||||
notmuch_query_get_query_string (notmuch_query_t *query)
|
||||
notmuch_query_get_query_string (const notmuch_query_t *query)
|
||||
{
|
||||
return query->query_string;
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort)
|
|||
}
|
||||
|
||||
notmuch_sort_t
|
||||
notmuch_query_get_sort (notmuch_query_t *query)
|
||||
notmuch_query_get_sort (const notmuch_query_t *query)
|
||||
{
|
||||
return query->sort;
|
||||
}
|
||||
|
@ -541,8 +541,18 @@ notmuch_threads_destroy (notmuch_threads_t *threads)
|
|||
talloc_free (threads);
|
||||
}
|
||||
|
||||
unsigned
|
||||
unsigned int
|
||||
notmuch_query_count_messages (notmuch_query_t *query)
|
||||
{
|
||||
notmuch_status_t status;
|
||||
unsigned int count;
|
||||
|
||||
status = notmuch_query_count_messages_st (query, &count);
|
||||
return status ? 0 : count;
|
||||
}
|
||||
|
||||
notmuch_status_t
|
||||
notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
|
||||
{
|
||||
notmuch_database_t *notmuch = query->notmuch;
|
||||
const char *query_string = query->query_string;
|
||||
|
@ -605,31 +615,44 @@ notmuch_query_count_messages (notmuch_query_t *query)
|
|||
"Query string was: %s\n",
|
||||
error.get_msg().c_str(),
|
||||
query->query_string);
|
||||
|
||||
return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||
}
|
||||
|
||||
return count;
|
||||
*count_out = count;
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned
|
||||
notmuch_query_count_threads (notmuch_query_t *query)
|
||||
{
|
||||
notmuch_status_t status;
|
||||
unsigned int count;
|
||||
|
||||
status = notmuch_query_count_threads_st (query, &count);
|
||||
return status ? 0 : count;
|
||||
}
|
||||
|
||||
notmuch_status_t
|
||||
notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count)
|
||||
{
|
||||
notmuch_messages_t *messages;
|
||||
GHashTable *hash;
|
||||
unsigned int count;
|
||||
notmuch_sort_t sort;
|
||||
notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
|
||||
|
||||
sort = query->sort;
|
||||
query->sort = NOTMUCH_SORT_UNSORTED;
|
||||
messages = notmuch_query_search_messages (query);
|
||||
ret = notmuch_query_search_messages_st (query, &messages);
|
||||
if (ret)
|
||||
return ret;
|
||||
query->sort = sort;
|
||||
if (messages == NULL)
|
||||
return 0;
|
||||
return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
|
||||
if (hash == NULL) {
|
||||
talloc_free (messages);
|
||||
return 0;
|
||||
return NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
while (notmuch_messages_valid (messages)) {
|
||||
|
@ -638,7 +661,7 @@ notmuch_query_count_threads (notmuch_query_t *query)
|
|||
char *thread_id_copy = talloc_strdup (messages, thread_id);
|
||||
if (unlikely (thread_id_copy == NULL)) {
|
||||
notmuch_message_destroy (message);
|
||||
count = 0;
|
||||
ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||
goto DONE;
|
||||
}
|
||||
g_hash_table_insert (hash, thread_id_copy, NULL);
|
||||
|
@ -646,11 +669,17 @@ notmuch_query_count_threads (notmuch_query_t *query)
|
|||
notmuch_messages_move_to_next (messages);
|
||||
}
|
||||
|
||||
count = g_hash_table_size (hash);
|
||||
*count = g_hash_table_size (hash);
|
||||
|
||||
DONE:
|
||||
g_hash_table_unref (hash);
|
||||
talloc_free (messages);
|
||||
|
||||
return count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
notmuch_database_t *
|
||||
notmuch_query_get_database (const notmuch_query_t *query)
|
||||
{
|
||||
return query->notmuch;
|
||||
}
|
||||
|
|
|
@ -447,6 +447,7 @@ _notmuch_thread_create (void *ctx,
|
|||
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
notmuch_status_t status;
|
||||
|
||||
seed_message = _notmuch_message_create (local, notmuch, seed_doc_id, NULL);
|
||||
if (! seed_message)
|
||||
|
@ -504,7 +505,11 @@ _notmuch_thread_create (void *ctx,
|
|||
* oldest or newest subject is desired. */
|
||||
notmuch_query_set_sort (thread_id_query, NOTMUCH_SORT_OLDEST_FIRST);
|
||||
|
||||
for (messages = notmuch_query_search_messages (thread_id_query);
|
||||
status = notmuch_query_search_messages_st (thread_id_query, &messages);
|
||||
if (status)
|
||||
goto DONE;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
notmuch_messages_move_to_next (messages))
|
||||
{
|
||||
|
|
83
mime-node.c
83
mime-node.c
|
@ -129,8 +129,6 @@ DONE:
|
|||
return status;
|
||||
}
|
||||
|
||||
#ifdef GMIME_ATLEAST_26
|
||||
|
||||
/* Signature list destructor (GMime 2.6) */
|
||||
static int
|
||||
_signature_list_free (GMimeSignatureList **proxy)
|
||||
|
@ -205,87 +203,6 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part,
|
|||
g_error_free (err);
|
||||
}
|
||||
|
||||
#else /* GMIME_ATLEAST_26 */
|
||||
|
||||
/* Signature validity destructor (GMime 2.4) */
|
||||
static int
|
||||
_signature_validity_free (GMimeSignatureValidity **proxy)
|
||||
{
|
||||
g_mime_signature_validity_free (*proxy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set up signature validity destructor (GMime 2.4) */
|
||||
static void
|
||||
set_signature_validity_destructor (mime_node_t *node,
|
||||
GMimeSignatureValidity *sig_validity)
|
||||
{
|
||||
GMimeSignatureValidity **proxy = talloc (node, GMimeSignatureValidity *);
|
||||
if (proxy) {
|
||||
*proxy = sig_validity;
|
||||
talloc_set_destructor (proxy, _signature_validity_free);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify a signed mime node (GMime 2.4) */
|
||||
static void
|
||||
node_verify (mime_node_t *node, GMimeObject *part,
|
||||
notmuch_crypto_context_t *cryptoctx)
|
||||
{
|
||||
GError *err = NULL;
|
||||
GMimeSignatureValidity *sig_validity;
|
||||
|
||||
node->verify_attempted = TRUE;
|
||||
sig_validity = g_mime_multipart_signed_verify
|
||||
(GMIME_MULTIPART_SIGNED (part), cryptoctx, &err);
|
||||
node->sig_validity = sig_validity;
|
||||
if (sig_validity) {
|
||||
set_signature_validity_destructor (node, sig_validity);
|
||||
} else {
|
||||
fprintf (stderr, "Failed to verify signed part: %s\n",
|
||||
err ? err->message : "no error explanation given");
|
||||
}
|
||||
|
||||
if (err)
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
/* Decrypt and optionally verify an encrypted mime node (GMime 2.4) */
|
||||
static void
|
||||
node_decrypt_and_verify (mime_node_t *node, GMimeObject *part,
|
||||
notmuch_crypto_context_t *cryptoctx)
|
||||
{
|
||||
GError *err = NULL;
|
||||
GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part);
|
||||
|
||||
node->decrypt_attempted = TRUE;
|
||||
node->decrypted_child = g_mime_multipart_encrypted_decrypt
|
||||
(encrypteddata, cryptoctx, &err);
|
||||
if (! node->decrypted_child) {
|
||||
fprintf (stderr, "Failed to decrypt part: %s\n",
|
||||
err ? err->message : "no error explanation given");
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
node->decrypt_success = TRUE;
|
||||
node->verify_attempted = TRUE;
|
||||
|
||||
/* The GMimeSignatureValidity returned here is a const, unlike the
|
||||
* one returned by g_mime_multipart_signed_verify() in
|
||||
* node_verify() above, so the destructor is not needed.
|
||||
*/
|
||||
node->sig_validity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);
|
||||
if (! node->sig_validity)
|
||||
fprintf (stderr, "Failed to verify encrypted signed part: %s\n",
|
||||
err ? err->message : "no error explanation given");
|
||||
|
||||
DONE:
|
||||
if (err)
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
#endif /* GMIME_ATLEAST_26 */
|
||||
|
||||
static mime_node_t *
|
||||
_mime_node_create (mime_node_t *parent, GMimeObject *part)
|
||||
{
|
||||
|
|
|
@ -30,16 +30,7 @@
|
|||
|
||||
#include <gmime/gmime.h>
|
||||
|
||||
/* GMIME_CHECK_VERSION in gmime 2.4 is not usable from the
|
||||
* preprocessor (it calls a runtime function). But since
|
||||
* GMIME_MAJOR_VERSION and friends were added in gmime 2.6, we can use
|
||||
* these to check the version number. */
|
||||
#ifdef GMIME_MAJOR_VERSION
|
||||
#define GMIME_ATLEAST_26
|
||||
typedef GMimeCryptoContext notmuch_crypto_context_t;
|
||||
#else
|
||||
typedef GMimeCipherContext notmuch_crypto_context_t;
|
||||
#endif
|
||||
|
||||
#include "notmuch.h"
|
||||
|
||||
|
@ -57,6 +48,7 @@ typedef GMimeCipherContext notmuch_crypto_context_t;
|
|||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "talloc-extra.h"
|
||||
|
||||
|
@ -394,17 +386,10 @@ struct mime_node {
|
|||
|
||||
/* True if signature verification on this part was attempted. */
|
||||
notmuch_bool_t verify_attempted;
|
||||
#ifdef GMIME_ATLEAST_26
|
||||
|
||||
/* The list of signatures for signed or encrypted containers. If
|
||||
* there are no signatures, this will be NULL. */
|
||||
GMimeSignatureList* sig_list;
|
||||
#else
|
||||
/* For signed or encrypted containers, the validity of the
|
||||
* signature. May be NULL if signature verification failed. If
|
||||
* there are simply no signatures, this will be non-NULL with an
|
||||
* empty signers list. */
|
||||
const GMimeSignatureValidity *sig_validity;
|
||||
#endif
|
||||
|
||||
/* Internal: Context inherited from the root iterator. */
|
||||
struct mime_node_context *ctx;
|
||||
|
@ -465,5 +450,22 @@ notmuch_database_dump (notmuch_database_t *notmuch,
|
|||
dump_format_t output_format,
|
||||
notmuch_bool_t gzip_output);
|
||||
|
||||
/* If status is non-zero (i.e. error) print appropriate
|
||||
messages to stderr.
|
||||
*/
|
||||
|
||||
notmuch_status_t
|
||||
print_status_query (const char *loc,
|
||||
const notmuch_query_t *query,
|
||||
notmuch_status_t status);
|
||||
|
||||
#include "command-line-arguments.h"
|
||||
|
||||
extern char *notmuch_requested_db_uuid;
|
||||
extern const notmuch_opt_desc_t notmuch_shared_options [];
|
||||
void notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch);
|
||||
|
||||
void notmuch_process_shared_options (const char* subcommand_name);
|
||||
int notmuch_minimal_options (const char* subcommand_name,
|
||||
int argc, char **argv);
|
||||
#endif
|
||||
|
|
|
@ -38,12 +38,21 @@ notmuch_compact_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
notmuch_opt_desc_t options[] = {
|
||||
{ NOTMUCH_OPT_STRING, &backup_path, "backup", 0, 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &quiet, "quiet", 'q', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
opt_index = parse_arguments (argc, argv, options, 1);
|
||||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (notmuch_requested_db_uuid) {
|
||||
fprintf (stderr, "Error: --uuid not implemented for compact\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (! quiet)
|
||||
printf ("Compacting database...\n");
|
||||
ret = notmuch_database_compact (path, backup_path,
|
||||
|
|
|
@ -872,8 +872,19 @@ int
|
|||
notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int opt_index;
|
||||
|
||||
argc--; argv++; /* skip subcommand argument */
|
||||
opt_index = notmuch_minimal_options ("config", argc, argv);
|
||||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (notmuch_requested_db_uuid)
|
||||
fprintf (stderr, "Warning: ignoring --uuid=%s\n",
|
||||
notmuch_requested_db_uuid);
|
||||
|
||||
/* skip at least subcommand argument */
|
||||
argc-= opt_index;
|
||||
argv+= opt_index;
|
||||
|
||||
if (argc < 1) {
|
||||
fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
|
||||
|
|
|
@ -33,17 +33,19 @@ enum {
|
|||
EXCLUDE_FALSE,
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
/* Return the number of files matching the query, or -1 for an error */
|
||||
static int
|
||||
count_files (notmuch_query_t *query)
|
||||
{
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
notmuch_filenames_t *filenames;
|
||||
unsigned int count = 0;
|
||||
notmuch_status_t status;
|
||||
int count = 0;
|
||||
|
||||
messages = notmuch_query_search_messages (query);
|
||||
if (messages == NULL)
|
||||
return 0;
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch count", query, status))
|
||||
return -1;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
|
@ -65,17 +67,24 @@ count_files (notmuch_query_t *query)
|
|||
return count;
|
||||
}
|
||||
|
||||
/* return 0 on success, -1 on failure */
|
||||
static int
|
||||
print_count (notmuch_database_t *notmuch, const char *query_str,
|
||||
const char **exclude_tags, size_t exclude_tags_length, int output)
|
||||
const char **exclude_tags, size_t exclude_tags_length, int output, int print_lastmod)
|
||||
{
|
||||
notmuch_query_t *query;
|
||||
size_t i;
|
||||
int count;
|
||||
unsigned int ucount;
|
||||
unsigned long revision;
|
||||
const char *uuid;
|
||||
int ret = 0;
|
||||
notmuch_status_t status;
|
||||
|
||||
query = notmuch_query_create (notmuch, query_str);
|
||||
if (query == NULL) {
|
||||
fprintf (stderr, "Out of memory\n");
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < exclude_tags_length; i++)
|
||||
|
@ -83,34 +92,54 @@ print_count (notmuch_database_t *notmuch, const char *query_str,
|
|||
|
||||
switch (output) {
|
||||
case OUTPUT_MESSAGES:
|
||||
printf ("%u\n", notmuch_query_count_messages (query));
|
||||
status = notmuch_query_count_messages_st (query, &ucount);
|
||||
if (print_status_query ("notmuch count", query, status))
|
||||
return -1;
|
||||
printf ("%u", ucount);
|
||||
break;
|
||||
case OUTPUT_THREADS:
|
||||
printf ("%u\n", notmuch_query_count_threads (query));
|
||||
status = notmuch_query_count_threads_st (query, &ucount);
|
||||
if (print_status_query ("notmuch count", query, status))
|
||||
return -1;
|
||||
printf ("%u", ucount);
|
||||
break;
|
||||
case OUTPUT_FILES:
|
||||
printf ("%u\n", count_files (query));
|
||||
count = count_files (query);
|
||||
if (count >= 0) {
|
||||
printf ("%u", count);
|
||||
} else {
|
||||
ret = -1;
|
||||
goto DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (print_lastmod) {
|
||||
revision = notmuch_database_get_revision (notmuch, &uuid);
|
||||
printf ("\t%s\t%lu\n", uuid, revision);
|
||||
} else {
|
||||
fputs ("\n", stdout);
|
||||
}
|
||||
|
||||
DONE:
|
||||
notmuch_query_destroy (query);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
count_file (notmuch_database_t *notmuch, FILE *input, const char **exclude_tags,
|
||||
size_t exclude_tags_length, int output)
|
||||
size_t exclude_tags_length, int output, int print_lastmod)
|
||||
{
|
||||
char *line = NULL;
|
||||
ssize_t line_len;
|
||||
size_t line_size;
|
||||
int ret = 0;
|
||||
|
||||
while (!ret && (line_len = getline (&line, &line_size, input)) != -1) {
|
||||
while (! ret && (line_len = getline (&line, &line_size, input)) != -1) {
|
||||
chomp_newline (line);
|
||||
ret = print_count (notmuch, line, exclude_tags, exclude_tags_length,
|
||||
output);
|
||||
output, print_lastmod);
|
||||
}
|
||||
|
||||
if (line)
|
||||
|
@ -130,6 +159,7 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
const char **search_exclude_tags = NULL;
|
||||
size_t search_exclude_tags_length = 0;
|
||||
notmuch_bool_t batch = FALSE;
|
||||
notmuch_bool_t print_lastmod = FALSE;
|
||||
FILE *input = stdin;
|
||||
char *input_file_name = NULL;
|
||||
int ret;
|
||||
|
@ -144,8 +174,10 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
(notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
|
||||
{ "false", EXCLUDE_FALSE },
|
||||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &print_lastmod, "lastmod", 'l', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &batch, "batch", 0, 0 },
|
||||
{ NOTMUCH_OPT_STRING, &input_file_name, "input", 'i', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -153,6 +185,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (input_file_name) {
|
||||
batch = TRUE;
|
||||
input = fopen (input_file_name, "r");
|
||||
|
@ -172,7 +206,9 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
query_str = query_string_from_args (config, argc-opt_index, argv+opt_index);
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
query_str = query_string_from_args (config, argc - opt_index, argv + opt_index);
|
||||
if (query_str == NULL) {
|
||||
fprintf (stderr, "Out of memory.\n");
|
||||
return EXIT_FAILURE;
|
||||
|
@ -185,10 +221,10 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
|
||||
if (batch)
|
||||
ret = count_file (notmuch, input, search_exclude_tags,
|
||||
search_exclude_tags_length, output);
|
||||
search_exclude_tags_length, output, print_lastmod);
|
||||
else
|
||||
ret = print_count (notmuch, query_str, search_exclude_tags,
|
||||
search_exclude_tags_length, output);
|
||||
search_exclude_tags_length, output, print_lastmod);
|
||||
|
||||
notmuch_database_destroy (notmuch);
|
||||
|
||||
|
|
|
@ -48,8 +48,13 @@ database_dump_file (notmuch_database_t *notmuch, gzFile output,
|
|||
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
notmuch_status_t status;
|
||||
|
||||
for (messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch dump", query, status))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
notmuch_messages_move_to_next (messages)) {
|
||||
int first = 1;
|
||||
|
@ -215,6 +220,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
char *output_file_name = NULL;
|
||||
int opt_index;
|
||||
|
||||
|
@ -228,6 +235,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &gzip_output, "gzip", 'z', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -235,6 +243,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (opt_index < argc) {
|
||||
query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index);
|
||||
if (query_str == NULL) {
|
||||
|
|
|
@ -34,12 +34,13 @@ EMACS=${EMACS-emacs}
|
|||
EMACSCLIENT=${EMACSCLIENT-emacsclient}
|
||||
|
||||
PRINT_ONLY=
|
||||
NO_WINDOW=
|
||||
USE_EMACSCLIENT=
|
||||
CLIENT_TYPE="-c"
|
||||
AUTO_DAEMON=
|
||||
CREATE_FRAME=
|
||||
|
||||
# The crux of it all: construct an elisp progn and eval it.
|
||||
ELISP="(prog1 'done (require 'notmuch) (notmuch-mua-new-mail)"
|
||||
ELISP="${ELISP} (setq message-exit-actions (list #'save-buffers-kill-terminal))"
|
||||
|
||||
# Short options compatible with mutt(1).
|
||||
while getopts :s:c:b:i:h opt; do
|
||||
|
@ -63,7 +64,7 @@ while getopts :s:c:b:i:h opt; do
|
|||
opt=${opt%%=*}
|
||||
;;
|
||||
# Long options without arguments.
|
||||
--help|--print|--no-window-system|--client)
|
||||
--help|--print|--no-window-system|--client|--auto-daemon|--create-frame)
|
||||
;;
|
||||
*)
|
||||
echo "$0: unknown long option ${opt}, or argument mismatch." >&2
|
||||
|
@ -81,9 +82,6 @@ while getopts :s:c:b:i:h opt; do
|
|||
--help|h)
|
||||
exec man notmuch-emacs-mua
|
||||
;;
|
||||
--client)
|
||||
USE_EMACSCLIENT="yes"
|
||||
;;
|
||||
--subject|s)
|
||||
ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")"
|
||||
;;
|
||||
|
@ -103,7 +101,17 @@ while getopts :s:c:b:i:h opt; do
|
|||
PRINT_ONLY=1
|
||||
;;
|
||||
--no-window-system)
|
||||
CLIENT_TYPE="-t"
|
||||
NO_WINDOW="-nw"
|
||||
;;
|
||||
--client)
|
||||
USE_EMACSCLIENT="yes"
|
||||
;;
|
||||
--auto-daemon)
|
||||
AUTO_DAEMON="--alternate-editor="
|
||||
CREATE_FRAME="-c"
|
||||
;;
|
||||
--create-frame)
|
||||
CREATE_FRAME="-c"
|
||||
;;
|
||||
*)
|
||||
# We should never end up here.
|
||||
|
@ -122,6 +130,11 @@ for arg; do
|
|||
ELISP="${ELISP} (message-goto-to) (insert \"${arg}, \")"
|
||||
done
|
||||
|
||||
# Kill the terminal/frame if we're creating one.
|
||||
if [ -z "$USE_EMACSCLIENT" -o -n "$CREATE_FRAME" -o -n "$NO_WINDOW" ]; then
|
||||
ELISP="${ELISP} (setq message-exit-actions (list #'save-buffers-kill-terminal))"
|
||||
fi
|
||||
|
||||
# End progn.
|
||||
ELISP="${ELISP})"
|
||||
|
||||
|
@ -132,7 +145,7 @@ fi
|
|||
|
||||
if [ -n "$USE_EMACSCLIENT" ]; then
|
||||
# Evaluate the progn.
|
||||
exec ${EMACSCLIENT} ${CLIENT_TYPE} -a '' --eval "${ELISP}"
|
||||
exec ${EMACSCLIENT} ${NO_WINDOW} ${CREATE_FRAME} ${AUTO_DAEMON} --eval "${ELISP}"
|
||||
else
|
||||
exec ${EMACS} --eval "${ELISP}"
|
||||
exec ${EMACS} ${NO_WINDOW} --eval "${ELISP}"
|
||||
fi
|
||||
|
|
|
@ -466,6 +466,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ NOTMUCH_OPT_BOOLEAN, &create_folder, "create-folder", 0, 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &keep, "keep", 0, 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &no_hooks, "no-hooks", 'n', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ NOTMUCH_OPT_END, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -473,6 +474,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
db_path = notmuch_config_get_database_path (config);
|
||||
new_tags = notmuch_config_get_new_tags (config, &new_tags_length);
|
||||
synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
|
||||
|
@ -521,7 +524,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Setup our handler for SIGINT. We do not set SA_RESTART so that copying
|
||||
/* Set up our handler for SIGINT. We do not set SA_RESTART so that copying
|
||||
* from standard input may be interrupted. */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
action.sa_handler = handle_sigint;
|
||||
|
@ -533,6 +536,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
/* Write the message to the Maildir new directory. */
|
||||
newpath = maildir_write_new (config, STDIN_FILENO, maildir);
|
||||
if (! newpath) {
|
||||
|
|
|
@ -528,6 +528,10 @@ add_files (notmuch_database_t *notmuch,
|
|||
"%s/%s", path,
|
||||
notmuch_filenames_get (db_files));
|
||||
|
||||
if (state->debug)
|
||||
printf ("(D) add_files_recursive, pass 2: queuing passed file %s for deletion from database\n",
|
||||
absolute);
|
||||
|
||||
_filename_list_add (state->removed_files, absolute);
|
||||
|
||||
notmuch_filenames_move_to_next (db_files);
|
||||
|
@ -542,6 +546,9 @@ add_files (notmuch_database_t *notmuch,
|
|||
{
|
||||
char *absolute = talloc_asprintf (state->removed_directories,
|
||||
"%s/%s", path, filename);
|
||||
if (state->debug)
|
||||
printf ("(D) add_files_recursive, pass 2: queuing passed directory %s for deletion from database\n",
|
||||
absolute);
|
||||
|
||||
_filename_list_add (state->removed_directories, absolute);
|
||||
}
|
||||
|
@ -610,6 +617,9 @@ add_files (notmuch_database_t *notmuch,
|
|||
char *absolute = talloc_asprintf (state->removed_files,
|
||||
"%s/%s", path,
|
||||
notmuch_filenames_get (db_files));
|
||||
if (state->debug)
|
||||
printf ("(D) add_files_recursive, pass 3: queuing leftover file %s for deletion from database\n",
|
||||
absolute);
|
||||
|
||||
_filename_list_add (state->removed_files, absolute);
|
||||
|
||||
|
@ -622,6 +632,10 @@ add_files (notmuch_database_t *notmuch,
|
|||
"%s/%s", path,
|
||||
notmuch_filenames_get (db_subdirs));
|
||||
|
||||
if (state->debug)
|
||||
printf ("(D) add_files_recursive, pass 3: queuing leftover directory %s for deletion from database\n",
|
||||
absolute);
|
||||
|
||||
_filename_list_add (state->removed_directories, absolute);
|
||||
|
||||
notmuch_filenames_move_to_next (db_subdirs);
|
||||
|
@ -662,7 +676,7 @@ setup_progress_printing_timer (void)
|
|||
struct sigaction action;
|
||||
struct itimerval timerval;
|
||||
|
||||
/* Setup our handler for SIGALRM */
|
||||
/* Set up our handler for SIGALRM */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
action.sa_handler = handle_sigalrm;
|
||||
sigemptyset (&action.sa_mask);
|
||||
|
@ -864,8 +878,11 @@ _remove_directory (void *ctx,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
status = notmuch_directory_delete (directory);
|
||||
|
||||
DONE:
|
||||
notmuch_directory_destroy (directory);
|
||||
if (status)
|
||||
notmuch_directory_destroy (directory);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -910,7 +927,11 @@ int
|
|||
notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
||||
{
|
||||
notmuch_database_t *notmuch;
|
||||
add_files_state_t add_files_state;
|
||||
add_files_state_t add_files_state = {
|
||||
.verbosity = VERBOSITY_NORMAL,
|
||||
.debug = FALSE,
|
||||
.output_is_a_tty = isatty (fileno (stdout)),
|
||||
};
|
||||
struct timeval tv_start;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
|
@ -925,15 +946,12 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
notmuch_bool_t quiet = FALSE, verbose = FALSE;
|
||||
notmuch_status_t status;
|
||||
|
||||
add_files_state.verbosity = VERBOSITY_NORMAL;
|
||||
add_files_state.debug = FALSE;
|
||||
add_files_state.output_is_a_tty = isatty (fileno (stdout));
|
||||
|
||||
notmuch_opt_desc_t options[] = {
|
||||
{ NOTMUCH_OPT_BOOLEAN, &quiet, "quiet", 'q', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &verbose, "verbose", 'v', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &add_files_state.debug, "debug", 'd', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &no_hooks, "no-hooks", 'n', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -941,6 +959,8 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
/* quiet trumps verbose */
|
||||
if (quiet)
|
||||
add_files_state.verbosity = VERBOSITY_QUIET;
|
||||
|
@ -992,10 +1012,11 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
fputs (status_string, stderr);
|
||||
free (status_string);
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
if (notmuch_database_needs_upgrade (notmuch)) {
|
||||
time_t now = time (NULL);
|
||||
struct tm *gm_time = gmtime (&now);
|
||||
|
@ -1047,7 +1068,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (notmuch == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* Setup our handler for SIGINT. We do this after having
|
||||
/* Set up our handler for SIGINT. We do this after having
|
||||
* potentially done a database upgrade we this interrupt handler
|
||||
* won't support. */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
|
@ -1059,9 +1080,6 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
talloc_free (dot_notmuch_path);
|
||||
dot_notmuch_path = NULL;
|
||||
|
||||
add_files_state.processed_files = 0;
|
||||
add_files_state.added_messages = 0;
|
||||
add_files_state.removed_messages = add_files_state.renamed_messages = 0;
|
||||
gettimeofday (&add_files_state.tv_start, NULL);
|
||||
|
||||
add_files_state.removed_files = _filename_list_create (config);
|
||||
|
|
|
@ -606,8 +606,13 @@ notmuch_reply_format_default(void *ctx,
|
|||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
mime_node_t *root;
|
||||
notmuch_status_t status;
|
||||
|
||||
for (messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch reply", query, status))
|
||||
return 1;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
notmuch_messages_move_to_next (messages))
|
||||
{
|
||||
|
@ -650,13 +655,22 @@ notmuch_reply_format_sprinter(void *ctx,
|
|||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
mime_node_t *node;
|
||||
unsigned count;
|
||||
notmuch_status_t status;
|
||||
|
||||
if (notmuch_query_count_messages (query) != 1) {
|
||||
status = notmuch_query_count_messages_st (query, &count);
|
||||
if (print_status_query ("notmuch reply", query, status))
|
||||
return 1;
|
||||
|
||||
if (count != 1) {
|
||||
fprintf (stderr, "Error: search term did not match precisely one message.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch reply", query, status))
|
||||
return 1;
|
||||
|
||||
message = notmuch_messages_get (messages);
|
||||
if (mime_node_open (ctx, message, &(params->crypto), &node) != NOTMUCH_STATUS_SUCCESS)
|
||||
return 1;
|
||||
|
@ -698,8 +712,13 @@ notmuch_reply_format_headers_only(void *ctx,
|
|||
notmuch_message_t *message;
|
||||
const char *in_reply_to, *orig_references, *references;
|
||||
char *reply_headers;
|
||||
notmuch_status_t status;
|
||||
|
||||
for (messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch reply", query, status))
|
||||
return 1;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages);
|
||||
notmuch_messages_move_to_next (messages))
|
||||
{
|
||||
|
@ -790,6 +809,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ "sender", FALSE },
|
||||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -797,6 +817,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (format == FORMAT_HEADERS_ONLY) {
|
||||
reply_format_func = notmuch_reply_format_headers_only;
|
||||
} else if (format == FORMAT_JSON) {
|
||||
|
@ -828,6 +850,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
query = notmuch_query_create (notmuch, query_string);
|
||||
if (query == NULL) {
|
||||
fprintf (stderr, "Out of memory\n");
|
||||
|
|
|
@ -154,6 +154,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_STRING, &input_file_name, "input", 'i', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &accumulate, "accumulate", 'a', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -163,6 +164,9 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
name_for_error = input_file_name ? input_file_name : "stdin";
|
||||
|
||||
if (! accumulate)
|
||||
|
|
212
notmuch-search.c
212
notmuch-search.c
|
@ -36,6 +36,12 @@ typedef enum {
|
|||
OUTPUT_COUNT = 1 << 7,
|
||||
} output_t;
|
||||
|
||||
typedef enum {
|
||||
DEDUP_NONE,
|
||||
DEDUP_MAILBOX,
|
||||
DEDUP_ADDRESS,
|
||||
} dedup_t;
|
||||
|
||||
typedef enum {
|
||||
NOTMUCH_FORMAT_JSON,
|
||||
NOTMUCH_FORMAT_TEXT,
|
||||
|
@ -55,6 +61,7 @@ typedef struct {
|
|||
int limit;
|
||||
int dupe;
|
||||
GHashTable *addresses;
|
||||
dedup_t dedup;
|
||||
} search_context_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -111,15 +118,22 @@ do_search_threads (search_context_t *ctx)
|
|||
sprinter_t *format = ctx->format;
|
||||
time_t date;
|
||||
int i;
|
||||
notmuch_status_t status;
|
||||
|
||||
if (ctx->offset < 0) {
|
||||
ctx->offset += notmuch_query_count_threads (ctx->query);
|
||||
unsigned count;
|
||||
notmuch_status_t status;
|
||||
status = notmuch_query_count_threads_st (ctx->query, &count);
|
||||
if (print_status_query ("notmuch search", ctx->query, status))
|
||||
return 1;
|
||||
|
||||
ctx->offset += count;
|
||||
if (ctx->offset < 0)
|
||||
ctx->offset = 0;
|
||||
}
|
||||
|
||||
threads = notmuch_query_search_threads (ctx->query);
|
||||
if (threads == NULL)
|
||||
status = notmuch_query_search_threads_st (ctx->query, &threads);
|
||||
if (print_status_query("notmuch search", ctx->query, status))
|
||||
return 1;
|
||||
|
||||
format->begin_list (format);
|
||||
|
@ -243,33 +257,87 @@ do_search_threads (search_context_t *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static mailbox_t *new_mailbox (void *ctx, const char *name, const char *addr)
|
||||
{
|
||||
mailbox_t *mailbox;
|
||||
|
||||
mailbox = talloc (ctx, mailbox_t);
|
||||
if (! mailbox)
|
||||
return NULL;
|
||||
|
||||
mailbox->name = talloc_strdup (mailbox, name);
|
||||
mailbox->addr = talloc_strdup (mailbox, addr);
|
||||
mailbox->count = 1;
|
||||
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
static int mailbox_compare (const void *v1, const void *v2)
|
||||
{
|
||||
const mailbox_t *m1 = v1, *m2 = v2;
|
||||
int ret;
|
||||
|
||||
ret = strcmp_null (m1->name, m2->name);
|
||||
if (! ret)
|
||||
ret = strcmp (m1->addr, m2->addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns TRUE iff name and addr is duplicate. If not, stores the
|
||||
* name/addr pair in order to detect subsequent duplicates. */
|
||||
static notmuch_bool_t
|
||||
is_duplicate (const search_context_t *ctx, const char *name, const char *addr)
|
||||
{
|
||||
notmuch_bool_t duplicate;
|
||||
char *key;
|
||||
GList *list, *l;
|
||||
mailbox_t *mailbox;
|
||||
|
||||
key = talloc_asprintf (ctx->format, "%s <%s>", name, addr);
|
||||
list = g_hash_table_lookup (ctx->addresses, addr);
|
||||
if (list) {
|
||||
mailbox_t find = {
|
||||
.name = name,
|
||||
.addr = addr,
|
||||
};
|
||||
|
||||
l = g_list_find_custom (list, &find, mailbox_compare);
|
||||
if (l) {
|
||||
mailbox = l->data;
|
||||
mailbox->count++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mailbox = new_mailbox (ctx->format, name, addr);
|
||||
if (! mailbox)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* XXX: It would be more efficient to prepend to the list, but
|
||||
* then we'd have to store the changed list head back to the
|
||||
* hash table. This check is here just to avoid the compiler
|
||||
* warning for unused result.
|
||||
*/
|
||||
if (list != g_list_append (list, mailbox))
|
||||
INTERNAL_ERROR ("appending to list changed list head\n");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
key = talloc_strdup (ctx->format, addr);
|
||||
if (! key)
|
||||
return FALSE;
|
||||
|
||||
duplicate = g_hash_table_lookup_extended (ctx->addresses, key, NULL, (gpointer)&mailbox);
|
||||
mailbox = new_mailbox (ctx->format, name, addr);
|
||||
if (! mailbox)
|
||||
return FALSE;
|
||||
|
||||
if (! duplicate) {
|
||||
mailbox = talloc (ctx->format, mailbox_t);
|
||||
mailbox->name = talloc_strdup (mailbox, name);
|
||||
mailbox->addr = talloc_strdup (mailbox, addr);
|
||||
mailbox->count = 1;
|
||||
g_hash_table_insert (ctx->addresses, key, mailbox);
|
||||
} else {
|
||||
mailbox->count++;
|
||||
talloc_free (key);
|
||||
}
|
||||
list = g_list_append (NULL, mailbox);
|
||||
if (! list)
|
||||
return FALSE;
|
||||
|
||||
return duplicate;
|
||||
g_hash_table_insert (ctx->addresses, key, list);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -287,7 +355,7 @@ print_mailbox (const search_context_t *ctx, const mailbox_t *mailbox)
|
|||
name_addr = internet_address_to_string (ia, FALSE);
|
||||
|
||||
if (format->is_text_printer) {
|
||||
if (count > 0) {
|
||||
if (ctx->output & OUTPUT_COUNT) {
|
||||
format->integer (format, count);
|
||||
format->string (format, "\t");
|
||||
}
|
||||
|
@ -301,7 +369,7 @@ print_mailbox (const search_context_t *ctx, const mailbox_t *mailbox)
|
|||
format->string (format, addr);
|
||||
format->map_key (format, "name-addr");
|
||||
format->string (format, name_addr);
|
||||
if (count > 0) {
|
||||
if (ctx->output & OUTPUT_COUNT) {
|
||||
format->map_key (format, "count");
|
||||
format->integer (format, count);
|
||||
}
|
||||
|
@ -338,13 +406,15 @@ process_address_list (const search_context_t *ctx,
|
|||
mailbox_t mbx = {
|
||||
.name = internet_address_get_name (address),
|
||||
.addr = internet_address_mailbox_get_addr (mailbox),
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
if (is_duplicate (ctx, mbx.name, mbx.addr))
|
||||
/* OUTPUT_COUNT only works with deduplication */
|
||||
if (ctx->dedup != DEDUP_NONE &&
|
||||
is_duplicate (ctx, mbx.name, mbx.addr))
|
||||
continue;
|
||||
|
||||
if (ctx->output & OUTPUT_COUNT)
|
||||
/* OUTPUT_COUNT and DEDUP_ADDRESS require a full pass. */
|
||||
if (ctx->output & OUTPUT_COUNT || ctx->dedup == DEDUP_ADDRESS)
|
||||
continue;
|
||||
|
||||
print_mailbox (ctx, &mbx);
|
||||
|
@ -378,14 +448,56 @@ _talloc_free_for_g_hash (void *ptr)
|
|||
}
|
||||
|
||||
static void
|
||||
print_hash_value (unused (gpointer key), gpointer value, gpointer user_data)
|
||||
_list_free_for_g_hash (void *ptr)
|
||||
{
|
||||
const mailbox_t *mailbox = value;
|
||||
search_context_t *ctx = user_data;
|
||||
g_list_free_full (ptr, _talloc_free_for_g_hash);
|
||||
}
|
||||
|
||||
/* Print the most common variant of a list of unique mailboxes, and
|
||||
* conflate the counts. */
|
||||
static void
|
||||
print_popular (const search_context_t *ctx, GList *list)
|
||||
{
|
||||
GList *l;
|
||||
mailbox_t *mailbox = NULL, *m;
|
||||
int max = 0;
|
||||
int total = 0;
|
||||
|
||||
for (l = list; l; l = l->next) {
|
||||
m = l->data;
|
||||
total += m->count;
|
||||
if (m->count > max) {
|
||||
mailbox = m;
|
||||
max = m->count;
|
||||
}
|
||||
}
|
||||
|
||||
if (! mailbox)
|
||||
INTERNAL_ERROR("Empty list in address hash table\n");
|
||||
|
||||
/* The original count is no longer needed, so overwrite. */
|
||||
mailbox->count = total;
|
||||
|
||||
print_mailbox (ctx, mailbox);
|
||||
}
|
||||
|
||||
static void
|
||||
print_list_value (void *mailbox, void *context)
|
||||
{
|
||||
print_mailbox (context, mailbox);
|
||||
}
|
||||
|
||||
static void
|
||||
print_hash_value (unused (void *key), void *list, void *context)
|
||||
{
|
||||
const search_context_t *ctx = context;
|
||||
|
||||
if (ctx->dedup == DEDUP_ADDRESS)
|
||||
print_popular (ctx, list);
|
||||
else
|
||||
g_list_foreach (list, print_list_value, context);
|
||||
}
|
||||
|
||||
static int
|
||||
_count_filenames (notmuch_message_t *message)
|
||||
{
|
||||
|
@ -412,15 +524,22 @@ do_search_messages (search_context_t *ctx)
|
|||
notmuch_filenames_t *filenames;
|
||||
sprinter_t *format = ctx->format;
|
||||
int i;
|
||||
notmuch_status_t status;
|
||||
|
||||
if (ctx->offset < 0) {
|
||||
ctx->offset += notmuch_query_count_messages (ctx->query);
|
||||
unsigned count;
|
||||
notmuch_status_t status;
|
||||
status = notmuch_query_count_messages_st (ctx->query, &count);
|
||||
if (print_status_query ("notmuch search", ctx->query, status))
|
||||
return 1;
|
||||
|
||||
ctx->offset += count;
|
||||
if (ctx->offset < 0)
|
||||
ctx->offset = 0;
|
||||
}
|
||||
|
||||
messages = notmuch_query_search_messages (ctx->query);
|
||||
if (messages == NULL)
|
||||
status = notmuch_query_search_messages_st (ctx->query, &messages);
|
||||
if (print_status_query ("notmuch search", ctx->query, status))
|
||||
return 1;
|
||||
|
||||
format->begin_list (format);
|
||||
|
@ -481,7 +600,8 @@ do_search_messages (search_context_t *ctx)
|
|||
notmuch_message_destroy (message);
|
||||
}
|
||||
|
||||
if (ctx->addresses && ctx->output & OUTPUT_COUNT)
|
||||
if (ctx->addresses &&
|
||||
(ctx->output & OUTPUT_COUNT || ctx->dedup == DEDUP_ADDRESS))
|
||||
g_hash_table_foreach (ctx->addresses, print_hash_value, ctx);
|
||||
|
||||
notmuch_messages_destroy (messages);
|
||||
|
@ -508,8 +628,9 @@ do_search_tags (const search_context_t *ctx)
|
|||
if (strcmp (notmuch_query_get_query_string (query), "*") == 0) {
|
||||
tags = notmuch_database_get_all_tags (notmuch);
|
||||
} else {
|
||||
messages = notmuch_query_search_messages (query);
|
||||
if (messages == NULL)
|
||||
notmuch_status_t status;
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch search", query, status))
|
||||
return 1;
|
||||
|
||||
tags = notmuch_messages_collect_tags (messages);
|
||||
|
@ -583,6 +704,8 @@ _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int ar
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (ctx->notmuch);
|
||||
|
||||
query_str = query_string_from_args (ctx->notmuch, argc, argv);
|
||||
if (query_str == NULL) {
|
||||
fprintf (stderr, "Out of memory.\n");
|
||||
|
@ -640,6 +763,7 @@ static search_context_t search_context = {
|
|||
.offset = 0,
|
||||
.limit = -1, /* unlimited */
|
||||
.dupe = -1,
|
||||
.dedup = DEDUP_MAILBOX,
|
||||
};
|
||||
|
||||
static const notmuch_opt_desc_t common_options[] = {
|
||||
|
@ -681,6 +805,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ NOTMUCH_OPT_INT, &ctx->limit, "limit", 'L', 0 },
|
||||
{ NOTMUCH_OPT_INT, &ctx->dupe, "duplicate", 'D', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) &common_options, NULL, 0, 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -689,6 +814,8 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (ctx->output != OUTPUT_FILES && ctx->output != OUTPUT_MESSAGES &&
|
||||
ctx->dupe != -1) {
|
||||
fprintf (stderr, "Error: --duplicate=N is only supported with --output=files and --output=messages.\n");
|
||||
|
@ -736,7 +863,13 @@ notmuch_address_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
(notmuch_keyword_t []){ { "true", NOTMUCH_EXCLUDE_TRUE },
|
||||
{ "false", NOTMUCH_EXCLUDE_FALSE },
|
||||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_KEYWORD, &ctx->dedup, "deduplicate", 'D',
|
||||
(notmuch_keyword_t []){ { "no", DEDUP_NONE },
|
||||
{ "mailbox", DEDUP_MAILBOX },
|
||||
{ "address", DEDUP_ADDRESS },
|
||||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) &common_options, NULL, 0, 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -744,15 +877,28 @@ notmuch_address_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (! (ctx->output & (OUTPUT_SENDER | OUTPUT_RECIPIENTS)))
|
||||
ctx->output |= OUTPUT_SENDER;
|
||||
|
||||
if (ctx->output & OUTPUT_COUNT && ctx->dedup == DEDUP_NONE) {
|
||||
fprintf (stderr, "--output=count is not applicable with --deduplicate=no\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (_notmuch_search_prepare (ctx, config,
|
||||
argc - opt_index, argv + opt_index))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
ctx->addresses = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
_talloc_free_for_g_hash, _talloc_free_for_g_hash);
|
||||
ctx->addresses = g_hash_table_new_full (strcase_hash, strcase_equal,
|
||||
_talloc_free_for_g_hash,
|
||||
_list_free_for_g_hash);
|
||||
|
||||
/* The order is not guaranteed if a full pass is required, so go
|
||||
* for fastest. */
|
||||
if (ctx->output & OUTPUT_COUNT || ctx->dedup == DEDUP_ADDRESS)
|
||||
notmuch_query_set_sort (ctx->query, NOTMUCH_SORT_UNSORTED);
|
||||
|
||||
ret = do_search_messages (ctx);
|
||||
|
||||
|
|
|
@ -145,6 +145,13 @@ notmuch_setup_command (notmuch_config_t *config,
|
|||
chomp_newline (response); \
|
||||
} while (0)
|
||||
|
||||
if (notmuch_minimal_options ("setup", argc, argv) < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (notmuch_requested_db_uuid)
|
||||
fprintf (stderr, "Warning: ignoring --uuid=%s\n",
|
||||
notmuch_requested_db_uuid);
|
||||
|
||||
if (notmuch_config_is_new (config))
|
||||
welcome_message_pre_setup ();
|
||||
|
||||
|
|
109
notmuch-show.c
109
notmuch-show.c
|
@ -334,8 +334,6 @@ show_text_part_content (GMimeObject *part, GMimeStream *stream_out,
|
|||
g_object_unref(stream_filter);
|
||||
}
|
||||
|
||||
#ifdef GMIME_ATLEAST_26
|
||||
|
||||
/* Get signature status string (GMime 2.6) */
|
||||
static const char*
|
||||
signature_status_to_string (GMimeSignatureStatus x)
|
||||
|
@ -427,91 +425,6 @@ format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node)
|
|||
sp->end (sp);
|
||||
}
|
||||
|
||||
#else /* GMIME_ATLEAST_26 */
|
||||
|
||||
/* Get signature status string (GMime 2.4) */
|
||||
static const char*
|
||||
signer_status_to_string (GMimeSignerStatus x)
|
||||
{
|
||||
switch (x) {
|
||||
case GMIME_SIGNER_STATUS_NONE:
|
||||
return "none";
|
||||
case GMIME_SIGNER_STATUS_GOOD:
|
||||
return "good";
|
||||
case GMIME_SIGNER_STATUS_BAD:
|
||||
return "bad";
|
||||
case GMIME_SIGNER_STATUS_ERROR:
|
||||
return "error";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/* Signature status sprinter (GMime 2.4) */
|
||||
static void
|
||||
format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node)
|
||||
{
|
||||
const GMimeSignatureValidity* validity = node->sig_validity;
|
||||
|
||||
sp->begin_list (sp);
|
||||
|
||||
if (!validity) {
|
||||
sp->end (sp);
|
||||
return;
|
||||
}
|
||||
|
||||
const GMimeSigner *signer = g_mime_signature_validity_get_signers (validity);
|
||||
while (signer) {
|
||||
sp->begin_map (sp);
|
||||
|
||||
/* status */
|
||||
sp->map_key (sp, "status");
|
||||
sp->string (sp, signer_status_to_string (signer->status));
|
||||
|
||||
if (signer->status == GMIME_SIGNER_STATUS_GOOD)
|
||||
{
|
||||
if (signer->fingerprint) {
|
||||
sp->map_key (sp, "fingerprint");
|
||||
sp->string (sp, signer->fingerprint);
|
||||
}
|
||||
/* these dates are seconds since the epoch; should we
|
||||
* provide a more human-readable format string? */
|
||||
if (signer->created) {
|
||||
sp->map_key (sp, "created");
|
||||
sp->integer (sp, signer->created);
|
||||
}
|
||||
if (signer->expires) {
|
||||
sp->map_key (sp, "expires");
|
||||
sp->integer (sp, signer->expires);
|
||||
}
|
||||
/* output user id only if validity is FULL or ULTIMATE. */
|
||||
/* note that gmime is using the term "trust" here, which
|
||||
* is WRONG. It's actually user id "validity". */
|
||||
if ((signer->name) && (signer->trust)) {
|
||||
if ((signer->trust == GMIME_SIGNER_TRUST_FULLY) || (signer->trust == GMIME_SIGNER_TRUST_ULTIMATE)) {
|
||||
sp->map_key (sp, "userid");
|
||||
sp->string (sp, signer->name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (signer->keyid) {
|
||||
sp->map_key (sp, "keyid");
|
||||
sp->string (sp, signer->keyid);
|
||||
}
|
||||
}
|
||||
if (signer->errors != GMIME_SIGNER_ERROR_NONE) {
|
||||
sp->map_key (sp, "errors");
|
||||
sp->integer (sp, signer->errors);
|
||||
}
|
||||
|
||||
sp->end (sp);
|
||||
signer = signer->next;
|
||||
}
|
||||
|
||||
sp->end (sp);
|
||||
}
|
||||
|
||||
#endif /* GMIME_ATLEAST_26 */
|
||||
|
||||
static notmuch_status_t
|
||||
format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node,
|
||||
int indent, const notmuch_show_params_t *params)
|
||||
|
@ -982,13 +895,22 @@ do_show_single (void *ctx,
|
|||
{
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
notmuch_status_t status;
|
||||
unsigned int count;
|
||||
|
||||
if (notmuch_query_count_messages (query) != 1) {
|
||||
status = notmuch_query_count_messages_st (query, &count);
|
||||
if (print_status_query ("notmuch show", query, status))
|
||||
return 1;
|
||||
|
||||
if (count != 1) {
|
||||
fprintf (stderr, "Error: search term did not match precisely one message.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch show", query, status))
|
||||
return 1;
|
||||
|
||||
message = notmuch_messages_get (messages);
|
||||
|
||||
if (message == NULL) {
|
||||
|
@ -1015,8 +937,8 @@ do_show (void *ctx,
|
|||
notmuch_messages_t *messages;
|
||||
notmuch_status_t status, res = NOTMUCH_STATUS_SUCCESS;
|
||||
|
||||
threads = notmuch_query_search_threads (query);
|
||||
if (! threads)
|
||||
status= notmuch_query_search_threads_st (query, &threads);
|
||||
if (print_status_query ("notmuch show", query, status))
|
||||
return 1;
|
||||
|
||||
sp->begin_list (sp);
|
||||
|
@ -1114,6 +1036,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.verify, "verify", 'v', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, ¶ms.output_body, "body", 'b', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, ¶ms.include_html, "include-html", 0, 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -1121,6 +1044,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
/* decryption implies verification */
|
||||
if (params.crypto.decrypt)
|
||||
params.crypto.verify = TRUE;
|
||||
|
@ -1210,6 +1135,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
query = notmuch_query_create (notmuch, query_string);
|
||||
if (query == NULL) {
|
||||
fprintf (stderr, "Out of memory\n");
|
||||
|
|
|
@ -97,6 +97,8 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,
|
|||
notmuch_query_t *query;
|
||||
notmuch_messages_t *messages;
|
||||
notmuch_message_t *message;
|
||||
notmuch_status_t status;
|
||||
|
||||
int ret = NOTMUCH_STATUS_SUCCESS;
|
||||
|
||||
if (! (flags & TAG_FLAG_REMOVE_ALL)) {
|
||||
|
@ -119,7 +121,11 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,
|
|||
/* tagging is not interested in any special sort order */
|
||||
notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED);
|
||||
|
||||
for (messages = notmuch_query_search_messages (query);
|
||||
status = notmuch_query_search_messages_st (query, &messages);
|
||||
if (print_status_query ("notmuch tag", query, status))
|
||||
return status;
|
||||
|
||||
for (;
|
||||
notmuch_messages_valid (messages) && ! interrupted;
|
||||
notmuch_messages_move_to_next (messages)) {
|
||||
message = notmuch_messages_get (messages);
|
||||
|
@ -195,7 +201,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
int opt_index;
|
||||
int ret;
|
||||
|
||||
/* Setup our handler for SIGINT */
|
||||
/* Set up our handler for SIGINT */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
action.sa_handler = handle_sigint;
|
||||
sigemptyset (&action.sa_mask);
|
||||
|
@ -206,6 +212,7 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ NOTMUCH_OPT_BOOLEAN, &batch, "batch", 0, 0 },
|
||||
{ NOTMUCH_OPT_STRING, &input_file_name, "input", 'i', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &remove_all, "remove-all", 0, 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -213,6 +220,8 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_process_shared_options (argv[0]);
|
||||
|
||||
if (input_file_name) {
|
||||
batch = TRUE;
|
||||
input = fopen (input_file_name, "r");
|
||||
|
@ -258,6 +267,8 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
if (notmuch_config_get_maildir_synchronize_flags (config))
|
||||
tag_flags |= TAG_FLAG_MAILDIR_SYNC;
|
||||
|
||||
|
|
134
notmuch.c
134
notmuch.c
|
@ -43,11 +43,64 @@ notmuch_help_command (notmuch_config_t *config, int argc, char *argv[]);
|
|||
static int
|
||||
notmuch_command (notmuch_config_t *config, int argc, char *argv[]);
|
||||
|
||||
static int
|
||||
_help_for (const char *topic);
|
||||
|
||||
static notmuch_bool_t print_version = FALSE, print_help = FALSE;
|
||||
char *notmuch_requested_db_uuid = NULL;
|
||||
|
||||
const notmuch_opt_desc_t notmuch_shared_options [] = {
|
||||
{ NOTMUCH_OPT_BOOLEAN, &print_version, "version", 'v', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &print_help, "help", 'h', 0 },
|
||||
{ NOTMUCH_OPT_STRING, ¬much_requested_db_uuid, "uuid", 'u', 0 },
|
||||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* any subcommand wanting to support these options should call
|
||||
* inherit notmuch_shared_options and call
|
||||
* notmuch_process_shared_options (subcommand_name);
|
||||
*/
|
||||
void
|
||||
notmuch_process_shared_options (const char *subcommand_name) {
|
||||
if (print_version) {
|
||||
printf ("notmuch " STRINGIFY(NOTMUCH_VERSION) "\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (print_help) {
|
||||
int ret = _help_for (subcommand_name);
|
||||
exit (ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is suitable for subcommands that do not actually open the
|
||||
* database.
|
||||
*/
|
||||
int notmuch_minimal_options (const char *subcommand_name,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int opt_index;
|
||||
|
||||
notmuch_opt_desc_t options[] = {
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
opt_index = parse_arguments (argc, argv, options, 1);
|
||||
|
||||
if (opt_index < 0)
|
||||
return -1;
|
||||
|
||||
/* We can't use argv here as it is sometimes NULL */
|
||||
notmuch_process_shared_options (subcommand_name);
|
||||
return opt_index;
|
||||
}
|
||||
|
||||
static command_t commands[] = {
|
||||
{ NULL, notmuch_command, TRUE,
|
||||
"Notmuch main command." },
|
||||
{ "setup", notmuch_setup_command, TRUE,
|
||||
"Interactively setup notmuch for first use." },
|
||||
"Interactively set up notmuch for first use." },
|
||||
{ "new", notmuch_new_command, FALSE,
|
||||
"Find and import new messages to the notmuch database." },
|
||||
{ "insert", notmuch_insert_command, FALSE,
|
||||
|
@ -167,6 +220,22 @@ be supported in the future.\n", notmuch_format_version);
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch)
|
||||
{
|
||||
const char *uuid = NULL;
|
||||
|
||||
if (!notmuch_requested_db_uuid)
|
||||
return;
|
||||
IGNORE_RESULT (notmuch_database_get_revision (notmuch, &uuid));
|
||||
|
||||
if (strcmp (notmuch_requested_db_uuid, uuid) != 0){
|
||||
fprintf (stderr, "Error: requested database revision %s does not match %s\n",
|
||||
notmuch_requested_db_uuid, uuid);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exec_man (const char *page)
|
||||
{
|
||||
|
@ -177,21 +246,19 @@ exec_man (const char *page)
|
|||
}
|
||||
|
||||
static int
|
||||
notmuch_help_command (notmuch_config_t *config, int argc, char *argv[])
|
||||
_help_for (const char *topic_name)
|
||||
{
|
||||
command_t *command;
|
||||
help_topic_t *topic;
|
||||
unsigned int i;
|
||||
|
||||
argc--; argv++; /* Ignore "help" */
|
||||
|
||||
if (argc == 0) {
|
||||
if (!topic_name) {
|
||||
printf ("The notmuch mail system.\n\n");
|
||||
usage (stdout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (strcmp (argv[0], "help") == 0) {
|
||||
if (strcmp (topic_name, "help") == 0) {
|
||||
printf ("The notmuch help system.\n\n"
|
||||
"\tNotmuch uses the man command to display help. In case\n"
|
||||
"\tof difficulties check that MANPATH includes the pages\n"
|
||||
|
@ -200,26 +267,46 @@ notmuch_help_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
command = find_command (argv[0]);
|
||||
command = find_command (topic_name);
|
||||
if (command) {
|
||||
char *page = talloc_asprintf (config, "notmuch-%s", command->name);
|
||||
char *page = talloc_asprintf (NULL, "notmuch-%s", command->name);
|
||||
exec_man (page);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (help_topics); i++) {
|
||||
topic = &help_topics[i];
|
||||
if (strcmp (argv[0], topic->name) == 0) {
|
||||
char *page = talloc_asprintf (config, "notmuch-%s", topic->name);
|
||||
if (strcmp (topic_name, topic->name) == 0) {
|
||||
char *page = talloc_asprintf (NULL, "notmuch-%s", topic->name);
|
||||
exec_man (page);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr,
|
||||
"\nSorry, %s is not a known command. There's not much I can do to help.\n\n",
|
||||
argv[0]);
|
||||
topic_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
notmuch_help_command (unused (notmuch_config_t * config), int argc, char *argv[])
|
||||
{
|
||||
int opt_index;
|
||||
|
||||
opt_index = notmuch_minimal_options ("help", argc, argv);
|
||||
if (opt_index < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* skip at least subcommand argument */
|
||||
argc-= opt_index;
|
||||
argv+= opt_index;
|
||||
|
||||
if (argc == 0) {
|
||||
return _help_for (NULL);
|
||||
}
|
||||
|
||||
return _help_for (argv[0]);
|
||||
}
|
||||
|
||||
/* Handle the case of "notmuch" being invoked with no command
|
||||
* argument. For now we just call notmuch_setup_command, but we plan
|
||||
* to be more clever about this in the future.
|
||||
|
@ -285,14 +372,12 @@ main (int argc, char *argv[])
|
|||
command_t *command;
|
||||
char *config_file_name = NULL;
|
||||
notmuch_config_t *config = NULL;
|
||||
notmuch_bool_t print_help=FALSE, print_version=FALSE;
|
||||
int opt_index;
|
||||
int ret;
|
||||
|
||||
notmuch_opt_desc_t options[] = {
|
||||
{ NOTMUCH_OPT_BOOLEAN, &print_help, "help", 'h', 0 },
|
||||
{ NOTMUCH_OPT_BOOLEAN, &print_version, "version", 'v', 0 },
|
||||
{ NOTMUCH_OPT_STRING, &config_file_name, "config", 'c', 0 },
|
||||
{ NOTMUCH_OPT_INHERIT, (void *) ¬much_shared_options, NULL, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -314,28 +399,11 @@ main (int argc, char *argv[])
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
/* Handle notmuch --help [command] and notmuch command --help. */
|
||||
if (print_help ||
|
||||
(opt_index + 1 < argc && strcmp (argv[opt_index + 1], "--help") == 0)) {
|
||||
/*
|
||||
* Pass the first positional argument as argv[1] so the help
|
||||
* command can give help for it. The help command ignores the
|
||||
* argv[0] passed to it.
|
||||
*/
|
||||
ret = notmuch_help_command (NULL, argc - opt_index + 1,
|
||||
argv + opt_index - 1);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (print_version) {
|
||||
printf ("notmuch " STRINGIFY(NOTMUCH_VERSION) "\n");
|
||||
ret = EXIT_SUCCESS;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (opt_index < argc)
|
||||
command_name = argv[opt_index];
|
||||
|
||||
notmuch_process_shared_options (command_name);
|
||||
|
||||
command = find_command (command_name);
|
||||
if (!command) {
|
||||
fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
test_description='notmuch new'
|
||||
|
||||
. ./perf-test-lib.sh
|
||||
. ./perf-test-lib.sh || exit 1
|
||||
|
||||
# ensure initial 'notmuch new' is run by memory_start
|
||||
uncache_database
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
test_description='dump and restore'
|
||||
|
||||
. ./perf-test-lib.sh
|
||||
. ./perf-test-lib.sh || exit 1
|
||||
|
||||
memory_start
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
test_description='notmuch new'
|
||||
|
||||
. ./perf-test-lib.sh
|
||||
. ./perf-test-lib.sh || exit 1
|
||||
|
||||
uncache_database
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
test_description='dump and restore'
|
||||
|
||||
. ./perf-test-lib.sh
|
||||
. ./perf-test-lib.sh || exit 1
|
||||
|
||||
time_start
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
test_description='tagging'
|
||||
|
||||
. ./perf-test-lib.sh
|
||||
. ./perf-test-lib.sh || exit 1
|
||||
|
||||
time_start
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
. ./version.sh
|
||||
. ./version.sh || exit 1
|
||||
|
||||
corpus_size=large
|
||||
|
||||
|
@ -25,7 +25,7 @@ do
|
|||
echo "error: unknown performance test option '$1'" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
. ../test/test-lib-common.sh
|
||||
. ../test/test-lib-common.sh || exit 1
|
||||
|
||||
set -e
|
||||
|
||||
|
@ -203,7 +203,7 @@ time_done ()
|
|||
fi
|
||||
}
|
||||
|
||||
cd -P "$test" || error "Cannot setup test environment"
|
||||
cd -P "$test" || error "Cannot set up test environment"
|
||||
test_failure=0
|
||||
test_count=0
|
||||
|
||||
|
|
21
status.c
Normal file
21
status.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "notmuch-client.h"
|
||||
|
||||
notmuch_status_t
|
||||
print_status_query (const char *loc,
|
||||
const notmuch_query_t *query,
|
||||
notmuch_status_t status)
|
||||
{
|
||||
if (status) {
|
||||
const char *msg;
|
||||
notmuch_database_t *notmuch;
|
||||
|
||||
fprintf (stderr, "%s: %s\n", loc,
|
||||
notmuch_status_to_string (status));
|
||||
|
||||
notmuch = notmuch_query_get_database (query);
|
||||
msg = notmuch_database_status_string (notmuch);
|
||||
if (msg)
|
||||
fputs (msg, stderr);
|
||||
}
|
||||
return status;
|
||||
}
|
|
@ -56,7 +56,17 @@ TEST_BINARIES := $(TEST_BINARIES:.cc=)
|
|||
test-binaries: $(TEST_BINARIES)
|
||||
|
||||
test: all test-binaries
|
||||
ifeq ($V,)
|
||||
@echo 'Use "$(MAKE) V=1" to print test headings and PASSIng results.'
|
||||
@env NOTMUCH_TEST_QUIET=1 ${test_src_dir}/notmuch-test $(OPTIONS)
|
||||
else
|
||||
# The user has explicitly enabled quiet execution.
|
||||
ifeq ($V,0)
|
||||
@env NOTMUCH_TEST_QUIET=1 ${test_src_dir}/notmuch-test $(OPTIONS)
|
||||
else
|
||||
@${test_src_dir}/notmuch-test $(OPTIONS)
|
||||
endif
|
||||
endif
|
||||
|
||||
check: test
|
||||
|
||||
|
|
|
@ -117,6 +117,13 @@ Note that some tests in the existing test suite rely on previous test
|
|||
items, so you cannot arbitrarily skip any test and expect the
|
||||
remaining tests to be unaffected.
|
||||
|
||||
Currently we do not consider skipped tests as build failures. For
|
||||
maximum robustness, when setting up automated build processes, you
|
||||
should explicitely skip tests, rather than relying on notmuch's
|
||||
detection of missing prerequisites. In the future we may treat tests
|
||||
unable to run because of missing prerequisites, but not explicitely
|
||||
skipped by the user, as failures.
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
The test script is written as a shell script. It should start with
|
||||
|
@ -138,7 +145,7 @@ Source 'test-lib.sh'
|
|||
After assigning test_description, the test script should source
|
||||
test-lib.sh like this:
|
||||
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
This test harness library does the following things:
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
################################################################
|
||||
# Test harness
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
test_description="online help"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_expect_success 'notmuch --help' 'notmuch --help'
|
||||
test_expect_success 'notmuch help' 'notmuch help'
|
||||
|
@ -12,9 +12,9 @@ if [ $NOTMUCH_HAVE_MAN -eq 1 ]; then
|
|||
test_expect_success 'notmuch help tag' 'notmuch help tag'
|
||||
else
|
||||
test_expect_success 'notmuch --help tag (man pages not available)' \
|
||||
'test_must_fail notmuch --help tag'
|
||||
'test_must_fail notmuch --help tag >/dev/null'
|
||||
test_expect_success 'notmuch help tag (man pages not available)' \
|
||||
'test_must_fail notmuch help tag'
|
||||
'test_must_fail notmuch help tag >/dev/null'
|
||||
fi
|
||||
|
||||
test_done
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch compact"'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_message '[subject]=One'
|
||||
add_message '[subject]=Two'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
test_description='"notmuch config"'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Get string value"
|
||||
test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
test_description='"notmuch setup"'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Notmuch new without a config suggests notmuch setup"
|
||||
output=$(notmuch --config=new-notmuch-config new 2>&1)
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch new" in several variations'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "No new messages"
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "No new mail."
|
||||
|
||||
|
||||
test_begin_subtest "Single new message"
|
||||
generate_message
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
test_begin_subtest "Multiple new messages"
|
||||
generate_message
|
||||
generate_message
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 2 new messages to the database."
|
||||
|
||||
|
||||
test_begin_subtest "No new messages (non-empty DB)"
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "No new mail."
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ mkdir "${MAIL_DIR}"/def
|
|||
mkdir "${MAIL_DIR}"/ghi
|
||||
generate_message [dir]=def
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ mv "${MAIL_DIR}"/ghi "${MAIL_DIR}"/abc
|
|||
rm "${MAIL_DIR}"/def/*
|
||||
generate_message [dir]=abc
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
|
@ -54,7 +54,7 @@ mkdir -p "$(dirname "$tmp_msg_filename")"
|
|||
mv "$gen_msg_filename" "$tmp_msg_filename"
|
||||
notmuch new > /dev/null
|
||||
mv "$tmp_msg_filename" "$gen_msg_filename"
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
|
@ -63,15 +63,18 @@ test_begin_subtest "Renamed message"
|
|||
generate_message
|
||||
notmuch new > /dev/null
|
||||
mv "$gen_msg_filename" "${gen_msg_filename}"-renamed
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Detected 1 file rename."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 2: queuing passed file ${gen_msg_filename} for deletion from database
|
||||
No new mail. Detected 1 file rename."
|
||||
|
||||
|
||||
test_begin_subtest "Deleted message"
|
||||
|
||||
rm "${gen_msg_filename}"-renamed
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Removed 1 message."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 3: queuing leftover file ${gen_msg_filename}-renamed for deletion from database
|
||||
No new mail. Removed 1 message."
|
||||
|
||||
|
||||
|
||||
test_begin_subtest "Renamed directory"
|
||||
|
@ -84,16 +87,17 @@ notmuch new > /dev/null
|
|||
|
||||
mv "${MAIL_DIR}"/dir "${MAIL_DIR}"/dir-renamed
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Detected 3 file renames."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 2: queuing passed directory ${MAIL_DIR}/dir for deletion from database
|
||||
No new mail. Detected 3 file renames."
|
||||
|
||||
|
||||
test_begin_subtest "Deleted directory"
|
||||
|
||||
rm -rf "${MAIL_DIR}"/dir-renamed
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Removed 3 messages."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 2: queuing passed directory ${MAIL_DIR}/dir-renamed for deletion from database
|
||||
No new mail. Removed 3 messages."
|
||||
|
||||
|
||||
test_begin_subtest "New directory (at end of list)"
|
||||
|
@ -102,7 +106,7 @@ generate_message [dir]=zzz
|
|||
generate_message [dir]=zzz
|
||||
generate_message [dir]=zzz
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 3 new messages to the database."
|
||||
|
||||
|
||||
|
@ -110,8 +114,9 @@ test_begin_subtest "Deleted directory (end of list)"
|
|||
|
||||
rm -rf "${MAIL_DIR}"/zzz
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Removed 3 messages."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 3: queuing leftover directory ${MAIL_DIR}/zzz for deletion from database
|
||||
No new mail. Removed 3 messages."
|
||||
|
||||
|
||||
test_begin_subtest "New symlink to directory"
|
||||
|
@ -122,7 +127,7 @@ mv "${MAIL_DIR}" "${TMP_DIRECTORY}"/actual_maildir
|
|||
mkdir "${MAIL_DIR}"
|
||||
ln -s "${TMP_DIRECTORY}"/actual_maildir "${MAIL_DIR}"/symlink
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
|
@ -132,13 +137,13 @@ external_msg_filename="${TMP_DIRECTORY}"/external/"$(basename "$gen_msg_filename
|
|||
mkdir -p "$(dirname "$external_msg_filename")"
|
||||
mv "$gen_msg_filename" "$external_msg_filename"
|
||||
ln -s "$external_msg_filename" "$gen_msg_filename"
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
|
||||
test_begin_subtest "Broken symlink aborts"
|
||||
ln -s does-not-exist "${MAIL_DIR}/broken"
|
||||
output=$(NOTMUCH_NEW 2>&1)
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
test_expect_equal "$output" \
|
||||
"Error reading file ${MAIL_DIR}/broken: No such file or directory
|
||||
Note: A fatal error was encountered: Something went wrong trying to read or write a file
|
||||
|
@ -152,7 +157,7 @@ generate_message [dir]=two/levels
|
|||
generate_message [dir]=two/levels
|
||||
generate_message [dir]=two/levels
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "Added 3 new messages to the database."
|
||||
|
||||
|
||||
|
@ -160,10 +165,11 @@ test_begin_subtest "Deleted two-level directory"
|
|||
|
||||
rm -rf "${MAIL_DIR}"/two
|
||||
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Removed 3 messages."
|
||||
output=$(NOTMUCH_NEW --debug)
|
||||
test_expect_equal "$output" "(D) add_files_recursive, pass 3: queuing leftover directory ${MAIL_DIR}/two for deletion from database
|
||||
No new mail. Removed 3 messages."
|
||||
|
||||
test_begin_subtest "Support single-message mbox (deprecated)"
|
||||
test_begin_subtest "Support single-message mbox"
|
||||
cat > "${MAIL_DIR}"/mbox_file1 <<EOF
|
||||
From test_suite@notmuchmail.org Fri Jan 5 15:43:57 2001
|
||||
From: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||
|
@ -172,7 +178,7 @@ Subject: Test mbox message 1
|
|||
|
||||
Body.
|
||||
EOF
|
||||
output=$(NOTMUCH_NEW 2>&1)
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
test_expect_equal "$output" "Added 1 new message to the database."
|
||||
|
||||
# This test requires that notmuch new has been run at least once.
|
||||
|
@ -196,7 +202,7 @@ Subject: Test mbox message 2
|
|||
|
||||
Body 2.
|
||||
EOF
|
||||
output=$(NOTMUCH_NEW 2>&1)
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
test_expect_equal "$output" \
|
||||
"Note: Ignoring non-mail file: ${MAIL_DIR}/.git/config
|
||||
Note: Ignoring non-mail file: ${MAIL_DIR}/.ignored_hidden_file
|
||||
|
@ -263,23 +269,23 @@ OLDCONFIG=$(notmuch config get new.tags)
|
|||
|
||||
test_begin_subtest "Empty tags in new.tags are forbidden"
|
||||
notmuch config set new.tags "foo;;bar"
|
||||
output=$(NOTMUCH_NEW 2>&1)
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden"
|
||||
|
||||
test_begin_subtest "Tags starting with '-' in new.tags are forbidden"
|
||||
notmuch config set new.tags "-foo;bar"
|
||||
output=$(NOTMUCH_NEW 2>&1)
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden"
|
||||
|
||||
test_expect_code 1 "Invalid tags set exit code" \
|
||||
"NOTMUCH_NEW 2>&1"
|
||||
"NOTMUCH_NEW --debug 2>&1"
|
||||
|
||||
notmuch config set new.tags $OLDCONFIG
|
||||
|
||||
|
||||
test_begin_subtest "Xapian exception: read only files"
|
||||
chmod u-w ${MAIL_DIR}/.notmuch/xapian/*.DB
|
||||
output=$(NOTMUCH_NEW 2>&1 | sed 's/: .*$//' )
|
||||
output=$(NOTMUCH_NEW --debug 2>&1 | sed 's/: .*$//' )
|
||||
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.DB
|
||||
test_expect_equal "$output" "A Xapian exception occurred opening database"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch count" for messages and threads'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_email_corpus
|
||||
|
||||
|
@ -93,5 +93,35 @@ notmuch count --output=messages >>EXPECTED
|
|||
notmuch count --output=messages tag:inbox >>EXPECTED
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
backup_database
|
||||
test_begin_subtest "error message for database open"
|
||||
dd if=/dev/zero of="${MAIL_DIR}/.notmuch/xapian/postlist.DB" count=3
|
||||
notmuch count '*' 2>OUTPUT 1>/dev/null
|
||||
output=$(sed 's/^\(A Xapian exception [^:]*\):.*$/\1/' OUTPUT)
|
||||
test_expect_equal "${output}" "A Xapian exception occurred opening database"
|
||||
restore_database
|
||||
|
||||
cat <<EOF > count-files.gdb
|
||||
set breakpoint pending on
|
||||
break count_files
|
||||
commands
|
||||
shell cp /dev/null ${MAIL_DIR}/.notmuch/xapian/postlist.DB
|
||||
continue
|
||||
end
|
||||
run
|
||||
EOF
|
||||
|
||||
backup_database
|
||||
test_begin_subtest "error message from query_search_messages"
|
||||
gdb --batch-silent --return-child-result -x count-files.gdb \
|
||||
--args notmuch count --output=files '*' 2>OUTPUT 1>/dev/null
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch count: A Xapian exception occurred
|
||||
A Xapian exception occurred performing query
|
||||
Query string was: *
|
||||
EOF
|
||||
sed 's/^\(A Xapian exception [^:]*\):.*$/\1/' < OUTPUT > OUTPUT.clean
|
||||
test_expect_equal_file EXPECTED OUTPUT.clean
|
||||
restore_database
|
||||
|
||||
test_done
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch insert"'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_require_external_prereq gdb
|
||||
|
||||
|
@ -188,7 +188,7 @@ notmuch config set new.tags $OLDCONFIG
|
|||
# DUPLICATE_MESSAGE_ID is not tested here, because it should actually pass.
|
||||
|
||||
for code in OUT_OF_MEMORY XAPIAN_EXCEPTION FILE_NOT_EMAIL \
|
||||
READ_ONLY_DATABASE UPGRADE_REQUIRED; do
|
||||
READ_ONLY_DATABASE UPGRADE_REQUIRED PATH_ERROR; do
|
||||
gen_insert_msg
|
||||
cat <<EOF > index-file-$code.gdb
|
||||
set breakpoint pending on
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch search" in several variations'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_email_corpus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='various settings for "notmuch search --output="'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_email_corpus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch address" in several variants'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_email_corpus
|
||||
|
||||
|
@ -145,4 +145,148 @@ cat <<EOF >EXPECTED
|
|||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_begin_subtest "--deduplicate=no --sort=oldest-first --output=sender"
|
||||
notmuch address --deduplicate=no --sort=oldest-first --output=sender '*' >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Alex Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Jan Janak <jan@ryngle.com>
|
||||
Jan Janak <jan@ryngle.com>
|
||||
Jan Janak <jan@ryngle.com>
|
||||
Israel Herraiz <isra@herraiz.org>
|
||||
Adrian Perez de Castro <aperez@igalia.com>
|
||||
Aron Griffis <agriffis@n01se.net>
|
||||
Ingmar Vanhassel <ingmar@exherbo.org>
|
||||
Alex Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Stewart Smith <stewart@flamingspork.com>
|
||||
Stewart Smith <stewart@flamingspork.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Stewart Smith <stewart@flamingspork.com>
|
||||
Jjgod Jiang <gzjjgod@gmail.com>
|
||||
Jan Janak <jan@ryngle.com>
|
||||
Rolland Santimano <rollandsantimano@yahoo.com>
|
||||
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Jjgod Jiang <gzjjgod@gmail.com>
|
||||
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Olivier Berger <olivier.berger@it-sudparis.eu>
|
||||
François Boulogne <boulogne.f@gmail.com>
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_begin_subtest "--deduplicate=no --sort=newest-first --output=sender --output=recipients"
|
||||
notmuch address --deduplicate=no --sort=newest-first --output=sender --output=recipients path:foo/new >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
notmuch@notmuchmail.org
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
notmuch@notmuchmail.org
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
notmuch@notmuchmail.org
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_begin_subtest "--deduplicate=address --output=sender --output=recipients"
|
||||
notmuch address --deduplicate=address --output=sender --output=recipients '*' | sort >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
"Discussion about the Arch User Repository (AUR)" <aur-general@archlinux.org>
|
||||
Adrian Perez de Castro <aperez@igalia.com>
|
||||
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
|
||||
Allan McRae <allan@archlinux.org>
|
||||
Aron Griffis <agriffis@n01se.net>
|
||||
Carl Worth <cworth@cworth.org>
|
||||
Chris Wilson <chris@chris-wilson.co.uk>
|
||||
François Boulogne <boulogne.f@gmail.com>
|
||||
Ingmar Vanhassel <ingmar@exherbo.org>
|
||||
Israel Herraiz <isra@herraiz.org>
|
||||
Jan Janak <jan@ryngle.com>
|
||||
Jjgod Jiang <gzjjgod@gmail.com>
|
||||
Keith Packard <keithp@keithp.com>
|
||||
Lars Kellogg-Stedman <lars@seas.harvard.edu>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Olivier Berger <olivier.berger@it-sudparis.eu>
|
||||
Rolland Santimano <rollandsantimano@yahoo.com>
|
||||
Stewart Smith <stewart@flamingspork.com>
|
||||
notmuch@notmuchmail.org
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
generate_message '[from]="Foo Bar <foo.bar@example.com>"'
|
||||
generate_message '[from]="Foo Bar <Foo.Bar@Example.Com>"'
|
||||
generate_message '[from]="Foo Bar <foo.bar@example.com>"'
|
||||
generate_message '[from]="Bar <Foo.Bar@Example.Com>"'
|
||||
generate_message '[from]="Foo <foo.bar@example.com>"'
|
||||
generate_message '[from]="<foo.bar@example.com>"'
|
||||
generate_message '[from]="foo.bar@example.com"'
|
||||
generate_message '[from]="Baz <foo.bar+baz@example.com>"'
|
||||
generate_message '[from]="Foo Bar <foo.bar+baz@example.com>"'
|
||||
generate_message '[from]="Baz <foo.bar+baz@example.com>"'
|
||||
notmuch new > /dev/null
|
||||
|
||||
test_begin_subtest "--deduplicate=no --output=sender"
|
||||
notmuch address --deduplicate=no --output=sender from:example.com | sort >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
Bar <Foo.Bar@Example.Com>
|
||||
Baz <foo.bar+baz@example.com>
|
||||
Baz <foo.bar+baz@example.com>
|
||||
Foo <foo.bar@example.com>
|
||||
Foo Bar <Foo.Bar@Example.Com>
|
||||
Foo Bar <foo.bar+baz@example.com>
|
||||
Foo Bar <foo.bar@example.com>
|
||||
Foo Bar <foo.bar@example.com>
|
||||
foo.bar@example.com
|
||||
foo.bar@example.com
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_begin_subtest "--deduplicate=mailbox --output=sender --output=count"
|
||||
notmuch address --deduplicate=mailbox --output=sender --output=count from:example.com | sort -n >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
1 Bar <Foo.Bar@Example.Com>
|
||||
1 Foo <foo.bar@example.com>
|
||||
1 Foo Bar <Foo.Bar@Example.Com>
|
||||
1 Foo Bar <foo.bar+baz@example.com>
|
||||
2 Baz <foo.bar+baz@example.com>
|
||||
2 Foo Bar <foo.bar@example.com>
|
||||
2 foo.bar@example.com
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_begin_subtest "--deduplicate=address --output=sender --output=count"
|
||||
notmuch address --deduplicate=address --output=sender --output=count from:example.com | sort -n >OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
3 Baz <foo.bar+baz@example.com>
|
||||
7 Foo Bar <foo.bar@example.com>
|
||||
EOF
|
||||
test_expect_equal_file OUTPUT EXPECTED
|
||||
|
||||
test_done
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch search" by folder: and path: (with variations)'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_message '[dir]=bad' '[subject]="To the bone"'
|
||||
add_message '[dir]=.' '[subject]="Top level"'
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# id:3wd4o8wa7fx.fsf@testarossa.amd.com
|
||||
|
||||
test_description='that notmuch does not overlap term positions'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_message '[to]="a@b.c, x@y.z"'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='messages with unquoted . in name'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_message \
|
||||
'[from]="Some.Name for Someone <bugs@quoting.com>"' \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch search" --offset and --limit parameters'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_email_corpus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch search, count and show" with excludes in several variations'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
# Generates a thread consisting of a top level message and 'length'
|
||||
# replies. The subject of the top message 'subject: top message"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch tag"'
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
add_message '[subject]=One'
|
||||
add_message '[subject]=Two'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="--format=json output"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Show message: json"
|
||||
add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"json-show-message\""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="--format=sexp output"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Show message: sexp"
|
||||
add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"sexp-show-message\""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="--format=text output"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Show message: text"
|
||||
add_message "[subject]=\"text-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"text-show-message\""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="output of multipart message"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
cat <<EOF > embedded_message
|
||||
From: Carl Worth <cworth@cworth.org>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="naming of threads with changing subject"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Initial thread name (oldest-first search)"
|
||||
add_message '[subject]="thread-naming: Initial thread subject"' \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="naming of authors with unusual addresses"
|
||||
. ./test-lib.sh
|
||||
. ./test-lib.sh || exit 1
|
||||
|
||||
test_begin_subtest "Add author with empty quoted real name"
|
||||
add_message '[subject]="author-naming: Initial thread subject"' \
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue