mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-22 02:48:08 +01:00
notmuch 0.35 release
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkiyHYXwaY0SiY6fqA0U5G1WqFSEFAmIAAxEACgkQA0U5G1Wq FSGIdw//aytmkD3YaI0jT9Q7JjvkChMjGYzP0KeVlJrSIjNu+tkIoMSFayPzR1Zg f6nQ6K/c8NDJROQYFsjDBltnY2cwC1DxWMN9infr80bJhHYQlrACzeBKrGGIho44 QceWgPW054GqYHsKozGNxZVlgKLeDImj2dX3E0scNYtVuhsyVO9x4Eb2xi6oDRze HvnpiKoE8zkwObK9REjwNG1n1dVmvSZ+H25akcb3siiwKFLNIwcPAYIMiSFaBsNe vwwJaUhZP6TnE+54QX03ssLFT5Dlm/d+YOT4EPAujRwGaLlaUsK04KHbyT/wWbgK wW5AUsOL8zTjQz5sg8+v90DRFlamRg8SK8piTJo+Dx5Lsjpqk5PgLG7DJ0WeTaxJ 35Bph1/5mnUWwi2dsNeJ11rK0vamouSsatF+VFScWxesLhsUhzFFt20VfiiYXxVQ t4mqH/aHitbbzqy3y0vwIj+USdIfskJyncgXKjNkwEMJuh25Sg815ilnvNXMWbv+ 7byXnxNpaDaLNO1h/2KYYbz+WGFU8fsLUp/O3WtITzIZms3gddnP2GNk55/B8Jfq 9zcNuljrUNlY3zJvXgiRj/7jCWiLevF0AMOpc1EmFmp0LLISkH+VdIVXIyLb06Y/ bj5QDYTtXLZViZ9T6rw5QlLtNAv25ZTmbV0nOK97c3Jfwt6QRdA= =7kSG -----END PGP SIGNATURE----- Merge tag '0.35' into debian/bullseye-backports notmuch 0.35 release
This commit is contained in:
commit
f1b2ab70c3
110 changed files with 1580 additions and 405 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,5 +16,6 @@
|
|||
/sh.config
|
||||
/sphinx.config
|
||||
/version.stamp
|
||||
/bindings/python-cffi/_notmuch_config.py
|
||||
TAGS
|
||||
tags
|
||||
|
|
|
@ -50,9 +50,9 @@ DETACHED_SIG_FILE=$(TAR_FILE).asc
|
|||
PV_FILE=bindings/python/notmuch/version.py
|
||||
|
||||
# Smash together user's values with our extra values
|
||||
FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(CPPFLAGS) $(CFLAGS) $(WARN_CFLAGS) $(extra_cflags) $(CONFIGURE_CFLAGS)
|
||||
FINAL_CXXFLAGS = $(CPPFLAGS) $(CXXFLAGS) $(WARN_CXXFLAGS) $(extra_cflags) $(extra_cxxflags) $(CONFIGURE_CXXFLAGS)
|
||||
FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lnotmuch_util -Llib -lnotmuch
|
||||
FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(WARN_CFLAGS) $(extra_cflags) $(CPPFLAGS) $(CONFIGURE_CFLAGS) $(CFLAGS)
|
||||
FINAL_CXXFLAGS = $(WARN_CXXFLAGS) $(extra_cflags) $(extra_cxxflags) $(CPPFLAGS) $(CONFIGURE_CXXFLAGS) $(CXXFLAGS)
|
||||
FINAL_NOTMUCH_LDFLAGS = -Lutil -lnotmuch_util -Llib -lnotmuch $(LDFLAGS)
|
||||
ifeq ($(LIBDIR_IN_LDCONFIG),0)
|
||||
FINAL_NOTMUCH_LDFLAGS += $(RPATH_LDFLAGS)
|
||||
endif
|
||||
|
|
|
@ -54,7 +54,6 @@ update-versions:
|
|||
sed -i -e "s/^__VERSION__[[:blank:]]*=.*$$/__VERSION__ = \'${VERSION}\'/" \
|
||||
-e "s/^SOVERSION[[:blank:]]*=.*$$/SOVERSION = \'${LIBNOTMUCH_VERSION_MAJOR}\'/" \
|
||||
${PV_FILE}
|
||||
cp version.txt bindings/python-cffi
|
||||
|
||||
# We invoke make recursively only to force ordering of our phony
|
||||
# targets in the case of parallel invocation of make (-j).
|
||||
|
|
106
NEWS
106
NEWS
|
@ -1,3 +1,109 @@
|
|||
Notmuch 0.35 (2022-02-06)
|
||||
=========================
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
Implement the `date` and `lastmod` fields in the S-expression parser.
|
||||
|
||||
Ignore trailing `/` for pathnames in both query parsers.
|
||||
|
||||
Rename configuration option `built_with.sexpr_query` to
|
||||
`built_with.sexp_queries`.
|
||||
|
||||
Do not assume a default mail root in split (e.g. XDG) configurations.
|
||||
|
||||
Fix some small memory leaks in `notmuch_database_open_with_config`.
|
||||
|
||||
CLI
|
||||
---
|
||||
|
||||
Improve handling of leading/trailing punctation and space for
|
||||
configuration lists.
|
||||
|
||||
Only ignore `.notmuch` at the top level in `notmuch new`.
|
||||
|
||||
Optionally show extra headers in `notmuch show`. See
|
||||
`show.extra_headers` in notmuch-config(1).
|
||||
|
||||
Emacs
|
||||
-----
|
||||
|
||||
Drop `C-TAB` binding in hello mode, document `backtab`.
|
||||
|
||||
Fix visual glitch in search mode by running `notmuch-search-hook`
|
||||
lazily.
|
||||
|
||||
Don't add space to completion candidates, improves compatibility with
|
||||
third party completion frameworks.
|
||||
|
||||
Make citation formating more robust against whitespace.
|
||||
|
||||
Use `--excludes=false` when generating the 'All tags' section.
|
||||
|
||||
Use cached copy of message body for `Fcc`, avoiding variant bodies for
|
||||
signed and/or encrypted messages.
|
||||
|
||||
Add notmuch-logo.svg and use it in notmuch-hello view, replacing
|
||||
the .png version.
|
||||
|
||||
Make header line in show buffers optional.
|
||||
|
||||
Add customizable names for search buffers.
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
Fix out-of-tree build for `python-cffi` bindings.
|
||||
|
||||
Rearrange position of {C,CXX,CPP,LD}FLAGS, prevent some clashes with
|
||||
installed version of notmuch.
|
||||
|
||||
Ignore more configure options.
|
||||
|
||||
Test Suite
|
||||
----------
|
||||
|
||||
Replace some uses of `gdb` in the test suite with `LD_PRELOAD` based
|
||||
shims.
|
||||
|
||||
Use `--with-colons` for gpgsm, fix compatibility with newer gnupg.
|
||||
|
||||
Python bindings
|
||||
---------------
|
||||
|
||||
Add `matched` property to message objects.
|
||||
|
||||
Users are reminded that the old python bindings in bindings/python are
|
||||
deprecated; this will probably be the last major release that ships
|
||||
them.
|
||||
|
||||
Completion
|
||||
----------
|
||||
|
||||
Use `database.mail_root` for path completion in bash/zsh.
|
||||
|
||||
Notmuch 0.34.3 (2022-01-09)
|
||||
===========================
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
Do not crash when presented with a .notmuch directory without a
|
||||
xapian/ subdirectory.
|
||||
|
||||
Python Bindings (notmuch2)
|
||||
--------------------------
|
||||
|
||||
Database constructor now searches for configuration by default. Pass
|
||||
`config=Database.CONFIG.EMPTY` to disable.
|
||||
|
||||
The `Message.replies()` method now returns OwnedMessage objects, to
|
||||
prevent certain memory de-allocation errors.
|
||||
|
||||
Fix for importing `notmuch2` module when building bindings
|
||||
documentation.
|
||||
|
||||
Notmuch 0.34.2 (2021-12-09)
|
||||
===========================
|
||||
|
||||
|
|
|
@ -3,21 +3,26 @@
|
|||
dir := bindings
|
||||
|
||||
# force the shared library to be built
|
||||
ruby-bindings: lib/$(LINKER_NAME)
|
||||
ruby-bindings: $(dir)/ruby.stamp
|
||||
|
||||
$(dir)/ruby.stamp: lib/$(LINKER_NAME)
|
||||
ifeq ($(HAVE_RUBY_DEV),1)
|
||||
cd $(dir)/ruby && \
|
||||
EXTRA_LDFLAGS="$(NO_UNDEFINED_LDFLAGS)" \
|
||||
LIBNOTMUCH="../../lib/$(LINKER_NAME)" \
|
||||
NOTMUCH_SRCDIR='$(NOTMUCH_SRCDIR)' \
|
||||
$(RUBY) extconf.rb --vendor
|
||||
$(MAKE) -C $(dir)/ruby CFLAGS="$(CFLAGS) -pipe -fno-plt -fPIC"
|
||||
$(MAKE) -C $(dir)/ruby CFLAGS="$(CFLAGS) -pipe -fno-plt -fPIC" && touch $@
|
||||
endif
|
||||
|
||||
python-cffi-bindings: lib/$(LINKER_NAME)
|
||||
python-cffi-bindings: $(dir)/python-cffi.stamp
|
||||
|
||||
$(dir)/python-cffi.stamp: lib/$(LINKER_NAME)
|
||||
ifeq ($(HAVE_PYTHON3_CFFI),1)
|
||||
cd $(dir)/python-cffi && \
|
||||
${PYTHON} setup.py build --build-lib build/stage && \
|
||||
mkdir -p build/stage/tests && cp tests/*.py build/stage/tests
|
||||
mkdir -p build/stage/tests && cp tests/*.py build/stage/tests && \
|
||||
touch ../python-cffi.stamp
|
||||
endif
|
||||
|
||||
CLEAN += $(patsubst %,$(dir)/ruby/%, \
|
||||
|
@ -26,6 +31,6 @@ CLEAN += $(patsubst %,$(dir)/ruby/%, \
|
|||
init.o message.o messages.o mkmf.log notmuch.so query.o \
|
||||
status.o tags.o thread.o threads.o)
|
||||
|
||||
CLEAN += bindings/ruby/.vendorarchdir.time
|
||||
CLEAN += bindings/ruby/.vendorarchdir.time $(dir)/ruby.stamp
|
||||
|
||||
CLEAN += bindings/python-cffi/build
|
||||
CLEAN += bindings/python-cffi/build $(dir)/python-cffi.stamp
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import cffi
|
||||
|
||||
from _notmuch_config import *
|
||||
|
||||
ffibuilder = cffi.FFI()
|
||||
ffibuilder.set_source(
|
||||
|
@ -16,8 +16,8 @@ ffibuilder.set_source(
|
|||
#ERROR libnotmuch version < 5.1 not supported
|
||||
#endif
|
||||
""",
|
||||
include_dirs=['../../lib'],
|
||||
library_dirs=['../../lib'],
|
||||
include_dirs=[NOTMUCH_INCLUDE_DIR],
|
||||
library_dirs=[NOTMUCH_LIB_DIR],
|
||||
libraries=['notmuch'],
|
||||
)
|
||||
ffibuilder.cdef(
|
||||
|
@ -54,6 +54,7 @@ ffibuilder.cdef(
|
|||
NOTMUCH_STATUS_NO_DATABASE,
|
||||
NOTMUCH_STATUS_DATABASE_EXISTS,
|
||||
NOTMUCH_STATUS_BAD_QUERY_SYNTAX,
|
||||
NOTMUCH_STATUS_NO_MAIL_ROOT,
|
||||
NOTMUCH_STATUS_LAST_STATUS
|
||||
} notmuch_status_t;
|
||||
typedef enum {
|
||||
|
|
|
@ -139,7 +139,7 @@ class Database(base.NotmuchObject):
|
|||
path = os.fsencode(path)
|
||||
return path
|
||||
|
||||
def __init__(self, path=None, mode=MODE.READ_ONLY, config=CONFIG.EMPTY):
|
||||
def __init__(self, path=None, mode=MODE.READ_ONLY, config=CONFIG.SEARCH):
|
||||
if isinstance(mode, str):
|
||||
mode = self.STR_MODE_MAP[mode]
|
||||
self.mode = mode
|
||||
|
|
|
@ -205,6 +205,20 @@ class Message(base.NotmuchObject):
|
|||
self._msg_p, capi.lib.NOTMUCH_MESSAGE_FLAG_EXCLUDED)
|
||||
return bool(ret)
|
||||
|
||||
@property
|
||||
def matched(self):
|
||||
"""Indicates whether this message was matched by the query.
|
||||
|
||||
When a thread is created from a search, some of the
|
||||
messages may not match the original query. This property
|
||||
is set to *True* for those that do match.
|
||||
|
||||
:raises ObjectDestroyedError: if used after destroyed.
|
||||
"""
|
||||
ret = capi.lib.notmuch_message_get_flag(
|
||||
self._msg_p, capi.lib.NOTMUCH_MESSAGE_FLAG_MATCH)
|
||||
return bool(ret)
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
"""The message date as an integer.
|
||||
|
@ -357,14 +371,14 @@ class Message(base.NotmuchObject):
|
|||
This method will only work if the message was created from a
|
||||
thread. Otherwise it will yield no results.
|
||||
|
||||
:returns: An iterator yielding :class:`Message` instances.
|
||||
:returns: An iterator yielding :class:`OwnedMessage` instances.
|
||||
:rtype: MessageIter
|
||||
"""
|
||||
# The notmuch_messages_valid call accepts NULL and this will
|
||||
# become an empty iterator, raising StopIteration immediately.
|
||||
# Hence no return value checking here.
|
||||
msgs_p = capi.lib.notmuch_message_get_replies(self._msg_p)
|
||||
return MessageIter(self, msgs_p, db=self._db)
|
||||
return MessageIter(self, msgs_p, db=self._db, msg_cls=OwnedMessage)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.messageid)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import setuptools
|
||||
from _notmuch_config import *
|
||||
|
||||
with open('version.txt') as fp:
|
||||
with open(NOTMUCH_VERSION_FILE) as fp:
|
||||
VERSION = fp.read().strip()
|
||||
|
||||
setuptools.setup(
|
||||
|
|
|
@ -23,9 +23,9 @@ class TestIter:
|
|||
|
||||
def test_set_get(self, maildir):
|
||||
# Ensure get-set works from different db objects
|
||||
with dbmod.Database.create(maildir.path) as db0:
|
||||
with dbmod.Database.create(maildir.path, config=dbmod.Database.CONFIG.EMPTY) as db0:
|
||||
db0.config['spam'] = 'ham'
|
||||
with dbmod.Database(maildir.path) as db1:
|
||||
with dbmod.Database(maildir.path, config=dbmod.Database.CONFIG.EMPTY) as db1:
|
||||
assert db1.config['spam'] == 'ham'
|
||||
|
||||
def test_get_keyerror(self, db):
|
||||
|
|
|
@ -13,7 +13,7 @@ import notmuch2._message as message
|
|||
|
||||
@pytest.fixture
|
||||
def db(maildir):
|
||||
with dbmod.Database.create(maildir.path) as db:
|
||||
with dbmod.Database.create(maildir.path, config=notmuch2.Database.CONFIG.EMPTY) as db:
|
||||
yield db
|
||||
|
||||
|
||||
|
@ -293,7 +293,7 @@ class TestQuery:
|
|||
maildir.deliver(body='baz',
|
||||
headers=[('In-Reply-To', '<{}>'.format(msgid))])
|
||||
notmuch('new')
|
||||
with dbmod.Database(maildir.path, 'rw') as db:
|
||||
with dbmod.Database(maildir.path, 'rw', config=notmuch2.Database.CONFIG.EMPTY) as db:
|
||||
yield db
|
||||
|
||||
def test_count_messages(self, db):
|
||||
|
|
|
@ -97,6 +97,9 @@ class TestMessage:
|
|||
def test_ghost_no(self, msg):
|
||||
assert not msg.ghost
|
||||
|
||||
def test_matched_no(self,msg):
|
||||
assert not msg.matched
|
||||
|
||||
def test_date(self, msg):
|
||||
# XXX Someone seems to treat things as local time instead of
|
||||
# UTC or the other way around.
|
||||
|
|
|
@ -23,7 +23,7 @@ class TestImmutable:
|
|||
"""
|
||||
maildir.deliver()
|
||||
notmuch('new')
|
||||
with database.Database(maildir.path) as db:
|
||||
with database.Database(maildir.path, config=database.Database.CONFIG.EMPTY) as db:
|
||||
yield db.tags
|
||||
|
||||
def test_type(self, tagset):
|
||||
|
@ -33,7 +33,7 @@ class TestImmutable:
|
|||
def test_hash(self, tagset, maildir, notmuch):
|
||||
h0 = hash(tagset)
|
||||
notmuch('tag', '+foo', '*')
|
||||
with database.Database(maildir.path) as db:
|
||||
with database.Database(maildir.path, config=database.Database.CONFIG.EMPTY) as db:
|
||||
h1 = hash(db.tags)
|
||||
assert h0 != h1
|
||||
|
||||
|
@ -42,7 +42,7 @@ class TestImmutable:
|
|||
|
||||
def test_neq(self, tagset, maildir, notmuch):
|
||||
notmuch('tag', '+foo', '*')
|
||||
with database.Database(maildir.path) as db:
|
||||
with database.Database(maildir.path, config=database.Database.CONFIG.EMPTY) as db:
|
||||
assert tagset != db.tags
|
||||
|
||||
def test_contains(self, tagset):
|
||||
|
@ -159,7 +159,8 @@ class TestMutableTagset:
|
|||
_, pathname = maildir.deliver()
|
||||
notmuch('new')
|
||||
with database.Database(maildir.path,
|
||||
mode=database.Mode.READ_WRITE) as db:
|
||||
mode=database.Mode.READ_WRITE,
|
||||
config=database.Database.CONFIG.EMPTY) as db:
|
||||
msg = db.get(pathname)
|
||||
yield msg.tags
|
||||
|
||||
|
@ -195,7 +196,8 @@ class TestMutableTagset:
|
|||
_, pathname = maildir.deliver(flagged=True)
|
||||
notmuch('new')
|
||||
with database.Database(maildir.path,
|
||||
mode=database.Mode.READ_WRITE) as db:
|
||||
mode=database.Mode.READ_WRITE,
|
||||
config=database.Database.CONFIG.EMPTY) as db:
|
||||
msg = db.get(pathname)
|
||||
msg.tags.discard('flagged')
|
||||
msg.tags.from_maildir_flags()
|
||||
|
@ -205,7 +207,8 @@ class TestMutableTagset:
|
|||
_, pathname = maildir.deliver(flagged=True)
|
||||
notmuch('new')
|
||||
with database.Database(maildir.path,
|
||||
mode=database.Mode.READ_WRITE) as db:
|
||||
mode=database.Mode.READ_WRITE,
|
||||
config=database.Database.CONFIG.EMPTY) as db:
|
||||
msg = db.get(pathname)
|
||||
flags = msg.path.name.split(',')[-1]
|
||||
assert 'F' in flags
|
||||
|
|
|
@ -13,7 +13,7 @@ def thread(maildir, notmuch):
|
|||
maildir.deliver(body='bar',
|
||||
headers=[('In-Reply-To', '<{}>'.format(msgid))])
|
||||
notmuch('new')
|
||||
with notmuch2.Database(maildir.path) as db:
|
||||
with notmuch2.Database(maildir.path, config=notmuch2.Database.CONFIG.EMPTY) as db:
|
||||
yield next(db.threads('foo'))
|
||||
|
||||
|
||||
|
@ -57,6 +57,13 @@ def test_iter(thread):
|
|||
def test_matched(thread):
|
||||
assert thread.matched == 1
|
||||
|
||||
def test_matched_iter(thread):
|
||||
count = 0
|
||||
msgs = list(iter(thread))
|
||||
for msg in msgs:
|
||||
if msg.matched:
|
||||
count += 1
|
||||
assert count == thread.matched
|
||||
|
||||
def test_authors_type(thread):
|
||||
assert isinstance(thread.authors, notmuch2.BinString)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
0.34.2
|
|
@ -1,3 +1,3 @@
|
|||
# this file should be kept in sync with ../../../version
|
||||
__VERSION__ = '0.34.2'
|
||||
__VERSION__ = '0.35'
|
||||
SOVERSION = '5'
|
||||
|
|
|
@ -103,12 +103,12 @@ _notmuch_search_terms()
|
|||
COMPREPLY=( $(compgen -P "from:" -W "`_notmuch_email ${cur}`" -- ${cur##from:}) )
|
||||
;;
|
||||
path:*)
|
||||
local path=`notmuch config get database.path`
|
||||
local path=`notmuch config get database.mail_root`
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -d "$path/${cur##path:}" | sed "s|^$path/||" ) )
|
||||
;;
|
||||
folder:*)
|
||||
local path=`notmuch config get database.path`
|
||||
local path=`notmuch config get database.mail_root`
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -d "$path/${cur##folder:}" | \
|
||||
sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
|
||||
|
@ -281,7 +281,7 @@ _notmuch_insert()
|
|||
$split &&
|
||||
case "${prev}" in
|
||||
--folder)
|
||||
local path=`notmuch config get database.path`
|
||||
local path=`notmuch config get database.mail_root`
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $(compgen -d "$path/${cur}" | \
|
||||
sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
|
||||
|
|
|
@ -69,8 +69,8 @@ _notmuch_term_mimetype() {
|
|||
|
||||
_notmuch_term_path() {
|
||||
local ret=1 expl
|
||||
local maildir="$(notmuch config get database.path)"
|
||||
[[ -d $maildir ]] || { _message -e "database.path not found" ; return $ret }
|
||||
local maildir="$(notmuch config get database.mail_root)"
|
||||
[[ -d $maildir ]] || { _message -e "database.mail_root not found" ; return $ret }
|
||||
|
||||
_description notmuch-folder expl 'maildir folder'
|
||||
_files "$expl[@]" -W $maildir -/ && ret=0
|
||||
|
@ -79,8 +79,8 @@ _notmuch_term_path() {
|
|||
|
||||
_notmuch_term_folder() {
|
||||
local ret=1 expl
|
||||
local maildir="$(notmuch config get database.path)"
|
||||
[[ -d $maildir ]] || { _message -e "database.path not found" ; return $ret }
|
||||
local maildir="$(notmuch config get database.mail_root)"
|
||||
[[ -d $maildir ]] || { _message -e "database.mail_root not found" ; return $ret }
|
||||
|
||||
_description notmuch-folder expl 'maildir folder'
|
||||
local ignoredfolders=( '*/(cur|new|tmp)' )
|
||||
|
|
40
configure
vendored
40
configure
vendored
|
@ -55,6 +55,8 @@ subdirs="${subdirs} bindings"
|
|||
# the directory structure and copy Makefiles.
|
||||
if [ "$srcdir" != "." ]; then
|
||||
|
||||
NOTMUCH_BUILDDIR=$PWD
|
||||
|
||||
for dir in . ${subdirs}; do
|
||||
mkdir -p "$dir"
|
||||
cp "$srcdir"/"$dir"/Makefile.local "$dir"
|
||||
|
@ -78,6 +80,8 @@ if [ "$srcdir" != "." ]; then
|
|||
"$srcdir"/bindings/python-cffi/notmuch2 \
|
||||
"$srcdir"/bindings/python-cffi/setup.py \
|
||||
bindings/python-cffi/
|
||||
else
|
||||
NOTMUCH_BUILDDIR=$NOTMUCH_SRCDIR
|
||||
fi
|
||||
|
||||
# Set several defaults (optionally specified by the user in
|
||||
|
@ -308,12 +312,22 @@ for option; do
|
|||
true
|
||||
elif [ "${option%%=*}" = '--host' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--bindir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--sbindir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--datadir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--localstatedir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--sharedstatedir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--libexecdir' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--exec-prefix' ] ; then
|
||||
true
|
||||
elif [ "${option%%=*}" = '--program-prefix' ] ; then
|
||||
true
|
||||
elif [ "${option}" = '--disable-maintainer-mode' ] ; then
|
||||
true
|
||||
elif [ "${option}" = '--disable-dependency-tracking' ] ; then
|
||||
|
@ -396,6 +410,18 @@ EOF
|
|||
exit 1
|
||||
fi
|
||||
|
||||
printf "C compiler supports address sanitizer... "
|
||||
test_cmdline="${CC} ${CFLAGS} ${CPPFLAGS} -fsanitize=address minimal.c ${LDFLAGS} -o minimal"
|
||||
if ${test_cmdline} >/dev/null 2>&1 && ./minimal
|
||||
then
|
||||
printf "Yes.\n"
|
||||
have_asan=1
|
||||
else
|
||||
printf "Nope, skipping those tests.\n"
|
||||
have_asan=0
|
||||
fi
|
||||
unset test_cmdline
|
||||
|
||||
printf "Reading libnotmuch version from source... "
|
||||
cat > _libversion.c <<EOF
|
||||
#include <stdio.h>
|
||||
|
@ -734,6 +760,7 @@ if command -v ${BASHCMD} > /dev/null; then
|
|||
printf "Yes (%s).\n" "$bash_absolute"
|
||||
else
|
||||
have_bash=0
|
||||
bash_absolute=
|
||||
printf "No. (%s not found)\n" "${BASHCMD}"
|
||||
fi
|
||||
|
||||
|
@ -744,6 +771,7 @@ if command -v ${PERL} > /dev/null; then
|
|||
printf "Yes (%s).\n" "$perl_absolute"
|
||||
else
|
||||
have_perl=0
|
||||
perl_absolute=
|
||||
printf "No. (%s not found)\n" "${PERL}"
|
||||
fi
|
||||
|
||||
|
@ -1245,6 +1273,7 @@ cat > Makefile.config <<EOF
|
|||
# directory (the current directory at the time configure was run).
|
||||
srcdir = ${srcdir}
|
||||
NOTMUCH_SRCDIR = ${NOTMUCH_SRCDIR}
|
||||
NOTMUCH_BUILDDIR = ${NOTMUCH_BUILDDIR}
|
||||
|
||||
# subdirectories to build
|
||||
subdirs = ${subdirs}
|
||||
|
@ -1531,6 +1560,9 @@ NOTMUCH_GMIME_X509_CERT_VALIDITY=${gmime_x509_cert_validity}
|
|||
# Whether GMime can verify signatures when decrypting with a session key:
|
||||
NOTMUCH_GMIME_VERIFY_WITH_SESSION_KEY=${gmime_verify_with_session_key}
|
||||
|
||||
# Does the C compiler support the address sanitizer
|
||||
NOTMUCH_HAVE_ASAN=${have_asan}
|
||||
|
||||
# do we have man pages?
|
||||
NOTMUCH_HAVE_MAN=$((have_sphinx))
|
||||
|
||||
|
@ -1579,6 +1611,14 @@ EOF
|
|||
printf "rsti_dir = '%s'\n" "$(cd emacs && pwd -P)"
|
||||
} > sphinx.config
|
||||
|
||||
cat > bindings/python-cffi/_notmuch_config.py <<EOF
|
||||
# _notmuch_config.py was automatically generated by the configure
|
||||
# script in the root of the notmuch source tree.
|
||||
NOTMUCH_VERSION_FILE='${NOTMUCH_SRCDIR}/version.txt'
|
||||
NOTMUCH_INCLUDE_DIR='${NOTMUCH_SRCDIR}/lib'
|
||||
NOTMUCH_LIB_DIR='${NOTMUCH_SRCDIR}/lib'
|
||||
EOF
|
||||
|
||||
# Finally, after everything configured, inform the user how to continue.
|
||||
cat <<EOF
|
||||
|
||||
|
|
31
debian/changelog
vendored
31
debian/changelog
vendored
|
@ -1,3 +1,34 @@
|
|||
notmuch (0.35-1~bpo11+1) bullseye-backports; urgency=medium
|
||||
|
||||
* Rebuild for bullseye-backports.
|
||||
|
||||
-- David Bremner <bremner@debian.org> Tue, 15 Feb 2022 20:54:43 -0400
|
||||
|
||||
notmuch (0.35-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sun, 06 Feb 2022 12:15:19 -0400
|
||||
|
||||
notmuch (0.35~rc0-2) experimental; urgency=medium
|
||||
|
||||
* Reupload with binaries
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sat, 29 Jan 2022 21:53:29 -0400
|
||||
|
||||
notmuch (0.35~rc0-1) experimental; urgency=medium
|
||||
|
||||
* New upstream release candidate
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sat, 29 Jan 2022 18:14:57 -0400
|
||||
|
||||
notmuch (0.34.3-1) unstable; urgency=medium
|
||||
|
||||
* New upstream bugfix release, with several fixes for the notmuch2
|
||||
python module.
|
||||
|
||||
-- David Bremner <bremner@debian.org> Sun, 09 Jan 2022 15:30:38 -0400
|
||||
|
||||
notmuch (0.34.2-1~bpo11+1) bullseye-backports; urgency=medium
|
||||
|
||||
* Rebuild for bullseye-backports.
|
||||
|
|
18
debian/control
vendored
18
debian/control
vendored
|
@ -56,7 +56,8 @@ Recommends:
|
|||
gnupg-agent,
|
||||
gpgsm,
|
||||
Suggests:
|
||||
mailscripts
|
||||
mailscripts,
|
||||
notmuch-doc,
|
||||
Description: thread-based email index, search and tagging
|
||||
Notmuch is a system for indexing, searching, reading, and tagging
|
||||
large collections of email messages in maildir or mh format. It uses
|
||||
|
@ -65,6 +66,21 @@ Description: thread-based email index, search and tagging
|
|||
.
|
||||
This package contains the notmuch command-line interface
|
||||
|
||||
Package: notmuch-doc
|
||||
Architecture: all
|
||||
Depends:
|
||||
${misc:Depends},
|
||||
${sphinxdoc:Depends},
|
||||
Suggests:
|
||||
notmuch
|
||||
Description: thread-based email index, search and tagging
|
||||
Notmuch is a system for indexing, searching, reading, and tagging
|
||||
large collections of email messages in maildir or mh format. It uses
|
||||
the Xapian library to provide fast, full-text search with a very
|
||||
convenient search syntax.
|
||||
.
|
||||
This package contains the HTML documentation
|
||||
|
||||
Package: libnotmuch5
|
||||
Section: libs
|
||||
Architecture: any
|
||||
|
|
2
debian/elpa-notmuch.elpa
vendored
2
debian/elpa-notmuch.elpa
vendored
|
@ -1,3 +1,3 @@
|
|||
debian/tmp/usr/share/emacs/site-lisp/*.el
|
||||
debian/tmp/usr/share/emacs/site-lisp/notmuch-logo.png
|
||||
debian/tmp/usr/share/emacs/site-lisp/notmuch-logo.svg
|
||||
emacs/notmuch-pkg.el
|
||||
|
|
1
debian/notmuch-doc.install
vendored
Normal file
1
debian/notmuch-doc.install
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
doc/_build/html usr/share/doc/notmuch
|
4
debian/rules
vendored
4
debian/rules
vendored
|
@ -3,7 +3,7 @@
|
|||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
%:
|
||||
dh $@ --with python3,elpa
|
||||
dh $@ --with python3,elpa,sphinxdoc
|
||||
|
||||
override_dh_auto_configure:
|
||||
BASHCMD=/bin/bash ./configure --prefix=/usr \
|
||||
|
@ -19,7 +19,7 @@ override_dh_auto_test:
|
|||
dh_auto_test -- V=1
|
||||
|
||||
override_dh_auto_build:
|
||||
dh_auto_build -- V=1
|
||||
dh_auto_build -- V=1 all sphinx-html
|
||||
PYBUILD_NAME=notmuch dh_auto_build --buildsystem=pybuild --sourcedirectory bindings/python
|
||||
PYBUILD_NAME=notmuch2 dh_auto_build --buildsystem=pybuild --sourcedirectory bindings/python-cffi
|
||||
$(MAKE) -C contrib/notmuch-mutt
|
||||
|
|
|
@ -145,9 +145,11 @@ headers = {
|
|||
Cc?: string,
|
||||
Bcc?: string,
|
||||
Reply-To?: string,
|
||||
Date: string
|
||||
Date: string,
|
||||
extra_header_pair*
|
||||
}
|
||||
|
||||
extra_header_pair= (header_name: string)
|
||||
# Encryption status (format_part_sprinter)
|
||||
encstatus = [{status: "good"|"bad"}]
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ endif
|
|||
|
||||
INFO_INFO_FILES := $(INFO_TEXI_FILES:.texi=.info)
|
||||
|
||||
.PHONY: sphinx-html sphinx-texinfo sphinx-info doc-prereqs
|
||||
.PHONY: sphinx-html sphinx-texinfo sphinx-info
|
||||
|
||||
.PHONY: install-man build-man apidocs install-apidocs
|
||||
|
||||
|
@ -47,23 +47,28 @@ $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.texi.stamp
|
|||
endif
|
||||
|
||||
ifeq ($(HAVE_PYTHON3_CFFI),1)
|
||||
doc-prereqs: python-cffi-bindings
|
||||
DOC_PREREQS=bindings/python-cffi.stamp
|
||||
else
|
||||
DOC_PREREQS=
|
||||
endif
|
||||
|
||||
sphinx-html: $(DOCBUILDDIR)/.html.stamp
|
||||
|
||||
$(DOCBUILDDIR)/.html.stamp: $(ALL_RST_FILES) doc-prereqs
|
||||
$(DOCBUILDDIR)/.html.stamp: $(ALL_RST_FILES) $(DOC_PREREQS)
|
||||
$(SPHINXBUILD) -b html -d $(DOCBUILDDIR)/html_doctrees $(ALLSPHINXOPTS) $(DOCBUILDDIR)/html
|
||||
touch $@
|
||||
|
||||
sphinx-texinfo: $(DOCBUILDDIR)/.texi.stamp
|
||||
|
||||
$(DOCBUILDDIR)/.texi.stamp: $(ALL_RST_FILES) doc-prereqs
|
||||
$(DOCBUILDDIR)/.texi.stamp: $(ALL_RST_FILES) $(DOC_PREREQS)
|
||||
$(SPHINXBUILD) -b texinfo -d $(DOCBUILDDIR)/texinfo_doctrees $(ALLSPHINXOPTS) $(DOCBUILDDIR)/texinfo
|
||||
touch $@
|
||||
|
||||
sphinx-info: sphinx-texinfo
|
||||
sphinx-info: $(DOCBUILDDIR)/.info.stamp
|
||||
|
||||
$(DOCBUILDDIR)/.info.stamp: $(DOCBUILDDIR)/.texi.stamp $(DOC_PREREQS)
|
||||
$(MAKE) -C $(DOCBUILDDIR)/texinfo info
|
||||
touch $@
|
||||
|
||||
# Use the man page converter that is available. We should never depend
|
||||
# on MAN_ROFF_FILES if a converter is not available.
|
||||
|
@ -112,6 +117,11 @@ build-man:
|
|||
install-man:
|
||||
@echo "No sphinx, will not install man pages."
|
||||
else
|
||||
|
||||
# it should be safe to depend on the stamp file, because it is created
|
||||
# after all roff files are moved into place.
|
||||
${MAN_GZIP_FILES}: ${DOCBUILDDIR}/.roff.stamp
|
||||
|
||||
build-man: ${MAN_GZIP_FILES}
|
||||
install-man: ${MAN_GZIP_FILES}
|
||||
mkdir -m0755 -p "$(DESTDIR)$(mandir)/man1"
|
||||
|
@ -127,7 +137,7 @@ ifneq ($(HAVE_SPHINX)$(HAVE_MAKEINFO),11)
|
|||
build-info:
|
||||
@echo "Missing sphinx or makeinfo, not building info pages"
|
||||
else
|
||||
build-info: sphinx-info
|
||||
build-info: $(DOCBUILDDIR)/.info.stamp
|
||||
endif
|
||||
|
||||
ifneq ($(HAVE_SPHINX)$(HAVE_MAKEINFO)$(HAVE_INSTALL_INFO),111)
|
||||
|
@ -145,5 +155,5 @@ $(dir)/config.dox: version.stamp
|
|||
echo "INPUT=${srcdir}/lib/notmuch.h" >> $@
|
||||
|
||||
CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
|
||||
CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp
|
||||
CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.stamp
|
||||
CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
|
||||
|
|
|
@ -14,7 +14,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'notmuch'
|
||||
copyright = u'2009-2021, Carl Worth and many others'
|
||||
copyright = u'2009-2022, Carl Worth and many others'
|
||||
|
||||
location = os.path.dirname(__file__)
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ Supported options for **address** include
|
|||
neither ``--output=sender`` nor ``--output=recipients`` is
|
||||
given, ``--output=sender`` is implied.
|
||||
|
||||
**sender**
|
||||
sender
|
||||
Output all addresses from the *From* header.
|
||||
|
||||
Note: Searching for **sender** should be much faster than
|
||||
|
@ -50,17 +50,17 @@ Supported options for **address** include
|
|||
cached directly in the database whereas other addresses need
|
||||
to be fetched from message files.
|
||||
|
||||
**recipients**
|
||||
recipients
|
||||
Output all addresses from the *To*, *Cc* and *Bcc* headers.
|
||||
|
||||
**count**
|
||||
count
|
||||
Print the count of how many times was the address encountered
|
||||
during search.
|
||||
|
||||
Note: With this option, addresses are printed only after the
|
||||
whole search is finished. This may take long time.
|
||||
|
||||
**address**
|
||||
address
|
||||
Output only the email addresses instead of the full mailboxes
|
||||
with names and email addresses. This option has no effect on
|
||||
the JSON or S-Expression output formats.
|
||||
|
@ -69,17 +69,17 @@ Supported options for **address** include
|
|||
|
||||
Control the deduplication of results.
|
||||
|
||||
**no**
|
||||
no
|
||||
Output all occurrences of addresses in the matching
|
||||
messages. This is not applicable with ``--output=count``.
|
||||
|
||||
**mailbox**
|
||||
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**
|
||||
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
|
||||
|
|
|
@ -55,14 +55,14 @@ The available configuration items are described below. Non-absolute
|
|||
paths are presumed relative to `$HOME` for items in section
|
||||
**database**.
|
||||
|
||||
**database.path**
|
||||
database.path
|
||||
Notmuch will store its database here, (in
|
||||
sub-directory named ``.notmuch`` if **database.mail\_root**
|
||||
is unset).
|
||||
|
||||
Default: see :ref:`database`
|
||||
|
||||
**database.mail_root**
|
||||
database.mail_root
|
||||
The top-level directory where your mail currently exists and to
|
||||
where mail will be delivered in the future. Files should be
|
||||
individual email messages.
|
||||
|
@ -72,7 +72,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
Default: For compatibility with older configurations, the value of
|
||||
database.path is used if **database.mail\_root** is unset.
|
||||
|
||||
**database.backup_dir**
|
||||
database.backup_dir
|
||||
Directory to store tag dumps when upgrading database.
|
||||
|
||||
History: this configuration value was introduced in notmuch 0.32.
|
||||
|
@ -80,7 +80,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
Default: A sibling directory of the Xapian database called
|
||||
`backups`.
|
||||
|
||||
**database.hook_dir**
|
||||
database.hook_dir
|
||||
Directory containing hooks run by notmuch commands. See
|
||||
:any:`notmuch-hooks(5)`.
|
||||
|
||||
|
@ -88,7 +88,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
|
||||
Default: See HOOKS, below.
|
||||
|
||||
**database.autocommit**
|
||||
database.autocommit
|
||||
|
||||
How often to commit transactions to disk. `0` means wait until
|
||||
command completes, otherwise an integer `n` specifies to commit to
|
||||
|
@ -96,30 +96,30 @@ paths are presumed relative to `$HOME` for items in section
|
|||
|
||||
History: this configuration value was introduced in notmuch 0.33.
|
||||
|
||||
**user.name**
|
||||
user.name
|
||||
Your full name.
|
||||
|
||||
Default: ``$NAME`` variable if set, otherwise read from
|
||||
``/etc/passwd``.
|
||||
|
||||
**user.primary\_email**
|
||||
user.primary\_email
|
||||
Your primary email address.
|
||||
|
||||
Default: ``$EMAIL`` variable if set, otherwise constructed from
|
||||
the username and hostname of the current machine.
|
||||
|
||||
**user.other\_email**
|
||||
user.other\_email
|
||||
A list of other email addresses at which you receive email.
|
||||
|
||||
Default: not set.
|
||||
|
||||
**new.tags**
|
||||
new.tags
|
||||
A list of tags that will be added to all messages incorporated by
|
||||
**notmuch new**.
|
||||
|
||||
Default: ``unread;inbox``.
|
||||
|
||||
**new.ignore**
|
||||
new.ignore
|
||||
A list to specify files and directories that will not be searched
|
||||
for messages by :any:`notmuch-new(1)`. Each entry in the list is either:
|
||||
|
||||
|
@ -137,7 +137,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
|
||||
Default: empty list.
|
||||
|
||||
**search.exclude\_tags**
|
||||
search.exclude\_tags
|
||||
A list of tags that will be excluded from search results by
|
||||
default. Using an excluded tag in a query will override that
|
||||
exclusion.
|
||||
|
@ -145,7 +145,21 @@ paths are presumed relative to `$HOME` for items in section
|
|||
Default: empty list. Note that :any:`notmuch-setup(1)` puts
|
||||
``deleted;spam`` here when creating new configuration file.
|
||||
|
||||
**maildir.synchronize\_flags**
|
||||
.. _show.extra_headers:
|
||||
|
||||
show.extra\_headers
|
||||
|
||||
By default :any:`notmuch-show(1)` includes the following headers
|
||||
in structured output if they are present in the message:
|
||||
`Subject`, `From`, `To`, `Cc`, `Bcc`, `Reply-To`, `Date`. This
|
||||
option allows the specification of a list of further
|
||||
headers to output.
|
||||
|
||||
History: This configuration value was introduced in notmuch 0.35.
|
||||
|
||||
Default: empty list.
|
||||
|
||||
maildir.synchronize\_flags
|
||||
If true, then the following maildir flags (in message filenames)
|
||||
will be synchronized with the corresponding notmuch tags:
|
||||
|
||||
|
@ -178,7 +192,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
|
||||
Default: ``true``.
|
||||
|
||||
**index.decrypt**
|
||||
index.decrypt
|
||||
Policy for decrypting encrypted messages during indexing. Must be
|
||||
one of: ``false``, ``auto``, ``nostash``, or ``true``.
|
||||
|
||||
|
@ -231,7 +245,7 @@ paths are presumed relative to `$HOME` for items in section
|
|||
|
||||
Default: ``auto``.
|
||||
|
||||
**index.header.<prefix>**
|
||||
index.header.<prefix>
|
||||
Define the query prefix <prefix>, based on a mail header. For
|
||||
example ``index.header.List=List-Id`` will add a probabilistic
|
||||
prefix ``List:`` that searches the ``List-Id`` field. User
|
||||
|
@ -240,18 +254,18 @@ paths are presumed relative to `$HOME` for items in section
|
|||
supported. See :any:`notmuch-search-terms(7)` for a list of existing
|
||||
prefixes, and an explanation of probabilistic prefixes.
|
||||
|
||||
**built_with.<name>**
|
||||
built_with.<name>
|
||||
Compile time feature <name>. Current possibilities include
|
||||
"retry_lock" (configure option, included by default).
|
||||
(since notmuch 0.30, "compact" and "field_processor" are
|
||||
always included.)
|
||||
|
||||
**query.<name>**
|
||||
query.<name>
|
||||
Expansion for named query called <name>. See
|
||||
:any:`notmuch-search-terms(7)` for more information about named
|
||||
queries.
|
||||
|
||||
**squery.<name>**
|
||||
squery.<name>
|
||||
Expansion for named query called <name>, using s-expression syntax. See
|
||||
:any:`notmuch-sexp-queries(7)` for more information about s-expression
|
||||
queries.
|
||||
|
|
|
@ -28,13 +28,13 @@ Supported options for **count** include
|
|||
|
||||
.. option:: --output=(messages|threads|files)
|
||||
|
||||
**messages**
|
||||
messages
|
||||
Output the number of matching messages. This is the default.
|
||||
|
||||
**threads**
|
||||
threads
|
||||
Output the number of matching threads.
|
||||
|
||||
**files**
|
||||
files
|
||||
Output the number of files associated with matching
|
||||
messages. This may be bigger than the number of matching
|
||||
messages due to duplicates (i.e. multiple files having the
|
||||
|
|
|
@ -39,7 +39,7 @@ Supported options for **dump** include
|
|||
Notmuch restore supports two plain text dump formats, both with
|
||||
one message-id per line, followed by a list of tags.
|
||||
|
||||
**batch-tag**
|
||||
batch-tag
|
||||
The default **batch-tag** dump format is intended to more
|
||||
robust against malformed message-ids and tags containing
|
||||
whitespace or non-\ :manpage:`ascii(7)` characters. Each line
|
||||
|
@ -58,7 +58,7 @@ Supported options for **dump** include
|
|||
:any:`notmuch-tag(1)`; note that the single message-id query is
|
||||
mandatory for :any:`notmuch-restore(1)`.
|
||||
|
||||
**sup**
|
||||
sup
|
||||
The **sup** dump file format is specifically chosen to be
|
||||
compatible with the format of files produced by
|
||||
:manpage:`sup-dump(1)`. So if you've previously been using sup
|
||||
|
@ -77,18 +77,18 @@ Supported options for **dump** include
|
|||
|
||||
Control what kind of metadata is included in the output.
|
||||
|
||||
**config**
|
||||
config
|
||||
Output configuration data stored in the database. Each line
|
||||
starts with "#@ ", followed by a space separated key-value
|
||||
pair. Both key and value are hex encoded if needed.
|
||||
|
||||
**properties**
|
||||
properties
|
||||
Output per-message (key,value) metadata. Each line starts
|
||||
with "#= ", followed by a message id, and a space separated
|
||||
list of key=value pairs. Ids, keys and values are hex encoded
|
||||
if needed. See :any:`notmuch-properties(7)` for more details.
|
||||
|
||||
**tags**
|
||||
tags
|
||||
Output per-message boolean metadata, namely tags. See *format* above
|
||||
for description of the output.
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ DESCRIPTION
|
|||
|
||||
**notmuch insert** reads a message from standard input and delivers it
|
||||
into the maildir directory given by configuration option
|
||||
**database.path**, then incorporates the message into the notmuch
|
||||
**database.mail_root**, then incorporates the message into the notmuch
|
||||
database. It is an alternative to using a separate tool to deliver the
|
||||
message then running :any:`notmuch-new(1)` afterwards.
|
||||
|
||||
|
@ -38,7 +38,7 @@ Supported options for **insert** include
|
|||
.. option:: --folder=<folder>
|
||||
|
||||
Deliver the message to the specified folder, relative to the
|
||||
top-level directory given by the value of **database.path**. The
|
||||
top-level directory given by the value of **database.mail_root**. The
|
||||
default is the empty string, which means delivering to the
|
||||
top-level directory.
|
||||
|
||||
|
|
|
@ -40,22 +40,22 @@ Supported options for **reply** include
|
|||
|
||||
.. option:: --format=(default|json|sexp|headers-only)
|
||||
|
||||
**default**
|
||||
default
|
||||
Includes subject and quoted message body as an RFC 2822
|
||||
message.
|
||||
|
||||
**json**
|
||||
json
|
||||
Produces JSON output containing headers for a reply message
|
||||
and the contents of the original message. This output can be
|
||||
used by a client to create a reply message intelligently.
|
||||
|
||||
**sexp**
|
||||
sexp
|
||||
Produces S-Expression output containing headers for a reply
|
||||
message and the contents of the original message. This output
|
||||
can be used by a client to create a reply message
|
||||
intelligently.
|
||||
|
||||
**headers-only**
|
||||
headers-only
|
||||
Only produces In-Reply-To, References, To, Cc, and Bcc
|
||||
headers.
|
||||
|
||||
|
@ -67,10 +67,10 @@ Supported options for **reply** include
|
|||
|
||||
.. option:: --reply-to=(all|sender)
|
||||
|
||||
**all** (default)
|
||||
all (default)
|
||||
Replies to all addresses.
|
||||
|
||||
**sender**
|
||||
sender
|
||||
Replies only to the sender. If replying to user's own message
|
||||
(Reply-to: or From: header is one of the user's configured
|
||||
email addresses), try To:, Cc:, and Bcc: headers in this
|
||||
|
|
|
@ -32,14 +32,14 @@ Supported options for **restore** include
|
|||
line specifying a message-id and a set of tags. For details of the
|
||||
actual formats, see :any:`notmuch-dump(1)`.
|
||||
|
||||
**sup**
|
||||
sup
|
||||
The **sup** dump file format is specifically chosen to be
|
||||
compatible with the format of files produced by sup-dump. So
|
||||
if you've previously been using sup for mail, then the
|
||||
**notmuch restore** command provides you a way to import all
|
||||
of your tags (or labels as sup calls them).
|
||||
|
||||
**batch-tag**
|
||||
batch-tag
|
||||
The **batch-tag** dump format is intended to more robust
|
||||
against malformed message-ids and tags containing whitespace
|
||||
or non-\ **ascii(7)** characters. See :any:`notmuch-dump(1)` for
|
||||
|
@ -49,7 +49,7 @@ Supported options for **restore** include
|
|||
changes if the **maildir.synchronize\_flags** configuration
|
||||
option is enabled. See :any:`notmuch-config(1)` for details.
|
||||
|
||||
**auto**
|
||||
auto
|
||||
This option (the default) tries to guess the format from the
|
||||
input. For correctly formed input in either supported format,
|
||||
this heuristic, based the fact that batch-tag format contains
|
||||
|
@ -59,18 +59,18 @@ Supported options for **restore** include
|
|||
|
||||
Control what kind of metadata is restored.
|
||||
|
||||
**config**
|
||||
config
|
||||
Restore configuration data to the database. Each configuration
|
||||
line starts with "#@ ", followed by a space separated
|
||||
key-value pair. Both key and value are hex encoded if needed.
|
||||
|
||||
**properties**
|
||||
properties
|
||||
Restore per-message (key,value) metadata. Each line starts
|
||||
with "#= ", followed by a message id, and a space separated
|
||||
list of key=value pairs. Ids, keys and values are hex encoded
|
||||
if needed. See :any:`notmuch-properties(7)` for more details.
|
||||
|
||||
**tags**
|
||||
tags
|
||||
Restore per-message metadata, namely tags. See *format* above
|
||||
for more details.
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ Supported options for **search** include
|
|||
|
||||
.. option:: --output=(summary|threads|messages|files|tags)
|
||||
|
||||
**summary**
|
||||
summary
|
||||
Output a summary of each thread with any message matching the
|
||||
search terms. The summary includes the thread ID, date, the
|
||||
number of messages in the thread (both the number matched and
|
||||
|
@ -52,19 +52,19 @@ Supported options for **search** include
|
|||
for some messages, the total number of files is printed in
|
||||
parentheses (see below for an example).
|
||||
|
||||
**threads**
|
||||
threads
|
||||
Output the thread IDs of all threads with any message matching
|
||||
the search terms, either one per line (``--format=text``),
|
||||
separated by null characters (``--format=text0``), as a JSON array
|
||||
(``--format=json``), or an S-Expression list (``--format=sexp``).
|
||||
|
||||
**messages**
|
||||
messages
|
||||
Output the message IDs of all messages matching the search
|
||||
terms, either one per line (``--format=text``), separated by null
|
||||
characters (``--format=text0``), as a JSON array (``--format=json``),
|
||||
or as an S-Expression list (``--format=sexp``).
|
||||
|
||||
**files**
|
||||
files
|
||||
Output the filenames of all messages matching the search
|
||||
terms, either one per line (``--format=text``), separated by null
|
||||
characters (``--format=text0``), as a JSON array (``--format=json``),
|
||||
|
@ -78,7 +78,7 @@ Supported options for **search** include
|
|||
in other directories that are included in the output, although
|
||||
these files alone would not match the search.
|
||||
|
||||
**tags**
|
||||
tags
|
||||
Output all tags that appear on any message matching the search
|
||||
terms, either one per line (``--format=text``), separated by null
|
||||
characters (``--format=text0``), as a JSON array (``--format=json``),
|
||||
|
@ -115,20 +115,20 @@ Supported options for **search** include
|
|||
terms. This option specifies whether to omit excluded messages in
|
||||
the search process.
|
||||
|
||||
**true** (default)
|
||||
true (default)
|
||||
Prevent excluded messages from matching the search terms.
|
||||
|
||||
**all**
|
||||
all
|
||||
Additionally prevent excluded messages from appearing in
|
||||
displayed results, in effect behaving as though the excluded
|
||||
messages do not exist.
|
||||
|
||||
**false**
|
||||
false
|
||||
Allow excluded messages to match search terms and appear in
|
||||
displayed results. Excluded messages are still marked in the
|
||||
relevant outputs.
|
||||
|
||||
**flag**
|
||||
flag
|
||||
Only has an effect when ``--output=summary``. The output is
|
||||
almost identical to **false**, but the "match count" is the
|
||||
number of matching non-excluded messages in the thread, rather
|
||||
|
|
|
@ -36,7 +36,7 @@ Supported options for **show** include
|
|||
|
||||
.. option:: --format=(text|json|sexp|mbox|raw)
|
||||
|
||||
**text** (default for messages)
|
||||
text (default for messages)
|
||||
The default plain-text format has all text-content MIME parts
|
||||
decoded. Various components in the output, (**message**,
|
||||
**header**, **body**, **attachment**, and MIME **part**), will
|
||||
|
@ -46,7 +46,7 @@ Supported options for **show** include
|
|||
'}'), to either open or close the component. For a multipart
|
||||
MIME message, these parts will be nested.
|
||||
|
||||
**json**
|
||||
json
|
||||
The output is formatted with Javascript Object Notation
|
||||
(JSON). This format is more robust than the text format for
|
||||
automated processing. The nested structure of multipart MIME
|
||||
|
@ -58,7 +58,7 @@ Supported options for **show** include
|
|||
as UTF-8 and any message content included in the output will
|
||||
be charset-converted to UTF-8.
|
||||
|
||||
**sexp**
|
||||
sexp
|
||||
The output is formatted as the Lisp s-expression (sexp)
|
||||
equivalent of the JSON format above. Objects are formatted as
|
||||
property lists whose keys are keywords (symbols preceded by a
|
||||
|
@ -66,7 +66,7 @@ Supported options for **show** include
|
|||
formatted as ``nil``. As for JSON, the s-expression output is
|
||||
always encoded as UTF-8.
|
||||
|
||||
**mbox**
|
||||
mbox
|
||||
All matching messages are output in the traditional, Unix mbox
|
||||
format with each message being prefixed by a line beginning
|
||||
with "From " and a blank line separating each message. Lines
|
||||
|
@ -77,7 +77,7 @@ Supported options for **show** include
|
|||
|
||||
http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
|
||||
|
||||
**raw** (default if ``--part`` is given)
|
||||
raw (default if ``--part`` is given)
|
||||
Write the raw bytes of the given MIME part of a message to
|
||||
standard out. For this format, it is an error to specify a
|
||||
query that matches more than one message.
|
||||
|
@ -221,6 +221,13 @@ email messages. For this, use a search term of "thread:<thread-id>" as
|
|||
can be seen in the first column of output from the
|
||||
:any:`notmuch-search(1)` command.
|
||||
|
||||
CONFIGURATION
|
||||
=============
|
||||
|
||||
Structured output (json / sexp) is influenced by the configuration
|
||||
option :ref:`show.extra_headers <show.extra_headers>`. See
|
||||
:any:`notmuch-config(1)` for details.
|
||||
|
||||
EXIT STATUS
|
||||
===========
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ must have executable permissions.
|
|||
|
||||
The currently available hooks are described below.
|
||||
|
||||
**pre-new**
|
||||
pre-new
|
||||
This hook is invoked by the :any:`notmuch-new(1)` command before
|
||||
scanning or importing new messages into the database. If this hook
|
||||
exits with a non-zero status, notmuch will abort further
|
||||
|
@ -28,7 +28,7 @@ The currently available hooks are described below.
|
|||
Typically this hook is used for fetching or delivering new mail to
|
||||
be imported into the database.
|
||||
|
||||
**post-new**
|
||||
post-new
|
||||
This hook is invoked by the :any:`notmuch-new(1)` command after
|
||||
new messages have been imported into the database and initial tags
|
||||
have been applied. The hook will not be run if there have been any
|
||||
|
@ -37,7 +37,7 @@ The currently available hooks are described below.
|
|||
Typically this hook is used to perform additional query-based
|
||||
tagging on the imported messages.
|
||||
|
||||
**post-insert**
|
||||
post-insert
|
||||
This hook is invoked by the :any:`notmuch-insert(1)` command after
|
||||
the message has been delivered, added to the database, and initial
|
||||
tags have been applied. The hook will not be run if there have
|
||||
|
|
|
@ -55,7 +55,7 @@ MESSAGE PROPERTIES
|
|||
The following properties are set by notmuch internally in the course
|
||||
of its normal activity.
|
||||
|
||||
**index.decryption**
|
||||
index.decryption
|
||||
If a message contains encrypted content, and notmuch tries to
|
||||
decrypt that content during indexing, it will add the property
|
||||
``index.decryption=success`` when the cleartext was successfully
|
||||
|
@ -75,8 +75,7 @@ of its normal activity.
|
|||
:any:`notmuch-config(1)`), then this property will not be set on that
|
||||
message.
|
||||
|
||||
**session-key**
|
||||
|
||||
session-key
|
||||
When :any:`notmuch-show(1)` or :any:`notmuch-reply(1)` encounters
|
||||
a message with an encrypted part, if notmuch finds a
|
||||
``session-key`` property associated with the message, it will try
|
||||
|
@ -111,8 +110,7 @@ of its normal activity.
|
|||
example, an AES-128 key might be stashed in a notmuch property as:
|
||||
``session-key=7:14B16AF65536C28AF209828DFE34C9E0``.
|
||||
|
||||
**index.repaired**
|
||||
|
||||
index.repaired
|
||||
Some messages arrive in forms that are confusing to view; they can
|
||||
be mangled by mail transport agents, or the sending mail user
|
||||
agent may structure them in a way that is confusing. If notmuch
|
||||
|
|
|
@ -21,7 +21,7 @@ build of notmuch supports it with
|
|||
|
||||
::
|
||||
|
||||
$ notmuch config get built_with.sexpr_query
|
||||
$ notmuch config get built_with.sexp_queries
|
||||
|
||||
|
||||
S-EXPRESSIONS
|
||||
|
@ -31,10 +31,12 @@ An *s-expression* is either an atom, or list of whitespace delimited
|
|||
s-expressions inside parentheses. Atoms are either
|
||||
|
||||
*basic value*
|
||||
|
||||
A basic value is an unquoted string containing no whitespace, double quotes, or
|
||||
parentheses.
|
||||
|
||||
*quoted string*
|
||||
|
||||
Double quotes (") delimit strings possibly containing whitespace
|
||||
or parentheses. These can contain double quote characters by
|
||||
escaping with backslash. E.g. ``"this is a quote \""``.
|
||||
|
@ -48,9 +50,11 @@ a *field*, *logical operation*, or *modifier*, and 0 or more
|
|||
subqueries.
|
||||
|
||||
``*``
|
||||
|
||||
"*" matches any non-empty string in the current field.
|
||||
|
||||
``()``
|
||||
|
||||
The empty list matches all messages
|
||||
|
||||
*term*
|
||||
|
@ -62,19 +66,23 @@ subqueries.
|
|||
phrase splitting see :any:`fields`.
|
||||
|
||||
``(`` *field* |q1| |q2| ... |qn| ``)``
|
||||
|
||||
Restrict the queries |q1| to |qn| to *field*, and combine with *and*
|
||||
(for most fields) or *or*. See :any:`fields` for more information.
|
||||
|
||||
``(`` *operator* |q1| |q2| ... |qn| ``)``
|
||||
|
||||
Combine queries |q1| to |qn|. Currently supported operators are
|
||||
``and``, ``or``, and ``not``. ``(not`` |q1| ... |qn| ``)`` is equivalent
|
||||
to ``(and (not`` |q1| ``) ... (not`` |qn| ``))``.
|
||||
|
||||
``(`` *modifier* |q1| |q2| ... |qn| ``)``
|
||||
|
||||
Combine queries |q1| to |qn|, and reinterpret the result (e.g. as a regular expression).
|
||||
See :any:`modifiers` for more information.
|
||||
|
||||
``(macro (`` |p1| ... |pn| ``) body)``
|
||||
|
||||
Define saved query with parameter substitution. The syntax is
|
||||
recognized only in saved s-expression queries (see ``squery.*`` in
|
||||
:any:`notmuch-config(1)`). Parameter names in ``body`` must be
|
||||
|
@ -164,26 +172,31 @@ MODIFIERS
|
|||
that are neither operators nor fields.
|
||||
|
||||
``(infix`` *atom* ``)``
|
||||
|
||||
Interpret *atom* as an infix notmuch query (see
|
||||
:any:`notmuch-search-terms(7)`). Not supported inside fields.
|
||||
|
||||
``(matching`` |q1| |q2| ... |qn| ``)`` ``(of`` |q1| |q2| ... |qn| ``)``
|
||||
|
||||
Match all messages have the same values of the current field as
|
||||
those matching all of |q1| ... |qn|. Supported in most term [#not-path]_ or
|
||||
phrase fields. Most commonly used in the ``thread`` field.
|
||||
|
||||
``(query`` *atom* ``)``
|
||||
|
||||
Expand to the saved query named by *atom*. See
|
||||
:any:`notmuch-config(1)` for more. Note that the saved query must
|
||||
be in infix syntax (:any:`notmuch-search-terms(7)`). Not supported
|
||||
inside fields.
|
||||
|
||||
``(regex`` *atom* ``)`` ``(rx`` *atom* ``)``
|
||||
|
||||
Interpret *atom* as a POSIX.2 regular expression (see
|
||||
:manpage:`regex(7)`). This applies in term fields and a subset [#not-phrase]_ of
|
||||
phrase fields (see :any:`field-table`).
|
||||
|
||||
``(starts-with`` *subword* ``)``
|
||||
|
||||
Matches any term starting with *subword*. This applies in either
|
||||
phrase or term :any:`fields <fields>`, or outside of fields [#not-body]_. Note that
|
||||
a ``starts-with`` query cannot be part of a phrase. The
|
||||
|
@ -193,63 +206,80 @@ EXAMPLES
|
|||
========
|
||||
|
||||
``Wizard``
|
||||
|
||||
Match all messages containing the word "wizard", ignoring case.
|
||||
|
||||
``added``
|
||||
|
||||
Match all messages containing "added", but also those containing "add", "additional",
|
||||
"Additional", "adds", etc... via stemming.
|
||||
|
||||
``(and Bob Marley)``
|
||||
|
||||
Match messages containing words "Bob" and "Marley", or their stems
|
||||
The words need not be adjacent.
|
||||
|
||||
``(not Bob Marley)``
|
||||
|
||||
Match messages containing neither "Bob" nor "Marley", nor their stems,
|
||||
|
||||
``"quick fox"`` ``quick-fox`` ``quick@fox``
|
||||
|
||||
Match the *phrase* "quick" followed by "fox" in phrase fields (or
|
||||
outside a field). Match the literal string in a term field.
|
||||
|
||||
``(folder (of (id 1234@invalid)))``
|
||||
|
||||
Match any message in the same folder as the one with Message-Id "1234@invalid"
|
||||
|
||||
``(id 1234@invalid blah@test)``
|
||||
|
||||
Matches Message-Id "1234@invalid" *or* Message-Id "blah@test"
|
||||
|
||||
``(and (infix "date:2009-11-18..2009-11-18") (tag unread))``
|
||||
|
||||
Match messages in the given date range with tag unread.
|
||||
|
||||
``(starts-with prelim)``
|
||||
|
||||
Match any words starting with "prelim".
|
||||
|
||||
``(subject quick "brown fox")``
|
||||
|
||||
Match messages whose subject contains "quick" (anywhere, stemmed) and
|
||||
the phrase "brown fox".
|
||||
|
||||
``(subject (starts-with prelim))``
|
||||
|
||||
Matches any word starting with "prelim", inside a message subject.
|
||||
|
||||
``(subject (starts-wih quick) "brown fox")``
|
||||
|
||||
Match messages whose subject contains "quick brown fox", but also
|
||||
"brown fox quicksand".
|
||||
|
||||
``(thread (of (id 1234@invalid)))``
|
||||
|
||||
Match any message in the same thread as the one with Message-Id "1234@invalid"
|
||||
|
||||
``(thread (matching (from bob@example.com) (to bob@example.com)))``
|
||||
|
||||
Match any (messages in) a thread containing a message from
|
||||
"bob@example.com" and a (possibly distinct) message to "bob at
|
||||
example.com")
|
||||
|
||||
``(to (or bob@example.com mallory@example.org))`` ``(or (to bob@example.com) (to mallory@example.org))``
|
||||
|
||||
Match in the "To" or "Cc" headers, "bob@example.com",
|
||||
"mallory@example.org", and also "bob@example.com.au" since it
|
||||
contains the adjacent triple "bob", "example", "com".
|
||||
|
||||
``(not (to *))``
|
||||
|
||||
Match messages with an empty or invalid 'To' and 'Cc' field.
|
||||
|
||||
``(List *)``
|
||||
|
||||
Match messages with a non-empty List-Id header, assuming
|
||||
configuration ``index.header.List=List-Id``
|
||||
|
||||
|
@ -306,10 +336,10 @@ NOTES
|
|||
in notmuch, this modifier is not supported in the
|
||||
``path`` field.
|
||||
|
||||
.. |q1| replace:: :math:`q_1`
|
||||
.. |q2| replace:: :math:`q_2`
|
||||
.. |qn| replace:: :math:`q_n`
|
||||
.. |q1| replace:: `q`\ :sub:`1`
|
||||
.. |q2| replace:: `q`\ :sub:`2`
|
||||
.. |qn| replace:: `q`\ :sub:`n`
|
||||
|
||||
.. |p1| replace:: :math:`p_1`
|
||||
.. |p2| replace:: :math:`p_2`
|
||||
.. |pn| replace:: :math:`p_n`
|
||||
.. |p1| replace:: `p`\ :sub:`1`
|
||||
.. |p2| replace:: `p`\ :sub:`2`
|
||||
.. |pn| replace:: `p`\ :sub:`n`
|
||||
|
|
|
@ -56,7 +56,7 @@ notmuch-hello key bindings
|
|||
``<tab>``
|
||||
Move to the next widget (button or text entry field)
|
||||
|
||||
``<backspace>``
|
||||
``<backtab>``
|
||||
Move to the previous widget.
|
||||
|
||||
``<return>``
|
||||
|
@ -175,6 +175,16 @@ variables.
|
|||
:index:`notmuch-search-oldest-first`
|
||||
Display the oldest threads at the top of the buffer
|
||||
|
||||
It is also possible to customize how the name of buffers containing
|
||||
search results is formatted using the following variables:
|
||||
|
||||
:index:`notmuch-search-buffer-name-format`
|
||||
|docstring::notmuch-search-buffer-name-format|
|
||||
|
||||
:index:`notmuch-saved-search-buffer-name-format`
|
||||
|docstring::notmuch-saved-search-buffer-name-format|
|
||||
|
||||
|
||||
.. _notmuch-show:
|
||||
|
||||
notmuch-show
|
||||
|
@ -222,6 +232,9 @@ Display of messages can be controlled by the following variables
|
|||
:index:`notmuch-message-headers-visible`
|
||||
|docstring::notmuch-message-headers-visible|
|
||||
|
||||
:index:`notmuch-show-header-line`
|
||||
|docstring::notmuch-show-header-line|
|
||||
|
||||
.. _show-copy:
|
||||
|
||||
Copy to kill-ring
|
||||
|
|
|
@ -42,7 +42,7 @@ emacs_mua := $(dir)/notmuch-emacs-mua
|
|||
emacs_mua_desktop := $(dir)/notmuch-emacs-mua.desktop
|
||||
|
||||
emacs_images := \
|
||||
$(srcdir)/$(dir)/notmuch-logo.png
|
||||
$(srcdir)/$(dir)/notmuch-logo.svg
|
||||
|
||||
emacs_bytecode = $(emacs_sources:.el=.elc)
|
||||
emacs_docstrings = $(emacs_sources:.el=.rsti)
|
||||
|
|
|
@ -45,7 +45,7 @@ Otherwise respect `fill-column'."
|
|||
:group 'coolj
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom coolj-line-prefix-regexp "^\\(>+ \\)*"
|
||||
(defcustom coolj-line-prefix-regexp "^\\(>+ ?\\)*"
|
||||
"Regular expression that matches line prefixes."
|
||||
:group 'coolj
|
||||
:type 'regexp)
|
||||
|
|
|
@ -198,7 +198,7 @@ fields of the search."
|
|||
(defvar notmuch-hello-indent 4
|
||||
"How much to indent non-headers.")
|
||||
|
||||
(defimage notmuch-hello-logo ((:type png :file "notmuch-logo.png")))
|
||||
(defimage notmuch-hello-logo ((:type svg :file "notmuch-logo.svg")))
|
||||
|
||||
(defcustom notmuch-show-logo t
|
||||
"Should the notmuch logo be shown?"
|
||||
|
@ -486,11 +486,14 @@ diagonal."
|
|||
(defun notmuch-hello-widget-search (widget &rest _ignore)
|
||||
(cl-case (widget-get widget :notmuch-search-type)
|
||||
(tree
|
||||
(notmuch-tree (widget-get widget :notmuch-search-terms)
|
||||
nil nil nil nil nil nil
|
||||
(widget-get widget :notmuch-search-oldest-first)))
|
||||
(let ((n (notmuch-search-format-buffer-name (widget-value widget) "tree" t)))
|
||||
(notmuch-tree (widget-get widget :notmuch-search-terms)
|
||||
nil nil n nil nil nil
|
||||
(widget-get widget :notmuch-search-oldest-first))))
|
||||
(unthreaded
|
||||
(notmuch-unthreaded (widget-get widget :notmuch-search-terms)))
|
||||
(let ((n (notmuch-search-format-buffer-name (widget-value widget)
|
||||
"unthreaded" t)))
|
||||
(notmuch-unthreaded (widget-get widget :notmuch-search-terms) nil nil n)))
|
||||
(t
|
||||
(notmuch-search (widget-get widget :notmuch-search-terms)
|
||||
(widget-get widget :notmuch-search-oldest-first)))))
|
||||
|
@ -557,7 +560,8 @@ with any properties in the original saved-search.
|
|||
|
||||
The values :show-empty-searches, :filter and :filter-count from
|
||||
options will be handled as specified for
|
||||
`notmuch-hello-insert-searches'."
|
||||
`notmuch-hello-insert-searches'. :disable-includes can be used to
|
||||
turn off the default exclude processing in `notmuch-count(1)'"
|
||||
(with-temp-buffer
|
||||
(dolist (elem query-list nil)
|
||||
(let ((count-query (or (notmuch-saved-search-get elem :count-query)
|
||||
|
@ -570,7 +574,11 @@ options will be handled as specified for
|
|||
(plist-get options :filter))))
|
||||
"\n")))
|
||||
(unless (= (notmuch--call-process-region (point-min) (point-max) notmuch-command
|
||||
t t nil "count" "--batch") 0)
|
||||
t t nil "count"
|
||||
(if (plist-get options :disable-excludes)
|
||||
"--exclude=false"
|
||||
"--exclude=true")
|
||||
"--batch") 0)
|
||||
(notmuch-logged-error
|
||||
"notmuch count --batch failed"
|
||||
"Please check that the notmuch CLI is new enough to support `count
|
||||
|
@ -702,7 +710,6 @@ with `notmuch-hello-query-counts'."
|
|||
;; that when we modify map it does not modify widget-keymap).
|
||||
(let ((map (make-composed-keymap (list (make-sparse-keymap) widget-keymap))))
|
||||
(set-keymap-parent map notmuch-common-keymap)
|
||||
(define-key map (kbd "<C-tab>") 'widget-backward)
|
||||
map)
|
||||
"Keymap for \"notmuch hello\" buffers.")
|
||||
|
||||
|
@ -786,7 +793,7 @@ Complete list of currently available key bindings:
|
|||
:help-echo "Refresh"
|
||||
(notmuch-hello-nice-number
|
||||
(string-to-number
|
||||
(car (notmuch--process-lines notmuch-command "count")))))
|
||||
(car (notmuch--process-lines notmuch-command "count" "--exclude=false")))))
|
||||
(widget-insert " messages.\n")))
|
||||
|
||||
(defun notmuch-hello-insert-saved-searches ()
|
||||
|
@ -918,7 +925,8 @@ following:
|
|||
nil
|
||||
:initially-hidden (not notmuch-show-all-tags-list)
|
||||
:hide-tags notmuch-hello-hide-tags
|
||||
:filter notmuch-hello-tag-list-make-query))
|
||||
:filter notmuch-hello-tag-list-make-query
|
||||
:disable-excludes t))
|
||||
|
||||
(defun notmuch-hello-insert-footer ()
|
||||
"Insert the notmuch-hello footer."
|
||||
|
|
27
emacs/notmuch-logo.svg
Normal file
27
emacs/notmuch-logo.svg
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"
|
||||
viewbox="0 0 100 100" fill="#000" stroke-width="2">
|
||||
<circle cx="50" cy="5" r="5" />
|
||||
<g transform="translate(50 20) rotate(20)">
|
||||
<circle cx="-47" cy="0" r="3" />
|
||||
<circle cx="47" cy="0" r="3" />
|
||||
<path d="M-47 -1 L0 -3 L47 -1 L47 1 L0 3 L-47 1 Z" />
|
||||
</g>
|
||||
<path d="M49 4 L45 88
|
||||
A5 5 0 0 1 40 93 L20 93 A5 5 0 0 0 15 100
|
||||
L85 100
|
||||
A5 5 0 0 0 80 93 L60 93 A5 5 0 0 1 55 88
|
||||
L55 90 L51 4 Z" />
|
||||
<g fill="#fff" stroke="#000">
|
||||
<rect x="7" y="33" width="30" height="18" />
|
||||
<line x1="7" y1="51" x2="18" y2="41" />
|
||||
<line x1="37" y1="51" x2="26" y2="41" />
|
||||
<polyline points="7 33 22 44 37 33" fill="none" />
|
||||
</g>
|
||||
<path d="M-18 0 A24 20 0 0 0 18 0" transform="translate(22 51.0)" />
|
||||
<path d="M-18 0 A24 20 0 0 0 18 0" transform="translate(78 71.5)" />
|
||||
<g fill="none" stroke="#000">
|
||||
<path d="M9 53.0 l 12 -42 l 2 0 l 12 42" />
|
||||
<path d="M91 73.5 l-12 -42 l-2 0 l-12 42" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -149,6 +149,7 @@ Otherwise set it according to `notmuch-fcc-dirs'."
|
|||
(buf (current-buffer))
|
||||
(mml-externalize-attachments message-fcc-externalize-attachments))
|
||||
(with-current-buffer (get-buffer-create " *message temp*")
|
||||
(message-clone-locals buf) ;; for message-encoded-mail-cache
|
||||
(erase-buffer)
|
||||
(insert-buffer-substring buf)
|
||||
,@body)))
|
||||
|
@ -158,7 +159,10 @@ Otherwise set it according to `notmuch-fcc-dirs'."
|
|||
|
||||
This should be called on a temporary copy.
|
||||
This is taken from the function message-do-fcc."
|
||||
(message-encode-message-body)
|
||||
(if (not message-encoded-mail-cache)
|
||||
(message-encode-message-body)
|
||||
(erase-buffer)
|
||||
(insert message-encoded-mail-cache))
|
||||
(save-restriction
|
||||
(message-narrow-to-headers)
|
||||
(mail-encode-encoded-word-buffer))
|
||||
|
@ -179,12 +183,12 @@ This is a rearranged version of message mode's message-do-fcc."
|
|||
(setq file (message-fetch-field "fcc" t)))
|
||||
(when file
|
||||
(with-temporary-notmuch-message-buffer
|
||||
(notmuch-maildir-setup-message-for-saving)
|
||||
(save-restriction
|
||||
(message-narrow-to-headers)
|
||||
(while (setq file (message-fetch-field "fcc" t))
|
||||
(push file files)
|
||||
(message-remove-header "fcc" nil t)))
|
||||
(notmuch-maildir-setup-message-for-saving)
|
||||
;; Process FCC operations.
|
||||
(mapc #'notmuch-fcc-handler files)
|
||||
(kill-buffer (current-buffer)))))))
|
||||
|
|
|
@ -84,6 +84,11 @@ visible for any given message."
|
|||
:type 'boolean
|
||||
:group 'notmuch-show)
|
||||
|
||||
(defcustom notmuch-show-header-line t
|
||||
"Show a header line with the current message's subject."
|
||||
:type 'boolean
|
||||
:group 'notmuch-show)
|
||||
|
||||
(defcustom notmuch-show-relative-dates t
|
||||
"Display relative dates in the message summary line."
|
||||
:type 'boolean
|
||||
|
@ -1345,11 +1350,12 @@ If no messages match the query return NIL."
|
|||
(notmuch-show-mapc
|
||||
(lambda () (notmuch-show-set-prop :orig-tags (notmuch-show-get-tags))))
|
||||
;; Set the header line to the subject of the first message.
|
||||
(setq header-line-format
|
||||
(replace-regexp-in-string "%" "%%"
|
||||
(notmuch-sanitize
|
||||
(notmuch-show-strip-re
|
||||
(notmuch-show-get-subject)))))
|
||||
(when notmuch-show-header-line
|
||||
(setq header-line-format
|
||||
(replace-regexp-in-string "%" "%%"
|
||||
(notmuch-sanitize
|
||||
(notmuch-show-strip-re
|
||||
(notmuch-show-get-subject))))))
|
||||
(run-hooks 'notmuch-show-hook)
|
||||
(if state
|
||||
(notmuch-show-apply-state state)
|
||||
|
|
|
@ -241,7 +241,7 @@ DATA is the content of an SVG picture (e.g., as returned by
|
|||
"Return SVG data representing a star icon.
|
||||
This can be used with `notmuch-tag-format-image-data'."
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\">
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\" xmlns=\"http://www.w3.org/2000/svg\">
|
||||
<g transform=\"translate(-242.81601,-315.59635)\">
|
||||
<path
|
||||
d=\"m 290.25762,334.31206 -17.64143,-11.77975 -19.70508,7.85447 5.75171,-20.41814 -13.55925,-16.31348 21.19618,-0.83936 11.325,-17.93675 7.34825,19.89939 20.55849,5.22795 -16.65471,13.13786 z\"
|
||||
|
@ -254,7 +254,7 @@ This can be used with `notmuch-tag-format-image-data'."
|
|||
"Return SVG data representing an empty star icon.
|
||||
This can be used with `notmuch-tag-format-image-data'."
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\">
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\" xmlns=\"http://www.w3.org/2000/svg\">
|
||||
<g transform=\"translate(-242.81601,-315.59635)\">
|
||||
<path
|
||||
d=\"m 290.25762,334.31206 -17.64143,-11.77975 -19.70508,7.85447 5.75171,-20.41814 -13.55925,-16.31348 21.19618,-0.83936 11.325,-17.93675 7.34825,19.89939 20.55849,5.22795 -16.65471,13.13786 z\"
|
||||
|
@ -267,7 +267,7 @@ This can be used with `notmuch-tag-format-image-data'."
|
|||
"Return SVG data representing a tag icon.
|
||||
This can be used with `notmuch-tag-format-image-data'."
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\">
|
||||
<svg version=\"1.1\" width=\"16\" height=\"16\" xmlns=\"http://www.w3.org/2000/svg\">
|
||||
<g transform=\"translate(0,-1036.3622)\">
|
||||
<path
|
||||
d=\"m 0.44642857,1040.9336 12.50000043,0 2.700893,3.6161 -2.700893,3.616 -12.50000043,0 z\"
|
||||
|
@ -429,17 +429,9 @@ initial input in the minibuffer."
|
|||
(set-keymap-parent map crm-local-completion-map)
|
||||
(define-key map " " 'self-insert-command)
|
||||
map)))
|
||||
(delete "" (completing-read-multiple
|
||||
prompt
|
||||
;; Append the separator to each completion so when the
|
||||
;; user completes a tag they can immediately begin
|
||||
;; entering another. `completing-read-multiple'
|
||||
;; ultimately splits the input on crm-separator, so we
|
||||
;; don't need to strip this back off (we just need to
|
||||
;; delete "empty" entries caused by trailing spaces).
|
||||
(mapcar (lambda (tag-op) (concat tag-op crm-separator)) tag-list)
|
||||
nil nil initial-input
|
||||
'notmuch-read-tag-changes-history))))
|
||||
(completing-read-multiple prompt tag-list
|
||||
nil nil initial-input
|
||||
'notmuch-read-tag-changes-history)))
|
||||
|
||||
;;; Tagging
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ Note that the author string should not contain whitespace
|
|||
(:foreground "dark blue"))
|
||||
(t
|
||||
(:bold t)))
|
||||
"Face used in tree mode for the date in messages matching the query."
|
||||
"Face used in tree mode for the author in messages matching the query."
|
||||
:group 'notmuch-tree
|
||||
:group 'notmuch-faces)
|
||||
|
||||
|
@ -236,7 +236,7 @@ Note that the author string should not contain whitespace
|
|||
|
||||
(defface notmuch-tree-no-match-author-face
|
||||
nil
|
||||
"Face used in tree mode for the date in messages matching the query."
|
||||
"Face used in tree mode for non-matching authors."
|
||||
:group 'notmuch-tree
|
||||
:group 'notmuch-faces)
|
||||
|
||||
|
@ -1191,11 +1191,11 @@ The arguments are:
|
|||
(setq query (notmuch-read-query (concat "Notmuch "
|
||||
(if unthreaded "unthreaded " "tree ")
|
||||
"view search: "))))
|
||||
(let ((buffer (get-buffer-create (generate-new-buffer-name
|
||||
(or buffer-name
|
||||
(concat "*notmuch-"
|
||||
(if unthreaded "unthreaded-" "tree-")
|
||||
query "*")))))
|
||||
(let* ((name
|
||||
(or buffer-name
|
||||
(notmuch-search-buffer-title query
|
||||
(if unthreaded "unthreaded" "tree"))))
|
||||
(buffer (get-buffer-create (generate-new-buffer-name name)))
|
||||
(inhibit-read-only t))
|
||||
(pop-to-buffer-same-window buffer))
|
||||
;; Don't track undo information for this buffer
|
||||
|
@ -1206,6 +1206,9 @@ The arguments are:
|
|||
|
||||
(defun notmuch-unthreaded (&optional query query-context target buffer-name
|
||||
open-target)
|
||||
"Display threads matching QUERY in unthreaded view.
|
||||
|
||||
See function NOTMUCH-TREE for documentation of the arguments"
|
||||
(interactive)
|
||||
(notmuch-tree query query-context target buffer-name open-target t))
|
||||
|
||||
|
|
|
@ -535,12 +535,12 @@ thread."
|
|||
(message "End of search results."))))
|
||||
|
||||
(defun notmuch-tree-from-search-current-query ()
|
||||
"Call notmuch tree with the current query."
|
||||
"Tree view of current query."
|
||||
(interactive)
|
||||
(notmuch-tree notmuch-search-query-string))
|
||||
|
||||
(defun notmuch-unthreaded-from-search-current-query ()
|
||||
"Call notmuch tree with the current query."
|
||||
"Unthreaded view of current query."
|
||||
(interactive)
|
||||
(notmuch-unthreaded notmuch-search-query-string))
|
||||
|
||||
|
@ -880,6 +880,14 @@ sets the :orig-tag property."
|
|||
(setq notmuch-search-target-thread "found")
|
||||
(goto-char pos))))
|
||||
|
||||
(defvar-local notmuch--search-hook-run nil
|
||||
"Flag used to ensure the notmuch-search-hook is only run once per buffer")
|
||||
|
||||
(defun notmuch--search-hook-wrapper ()
|
||||
(unless notmuch--search-hook-run
|
||||
(setq notmuch--search-hook-run t)
|
||||
(run-hooks 'notmuch-search-hook)))
|
||||
|
||||
(defun notmuch-search-process-filter (proc string)
|
||||
"Process and filter the output of \"notmuch search\"."
|
||||
(let ((results-buf (process-buffer proc))
|
||||
|
@ -892,7 +900,9 @@ sets the :orig-tag property."
|
|||
(goto-char (point-max))
|
||||
(insert string))
|
||||
(notmuch-sexp-parse-partial-list 'notmuch-search-append-result
|
||||
results-buf)))))
|
||||
results-buf))
|
||||
(with-current-buffer results-buf
|
||||
(notmuch--search-hook-wrapper)))))
|
||||
|
||||
;;; Commands (and some helper functions used by them)
|
||||
|
||||
|
@ -905,7 +915,39 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
|
|||
(notmuch-search-get-tags-region (point-min) (point-max)) "Tag all")))
|
||||
(notmuch-search-tag tag-changes (point-min) (point-max) t))
|
||||
|
||||
(defun notmuch-search-buffer-title (query)
|
||||
(defcustom notmuch-search-buffer-name-format "*notmuch-%t-%s*"
|
||||
"Format for the name of search results buffers.
|
||||
|
||||
In this spec, %s will be replaced by a description of the search
|
||||
query and %t by its type (search, tree or unthreaded). The
|
||||
buffer name is formatted using `format-spec': see its docstring
|
||||
for additional parameters for the s and t format specifiers.
|
||||
|
||||
See also `notmuch-saved-search-buffer-name-format'"
|
||||
:type 'string
|
||||
:group 'notmuch-search)
|
||||
|
||||
(defcustom notmuch-saved-search-buffer-name-format "*notmuch-saved-%t-%s*"
|
||||
"Format for the name of search results buffers for saved searches.
|
||||
|
||||
In this spec, %s will be replaced by the saved search name and %t
|
||||
by its type (search, tree or unthreaded). The buffer name is
|
||||
formatted using `format-spec': see its docstring for additional
|
||||
parameters for the s and t format specifiers.
|
||||
|
||||
See also `notmuch-search-buffer-name-format'"
|
||||
:type 'string
|
||||
:group 'notmuch-search)
|
||||
|
||||
(defun notmuch-search-format-buffer-name (query type saved)
|
||||
"Compose a buffer name for the given QUERY, TYPE (search, tree,
|
||||
unthreaded) and whether it's SAVED (t or nil)."
|
||||
(let ((fmt (if saved
|
||||
notmuch-saved-search-buffer-name-format
|
||||
notmuch-search-buffer-name-format)))
|
||||
(format-spec fmt `((?t . ,(or type "search")) (?s . ,query)))))
|
||||
|
||||
(defun notmuch-search-buffer-title (query &optional type)
|
||||
"Returns the title for a buffer with notmuch search results."
|
||||
(let* ((saved-search
|
||||
(let (longest
|
||||
|
@ -920,19 +962,20 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
|
|||
do (setq longest tuple))
|
||||
longest))
|
||||
(saved-search-name (notmuch-saved-search-get saved-search :name))
|
||||
(saved-search-type (notmuch-saved-search-get saved-search :search-type))
|
||||
(saved-search-query (notmuch-saved-search-get saved-search :query)))
|
||||
(cond ((and saved-search (equal saved-search-query query))
|
||||
;; Query is the same as saved search (ignoring case)
|
||||
(concat "*notmuch-saved-search-" saved-search-name "*"))
|
||||
(notmuch-search-format-buffer-name saved-search-name
|
||||
saved-search-type
|
||||
t))
|
||||
(saved-search
|
||||
(concat "*notmuch-search-"
|
||||
(replace-regexp-in-string
|
||||
(concat "^" (regexp-quote saved-search-query))
|
||||
(concat "[ " saved-search-name " ]")
|
||||
query)
|
||||
"*"))
|
||||
(t
|
||||
(concat "*notmuch-search-" query "*")))))
|
||||
(let ((query (replace-regexp-in-string
|
||||
(concat "^" (regexp-quote saved-search-query))
|
||||
(concat "[ " saved-search-name " ]")
|
||||
query)))
|
||||
(notmuch-search-format-buffer-name query saved-search-type t)))
|
||||
(t (notmuch-search-format-buffer-name query type nil)))))
|
||||
|
||||
(defun notmuch-read-query (prompt)
|
||||
"Read a notmuch-query from the minibuffer with completion.
|
||||
|
@ -1036,8 +1079,7 @@ the configured default sort order."
|
|||
(process-put proc 'parse-buf
|
||||
(generate-new-buffer " *notmuch search parse*"))
|
||||
(set-process-filter proc 'notmuch-search-process-filter)
|
||||
(set-process-query-on-exit-flag proc nil))))
|
||||
(run-hooks 'notmuch-search-hook)))
|
||||
(set-process-query-on-exit-flag proc nil))))))
|
||||
|
||||
(defun notmuch-search-refresh-view ()
|
||||
"Refresh the current view.
|
||||
|
|
|
@ -32,7 +32,7 @@ notmuch_built_with (const char *name)
|
|||
return HAVE_XAPIAN_DB_RETRY_LOCK;
|
||||
} else if (STRNCMP_LITERAL (name, "session_key") == 0) {
|
||||
return true;
|
||||
} else if (STRNCMP_LITERAL (name, "sexpr_query") == 0) {
|
||||
} else if (STRNCMP_LITERAL (name, "sexp_queries") == 0) {
|
||||
return HAVE_SFSEXP;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -435,11 +435,6 @@ _notmuch_config_load_from_file (notmuch_database_t *notmuch,
|
|||
for (gchar **keys_p = keys; *keys_p; keys_p++) {
|
||||
char *absolute_key = talloc_asprintf (notmuch, "%s.%s", *grp, *keys_p);
|
||||
char *normalized_val;
|
||||
val = g_key_file_get_value (file, *grp, *keys_p, NULL);
|
||||
if (! val) {
|
||||
status = NOTMUCH_STATUS_FILE_ERROR;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
/* If we opened from a given path, do not overwrite it */
|
||||
if (strcmp (absolute_key, "database.path") == 0 &&
|
||||
|
@ -447,6 +442,12 @@ _notmuch_config_load_from_file (notmuch_database_t *notmuch,
|
|||
notmuch->xapian_db)
|
||||
continue;
|
||||
|
||||
val = g_key_file_get_string (file, *grp, *keys_p, NULL);
|
||||
if (! val) {
|
||||
status = NOTMUCH_STATUS_FILE_ERROR;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
normalized_val = _expand_path (notmuch, absolute_key, val);
|
||||
_notmuch_string_map_set (notmuch->config, absolute_key, normalized_val);
|
||||
g_free (val);
|
||||
|
@ -596,6 +597,8 @@ _notmuch_config_key_to_string (notmuch_config_key_t key)
|
|||
return "user.name";
|
||||
case NOTMUCH_CONFIG_AUTOCOMMIT:
|
||||
return "database.autocommit";
|
||||
case NOTMUCH_CONFIG_EXTRA_HEADERS:
|
||||
return "show.extra_headers";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -643,6 +646,7 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key)
|
|||
return "";
|
||||
case NOTMUCH_CONFIG_AUTOCOMMIT:
|
||||
return "8000";
|
||||
case NOTMUCH_CONFIG_EXTRA_HEADERS:
|
||||
case NOTMUCH_CONFIG_HOOK_DIR:
|
||||
case NOTMUCH_CONFIG_BACKUP_DIR:
|
||||
case NOTMUCH_CONFIG_OTHER_EMAIL:
|
||||
|
@ -657,6 +661,10 @@ notmuch_status_t
|
|||
_notmuch_config_load_defaults (notmuch_database_t *notmuch)
|
||||
{
|
||||
notmuch_config_key_t key;
|
||||
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
|
||||
|
||||
if (notmuch->config == NULL)
|
||||
notmuch->config = _notmuch_string_map_create (notmuch);
|
||||
|
||||
for (key = NOTMUCH_CONFIG_FIRST;
|
||||
key < NOTMUCH_CONFIG_LAST;
|
||||
|
@ -666,11 +674,14 @@ _notmuch_config_load_defaults (notmuch_database_t *notmuch)
|
|||
|
||||
val = _notmuch_string_map_get (notmuch->config, key_string);
|
||||
if (! val) {
|
||||
if (key == NOTMUCH_CONFIG_MAIL_ROOT && (notmuch->params & NOTMUCH_PARAM_SPLIT))
|
||||
status = NOTMUCH_STATUS_NO_MAIL_ROOT;
|
||||
|
||||
_notmuch_string_map_set (notmuch->config, key_string, _notmuch_config_default (notmuch,
|
||||
key));
|
||||
}
|
||||
}
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
@ -160,11 +160,12 @@ operator&= (_notmuch_features &a, _notmuch_features b)
|
|||
|
||||
/*
|
||||
* Configuration options for xapian database fields */
|
||||
typedef enum notmuch_field_flags {
|
||||
typedef enum {
|
||||
NOTMUCH_FIELD_NO_FLAGS = 0,
|
||||
NOTMUCH_FIELD_EXTERNAL = 1 << 0,
|
||||
NOTMUCH_FIELD_PROBABILISTIC = 1 << 1,
|
||||
NOTMUCH_FIELD_PROCESSOR = 1 << 2,
|
||||
NOTMUCH_FIELD_STRIP_TRAILING_SLASH = 1 << 3,
|
||||
} notmuch_field_flag_t;
|
||||
|
||||
/*
|
||||
|
@ -191,12 +192,17 @@ operator& (notmuch_field_flag_t a, notmuch_field_flag_t b)
|
|||
Xapian::QueryParser::FLAG_PURE_NOT)
|
||||
|
||||
/*
|
||||
* Which parameters were explicit when the database was opened */
|
||||
* explicit and implied parameters to open */
|
||||
typedef enum {
|
||||
NOTMUCH_PARAM_NONE = 0,
|
||||
/* database passed explicitely */
|
||||
NOTMUCH_PARAM_DATABASE = 1 << 0,
|
||||
/* config file passed explicitely */
|
||||
NOTMUCH_PARAM_CONFIG = 1 << 1,
|
||||
/* profile name passed explicitely */
|
||||
NOTMUCH_PARAM_PROFILE = 1 << 2,
|
||||
/* split (e.g. XDG) configuration */
|
||||
NOTMUCH_PARAM_SPLIT = 1 << 3,
|
||||
} notmuch_open_param_t;
|
||||
|
||||
/*
|
||||
|
@ -374,5 +380,10 @@ notmuch_status_t
|
|||
_notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr,
|
||||
Xapian::Query &output);
|
||||
#endif
|
||||
|
||||
/* parse-time-vrp.h */
|
||||
notmuch_status_t
|
||||
_notmuch_date_strings_to_query (Xapian::valueno slot, const std::string &from, const std::string &to,
|
||||
Xapian::Query &output, std::string &msg);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -311,6 +311,8 @@ notmuch_status_to_string (notmuch_status_t status)
|
|||
return "Database exists, not recreated";
|
||||
case NOTMUCH_STATUS_BAD_QUERY_SYNTAX:
|
||||
return "Syntax error in query";
|
||||
case NOTMUCH_STATUS_NO_MAIL_ROOT:
|
||||
return "No mail root found";
|
||||
default:
|
||||
case NOTMUCH_STATUS_LAST_STATUS:
|
||||
return "Unknown error status value";
|
||||
|
@ -590,10 +592,12 @@ notmuch_database_compact (const char *path,
|
|||
notmuch_database_t *notmuch = NULL;
|
||||
char *message = NULL;
|
||||
|
||||
ret = notmuch_database_open_verbose (path,
|
||||
NOTMUCH_DATABASE_MODE_READ_WRITE,
|
||||
¬much,
|
||||
&message);
|
||||
ret = notmuch_database_open_with_config (path,
|
||||
NOTMUCH_DATABASE_MODE_READ_WRITE,
|
||||
"",
|
||||
NULL,
|
||||
¬much,
|
||||
&message);
|
||||
if (ret) {
|
||||
if (status_cb) status_cb (message, closure);
|
||||
return ret;
|
||||
|
@ -751,6 +755,8 @@ notmuch_database_destroy (notmuch_database_t *notmuch)
|
|||
notmuch->date_range_processor = NULL;
|
||||
delete notmuch->last_mod_range_processor;
|
||||
notmuch->last_mod_range_processor = NULL;
|
||||
delete notmuch->stemmer;
|
||||
notmuch->stemmer = NULL;
|
||||
|
||||
talloc_free (notmuch);
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
|
||||
#include "notmuch-private.h"
|
||||
|
||||
struct _notmuch_indexopts {
|
||||
_notmuch_crypto_t crypto;
|
||||
};
|
||||
|
||||
notmuch_indexopts_t *
|
||||
notmuch_database_get_default_indexopts (notmuch_database_t *db)
|
||||
{
|
||||
|
|
|
@ -121,7 +121,7 @@ typedef enum {
|
|||
*/
|
||||
#define NOTMUCH_MESSAGE_ID_MAX (200 - sizeof (NOTMUCH_METADATA_THREAD_ID_PREFIX))
|
||||
|
||||
typedef enum _notmuch_private_status {
|
||||
typedef enum {
|
||||
/* First, copy all the public status values. */
|
||||
NOTMUCH_PRIVATE_STATUS_SUCCESS = NOTMUCH_STATUS_SUCCESS,
|
||||
NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY = NOTMUCH_STATUS_OUT_OF_MEMORY,
|
||||
|
@ -173,7 +173,7 @@ typedef enum _notmuch_private_status {
|
|||
(notmuch_status_t) private_status)
|
||||
|
||||
/* Flags shared by various lookup functions. */
|
||||
typedef enum _notmuch_find_flags {
|
||||
typedef enum {
|
||||
/* Lookup without creating any documents. This is the default
|
||||
* behavior. */
|
||||
NOTMUCH_FIND_LOOKUP = 0,
|
||||
|
@ -711,9 +711,7 @@ _notmuch_thread_create (void *ctx,
|
|||
|
||||
/* indexopts.c */
|
||||
|
||||
struct _notmuch_indexopts {
|
||||
_notmuch_crypto_t crypto;
|
||||
};
|
||||
struct _notmuch_indexopts;
|
||||
|
||||
#define CONFIG_HEADER_PREFIX "index.header."
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ NOTMUCH_BEGIN_DECLS
|
|||
* version in Makefile.local.
|
||||
*/
|
||||
#define LIBNOTMUCH_MAJOR_VERSION 5
|
||||
#define LIBNOTMUCH_MINOR_VERSION 5
|
||||
#define LIBNOTMUCH_MINOR_VERSION 6
|
||||
#define LIBNOTMUCH_MICRO_VERSION 0
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ typedef int notmuch_bool_t;
|
|||
* A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
|
||||
* completed without error. Any other value indicates an error.
|
||||
*/
|
||||
typedef enum _notmuch_status {
|
||||
typedef enum {
|
||||
/**
|
||||
* No error occurred.
|
||||
*/
|
||||
|
@ -224,6 +224,10 @@ typedef enum _notmuch_status {
|
|||
* Syntax error in query
|
||||
*/
|
||||
NOTMUCH_STATUS_BAD_QUERY_SYNTAX,
|
||||
/**
|
||||
* No mail root could be deduced from parameters and environment
|
||||
*/
|
||||
NOTMUCH_STATUS_NO_MAIL_ROOT,
|
||||
/**
|
||||
* Not an actual status value. Just a way to find out how many
|
||||
* valid status values there are.
|
||||
|
@ -323,7 +327,7 @@ typedef enum {
|
|||
* config_path="" and error_message=NULL
|
||||
* @deprecated Deprecated as of libnotmuch 5.4 (notmuch 0.32)
|
||||
*/
|
||||
/* NOTMUCH_DEPRECATED(5, 4) */
|
||||
NOTMUCH_DEPRECATED(5, 4)
|
||||
notmuch_status_t
|
||||
notmuch_database_open (const char *path,
|
||||
notmuch_database_mode_t mode,
|
||||
|
@ -335,7 +339,7 @@ notmuch_database_open (const char *path,
|
|||
* @deprecated Deprecated as of libnotmuch 5.4 (notmuch 0.32)
|
||||
*
|
||||
*/
|
||||
/* NOTMUCH_DEPRECATED(5, 4) */
|
||||
NOTMUCH_DEPRECATED(5, 4)
|
||||
notmuch_status_t
|
||||
notmuch_database_open_verbose (const char *path,
|
||||
notmuch_database_mode_t mode,
|
||||
|
@ -1686,7 +1690,7 @@ notmuch_message_reindex (notmuch_message_t *message,
|
|||
/**
|
||||
* Message flags.
|
||||
*/
|
||||
typedef enum _notmuch_message_flag {
|
||||
typedef enum {
|
||||
NOTMUCH_MESSAGE_FLAG_MATCH,
|
||||
NOTMUCH_MESSAGE_FLAG_EXCLUDED,
|
||||
|
||||
|
@ -2532,7 +2536,7 @@ notmuch_config_list_destroy (notmuch_config_list_t *config_list);
|
|||
/**
|
||||
* Configuration keys known to libnotmuch
|
||||
*/
|
||||
typedef enum _notmuch_config_key {
|
||||
typedef enum {
|
||||
NOTMUCH_CONFIG_FIRST,
|
||||
NOTMUCH_CONFIG_DATABASE_PATH = NOTMUCH_CONFIG_FIRST,
|
||||
NOTMUCH_CONFIG_MAIL_ROOT,
|
||||
|
@ -2546,6 +2550,7 @@ typedef enum _notmuch_config_key {
|
|||
NOTMUCH_CONFIG_OTHER_EMAIL,
|
||||
NOTMUCH_CONFIG_USER_NAME,
|
||||
NOTMUCH_CONFIG_AUTOCOMMIT,
|
||||
NOTMUCH_CONFIG_EXTRA_HEADERS,
|
||||
NOTMUCH_CONFIG_LAST
|
||||
} notmuch_config_key_t;
|
||||
|
||||
|
|
63
lib/open.cc
63
lib/open.cc
|
@ -19,9 +19,8 @@ notmuch_database_open (const char *path,
|
|||
char *status_string = NULL;
|
||||
notmuch_status_t status;
|
||||
|
||||
status = notmuch_database_open_verbose (path, mode, database,
|
||||
&status_string);
|
||||
|
||||
status = notmuch_database_open_with_config (path, mode, "", NULL,
|
||||
database, &status_string);
|
||||
if (status_string) {
|
||||
fputs (status_string, stderr);
|
||||
free (status_string);
|
||||
|
@ -187,11 +186,10 @@ _db_dir_exists (const char *database_path, char **message)
|
|||
}
|
||||
|
||||
static notmuch_status_t
|
||||
_choose_database_path (void *ctx,
|
||||
_choose_database_path (notmuch_database_t *notmuch,
|
||||
const char *profile,
|
||||
GKeyFile *key_file,
|
||||
const char **database_path,
|
||||
bool *split,
|
||||
char **message)
|
||||
{
|
||||
if (! *database_path) {
|
||||
|
@ -199,24 +197,24 @@ _choose_database_path (void *ctx,
|
|||
}
|
||||
|
||||
if (! *database_path && key_file) {
|
||||
char *path = g_key_file_get_value (key_file, "database", "path", NULL);
|
||||
char *path = g_key_file_get_string (key_file, "database", "path", NULL);
|
||||
if (path) {
|
||||
if (path[0] == '/')
|
||||
*database_path = talloc_strdup (ctx, path);
|
||||
*database_path = talloc_strdup (notmuch, path);
|
||||
else
|
||||
*database_path = talloc_asprintf (ctx, "%s/%s", getenv ("HOME"), path);
|
||||
*database_path = talloc_asprintf (notmuch, "%s/%s", getenv ("HOME"), path);
|
||||
g_free (path);
|
||||
}
|
||||
}
|
||||
if (! *database_path) {
|
||||
notmuch_status_t status;
|
||||
|
||||
*database_path = _xdg_dir (ctx, "XDG_DATA_HOME", ".local/share", profile);
|
||||
*database_path = _xdg_dir (notmuch, "XDG_DATA_HOME", ".local/share", profile);
|
||||
status = _db_dir_exists (*database_path, message);
|
||||
if (status) {
|
||||
*database_path = NULL;
|
||||
} else {
|
||||
*split = true;
|
||||
notmuch->params |= NOTMUCH_PARAM_SPLIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +225,7 @@ _choose_database_path (void *ctx,
|
|||
if (! *database_path) {
|
||||
notmuch_status_t status;
|
||||
|
||||
*database_path = talloc_asprintf (ctx, "%s/mail", getenv ("HOME"));
|
||||
*database_path = talloc_asprintf (notmuch, "%s/mail", getenv ("HOME"));
|
||||
status = _db_dir_exists (*database_path, message);
|
||||
if (status) {
|
||||
*database_path = NULL;
|
||||
|
@ -511,11 +509,9 @@ notmuch_database_open_with_config (const char *database_path,
|
|||
char **status_string)
|
||||
{
|
||||
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
|
||||
void *local = talloc_new (NULL);
|
||||
notmuch_database_t *notmuch = NULL;
|
||||
char *message = NULL;
|
||||
GKeyFile *key_file = NULL;
|
||||
bool split = false;
|
||||
|
||||
_notmuch_init ();
|
||||
|
||||
|
@ -531,8 +527,8 @@ notmuch_database_open_with_config (const char *database_path,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
if ((status = _choose_database_path (local, profile, key_file,
|
||||
&database_path, &split,
|
||||
if ((status = _choose_database_path (notmuch, profile, key_file,
|
||||
&database_path,
|
||||
&message)))
|
||||
goto DONE;
|
||||
|
||||
|
@ -550,8 +546,6 @@ notmuch_database_open_with_config (const char *database_path,
|
|||
status = _finish_open (notmuch, profile, mode, key_file, &message);
|
||||
|
||||
DONE:
|
||||
talloc_free (local);
|
||||
|
||||
if (key_file)
|
||||
g_key_file_free (key_file);
|
||||
|
||||
|
@ -613,9 +607,7 @@ notmuch_database_create_with_config (const char *database_path,
|
|||
const char *notmuch_path = NULL;
|
||||
char *message = NULL;
|
||||
GKeyFile *key_file = NULL;
|
||||
void *local = talloc_new (NULL);
|
||||
int err;
|
||||
bool split = false;
|
||||
|
||||
_notmuch_init ();
|
||||
|
||||
|
@ -631,8 +623,8 @@ notmuch_database_create_with_config (const char *database_path,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
if ((status = _choose_database_path (local, profile, key_file,
|
||||
&database_path, &split, &message)))
|
||||
if ((status = _choose_database_path (notmuch, profile, key_file,
|
||||
&database_path, &message)))
|
||||
goto DONE;
|
||||
|
||||
status = _db_dir_exists (database_path, &message);
|
||||
|
@ -641,37 +633,34 @@ notmuch_database_create_with_config (const char *database_path,
|
|||
|
||||
_set_database_path (notmuch, database_path);
|
||||
|
||||
if (key_file && ! split) {
|
||||
if (key_file && ! (notmuch->params & NOTMUCH_PARAM_SPLIT)) {
|
||||
char *mail_root = notmuch_canonicalize_file_name (
|
||||
g_key_file_get_value (key_file, "database", "mail_root", NULL));
|
||||
g_key_file_get_string (key_file, "database", "mail_root", NULL));
|
||||
char *db_path = notmuch_canonicalize_file_name (database_path);
|
||||
|
||||
split = (mail_root && (0 != strcmp (mail_root, db_path)));
|
||||
if (mail_root && (0 != strcmp (mail_root, db_path)))
|
||||
notmuch->params |= NOTMUCH_PARAM_SPLIT;
|
||||
|
||||
free (mail_root);
|
||||
free (db_path);
|
||||
}
|
||||
|
||||
if (split) {
|
||||
if (notmuch->params & NOTMUCH_PARAM_SPLIT) {
|
||||
notmuch_path = database_path;
|
||||
} else {
|
||||
if (! (notmuch_path = talloc_asprintf (local, "%s/%s", database_path, ".notmuch"))) {
|
||||
if (! (notmuch_path = talloc_asprintf (notmuch, "%s/%s", database_path, ".notmuch"))) {
|
||||
status = NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
err = mkdir (notmuch_path, 0755);
|
||||
if (err) {
|
||||
if (errno == EEXIST) {
|
||||
status = NOTMUCH_STATUS_DATABASE_EXISTS;
|
||||
talloc_free (notmuch);
|
||||
notmuch = NULL;
|
||||
} else {
|
||||
if (errno != EEXIST) {
|
||||
IGNORE_RESULT (asprintf (&message, "Error: Cannot create directory %s: %s.\n",
|
||||
notmuch_path, strerror (errno)));
|
||||
status = NOTMUCH_STATUS_FILE_ERROR;
|
||||
goto DONE;
|
||||
}
|
||||
goto DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -712,8 +701,6 @@ notmuch_database_create_with_config (const char *database_path,
|
|||
}
|
||||
|
||||
DONE:
|
||||
talloc_free (local);
|
||||
|
||||
if (key_file)
|
||||
g_key_file_free (key_file);
|
||||
|
||||
|
@ -813,11 +800,9 @@ notmuch_database_load_config (const char *database_path,
|
|||
char **status_string)
|
||||
{
|
||||
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS, warning = NOTMUCH_STATUS_SUCCESS;
|
||||
void *local = talloc_new (NULL);
|
||||
notmuch_database_t *notmuch = NULL;
|
||||
char *message = NULL;
|
||||
GKeyFile *key_file = NULL;
|
||||
bool split = false;
|
||||
|
||||
_notmuch_init ();
|
||||
|
||||
|
@ -839,8 +824,8 @@ notmuch_database_load_config (const char *database_path,
|
|||
goto DONE;
|
||||
}
|
||||
|
||||
status = _choose_database_path (local, profile, key_file,
|
||||
&database_path, &split, &message);
|
||||
status = _choose_database_path (notmuch, profile, key_file,
|
||||
&database_path, &message);
|
||||
switch (status) {
|
||||
case NOTMUCH_STATUS_NO_DATABASE:
|
||||
case NOTMUCH_STATUS_SUCCESS:
|
||||
|
@ -875,8 +860,6 @@ notmuch_database_load_config (const char *database_path,
|
|||
goto DONE;
|
||||
|
||||
DONE:
|
||||
talloc_free (local);
|
||||
|
||||
if (status_string)
|
||||
*status_string = message;
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ typedef enum {
|
|||
SEXP_FLAG_EXPAND = 1 << 6,
|
||||
SEXP_FLAG_DO_EXPAND = 1 << 7,
|
||||
SEXP_FLAG_ORPHAN = 1 << 8,
|
||||
SEXP_FLAG_RANGE = 1 << 9,
|
||||
SEXP_FLAG_PATHNAME = 1 << 10,
|
||||
} _sexp_flag_t;
|
||||
|
||||
/*
|
||||
|
@ -66,16 +68,21 @@ static _sexp_prefix_t prefixes[] =
|
|||
SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_EXPAND },
|
||||
{ "body", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_FIELD },
|
||||
{ "date", Xapian::Query::OP_INVALID, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_RANGE },
|
||||
{ "from", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
{ "folder", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND |
|
||||
SEXP_FLAG_PATHNAME },
|
||||
{ "id", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX },
|
||||
{ "infix", Xapian::Query::OP_INVALID, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_SINGLE | SEXP_FLAG_ORPHAN },
|
||||
{ "is", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
{ "lastmod", Xapian::Query::OP_INVALID, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_RANGE },
|
||||
{ "matching", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_DO_EXPAND },
|
||||
{ "mid", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
|
@ -89,7 +96,8 @@ static _sexp_prefix_t prefixes[] =
|
|||
{ "or", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
SEXP_FLAG_NONE },
|
||||
{ "path", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX },
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX |
|
||||
SEXP_FLAG_PATHNAME },
|
||||
{ "property", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
{ "query", Xapian::Query::OP_INVALID, Xapian::Query::MatchNothing,
|
||||
|
@ -446,6 +454,79 @@ _sexp_expand_param (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
|
|||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
static notmuch_status_t
|
||||
_sexp_parse_range (notmuch_database_t *notmuch, const _sexp_prefix_t *prefix,
|
||||
const sexp_t *sx, Xapian::Query &output)
|
||||
{
|
||||
const char *from, *to;
|
||||
std::string msg;
|
||||
|
||||
/* empty range matches everything */
|
||||
if (! sx) {
|
||||
output = Xapian::Query::MatchAll;
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (sx->ty == SEXP_LIST) {
|
||||
_notmuch_database_log (notmuch, "expected atom as first argument of '%s'\n", prefix->name);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
from = sx->val;
|
||||
to = from;
|
||||
|
||||
if (sx->next) {
|
||||
if (sx->next->ty == SEXP_LIST) {
|
||||
_notmuch_database_log (notmuch, "expected atom as second argument of '%s'\n",
|
||||
prefix->name);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
if (sx->next->next) {
|
||||
_notmuch_database_log (notmuch, "'%s' expects maximum of two arguments\n", prefix->name);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
to = sx->next->val;
|
||||
}
|
||||
|
||||
if (strcmp (prefix->name, "date") == 0) {
|
||||
notmuch_status_t status;
|
||||
status = _notmuch_date_strings_to_query (NOTMUCH_VALUE_TIMESTAMP, from, to, output, msg);
|
||||
if (status) {
|
||||
if (! msg.empty ())
|
||||
_notmuch_database_log (notmuch, "%s\n", msg.c_str ());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (strcmp (prefix->name, "lastmod") == 0) {
|
||||
long from_idx, to_idx;
|
||||
|
||||
try {
|
||||
from_idx = std::stol (from);
|
||||
} catch (std::logic_error &e) {
|
||||
_notmuch_database_log (notmuch, "bad 'from' revision: '%s'\n", from);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
try {
|
||||
to_idx = std::stol (to);
|
||||
} catch (std::logic_error &e) {
|
||||
_notmuch_database_log (notmuch, "bad 'to' revision: '%s'\n", to);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
output = Xapian::Query (Xapian::Query::OP_VALUE_RANGE, NOTMUCH_VALUE_LAST_MOD,
|
||||
Xapian::sortable_serialise (from_idx),
|
||||
Xapian::sortable_serialise (to_idx));
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_notmuch_database_log (notmuch, "unimplimented range prefix: '%s'\n", prefix->name);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
/* Here we expect the s-expression to be a proper list, with first
|
||||
* element defining and operation, or as a special case the empty
|
||||
* list */
|
||||
|
@ -467,8 +548,13 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
|||
return _sexp_parse_wildcard (notmuch, parent, env, "", output);
|
||||
}
|
||||
|
||||
char *atom = sx->val;
|
||||
|
||||
if (parent && parent->flags & SEXP_FLAG_PATHNAME)
|
||||
strip_trailing (atom, '/');
|
||||
|
||||
if (parent && (parent->flags & SEXP_FLAG_BOOLEAN)) {
|
||||
output = Xapian::Query (term_prefix + sx->val);
|
||||
output = Xapian::Query (term_prefix + atom);
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -519,7 +605,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
|||
|
||||
for (_sexp_prefix_t *prefix = prefixes; prefix && prefix->name; prefix++) {
|
||||
if (strcmp (prefix->name, sx->list->val) == 0) {
|
||||
if (prefix->flags & SEXP_FLAG_FIELD) {
|
||||
if (prefix->flags & (SEXP_FLAG_FIELD | SEXP_FLAG_RANGE)) {
|
||||
if (parent) {
|
||||
_notmuch_database_log (notmuch, "nested field: '%s' inside '%s'\n",
|
||||
prefix->name, parent->name);
|
||||
|
@ -541,6 +627,9 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
|||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
if (prefix->flags & SEXP_FLAG_RANGE)
|
||||
return _sexp_parse_range (notmuch, prefix, sx->list->next, output);
|
||||
|
||||
if (strcmp (prefix->name, "infix") == 0) {
|
||||
return _sexp_parse_infix (notmuch, sx->list->next, output);
|
||||
}
|
||||
|
|
|
@ -24,22 +24,28 @@
|
|||
#include "parse-time-vrp.h"
|
||||
#include "parse-time-string.h"
|
||||
|
||||
Xapian::Query
|
||||
ParseTimeRangeProcessor::operator() (const std::string &begin, const std::string &end)
|
||||
notmuch_status_t
|
||||
_notmuch_date_strings_to_query (Xapian::valueno slot,
|
||||
const std::string &begin, const std::string &end,
|
||||
Xapian::Query &output, std::string &msg)
|
||||
{
|
||||
double from = DBL_MIN, to = DBL_MAX;
|
||||
time_t parsed_time, now;
|
||||
std::string str;
|
||||
|
||||
/* Use the same 'now' for begin and end. */
|
||||
if (time (&now) == (time_t) -1)
|
||||
throw Xapian::QueryParserError ("unable to get current time");
|
||||
if (time (&now) == (time_t) -1) {
|
||||
msg = "unable to get current time";
|
||||
return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
if (! begin.empty ()) {
|
||||
if (parse_time_string (begin.c_str (), &parsed_time, &now, PARSE_TIME_ROUND_DOWN))
|
||||
throw Xapian::QueryParserError ("Didn't understand date specification '" + begin + "'");
|
||||
else
|
||||
from = (double) parsed_time;
|
||||
if (parse_time_string (begin.c_str (), &parsed_time, &now, PARSE_TIME_ROUND_DOWN)) {
|
||||
msg = "Didn't understand date specification '" + begin + "'";
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
from = (double) parsed_time;
|
||||
}
|
||||
|
||||
if (! end.empty ()) {
|
||||
|
@ -48,15 +54,30 @@ ParseTimeRangeProcessor::operator() (const std::string &begin, const std::string
|
|||
else
|
||||
str = end;
|
||||
|
||||
if (parse_time_string (str.c_str (), &parsed_time, &now, PARSE_TIME_ROUND_UP_INCLUSIVE))
|
||||
throw Xapian::QueryParserError ("Didn't understand date specification '" + str + "'");
|
||||
else
|
||||
to = (double) parsed_time;
|
||||
if (parse_time_string (str.c_str (), &parsed_time, &now, PARSE_TIME_ROUND_UP_INCLUSIVE)) {
|
||||
msg = "Didn't understand date specification '" + str + "'";
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
to = (double) parsed_time;
|
||||
}
|
||||
|
||||
return Xapian::Query (Xapian::Query::OP_VALUE_RANGE, slot,
|
||||
Xapian::sortable_serialise (from),
|
||||
Xapian::sortable_serialise (to));
|
||||
output = Xapian::Query (Xapian::Query::OP_VALUE_RANGE, slot,
|
||||
Xapian::sortable_serialise (from),
|
||||
Xapian::sortable_serialise (to));
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Xapian::Query
|
||||
ParseTimeRangeProcessor::operator() (const std::string &begin, const std::string &end)
|
||||
{
|
||||
|
||||
Xapian::Query output;
|
||||
std::string msg;
|
||||
|
||||
if (_notmuch_date_strings_to_query (slot, begin, end, output, msg))
|
||||
throw Xapian::QueryParserError (msg);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/* XXX TODO: is throwing an exception the right thing to do here? */
|
||||
|
|
|
@ -46,7 +46,7 @@ prefix_t prefix_table[] = {
|
|||
{ "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
|
||||
NOTMUCH_FIELD_PROCESSOR },
|
||||
{ "path", "P", NOTMUCH_FIELD_EXTERNAL |
|
||||
NOTMUCH_FIELD_PROCESSOR },
|
||||
NOTMUCH_FIELD_PROCESSOR | NOTMUCH_FIELD_STRIP_TRAILING_SLASH },
|
||||
{ "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
|
||||
/*
|
||||
* Unconditionally add ':' to reduce potential ambiguity with
|
||||
|
@ -55,7 +55,7 @@ prefix_t prefix_table[] = {
|
|||
* discussion.
|
||||
*/
|
||||
{ "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
|
||||
NOTMUCH_FIELD_PROCESSOR },
|
||||
NOTMUCH_FIELD_PROCESSOR | NOTMUCH_FIELD_STRIP_TRAILING_SLASH },
|
||||
{ "date", NULL, NOTMUCH_FIELD_EXTERNAL |
|
||||
NOTMUCH_FIELD_PROCESSOR },
|
||||
{ "query", NULL, NOTMUCH_FIELD_EXTERNAL |
|
||||
|
|
|
@ -235,7 +235,15 @@ RegexpFieldProcessor::operator() (const std::string & str)
|
|||
return parser.parse_query (query_str, NOTMUCH_QUERY_PARSER_FLAGS, term_prefix);
|
||||
} else {
|
||||
/* Boolean prefix */
|
||||
std::string term = term_prefix + str;
|
||||
std::string query_str;
|
||||
std::string term;
|
||||
|
||||
if (str.length () > 1 && str.at (str.size () - 1) == '/')
|
||||
query_str = str.substr (0, str.size () - 1);
|
||||
else
|
||||
query_str = str;
|
||||
|
||||
term = term_prefix + query_str;
|
||||
return Xapian::Query (term);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ struct sprinter;
|
|||
struct notmuch_show_params;
|
||||
|
||||
typedef struct notmuch_show_format {
|
||||
struct sprinter *(*new_sprinter)(const void *ctx, FILE *stream);
|
||||
struct sprinter *(*new_sprinter)(notmuch_database_t * db, FILE *stream);
|
||||
notmuch_status_t (*part)(const void *ctx, struct sprinter *sprinter,
|
||||
struct mime_node *node, int indent,
|
||||
const struct notmuch_show_params *params);
|
||||
|
@ -426,13 +426,13 @@ mime_node_seek_dfs (mime_node_t *node, int n);
|
|||
const _notmuch_message_crypto_t *
|
||||
mime_node_get_message_crypto_status (mime_node_t *node);
|
||||
|
||||
typedef enum dump_formats {
|
||||
typedef enum {
|
||||
DUMP_FORMAT_AUTO,
|
||||
DUMP_FORMAT_BATCH_TAG,
|
||||
DUMP_FORMAT_SUP
|
||||
} dump_format_t;
|
||||
|
||||
typedef enum dump_includes {
|
||||
typedef enum {
|
||||
DUMP_INCLUDE_TAGS = 1,
|
||||
DUMP_INCLUDE_CONFIG = 2,
|
||||
DUMP_INCLUDE_PROPERTIES = 4
|
||||
|
@ -499,11 +499,10 @@ int notmuch_minimal_options (const char *subcommand_name,
|
|||
struct _notmuch_client_indexing_cli_choices {
|
||||
int decrypt_policy;
|
||||
bool decrypt_policy_set;
|
||||
notmuch_indexopts_t *opts;
|
||||
};
|
||||
extern struct _notmuch_client_indexing_cli_choices indexing_cli_choices;
|
||||
extern const notmuch_opt_desc_t notmuch_shared_indexing_options [];
|
||||
notmuch_status_t
|
||||
notmuch_process_shared_indexing_options (notmuch_database_t *notmuch);
|
||||
notmuch_process_shared_indexing_options (notmuch_indexopts_t *opts);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -383,7 +383,10 @@ _config_set_list (notmuch_conffile_t *config,
|
|||
const char *list[],
|
||||
size_t length)
|
||||
{
|
||||
g_key_file_set_string_list (config->key_file, group, key, list, length);
|
||||
if (length > 1)
|
||||
g_key_file_set_string_list (config->key_file, group, key, list, length);
|
||||
else
|
||||
g_key_file_set_string (config->key_file, group, key, list[0]);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -680,9 +683,9 @@ _notmuch_config_list_built_with ()
|
|||
printf ("%sretry_lock=%s\n",
|
||||
BUILT_WITH_PREFIX,
|
||||
notmuch_built_with ("retry_lock") ? "true" : "false");
|
||||
printf ("%ssexpr_query=%s\n",
|
||||
printf ("%ssexp_queries=%s\n",
|
||||
BUILT_WITH_PREFIX,
|
||||
notmuch_built_with ("sexpr_query") ? "true" : "false");
|
||||
notmuch_built_with ("sexp_queries") ? "true" : "false");
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -461,6 +461,8 @@ notmuch_insert_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
char *maildir;
|
||||
char *newpath;
|
||||
int opt_index;
|
||||
notmuch_indexopts_t *indexopts = notmuch_database_get_default_indexopts (notmuch);
|
||||
|
||||
void *local = talloc_new (NULL);
|
||||
|
||||
notmuch_opt_desc_t options[] = {
|
||||
|
@ -550,7 +552,7 @@ notmuch_insert_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
status = notmuch_process_shared_indexing_options (notmuch);
|
||||
status = notmuch_process_shared_indexing_options (indexopts);
|
||||
if (status != NOTMUCH_STATUS_SUCCESS) {
|
||||
fprintf (stderr, "Error: Failed to process index options. (%s)\n",
|
||||
notmuch_status_to_string (status));
|
||||
|
@ -558,7 +560,7 @@ notmuch_insert_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
}
|
||||
|
||||
/* Index the message. */
|
||||
status = add_file (notmuch, newpath, tag_ops, synchronize_flags, keep, indexing_cli_choices.opts);
|
||||
status = add_file (notmuch, newpath, tag_ops, synchronize_flags, keep, indexopts);
|
||||
|
||||
/* Commit changes. */
|
||||
close_status = notmuch_database_close (notmuch);
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef struct {
|
|||
const char *db_path;
|
||||
const char *mail_root;
|
||||
|
||||
notmuch_indexopts_t *indexopts;
|
||||
int output_is_a_tty;
|
||||
enum verbosity verbosity;
|
||||
bool debug;
|
||||
|
@ -376,7 +377,7 @@ add_file (notmuch_database_t *notmuch, const char *filename,
|
|||
if (status)
|
||||
goto DONE;
|
||||
|
||||
status = notmuch_database_index_file (notmuch, filename, indexing_cli_choices.opts, &message);
|
||||
status = notmuch_database_index_file (notmuch, filename, state->indexopts, &message);
|
||||
switch (status) {
|
||||
/* Success. */
|
||||
case NOTMUCH_STATUS_SUCCESS:
|
||||
|
@ -600,11 +601,12 @@ add_files (notmuch_database_t *notmuch,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Ignore the .notmuch directory and any "tmp" directory
|
||||
/* Ignore any top level .notmuch directory and any "tmp" directory
|
||||
* that appears within a maildir.
|
||||
*/
|
||||
if ((is_maildir && strcmp (entry->d_name, "tmp") == 0) ||
|
||||
strcmp (entry->d_name, ".notmuch") == 0)
|
||||
(strcmp (entry->d_name, ".notmuch") == 0
|
||||
&& (strcmp (path, state->mail_root)) == 0))
|
||||
continue;
|
||||
|
||||
next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
|
||||
|
@ -1150,6 +1152,8 @@ notmuch_new_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
else if (verbose)
|
||||
add_files_state.verbosity = VERBOSITY_VERBOSE;
|
||||
|
||||
add_files_state.indexopts = notmuch_database_get_default_indexopts (notmuch);
|
||||
|
||||
add_files_state.new_tags = notmuch_config_get_values (notmuch, NOTMUCH_CONFIG_NEW_TAGS);
|
||||
|
||||
if (print_status_database (
|
||||
|
@ -1217,7 +1221,7 @@ notmuch_new_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
if (notmuch == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
status = notmuch_process_shared_indexing_options (notmuch);
|
||||
status = notmuch_process_shared_indexing_options (add_files_state.indexopts);
|
||||
if (status != NOTMUCH_STATUS_SUCCESS) {
|
||||
fprintf (stderr, "Error: Failed to process index options. (%s)\n",
|
||||
notmuch_status_to_string (status));
|
||||
|
|
|
@ -90,6 +90,7 @@ notmuch_reindex_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
int opt_index;
|
||||
int ret;
|
||||
notmuch_status_t status;
|
||||
notmuch_indexopts_t *indexopts = notmuch_database_get_default_indexopts (notmuch);
|
||||
|
||||
/* Set up our handler for SIGINT */
|
||||
memset (&action, 0, sizeof (struct sigaction));
|
||||
|
@ -110,7 +111,7 @@ notmuch_reindex_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
|
||||
notmuch_process_shared_options (notmuch, argv[0]);
|
||||
|
||||
status = notmuch_process_shared_indexing_options (notmuch);
|
||||
status = notmuch_process_shared_indexing_options (indexopts);
|
||||
if (status != NOTMUCH_STATUS_SUCCESS) {
|
||||
fprintf (stderr, "Error: Failed to process index options. (%s)\n",
|
||||
notmuch_status_to_string (status));
|
||||
|
@ -128,7 +129,7 @@ notmuch_reindex_command (notmuch_database_t *notmuch, int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = reindex_query (notmuch, query_string, indexing_cli_choices.opts);
|
||||
ret = reindex_query (notmuch, query_string, indexopts);
|
||||
|
||||
notmuch_database_destroy (notmuch);
|
||||
|
||||
|
|
|
@ -209,6 +209,30 @@ _is_from_line (const char *line)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Output extra headers if configured with the `show.extra_headers'
|
||||
* configuration option
|
||||
*/
|
||||
static void
|
||||
format_extra_headers_sprinter (sprinter_t *sp, GMimeMessage *message)
|
||||
{
|
||||
GMimeHeaderList *header_list = g_mime_object_get_header_list (GMIME_OBJECT (message));
|
||||
|
||||
for (notmuch_config_values_t *extra_headers = notmuch_config_get_values (
|
||||
sp->notmuch, NOTMUCH_CONFIG_EXTRA_HEADERS);
|
||||
notmuch_config_values_valid (extra_headers);
|
||||
notmuch_config_values_move_to_next (extra_headers)) {
|
||||
GMimeHeader *header;
|
||||
const char *header_name = notmuch_config_values_get (extra_headers);
|
||||
|
||||
header = g_mime_header_list_get_header (header_list, header_name);
|
||||
if (header == NULL)
|
||||
continue;
|
||||
|
||||
sp->map_key (sp, g_mime_header_get_name (header));
|
||||
sp->string (sp, g_mime_header_get_value (header));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
format_headers_sprinter (sprinter_t *sp, GMimeMessage *message,
|
||||
bool reply, const _notmuch_message_crypto_t *msg_crypto)
|
||||
|
@ -269,6 +293,9 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage *message,
|
|||
sp->string (sp, g_mime_message_get_date_string (sp, message));
|
||||
}
|
||||
|
||||
/* Output extra headers the user has configured, if any */
|
||||
if (! reply)
|
||||
format_extra_headers_sprinter (sp, message);
|
||||
sp->end (sp);
|
||||
talloc_free (local);
|
||||
}
|
||||
|
|
13
notmuch.c
13
notmuch.c
|
@ -141,21 +141,18 @@ const notmuch_opt_desc_t notmuch_shared_indexing_options [] = {
|
|||
|
||||
|
||||
notmuch_status_t
|
||||
notmuch_process_shared_indexing_options (notmuch_database_t *notmuch)
|
||||
notmuch_process_shared_indexing_options (notmuch_indexopts_t *opts)
|
||||
{
|
||||
if (indexing_cli_choices.opts == NULL)
|
||||
indexing_cli_choices.opts = notmuch_database_get_default_indexopts (notmuch);
|
||||
if (opts == NULL)
|
||||
return NOTMUCH_STATUS_NULL_POINTER;
|
||||
|
||||
if (indexing_cli_choices.decrypt_policy_set) {
|
||||
notmuch_status_t status;
|
||||
if (indexing_cli_choices.opts == NULL)
|
||||
return NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||
status = notmuch_indexopts_set_decrypt_policy (indexing_cli_choices.opts,
|
||||
status = notmuch_indexopts_set_decrypt_policy (opts,
|
||||
indexing_cli_choices.decrypt_policy);
|
||||
if (status != NOTMUCH_STATUS_SUCCESS) {
|
||||
fprintf (stderr, "Error: Failed to set index decryption policy to %d. (%s)\n",
|
||||
indexing_cli_choices.decrypt_policy, notmuch_status_to_string (status));
|
||||
notmuch_indexopts_destroy (indexing_cli_choices.opts);
|
||||
indexing_cli_choices.opts = NULL;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ json_separator (struct sprinter *sp)
|
|||
}
|
||||
|
||||
struct sprinter *
|
||||
sprinter_json_create (const void *ctx, FILE *stream)
|
||||
sprinter_json_create (notmuch_database_t *db, FILE *stream)
|
||||
{
|
||||
static const struct sprinter_json template = {
|
||||
.vtable = {
|
||||
|
@ -192,11 +192,12 @@ sprinter_json_create (const void *ctx, FILE *stream)
|
|||
};
|
||||
struct sprinter_json *res;
|
||||
|
||||
res = talloc (ctx, struct sprinter_json);
|
||||
res = talloc (db, struct sprinter_json);
|
||||
if (! res)
|
||||
return NULL;
|
||||
|
||||
*res = template;
|
||||
res->vtable.notmuch = db;
|
||||
res->stream = stream;
|
||||
return &res->vtable;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ sexp_separator (struct sprinter *sp)
|
|||
}
|
||||
|
||||
struct sprinter *
|
||||
sprinter_sexp_create (const void *ctx, FILE *stream)
|
||||
sprinter_sexp_create (notmuch_database_t *db, FILE *stream)
|
||||
{
|
||||
static const struct sprinter_sexp template = {
|
||||
.vtable = {
|
||||
|
@ -227,11 +227,12 @@ sprinter_sexp_create (const void *ctx, FILE *stream)
|
|||
};
|
||||
struct sprinter_sexp *res;
|
||||
|
||||
res = talloc (ctx, struct sprinter_sexp);
|
||||
res = talloc (db, struct sprinter_sexp);
|
||||
if (! res)
|
||||
return NULL;
|
||||
|
||||
*res = template;
|
||||
res->vtable.notmuch = db;
|
||||
res->stream = stream;
|
||||
return &res->vtable;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ text_map_key (unused (struct sprinter *sp), unused (const char *key))
|
|||
}
|
||||
|
||||
struct sprinter *
|
||||
sprinter_text_create (const void *ctx, FILE *stream)
|
||||
sprinter_text_create (notmuch_database_t *db, FILE *stream)
|
||||
{
|
||||
static const struct sprinter_text template = {
|
||||
.vtable = {
|
||||
|
@ -134,21 +134,22 @@ sprinter_text_create (const void *ctx, FILE *stream)
|
|||
};
|
||||
struct sprinter_text *res;
|
||||
|
||||
res = talloc (ctx, struct sprinter_text);
|
||||
res = talloc (db, struct sprinter_text);
|
||||
if (! res)
|
||||
return NULL;
|
||||
|
||||
*res = template;
|
||||
res->vtable.notmuch = db;
|
||||
res->stream = stream;
|
||||
return &res->vtable;
|
||||
}
|
||||
|
||||
struct sprinter *
|
||||
sprinter_text0_create (const void *ctx, FILE *stream)
|
||||
sprinter_text0_create (notmuch_database_t *db, FILE *stream)
|
||||
{
|
||||
struct sprinter *sp;
|
||||
|
||||
sp = sprinter_text_create (ctx, stream);
|
||||
sp = sprinter_text_create (db, stream);
|
||||
if (! sp)
|
||||
return NULL;
|
||||
|
||||
|
|
13
sprinter.h
13
sprinter.h
|
@ -9,6 +9,11 @@
|
|||
* (strings, integers and booleans).
|
||||
*/
|
||||
typedef struct sprinter {
|
||||
/*
|
||||
* Open notmuch database
|
||||
*/
|
||||
notmuch_database_t *notmuch;
|
||||
|
||||
/* Start a new map/dictionary structure. This should be followed by
|
||||
* a sequence of alternating calls to map_key and one of the
|
||||
* value-printing functions until the map is ended by end.
|
||||
|
@ -65,20 +70,20 @@ typedef struct sprinter {
|
|||
/* Create a new unstructured printer that emits the default text format
|
||||
* for "notmuch search". */
|
||||
struct sprinter *
|
||||
sprinter_text_create (const void *ctx, FILE *stream);
|
||||
sprinter_text_create (notmuch_database_t *db, FILE *stream);
|
||||
|
||||
/* Create a new unstructured printer that emits the text format for
|
||||
* "notmuch search", with each field separated by a null character
|
||||
* instead of the newline character. */
|
||||
struct sprinter *
|
||||
sprinter_text0_create (const void *ctx, FILE *stream);
|
||||
sprinter_text0_create (notmuch_database_t *db, FILE *stream);
|
||||
|
||||
/* Create a new structure printer that emits JSON. */
|
||||
struct sprinter *
|
||||
sprinter_json_create (const void *ctx, FILE *stream);
|
||||
sprinter_json_create (notmuch_database_t *db, FILE *stream);
|
||||
|
||||
/* Create a new structure printer that emits S-Expressions. */
|
||||
struct sprinter *
|
||||
sprinter_sexp_create (const void *ctx, FILE *stream);
|
||||
sprinter_sexp_create (notmuch_database_t *db, FILE *stream);
|
||||
|
||||
#endif // NOTMUCH_SPRINTER_H
|
||||
|
|
|
@ -51,7 +51,7 @@ cat <<EOF > EXPECTED
|
|||
built_with.compact=something
|
||||
built_with.field_processor=something
|
||||
built_with.retry_lock=something
|
||||
built_with.sexpr_query=something
|
||||
built_with.sexp_queries=something
|
||||
database.autocommit=8000
|
||||
database.mail_root=MAIL_DIR
|
||||
database.path=MAIL_DIR
|
||||
|
@ -67,6 +67,35 @@ user.primary_email=test_suite@notmuchmail.org
|
|||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Round trip config item with leading spaces"
|
||||
test_subtest_known_broken
|
||||
notmuch config set foo.bar " thing"
|
||||
output=$(notmuch config get foo.bar)
|
||||
test_expect_equal "${output}" " thing"
|
||||
|
||||
test_begin_subtest "Round trip config item with leading tab"
|
||||
test_subtest_known_broken
|
||||
notmuch config set foo.bar " thing"
|
||||
output=$(notmuch config get foo.bar)
|
||||
test_expect_equal "${output}" " thing"
|
||||
|
||||
test_begin_subtest "Round trip config item with embedded tab"
|
||||
notmuch config set foo.bar "thing other"
|
||||
output=$(notmuch config get foo.bar)
|
||||
test_expect_equal "${output}" "thing other"
|
||||
|
||||
test_begin_subtest "Round trip config item with embedded backslash"
|
||||
notmuch config set foo.bar 'thing\other'
|
||||
output=$(notmuch config get foo.bar)
|
||||
test_expect_equal "${output}" "thing\other"
|
||||
|
||||
test_begin_subtest "Round trip config item with embedded NL/CR"
|
||||
notmuch config set foo.bar 'thing
|
||||
other'
|
||||
output=$(notmuch config get foo.bar)
|
||||
test_expect_equal "${output}" "thing
|
||||
other"
|
||||
|
||||
test_begin_subtest "Top level --config=FILE option"
|
||||
cp "${NOTMUCH_CONFIG}" alt-config
|
||||
notmuch --config=alt-config config set user.name "Another Name"
|
||||
|
|
|
@ -23,6 +23,13 @@ EOF
|
|||
expected_dir=$NOTMUCH_SRCDIR/test/setup.expected-output
|
||||
test_expect_equal_file ${expected_dir}/config-with-comments new-notmuch-config
|
||||
|
||||
test_begin_subtest "setup consistent with config-set for single items"
|
||||
# note this relies on the config state from the previous test.
|
||||
notmuch --config=new-notmuch-config config list > list.setup
|
||||
notmuch --config=new-notmuch-config config set search.exclude_tags baz
|
||||
notmuch --config=new-notmuch-config config list > list.config
|
||||
test_expect_equal_file list.setup list.config
|
||||
|
||||
test_begin_subtest "notmuch with a config but without a database suggests notmuch new"
|
||||
notmuch 2>&1 | notmuch_dir_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
|
|
|
@ -329,6 +329,18 @@ notmuch config set new.tags "foo;;bar"
|
|||
output=$(NOTMUCH_NEW --quiet 2>&1)
|
||||
test_expect_equal "$output" ""
|
||||
|
||||
test_begin_subtest "leading/trailing whitespace in new.tags is ignored"
|
||||
# avoid complications with leading spaces and "notmuch config"
|
||||
sed -i 's/^tags=.*$/tags= fu bar ; ; bar /' notmuch-config
|
||||
add_message
|
||||
NOTMUCH_NEW --quiet
|
||||
notmuch dump id:$gen_msg_id | sed 's/ --.*$//' > OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
#notmuch-dump batch-tag:3 config,properties,tags
|
||||
+bar +fu%20bar
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Tags starting with '-' in new.tags are forbidden"
|
||||
notmuch config set new.tags "-foo;bar"
|
||||
output=$(NOTMUCH_NEW --debug 2>&1)
|
||||
|
@ -339,6 +351,16 @@ test_expect_code 1 "NOTMUCH_NEW --debug 2>&1"
|
|||
|
||||
notmuch config set new.tags $OLDCONFIG
|
||||
|
||||
test_begin_subtest ".notmuch only ignored at top level"
|
||||
generate_message '[dir]=foo/bar/.notmuch/cur' '[subject]="Do not ignore, very important"'
|
||||
NOTMUCH_NEW > OUTPUT
|
||||
notmuch search subject:Do-not-ignore | notmuch_search_sanitize >> OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
Added 1 new message to the database.
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Do not ignore, very important (inbox unread)
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "RFC822 group names are indexed"
|
||||
test_subtest_known_broken
|
||||
generate_message [to]="undisclosed-recipients:"
|
||||
|
@ -368,31 +390,26 @@ chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
|
|||
test_expect_equal "$output" "A Xapian exception occurred opening database"
|
||||
|
||||
|
||||
make_shim dif-shim<<EOF
|
||||
#include <notmuch-test.h>
|
||||
|
||||
WRAP_DLFUNC(notmuch_status_t, notmuch_database_index_file, \
|
||||
(notmuch_database_t *database, const char *filename, notmuch_indexopts_t *indexopts, notmuch_message_t **message))
|
||||
|
||||
if (unlink ("${MAIL_DIR}/vanish")) {
|
||||
fprintf (stderr, "unlink failed\n");
|
||||
exit (42);
|
||||
}
|
||||
return notmuch_database_index_file_orig (database, filename, indexopts, message);
|
||||
}
|
||||
EOF
|
||||
|
||||
test_begin_subtest "Handle files vanishing between scandir and add_file"
|
||||
|
||||
# A file for scandir to find. It won't get indexed, so can be empty.
|
||||
touch ${MAIL_DIR}/vanish
|
||||
|
||||
# Breakpoint to remove the file before indexing
|
||||
cat <<EOF > notmuch-new-vanish.gdb
|
||||
set breakpoint pending on
|
||||
set logging file notmuch-new-vanish-gdb.log
|
||||
set logging on
|
||||
break notmuch_database_index_file
|
||||
commands
|
||||
shell rm -f ${MAIL_DIR}/vanish
|
||||
continue
|
||||
end
|
||||
run
|
||||
EOF
|
||||
|
||||
${TEST_GDB} --batch-silent --return-child-result -x notmuch-new-vanish.gdb \
|
||||
--args notmuch new 2>OUTPUT 1>/dev/null
|
||||
notmuch_with_shim dif-shim new 2>OUTPUT 1>/dev/null
|
||||
echo "exit status: $?" >> OUTPUT
|
||||
|
||||
# Clean up the file in case gdb isn't available.
|
||||
rm -f ${MAIL_DIR}/vanish
|
||||
|
||||
cat <<EOF > EXPECTED
|
||||
Unexpected error with file ${MAIL_DIR}/vanish
|
||||
add_file: Something went wrong trying to read or write a file
|
||||
|
|
40
test/T051-new-renames.sh
Executable file
40
test/T051-new-renames.sh
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description='"notmuch new" with directory renames'
|
||||
. $(dirname "$0")/test-lib.sh || exit 1
|
||||
|
||||
for loop in {1..10}; do
|
||||
|
||||
rm -rf ${MAIL_DIR}
|
||||
|
||||
for i in {1..10}; do
|
||||
generate_message '[dir]=foo' '[subject]="Message foo $i"'
|
||||
done
|
||||
|
||||
for i in {1..10}; do
|
||||
generate_message '[dir]=bar' '[subject]="Message bar $i"'
|
||||
done
|
||||
|
||||
test_begin_subtest "Index the messages, round $loop"
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "Added 20 new messages to the database."
|
||||
|
||||
all_files=$(notmuch search --output=files \*)
|
||||
count_foo=$(notmuch count folder:foo)
|
||||
|
||||
test_begin_subtest "Rename folder"
|
||||
mv ${MAIL_DIR}/foo ${MAIL_DIR}/baz
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Detected $count_foo file renames."
|
||||
|
||||
test_begin_subtest "Rename folder back"
|
||||
mv ${MAIL_DIR}/baz ${MAIL_DIR}/foo
|
||||
output=$(NOTMUCH_NEW)
|
||||
test_expect_equal "$output" "No new mail. Detected $count_foo file renames."
|
||||
|
||||
test_begin_subtest "Files remain the same"
|
||||
output=$(notmuch search --output=files \*)
|
||||
test_expect_equal "$output" "$all_files"
|
||||
|
||||
done
|
||||
|
||||
test_done
|
|
@ -277,7 +277,7 @@ EOF
|
|||
built_with.compact=something
|
||||
built_with.field_processor=something
|
||||
built_with.retry_lock=something
|
||||
built_with.sexpr_query=something
|
||||
built_with.sexp_queries=something
|
||||
database.autocommit=8000
|
||||
database.backup_dir
|
||||
database.hook_dir
|
||||
|
@ -318,7 +318,14 @@ to=m.header('To')
|
|||
print(to)
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
;& # fall through
|
||||
;;
|
||||
*)
|
||||
backup_database
|
||||
test_begin_subtest ".notmuch without xapian/ handled gracefully ($config)"
|
||||
rm -r $XAPIAN_PATH
|
||||
test_expect_success "notmuch new"
|
||||
restore_database
|
||||
;;
|
||||
esac
|
||||
|
||||
case $config in
|
||||
|
|
|
@ -102,22 +102,25 @@ 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
|
||||
set logging file count-files-gdb.log
|
||||
set logging on
|
||||
break count_files
|
||||
commands
|
||||
shell cp /dev/null ${MAIL_DIR}/.notmuch/xapian/postlist.*
|
||||
continue
|
||||
end
|
||||
run
|
||||
make_shim qsm-shim<<EOF
|
||||
#include <notmuch-test.h>
|
||||
|
||||
WRAP_DLFUNC (notmuch_status_t, notmuch_query_search_messages, (notmuch_query_t *query, notmuch_messages_t **messages))
|
||||
|
||||
/* XXX WARNING THIS CORRUPTS THE DATABASE */
|
||||
int fd = open ("target_postlist", O_WRONLY|O_TRUNC);
|
||||
if (fd < 0)
|
||||
exit (8);
|
||||
close (fd);
|
||||
|
||||
return notmuch_query_search_messages_orig(query, messages);
|
||||
}
|
||||
EOF
|
||||
|
||||
backup_database
|
||||
test_begin_subtest "error message from query_search_messages"
|
||||
${TEST_GDB} --batch-silent --return-child-result -x count-files.gdb \
|
||||
--args notmuch count --output=files '*' 2>OUTPUT 1>/dev/null
|
||||
ln -s ${MAIL_DIR}/.notmuch/xapian/postlist.* target_postlist
|
||||
notmuch_with_shim qsm-shim count --output=files '*' 2>OUTPUT 1>/dev/null
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch count: A Xapian exception occurred
|
||||
A Xapian exception occurred performing query
|
||||
|
|
|
@ -234,6 +234,18 @@ output=$(notmuch show --format=json id:$gen_msg_id)
|
|||
test_json_nodes <<<"$output" \
|
||||
'new_tags:[0][0][0]["tags"] = ["bar", "foo"]'
|
||||
|
||||
test_begin_subtest "leading/trailing whitespace in new.tags is ignored"
|
||||
# avoid complications with leading spaces and "notmuch config"
|
||||
sed -i 's/^tags=.*$/tags= fu bar ; ; bar /' notmuch-config
|
||||
gen_insert_msg
|
||||
notmuch insert < $gen_msg_filename
|
||||
notmuch dump id:$gen_msg_id | sed 's/ --.*$//' > OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
#notmuch-dump batch-tag:3 config,properties,tags
|
||||
+bar +fu%20bar
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Tags starting with '-' in new.tags are forbidden"
|
||||
notmuch config set new.tags "-foo;bar"
|
||||
gen_insert_msg
|
||||
|
|
|
@ -185,6 +185,50 @@ notmuch search folder:'""' > EXPECTED
|
|||
notmuch search --query=sexp '(folder "")' > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Search by 'folder' with --output=files"
|
||||
output=$(notmuch search --output=files --query=sexp '(folder bad/news)' | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "Search by 'folder' with --output=files (trailing /)"
|
||||
output=$(notmuch search --output=files --query=sexp '(folder bad/news/)' | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "Search by 'folder' (multiple)"
|
||||
output=$(notmuch search --query=sexp '(folder bad bad/news things/bad)' | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "Search by 'folder' (multiple, trailing /)"
|
||||
output=$(notmuch search --query=sexp '(folder bad bad/news/ things/bad)' | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "Search by 'path' with --output=files"
|
||||
output=$(notmuch search --output=files --query=sexp '(path bad/news)' | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "Search by 'path' with --output=files (trailing /)"
|
||||
output=$(notmuch search --output=files --query=sexp '(path bad/news/)' | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "Search by 'path' specification (multiple)"
|
||||
output=$(notmuch search --query=sexp '(path bad bad/news things/bad)' | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "Search by 'path' specification (multiple, trailing /)"
|
||||
output=$(notmuch search --query=sexp '(path bad bad/news/ things/bad)' | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "Search by 'id'"
|
||||
add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
|
||||
output=$(notmuch search --query=sexp "(id ${gen_msg_id})" | notmuch_search_sanitize)
|
||||
|
@ -346,7 +390,7 @@ output=$(notmuch search --query=sexp '(attachment (starts-with not))' | notmuch_
|
|||
test_expect_equal "$output" 'thread:XXX 2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)'
|
||||
|
||||
test_begin_subtest "starts-with, folder"
|
||||
notmuch search --output=files --query=sexp '(folder (starts-with bad))' | notmuch_dir_sanitize | sed 's/[0-9]*$/XXX/' > OUTPUT
|
||||
notmuch search --output=files --query=sexp '(folder (starts-with bad))' | notmuch_search_files_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
MAIL_DIR/bad/msg-XXX
|
||||
MAIL_DIR/bad/news/msg-XXX
|
||||
|
@ -768,6 +812,144 @@ notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
|
|||
notmuch search --query=sexp '(and (infix "date:2009-11-18..2009-11-18") (infix "tag:unread"))' > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, empty"
|
||||
notmuch search from:keithp | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp '(and (date) (from keithp))'| notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, one argument"
|
||||
notmuch search date:2009-11-18 and from:keithp | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp '(and (date 2009-11-18) (from keithp))' | notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, two arguments"
|
||||
notmuch search date:2009-11-17..2009-11-18 and from:keithp | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp '(and (date 2009-11-17 2009-11-18) (from keithp))' | notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, illegal nesting 1"
|
||||
notmuch search --query=sexp '(to (date))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
nested field: 'date' inside 'to'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, illegal nesting 2"
|
||||
notmuch search --query=sexp '(to (date 2021-11-18))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
nested field: 'date' inside 'to'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, illegal nesting 3"
|
||||
notmuch search --query=sexp '(date (to))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
expected atom as first argument of 'date'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, illegal nesting 4"
|
||||
notmuch search --query=sexp '(date today (to))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
expected atom as second argument of 'date'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, too many arguments"
|
||||
notmuch search --query=sexp '(date yesterday and tommorow)' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
'date' expects maximum of two arguments
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "date query, bad date"
|
||||
notmuch search --query=sexp '(date "hawaiian-pizza-day")' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
Didn't understand date specification 'hawaiian-pizza-day'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, empty"
|
||||
notmuch search from:keithp | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp '(and (lastmod) (from keithp))'| notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, one argument"
|
||||
notmuch tag +4EFC743A.3060609@april.org id:4EFC743A.3060609@april.org
|
||||
revision=$(notmuch count --lastmod '*' | cut -f3)
|
||||
notmuch search lastmod:$revision..$revision | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp "(and (lastmod $revision))" | notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, two arguments"
|
||||
notmuch tag +keithp from:keithp
|
||||
revision2=$(notmuch count --lastmod '*' | cut -f3)
|
||||
notmuch search lastmod:$revision..$revision2 | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp "(and (lastmod $revision $revision2))" | notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, illegal nesting 1"
|
||||
notmuch search --query=sexp '(to (lastmod))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
nested field: 'lastmod' inside 'to'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, bad from revision"
|
||||
notmuch search --query=sexp '(lastmod apples)' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
bad 'from' revision: 'apples'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, bad to revision"
|
||||
notmuch search --query=sexp '(lastmod 0 apples)' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
bad 'to' revision: 'apples'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, illegal nesting 2"
|
||||
notmuch search --query=sexp '(to (lastmod 2021-11-18))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
nested field: 'lastmod' inside 'to'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, illegal nesting 3"
|
||||
notmuch search --query=sexp '(lastmod (to))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
expected atom as first argument of 'lastmod'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, illegal nesting 4"
|
||||
notmuch search --query=sexp '(lastmod today (to))' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
expected atom as second argument of 'lastmod'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "lastmod query, too many arguments"
|
||||
notmuch search --query=sexp '(lastmod yesterday and tommorow)' > OUTPUT 2>&1
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
'lastmod' expects maximum of two arguments
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "user header (unknown header)"
|
||||
notmuch search --query=sexp '(FooBar)' >& OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
|
|
|
@ -18,6 +18,12 @@ test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; T
|
|||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "search by path: specification (multiple)"
|
||||
output=$(notmuch search path:bad path:bad/news path:things/bad | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
|
||||
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
|
||||
|
||||
test_begin_subtest "Top level folder"
|
||||
output=$(notmuch search folder:'""' | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Top level (inbox unread)"
|
||||
|
@ -28,8 +34,13 @@ test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1(2)] Notmuch Test Suite
|
|||
|
||||
test_begin_subtest "Folder search with --output=files"
|
||||
output=$(notmuch search --output=files folder:bad/news | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-003
|
||||
MAIL_DIR/duplicate/bad/news/msg-003"
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "Folder search with --output=files (trailing /)"
|
||||
output=$(notmuch search --output=files folder:bad/news/ | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
|
||||
MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "After removing duplicate instance of matching path"
|
||||
rm -r "${MAIL_DIR}/bad/news"
|
||||
|
@ -39,7 +50,7 @@ test_expect_equal "$output" ""
|
|||
|
||||
test_begin_subtest "Folder search with --output=files part #2"
|
||||
output=$(notmuch search --output=files folder:duplicate/bad/news | notmuch_search_files_sanitize)
|
||||
test_expect_equal "$output" "MAIL_DIR/duplicate/bad/news/msg-003"
|
||||
test_expect_equal "$output" "MAIL_DIR/duplicate/bad/news/msg-XXX"
|
||||
|
||||
test_begin_subtest "After removing duplicate instance of matching path part #2"
|
||||
output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize)
|
||||
|
@ -120,6 +131,13 @@ test_expect_equal "$output" "MAIL_DIR/bar/17:2,
|
|||
MAIL_DIR/bar/18:2,
|
||||
MAIL_DIR/cur/51:2,"
|
||||
|
||||
test_begin_subtest "path: search (trailing /)"
|
||||
output=$(notmuch search --output=files path:"bar/" | notmuch_search_files_sanitize | sort)
|
||||
# cur/51:2, is a duplicate of bar/18:2,
|
||||
test_expect_equal "$output" "MAIL_DIR/bar/17:2,
|
||||
MAIL_DIR/bar/18:2,
|
||||
MAIL_DIR/cur/51:2,"
|
||||
|
||||
test_begin_subtest "top level path: search"
|
||||
output=$(notmuch search --output=files path:'""' | notmuch_search_files_sanitize | sort)
|
||||
test_expect_equal "$output" "MAIL_DIR/01:2,
|
||||
|
|
|
@ -156,4 +156,46 @@ EOF
|
|||
output=$(notmuch show --format=json --body=false --format-version=2 id:message-id@example.com)
|
||||
test_expect_equal_json "$output" "$(cat EXPECTED)"
|
||||
|
||||
test_begin_subtest "show extra headers"
|
||||
add_message "[subject]=\"extra-headers\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[in-reply-to]=\"<parent@notmuch-test-suite>\"" "[body]=\"extra-headers test\""\
|
||||
"[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
|
||||
by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
|
||||
for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
|
||||
|
||||
notmuch config set show.extra_headers "in-reply-to;received"
|
||||
output=$(notmuch show --format=json --body=false id:${gen_msg_id} | notmuch_json_show_sanitize)
|
||||
cat <<EOF > EXPECTED
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"crypto": {},
|
||||
"date_relative": "2000-01-01",
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"YYYYY"
|
||||
],
|
||||
"headers": {
|
||||
"Date": "Sat, 01 Jan 2000 12:00:00 +0000",
|
||||
"From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
|
||||
"In-Reply-To": "<parent@notmuch-test-suite>",
|
||||
"Received": "from mail.example.com (mail.example.com [1.1.1.1])\tby mail.notmuchmail.org (some MTA) with ESMTP id 12345678\tfor <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)",
|
||||
"Subject": "extra-headers",
|
||||
"To": "Notmuch Test Suite <test_suite@notmuchmail.org>"
|
||||
},
|
||||
"id": "XXXXX",
|
||||
"match": true,
|
||||
"tags": [
|
||||
"inbox",
|
||||
"unread"
|
||||
],
|
||||
"timestamp": 946728000
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
EOF
|
||||
test_expect_equal_json "${output}" "$(cat EXPECTED)"
|
||||
|
||||
test_done
|
||||
|
|
|
@ -47,4 +47,18 @@ filename=$(notmuch search --output=files "id:$id")
|
|||
attachment_length=$(( $(base64 $NOTMUCH_SRCDIR/test/README | wc -c) - 1 ))
|
||||
test_expect_equal "$output" "((((:id \"$id\" :match t :excluded nil :filename (\"$filename\") :timestamp 946728000 :date_relative \"2000-01-01\" :tags (\"inbox\") :body ((:id 1 :content-type \"multipart/mixed\" :content ((:id 2 :content-type \"text/plain\" :content \"This is a test message with inline attachment with a filename\") (:id 3 :content-type \"application/octet-stream\" :content-disposition \"inline\" :filename \"README\" :content-transfer-encoding \"base64\" :content-length $attachment_length)))) :crypto () :headers (:Subject \"sexp-show-inline-attachment-filename\" :From \"Notmuch Test Suite <test_suite@notmuchmail.org>\" :To \"test_suite@notmuchmail.org\" :Date \"Sat, 01 Jan 2000 12:00:00 +0000\")) ())))"
|
||||
|
||||
test_begin_subtest "show extra headers"
|
||||
add_message "[subject]=\"extra-headers\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[in-reply-to]=\"<parent@notmuch-test-suite>\"" "[body]=\"extra-headers test\""\
|
||||
"[header]=\"Received: from mail.example.com (mail.example.com [1.1.1.1])
|
||||
by mail.notmuchmail.org (some MTA) with ESMTP id 12345678
|
||||
for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)\"" \
|
||||
|
||||
notmuch config set show.extra_headers "in-reply-to;received"
|
||||
notmuch show --format=sexp --body=false id:${gen_msg_id} | \
|
||||
notmuch_dir_sanitize | sed 's/msg-[0-9]*/MSG/g'> OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
((((:id "MSG@notmuch-test-suite" :match t :excluded nil :filename ("MAIL_DIR/MSG") :timestamp 946728000 :date_relative "2000-01-01" :tags ("inbox" "unread") :crypto () :headers (:Subject "extra-headers" :From "Notmuch Test Suite <test_suite@notmuchmail.org>" :To "Notmuch Test Suite <test_suite@notmuchmail.org>" :Date "Sat, 01 Jan 2000 12:00:00 +0000" :In-Reply-To "<parent@notmuch-test-suite>" :Received "from mail.example.com (mail.example.com [1.1.1.1])\011by mail.notmuchmail.org (some MTA) with ESMTP id 12345678\011for <test_suite_other@notmuchmail.org>; Sat, 10 Apr 2010 07:54:51 -0400 (EDT)")) ())))
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_done
|
||||
|
|
|
@ -485,6 +485,31 @@ Sender <sender@example.com> writes:
|
|||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Reply with show.extra_headers set"
|
||||
notmuch config set show.extra_headers Received
|
||||
add_message '[from]="Sender <sender@example.com>"' \
|
||||
[to]=test_suite_other@notmuchmail.org
|
||||
|
||||
test_emacs "(let ((message-hidden-headers '()))
|
||||
(notmuch-search \"id:\\\"${gen_msg_id}\\\"\")
|
||||
(notmuch-test-wait)
|
||||
(notmuch-search-reply-to-thread)
|
||||
(test-output))"
|
||||
cat <<EOF >EXPECTED
|
||||
From: Notmuch Test Suite <test_suite_other@notmuchmail.org>
|
||||
To: Sender <sender@example.com>
|
||||
Subject: Re: ${test_subtest_name}
|
||||
In-Reply-To: <${gen_msg_id}>
|
||||
Fcc: ${MAIL_DIR}/sent
|
||||
References: <${gen_msg_id}>
|
||||
--text follows this line--
|
||||
Sender <sender@example.com> writes:
|
||||
|
||||
> This is just a test message (#${gen_msg_cnt})
|
||||
EOF
|
||||
notmuch config set show.extra_headers
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "Reply from address in named group list within emacs"
|
||||
add_message '[from]="Sender <sender@example.com>"' \
|
||||
'[to]=group:test_suite@notmuchmail.org,someone@example.com\;' \
|
||||
|
@ -680,7 +705,7 @@ References: <XXX>
|
|||
--text follows this line--
|
||||
test_suite@notmuchmail.org writes:
|
||||
|
||||
> This is just a test message (#7)
|
||||
> This is just a test message (#${gen_msg_cnt})
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
|
|
@ -13,16 +13,29 @@ test_description='PGP/MIME signature verification and decryption'
|
|||
test_require_emacs
|
||||
add_gnupg_home
|
||||
|
||||
test_begin_subtest "emacs delivery of signed message"
|
||||
test_begin_subtest "emacs delivery of signed message via fcc"
|
||||
test_expect_success \
|
||||
'emacs_fcc_message \
|
||||
"test signed message 001" \
|
||||
"This is a test signed message." \
|
||||
"(mml-secure-message-sign)"'
|
||||
|
||||
test_begin_subtest "emacs delivery of signed message via fcc and smtp"
|
||||
emacs_deliver_message \
|
||||
'signed message sent via SMTP' \
|
||||
'This is a test that messages are sent via SMTP' \
|
||||
"(add-hook 'message-send-mail-hook (lambda () (sleep-for 1)))
|
||||
(mml-secure-message-sign)"
|
||||
msg_file=$(notmuch search --output=files subject:signed-message-sent-via-SMTP)
|
||||
test_expect_equal_message_body sent_message "$msg_file"
|
||||
|
||||
test_begin_subtest "signed part content-type indexing"
|
||||
output=$(notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize)
|
||||
test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)"
|
||||
notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize > OUTPUT
|
||||
cat <<EOF >EXPECTED
|
||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)
|
||||
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; signed message sent via SMTP (inbox signed)
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "signature verification"
|
||||
output=$(notmuch show --format=json --verify subject:"test signed message 001" \
|
||||
|
|
|
@ -24,8 +24,8 @@ test_expect_equal "$output" "No new mail."
|
|||
|
||||
test_begin_subtest "Multiple files for same message"
|
||||
cat <<EOF >EXPECTED
|
||||
MAIL_DIR/msg-001
|
||||
MAIL_DIR/spam/msg-001
|
||||
MAIL_DIR/msg-XXX
|
||||
MAIL_DIR/spam/msg-XXX
|
||||
EOF
|
||||
notmuch search --output=files id:$id_x | notmuch_search_files_sanitize >OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
|
48
test/T392-python-cffi-notmuch.sh
Executable file
48
test/T392-python-cffi-notmuch.sh
Executable file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env bash
|
||||
test_description="python bindings (notmuch test suite)"
|
||||
. $(dirname "$0")/test-lib.sh || exit 1
|
||||
|
||||
if [ $NOTMUCH_HAVE_PYTHON3_CFFI -eq 0 -o $NOTMUCH_HAVE_PYTHON3_PYTEST -eq 0 ]; then
|
||||
test_done
|
||||
fi
|
||||
|
||||
add_email_corpus
|
||||
|
||||
cat <<EOF > recurse.py
|
||||
from notmuch2 import Database
|
||||
def show_msgs(msgs, level):
|
||||
print('{:s} {:s}'.format(' ' * level*4, type(msgs).__name__))
|
||||
for msg in msgs:
|
||||
print('{:s} {:s}'.format(' ' * (level*4+2), type(msg).__name__))
|
||||
replies=msg.replies()
|
||||
show_msgs(replies, level+1)
|
||||
db = Database(config=Database.CONFIG.SEARCH)
|
||||
msg=db.find("87ocn0qh6d.fsf@yoom.home.cworth.org")
|
||||
threads = db.threads(query="thread:"+msg.threadid)
|
||||
thread = next (threads)
|
||||
show_msgs(thread, 0)
|
||||
EOF
|
||||
|
||||
test_begin_subtest "recursive traversal of replies (no crash)"
|
||||
test_python < recurse.py
|
||||
error=$?
|
||||
test_expect_equal "${error}" 0
|
||||
|
||||
test_begin_subtest "recursive traversal of replies (output)"
|
||||
test_python < recurse.py
|
||||
tail -n 10 < OUTPUT > OUTPUT.sample
|
||||
cat <<EOF > EXPECTED
|
||||
OwnedMessage
|
||||
MessageIter
|
||||
OwnedMessage
|
||||
MessageIter
|
||||
OwnedMessage
|
||||
MessageIter
|
||||
OwnedMessage
|
||||
MessageIter
|
||||
OwnedMessage
|
||||
MessageIter
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT.sample
|
||||
|
||||
test_done
|
|
@ -68,6 +68,16 @@ test_emacs '(notmuch-hello)
|
|||
notmuch tag -$tag '*'
|
||||
test_expect_equal_file $EXPECTED/notmuch-hello-long-names OUTPUT
|
||||
|
||||
test_begin_subtest "All tags show up"
|
||||
tag=exclude_me
|
||||
notmuch tag +$tag '*'
|
||||
notmuch config set search.exclude_tags $tag
|
||||
test_emacs '(notmuch-hello)
|
||||
(test-output)'
|
||||
notmuch tag -$tag '*'
|
||||
test_expect_equal_file $EXPECTED/notmuch-hello-all-tags OUTPUT
|
||||
|
||||
test_done
|
||||
test_begin_subtest "notmuch-hello with nonexistent CWD"
|
||||
test_emacs '
|
||||
(notmuch-hello)
|
||||
|
|
|
@ -220,7 +220,9 @@ test_emacs '(notmuch-show "id:basic-encrypted@crypto.notmuchmail.org")
|
|||
test_expect_equal_file $EXPECTED/notmuch-show-decrypted-message OUTPUT
|
||||
|
||||
test_begin_subtest "show encrypted rfc822 message"
|
||||
test_subtest_known_broken
|
||||
if ${TEST_EMACS} --quick --batch --eval '(kill-emacs (if (version< emacs-version "28") 0 1))'; then
|
||||
test_subtest_known_broken
|
||||
fi
|
||||
test_emacs '(notmuch-show "id:encrypted-rfc822-attachment@crypto.notmuchmail.org")
|
||||
(test-visible-output)'
|
||||
test_expect_code 1 'fgrep "!!!" OUTPUT'
|
||||
|
|
|
@ -9,10 +9,8 @@ test_begin_subtest "building database"
|
|||
test_expect_success "NOTMUCH_NEW"
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <stdio.h>
|
||||
#include <notmuch.h>
|
||||
#include <notmuch-test.h>
|
||||
#include <talloc.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
notmuch_database_t *db;
|
||||
|
@ -82,7 +80,7 @@ cat <<EOF > EXPECTED
|
|||
== stdout ==
|
||||
0
|
||||
== stderr ==
|
||||
A Xapian exception occurred at lib/database.cc:XXX: Database has been closed
|
||||
A Xapian exception occurred at database.cc:XXX: Database has been closed
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
@ -147,7 +145,7 @@ cat <<EOF > EXPECTED
|
|||
== stdout ==
|
||||
1
|
||||
== stderr ==
|
||||
A Xapian exception occurred at lib/database.cc:XXX: Database has been closed
|
||||
A Xapian exception occurred at database.cc:XXX: Database has been closed
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
|
|
@ -9,10 +9,8 @@ test_begin_subtest "building database"
|
|||
test_expect_success "NOTMUCH_NEW"
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <stdio.h>
|
||||
#include <notmuch.h>
|
||||
#include <notmuch-test.h>
|
||||
#include <talloc.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
notmuch_database_t *db;
|
||||
|
@ -53,7 +51,7 @@ cat <<EOF > EXPECTED
|
|||
== stdout ==
|
||||
1
|
||||
== stderr ==
|
||||
A Xapian exception occurred at lib/directory.cc:XXX: Database has been closed
|
||||
A Xapian exception occurred at directory.cc:XXX: Database has been closed
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
@ -70,7 +68,7 @@ cat <<EOF > EXPECTED
|
|||
== stdout ==
|
||||
1
|
||||
== stderr ==
|
||||
A Xapian exception occurred at lib/directory.cc:XXX: Database has been closed
|
||||
A Xapian exception occurred at directory.cc:XXX: Database has been closed
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
|
|
@ -9,10 +9,8 @@ test_begin_subtest "building database"
|
|||
test_expect_success "NOTMUCH_NEW"
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <stdio.h>
|
||||
#include <notmuch.h>
|
||||
#include <notmuch-test.h>
|
||||
#include <talloc.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
notmuch_database_t *db;
|
||||
|
|
|
@ -19,9 +19,8 @@ cat <<'EOF' > c_tail
|
|||
EOF
|
||||
|
||||
cat <<EOF > c_head0
|
||||
#include <stdio.h>
|
||||
#include <notmuch.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
notmuch_database_t *db;
|
||||
|
|
|
@ -24,9 +24,8 @@ cat <<'EOF' > c_tail
|
|||
EOF
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <stdio.h>
|
||||
#include <notmuch.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
notmuch_database_t *db;
|
||||
|
|
|
@ -23,8 +23,6 @@ EOF
|
|||
}
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
|
@ -272,6 +270,29 @@ EOF
|
|||
test_expect_equal_file EXPECTED OUTPUT
|
||||
restore_database
|
||||
|
||||
test_begin_subtest "notmuch_config_get_values (ignore leading/trailing whitespace)"
|
||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL%
|
||||
{
|
||||
notmuch_config_values_t *values;
|
||||
EXPECT0(notmuch_config_set (db, NOTMUCH_CONFIG_NEW_TAGS, " a ; b c ; d "));
|
||||
for (values = notmuch_config_get_values (db, NOTMUCH_CONFIG_NEW_TAGS);
|
||||
notmuch_config_values_valid (values);
|
||||
notmuch_config_values_move_to_next (values))
|
||||
{
|
||||
puts (notmuch_config_values_get (values));
|
||||
}
|
||||
}
|
||||
EOF
|
||||
cat <<'EOF' >EXPECTED
|
||||
== stdout ==
|
||||
a
|
||||
b c
|
||||
d
|
||||
== stderr ==
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
restore_database
|
||||
|
||||
test_begin_subtest "notmuch_config_get_values_string"
|
||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL%
|
||||
{
|
||||
|
@ -418,6 +439,7 @@ cat <<'EOF' >EXPECTED
|
|||
09: 'NULL'
|
||||
10: 'USER_FULL_NAME'
|
||||
11: '8000'
|
||||
12: 'NULL'
|
||||
== stderr ==
|
||||
EOF
|
||||
unset MAILDIR
|
||||
|
@ -616,8 +638,6 @@ cp notmuch-config.bak notmuch-config
|
|||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
cat <<EOF > c_head2
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
|
@ -730,6 +750,7 @@ cat <<'EOF' >EXPECTED
|
|||
09: 'test_suite_other@notmuchmail.org;test_suite@otherdomain.org'
|
||||
10: 'Notmuch Test Suite'
|
||||
11: '8000'
|
||||
12: 'NULL'
|
||||
== stderr ==
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
@ -763,6 +784,7 @@ cat <<'EOF' >EXPECTED
|
|||
09: 'NULL'
|
||||
10: 'USER_FULL_NAME'
|
||||
11: '8000'
|
||||
12: 'NULL'
|
||||
== stderr ==
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT.clean
|
||||
|
@ -839,6 +861,7 @@ maildir.synchronize_flags true
|
|||
new.ignore sekrit_junk
|
||||
new.tags unread;inbox
|
||||
search.exclude_tags foo;bar;fub
|
||||
show.extra_headers (null)
|
||||
test.key1 testvalue1
|
||||
test.key2 testvalue2
|
||||
user.name Notmuch Test Suite
|
||||
|
@ -953,6 +976,7 @@ EOF
|
|||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "open: database parameter overrides implicit config"
|
||||
cp $NOTMUCH_CONFIG ${NOTMUCH_CONFIG}.bak
|
||||
notmuch config set database.path ${MAIL_DIR}/nonexistent
|
||||
cat c_head3 - c_tail3 <<'EOF' | test_C ${MAIL_DIR}
|
||||
const char *path = NULL;
|
||||
|
@ -963,6 +987,7 @@ cat c_head3 - c_tail3 <<'EOF' | test_C ${MAIL_DIR}
|
|||
path = notmuch_database_get_path (db);
|
||||
printf ("path: %s\n", path ? path : "(null)");
|
||||
EOF
|
||||
cp ${NOTMUCH_CONFIG}.bak ${NOTMUCH_CONFIG}
|
||||
cat <<EOF> EXPECTED
|
||||
== stdout ==
|
||||
status: 0
|
||||
|
@ -973,4 +998,43 @@ EOF
|
|||
notmuch_dir_sanitize < OUTPUT > OUTPUT.clean
|
||||
test_expect_equal_file EXPECTED OUTPUT.clean
|
||||
|
||||
cat <<EOF > c_body
|
||||
notmuch_status_t st = notmuch_database_open_with_config(NULL,
|
||||
NOTMUCH_DATABASE_MODE_READ_ONLY,
|
||||
"", NULL, &db, NULL);
|
||||
printf ("status == SUCCESS: %d\n", st == NOTMUCH_STATUS_SUCCESS);
|
||||
if (db) {
|
||||
const char *mail_root = NULL;
|
||||
mail_root = notmuch_config_get (db, NOTMUCH_CONFIG_MAIL_ROOT);
|
||||
printf ("mail_root: %s\n", mail_root ? mail_root : "(null)");
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF> EXPECTED.common
|
||||
== stdout ==
|
||||
status == SUCCESS: 0
|
||||
db == NULL: 1
|
||||
== stderr ==
|
||||
EOF
|
||||
|
||||
test_begin_subtest "open/error: config=empty with no mail root in db "
|
||||
old_NOTMUCH_CONFIG=${NOTMUCH_CONFIG}
|
||||
unset NOTMUCH_CONFIG
|
||||
cat c_head3 c_body c_tail3 | test_C
|
||||
export NOTMUCH_CONFIG=${old_NOTMUCH_CONFIG}
|
||||
notmuch_dir_sanitize < OUTPUT > OUTPUT.clean
|
||||
test_expect_equal_file EXPECTED.common OUTPUT.clean
|
||||
|
||||
test_begin_subtest "open/error: config=empty with no mail root in db (xdg)"
|
||||
old_NOTMUCH_CONFIG=${NOTMUCH_CONFIG}
|
||||
unset NOTMUCH_CONFIG
|
||||
backup_database
|
||||
mkdir -p home/.local/share/notmuch
|
||||
mv mail/.notmuch home/.local/share/notmuch/default
|
||||
cat c_head3 c_body c_tail3 | test_C
|
||||
restore_database
|
||||
export NOTMUCH_CONFIG=${old_NOTMUCH_CONFIG}
|
||||
notmuch_dir_sanitize < OUTPUT > OUTPUT.clean
|
||||
test_expect_equal_file EXPECTED.common OUTPUT.clean
|
||||
|
||||
test_done
|
||||
|
|
|
@ -6,8 +6,6 @@ test_description="library reopen API"
|
|||
add_email_corpus
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
int main (int argc, char** argv)
|
||||
|
|
|
@ -6,10 +6,6 @@ test_description="message property API"
|
|||
add_email_corpus
|
||||
|
||||
cat <<EOF > c_head
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <talloc.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
void print_properties (notmuch_message_t *message, const char *prefix, notmuch_bool_t exact) {
|
||||
|
|
|
@ -9,9 +9,6 @@ if [ $NOTMUCH_HAVE_XAPIAN_DB_RETRY_LOCK -ne 1 ]; then
|
|||
test_subtest_known_broken
|
||||
fi
|
||||
test_C ${MAIL_DIR} <<'EOF'
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <notmuch-test.h>
|
||||
|
||||
void
|
||||
|
|
|
@ -10,11 +10,8 @@ test_begin_subtest "catching DatabaseModifiedError in _notmuch_message_ensure_me
|
|||
first_id=$(notmuch search --output=messages '*'| head -1 | sed s/^id://)
|
||||
|
||||
test_C ${MAIL_DIR} <<EOF
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <notmuch-test.h>
|
||||
#include <talloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
|
|
@ -58,13 +58,13 @@ test_expect_equal_file EXPECTED OUTPUT
|
|||
test_begin_subtest "notmuch search --output=files with partially gzipped mail store"
|
||||
notmuch search --output=files '*' | notmuch_search_files_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
MAIL_DIR/msg-001.gz
|
||||
MAIL_DIR/msg-002.gz
|
||||
MAIL_DIR/msg-003.gz
|
||||
MAIL_DIR/msg-004
|
||||
MAIL_DIR/msg-005.gz
|
||||
MAIL_DIR/msg-006
|
||||
MAIL_DIR/msg-007.gz
|
||||
MAIL_DIR/msg-XXX.gz
|
||||
MAIL_DIR/msg-XXX.gz
|
||||
MAIL_DIR/msg-XXX.gz
|
||||
MAIL_DIR/msg-XXX
|
||||
MAIL_DIR/msg-XXX.gz
|
||||
MAIL_DIR/msg-XXX
|
||||
MAIL_DIR/msg-XXX.gz
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue