all:
# List all subdirectories here. Each contains its own Makefile.local
-subdirs = compat completion emacs lib util test
+subdirs = compat completion emacs lib man util test
# We make all targets depend on the Makefiles themselves.
global_deps = Makefile Makefile.config Makefile.local \
FINAL_LIBNOTMUCH_LDFLAGS = $(LDFLAGS) $(AS_NEEDED_LDFLAGS) $(CONFIGURE_LDFLAGS)
.PHONY: all
-all: notmuch notmuch-shared notmuch.1.gz
+all: notmuch notmuch-shared
ifeq ($(MAKECMDGOALS),)
ifeq ($(shell cat .first-build-message 2>/dev/null),)
@NOTMUCH_FIRST_BUILD=1 $(MAKE) --no-print-directory all
.PHONY: update-versions
-update-versions:
- sed -i "s/^.TH NOTMUCH 1.*$$/.TH NOTMUCH 1 ${DATE} \"Notmuch ${VERSION}\"/" notmuch.1
+update-versions: update-man-versions
sed -i "s/^__VERSION__[[:blank:]]*=.*$$/__VERSION__ = \'${VERSION}\'/" $(PV_FILE)
# We invoke make recursively only to force ordering of our phony
echo "Please edit version and $(PV_FILE) to have consistent versions." && false)
@echo "Good."
-.PHONY: verify-version-manpage
-verify-version-manpage: verify-version-components
- @echo -n "Checking that manual page version is $(VERSION)..."
- @[ "$(VERSION)" = $$(sed -n '/^[.]TH NOTMUCH 1/{s/.*"Notmuch //;s/".*//p;}' notmuch.1) ] || \
- (echo "No." && \
- echo "Please edit version and notmuch.1 to have consistent versions." && false)
- @echo "Good."
-
.PHONY: verify-version-components
verify-version-components:
@echo -n "Checking that $(VERSION) consists only of digits and periods..."
notmuch-time.c \
query-string.c \
show-message.c \
+ mime-node.c \
json.c
notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
notmuch-shared: $(notmuch_client_modules) lib/$(LINKER_NAME)
$(call quiet,$(FINAL_NOTMUCH_LINKER) $(CFLAGS)) $(notmuch_client_modules) $(FINAL_NOTMUCH_LDFLAGS) -o $@
-notmuch.1.gz: notmuch.1
- gzip --stdout $^ > $@
-
.PHONY: install
-install: all notmuch.1.gz
- mkdir -p "$(DESTDIR)$(mandir)/man1"
- install -m0644 notmuch.1.gz "$(DESTDIR)$(mandir)/man1/"
+install: all install-man
mkdir -p "$(DESTDIR)$(prefix)/bin/"
install notmuch-shared "$(DESTDIR)$(prefix)/bin/notmuch"
ifeq ($(MAKECMDGOALS), install)
desktop-file-install --mode 0644 --dir "$(DESTDIR)$(desktop_dir)" notmuch.desktop
SRCS := $(SRCS) $(notmuch_client_srcs)
-CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) notmuch.elc notmuch.1.gz
+CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) notmuch.elc
import email
from notmuch import Database, Query, NotmuchError, STATUS
-from ConfigParser import SafeConfigParser
+try:
+ # python3.x
+ from configparser import SafeConfigParser
+except ImportError:
+ # python2.x
+ from ConfigParser import SafeConfigParser
from cStringIO import StringIO
PREFIX = re.compile('(\w+):(.*$)')
removed.
"""
self._assert_db_is_initialized()
- return self._remove_message(self._db, filename)
+ return self._remove_message(self._db, _str(filename))
def find_message(self, msgid):
"""Returns a :class:`Message` as identified by its message ID
""" Reads a user's notmuch config and returns his db location
Throws a NotmuchError if it cannot find it"""
- from ConfigParser import SafeConfigParser
+ try:
+ # python3.x
+ from configparser import SafeConfigParser
+ except ImportError:
+ # python2.x
+ from ConfigParser import SafeConfigParser
+
config = SafeConfigParser()
conf_f = os.getenv('NOTMUCH_CONFIG',
os.path.expanduser('~/.notmuch-config'))
_move_to_next.argtypes = [NotmuchFilenamesP]
_move_to_next.restype = None
- def next(self):
+ def __next__(self):
if self._files_p is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
self._files_p = None
raise StopIteration
- file = Filenames._get(self._files_p)
+ file_ = Filenames._get(self._files_p)
self._move_to_next(self._files_p)
- return file
+ return file_.decode('utf-8', 'ignore')
+ next = __next__ # python2.x iterator protocol compatibility
def __len__(self):
"""len(:class:`Filenames`) returns the number of contained files
"""
from ctypes import c_char_p
from notmuch.globals import (nmlib, STATUS, NotmuchError,
- NotmuchFilenamesP, NotmuchMessageP)
+ NotmuchFilenamesP, NotmuchMessageP, _str, Python3StringMixIn)
-class Filenames(object):
+class Filenames(Python3StringMixIn):
"""Represents a list of filenames as returned by notmuch
This object contains the Filenames iterator. The main function is
raise NotmuchError(STATUS.NOT_INITIALIZED)
while self._valid(self._files):
- yield Filenames._get(self._files)
+ yield Filenames._get(self._files).decode('utf-8', 'ignore')
self._move_to_next(self._files)
self._files = None
- def __str__(self):
- return unicode(self).encode('utf-8')
-
def __unicode__(self):
"""Represent Filenames() as newline-separated list of full paths
Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
"""
-
+import sys
from ctypes import CDLL, c_char_p, c_int, Structure, POINTER
#-----------------------------------------------------------------------------
raise ImportError("Could not find shared 'notmuch' library.")
+if sys.version_info[0] == 2:
+ class Python3StringMixIn(object):
+ def __str__(self):
+ return unicode(self).encode('utf-8')
+else:
+ class Python3StringMixIn(object):
+ def __str__(self):
+ return self.__unicode__()
+
+
class Enum(object):
"""Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
def __init__(self, names):
"""Get a (unicode) string representation of a notmuch_status_t value."""
# define strings for custom error messages
if status == STATUS.NOT_INITIALIZED:
- return u"Operation on uninitialized object impossible."
+ return "Operation on uninitialized object impossible."
return unicode(Status._status2str(status))
STATUS = Status(['SUCCESS',
STATUS.__name__ = 'STATUS'
-class NotmuchError(Exception):
+class NotmuchError(Exception, Python3StringMixIn):
"""Is initiated with a (notmuch.STATUS[, message=None]). It will not
return an instance of the class NotmuchError, but a derived instance
of a more specific Error Message, e.g. OutOfMemoryError. Each status
self.status = status
self.message = message
- def __str__(self):
- return unicode(self).encode('utf-8')
-
def __unicode__(self):
if self.message is not None:
return self.message
elif self.status is not None:
return STATUS.status2str(self.status)
else:
- return u'Unknown error'
+ return 'Unknown error'
# List of Subclassed exceptions that correspond to STATUS values and are
from ctypes import c_char_p, c_long, c_uint, c_int
from datetime import date
-from notmuch.globals import (nmlib, STATUS, NotmuchError, Enum, _str,
+from notmuch.globals import (
+ nmlib, STATUS, NotmuchError, Enum, _str, Python3StringMixIn,
NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP)
from notmuch.tag import Tags
from notmuch.filename import Filenames
_move_to_next.argtypes = [NotmuchMessagesP]
_move_to_next.restype = None
- def next(self):
+ def __next__(self):
if self._msgs is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
msg = Message(Messages._get(self._msgs), self)
self._move_to_next(self._msgs)
return msg
+ next = __next__ # python2.x iterator protocol compatibility
def __nonzero__(self):
"""
if self._msgs is not None:
self._destroy(self._msgs)
- def print_messages(self, format, indent=0, entire_thread=False):
- """Outputs messages as needed for 'notmuch show' to sys.stdout
+ def format_messages(self, format, indent=0, entire_thread=False):
+ """Formats messages as needed for 'notmuch show'.
:param format: A string of either 'text' or 'json'.
:param indent: A number indicating the reply depth of these messages.
:param entire_thread: A bool, indicating whether we want to output
whole threads or only the matching messages.
+ :return: a list of lines
"""
+ result = list()
+
if format.lower() == "text":
set_start = ""
set_end = ""
first_set = True
- sys.stdout.write(set_start)
+ result.append(set_start)
# iterate through all toplevel messages in this thread
for msg in self:
# if not msg:
# break
if not first_set:
- sys.stdout.write(set_sep)
+ result.append(set_sep)
first_set = False
- sys.stdout.write(set_start)
+ result.append(set_start)
match = msg.is_match()
next_indent = indent
if (match or entire_thread):
if format.lower() == "text":
- sys.stdout.write(msg.format_message_as_text(indent))
+ result.append(msg.format_message_as_text(indent))
else:
- sys.stdout.write(msg.format_message_as_json(indent))
+ result.append(msg.format_message_as_json(indent))
next_indent = indent + 1
# get replies and print them also out (if there are any)
- replies = msg.get_replies()
- if not replies is None:
- sys.stdout.write(set_sep)
- replies.print_messages(format, next_indent, entire_thread)
+ replies = msg.get_replies().format_messages(format, next_indent, entire_thread)
+ if replies:
+ result.append(set_sep)
+ result.extend(replies)
+
+ result.append(set_end)
+ result.append(set_end)
+
+ return result
+
+ def print_messages(self, format, indent=0, entire_thread=False, handle=sys.stdout):
+ """Outputs messages as needed for 'notmuch show' to a file like object.
+
+ :param format: A string of either 'text' or 'json'.
+ :param handle: A file like object to print to (default is sys.stdout).
+ :param indent: A number indicating the reply depth of these messages.
+ :param entire_thread: A bool, indicating whether we want to output
+ whole threads or only the matching messages.
+ """
+ handle.write(''.join(self.format_messages(format, indent, entire_thread)))
+
+
+class EmptyMessagesResult(Messages):
+ def __init__(self, parent):
+ self._msgs = None
+ self._parent = parent
- sys.stdout.write(set_end)
- sys.stdout.write(set_end)
+ def __next__(self):
+ raise StopIteration()
+ next = __next__
-class Message(object):
+class Message(Python3StringMixIn):
"""Represents a single Email message
Technically, this wraps the underlying *notmuch_message_t*
"""
if self._msg is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
- return Message._get_message_id(self._msg)
+ return Message._get_message_id(self._msg).decode('utf-8', 'ignore')
def get_thread_id(self):
"""Returns the thread ID
if self._msg is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
- return Message._get_thread_id(self._msg)
+ return Message._get_thread_id(self._msg).decode('utf-8', 'ignore')
def get_replies(self):
"""Gets all direct replies to this message as :class:`Messages`
number of subsequent calls to :meth:`get_replies`). If this message
was obtained through some non-thread means, (such as by a call to
:meth:`Query.search_messages`), then this function will return
- `None`.
+ an empty Messages iterator.
- :returns: :class:`Messages` or `None` if there are no replies to
- this message.
+ :returns: :class:`Messages`.
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
is not initialized.
"""
msgs_p = Message._get_replies(self._msg)
if msgs_p is None:
- return None
+ return EmptyMessagesResult(self)
return Messages(msgs_p, self)
raise NotmuchError(STATUS.NOT_INITIALIZED)
#Returns NULL if any error occurs.
- header = Message._get_header(self._msg, header)
+ header = Message._get_header(self._msg, _str(header))
if header == None:
raise NotmuchError(STATUS.NULL_POINTER)
- return header.decode('UTF-8', errors='ignore')
+ return header.decode('UTF-8', 'ignore')
def get_filename(self):
"""Returns the file path of the message file
"""
if self._msg is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
- return Message._get_filename(self._msg)
+ return Message._get_filename(self._msg).decode('utf-8', 'ignore')
def get_filenames(self):
"""Get all filenames for the email corresponding to 'message'
"""Represent a Message() object by str()"""
return self.__str__()
- def __str__(self):
- return unicode(self).encode('utf-8')
-
def __unicode__(self):
format = "%s (%s) (%s)"
return format % (self.get_header('from'),
Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
"""
from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP
+from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, _str, Python3StringMixIn
-class Tags(object):
+class Tags(Python3StringMixIn):
"""Represents a list of notmuch tags
This object provides an iterator over a list of notmuch tags (which
_move_to_next.argtypes = [NotmuchTagsP]
_move_to_next.restype = None
- def next(self):
+ def __next__(self):
if self._tags is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
if not self._valid(self._tags):
tag = Tags._get(self._tags).decode('UTF-8')
self._move_to_next(self._tags)
return tag
+ next = __next__ # python2.x iterator protocol compatibility
def __nonzero__(self):
"""Implement bool(Tags) check that can be repeatedly used
left."""
return self._valid(self._tags) > 0
- def __str__(self):
- return unicode(self).encode('utf-8')
-
def __unicode__(self):
"""string representation of :class:`Tags`: a space separated list of tags
from ctypes import c_char_p, c_long, c_int
from notmuch.globals import (nmlib, STATUS,
NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP,
- NotmuchTagsP,)
+ NotmuchTagsP, Python3StringMixIn)
from notmuch.message import Messages
from notmuch.tag import Tags
from datetime import date
-class Threads(object):
+class Threads(Python3StringMixIn):
"""Represents a list of notmuch threads
This object provides an iterator over a list of notmuch threads
_move_to_next.argtypes = [NotmuchThreadsP]
_move_to_next.restype = None
- def next(self):
+ def __next__(self):
if self._threads is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
thread = Thread(Threads._get(self._threads), self)
self._move_to_next(self._threads)
return thread
+ next = __next__ # python2.x iterator protocol compatibility
def __len__(self):
"""len(:class:`Threads`) returns the number of contained Threads
"""
if self._thread is None:
raise NotmuchError(STATUS.NOT_INITIALIZED)
- return Thread._get_thread_id(self._thread)
+ return Thread._get_thread_id(self._thread).decode('utf-8', 'ignore')
_get_total_messages = nmlib.notmuch_thread_get_total_messages
_get_total_messages.argtypes = [NotmuchThreadP]
authors = Thread._get_authors(self._thread)
if authors is None:
return None
- return authors.decode('UTF-8', errors='ignore')
+ return authors.decode('UTF-8', 'ignore')
def get_subject(self):
"""Returns the Subject of 'thread'
subject = Thread._get_subject(self._thread)
if subject is None:
return None
- return subject.decode('UTF-8', errors='ignore')
+ return subject.decode('UTF-8', 'ignore')
def get_newest_date(self):
"""Returns time_t of the newest message date
raise NotmuchError(STATUS.NULL_POINTER)
return Tags(tags_p, self)
- def __str__(self):
- return unicode(self).encode('utf-8')
-
def __unicode__(self):
frm = "thread:%s %12s [%d/%d] %s; %s (%s)"
# get the notmuch version number without importing the notmuch module
version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'notmuch', 'version.py')
-execfile(version_file)
+exec(compile(open(version_file).read(), version_file, 'exec'))
assert __VERSION__, 'Failed to read the notmuch binding version number'
setup(name='notmuch',
usr/bin
-usr/share/man/man1
+usr/share/man
etc/bash_completion.d
:notify #'notmuch-hello-widget-search
:notmuch-search-terms query
formatted-name)
- ;; Insert enough space to consume the rest of the
- ;; column. Because the button for the name is `(1+
- ;; (length name))' long (due to the trailing space) we
- ;; can just insert `(- widest (length name))' spaces -
- ;; the column separator is included in the button if
- ;; `(equal widest (length name)'.
- (widget-insert (make-string (max 1
- (- widest (length name)))
- ? ))))
+ (unless (eq (% count tags-per-line) (1- tags-per-line))
+ ;; If this is not the last tag on the line, insert
+ ;; enough space to consume the rest of the column.
+ ;; Because the button for the name is `(1+ (length
+ ;; name))' long (due to the trailing space) we can
+ ;; just insert `(- widest (length name))' spaces - the
+ ;; column separator is included in the button if
+ ;; `(equal widest (length name)'.
+ (widget-insert (make-string (max 1
+ (- widest (length name)))
+ ? )))))
(setq count (1+ count))
(if (eq (% count tags-per-line) 0)
(widget-insert "\n")))
(if (re-search-backward message-signature-separator nil t)
(forward-line -1)
(goto-char (point-max)))
- (insert body))
+ (insert body)
+ (push-mark))
(set-buffer-modified-p nil)
(message-goto-body))
:group 'notmuch
:type 'hook)
-(defcustom notmuch-show-insert-text/plain-hook '(notmuch-wash-excerpt-citations)
+(defcustom notmuch-show-insert-text/plain-hook '(notmuch-wash-wrap-long-lines
+ notmuch-wash-tidy-citations
+ notmuch-wash-elide-blank-lines
+ notmuch-wash-excerpt-citations)
"Functions used to improve the display of text/plain parts."
:group 'notmuch
:type 'hook
nil))
nil))))
+;; Handler for wash generated inline patch fake parts.
+(defun notmuch-show-insert-part-inline-patch-fake-part (msg part content-type nth depth declared-type)
+ (notmuch-show-insert-part-*/* msg part "text/x-diff" nth depth "inline patch"))
+
(defun notmuch-show-insert-part-*/* (msg part content-type nth depth declared-type)
;; This handler _must_ succeed - it is the handler of last resort.
(notmuch-show-insert-part-header nth content-type declared-type (plist-get part :filename))
(defvar diff-file-header-re) ; From `diff-mode.el'.
+(defun notmuch-wash-subject-to-filename (subject &optional maxlen)
+ "Convert a mail SUBJECT into a filename.
+
+The resulting filename is similar to the names generated by \"git
+format-patch\", without the leading patch sequence number
+\"0001-\" and \".patch\" extension. Any leading \"[PREFIX]\"
+style strings are removed prior to conversion.
+
+Optional argument MAXLEN is the maximum length of the resulting
+filename, before trimming any trailing . and - characters."
+ (let* ((s (replace-regexp-in-string "^ *\\(\\[[^]]*\\] *\\)*" "" subject))
+ (s (replace-regexp-in-string "[^A-Za-z0-9._]+" "-" s))
+ (s (replace-regexp-in-string "\\.+" "." s))
+ (s (if maxlen (substring s 0 (min (length s) maxlen)) s))
+ (s (replace-regexp-in-string "[.-]*$" "" s)))
+ s))
+
+(defun notmuch-wash-subject-to-patch-sequence-number (subject)
+ "Convert a patch mail SUBJECT into a patch sequence number.
+
+Return the patch sequence number N from the last \"[PATCH N/M]\"
+style prefix in SUBJECT, or nil if such a prefix can't be found."
+ (when (string-match
+ "^ *\\(\\[[^]]*\\] *\\)*\\[[^]]*?\\([0-9]+\\)/[0-9]+[^]]*\\].*"
+ subject)
+ (string-to-number (substring subject (match-beginning 2) (match-end 2)))))
+
+(defun notmuch-wash-subject-to-patch-filename (subject)
+ "Convert a patch mail SUBJECT into a filename.
+
+The resulting filename is similar to the names generated by \"git
+format-patch\". If the patch mail was generated and sent using
+\"git format-patch/send-email\", this should re-create the
+original filename the sender had."
+ (format "%04d-%s.patch"
+ (or (notmuch-wash-subject-to-patch-sequence-number subject) 1)
+ (notmuch-wash-subject-to-filename subject 52)))
+
(defun notmuch-wash-convert-inline-patch-to-part (msg depth)
"Convert an inline patch into a fake 'text/x-diff' attachment.
(setq patch-end (match-beginning 0)))
(save-restriction
(narrow-to-region patch-start patch-end)
- (setq part (plist-put part :content-type "text/x-diff"))
+ (setq part (plist-put part :content-type "inline-patch-fake-part"))
(setq part (plist-put part :content (buffer-string)))
(setq part (plist-put part :id -1))
- (setq part (plist-put part :filename "inline patch"))
+ (setq part (plist-put part :filename
+ (notmuch-wash-subject-to-patch-filename
+ (plist-get
+ (plist-get msg :headers) :Subject))))
(delete-region (point-min) (point-max))
(notmuch-show-insert-bodypart nil part depth))))))
"\t"
(notmuch-documentation-first-line action))))))
-(defalias 'notmuch-substitute-one-command-key
- (apply-partially 'notmuch-substitute-one-command-key-with-prefix nil))
+(defun notmuch-substitute-command-keys-one (key)
+ ;; A `keymap' key indicates inheritance from a parent keymap - the
+ ;; inherited mappings follow, so there is nothing to print for
+ ;; `keymap' itself.
+ (when (not (eq key 'keymap))
+ (notmuch-substitute-one-command-key-with-prefix nil key)))
(defun notmuch-substitute-command-keys (doc)
"Like `substitute-command-keys' but with documentation, not function names."
(let ((beg 0))
(while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
- (let ((map (substring doc (match-beginning 1) (match-end 1))))
- (setq doc (replace-match (mapconcat 'notmuch-substitute-one-command-key
- (cdr (symbol-value (intern map))) "\n") 1 1 doc)))
+ (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1)))
+ (keymap (symbol-value (intern keymap-name))))
+ (setq doc (replace-match
+ (mapconcat #'notmuch-substitute-command-keys-one
+ (cdr keymap) "\n")
+ 1 1 doc)))
(setq beg (match-end 0)))
doc))
"*")
32 nil nil t))
crypto-switch)
- (error "End of search results"))))
+ (message "End of search results."))))
(defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
"Begin composing a reply to the entire current thread in a new buffer."
if (i > 1)
fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n");
}
+ if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) {
+ /* Don't index encrypted parts. */
+ continue;
+ }
_index_mime_part (message,
g_mime_multipart_get_part (multipart, i));
}
void
notmuch_messages_move_to_next (notmuch_messages_t *messages)
{
- if (! messages->is_of_list_type)
- return _notmuch_mset_messages_move_to_next (messages);
+ if (! messages->is_of_list_type) {
+ _notmuch_mset_messages_move_to_next (messages);
+ return;
+ }
if (messages->iterator == NULL)
return;
--- /dev/null
+all:
+ $(MAKE) -C .. all
+
+.DEFAULT:
+ $(MAKE) -C .. $@
--- /dev/null
+# -*- Makefile -*-
+
+dir := man
+
+# this variable seems to be needed to prevent lazy evaluation causing
+# problems with $(dir) changing values.
+MAIN_PAGE := $(dir)/man1/notmuch.1
+
+MAN1 := \
+ $(MAIN_PAGE) \
+ $(dir)/man1/notmuch-config.1 \
+ $(dir)/man1/notmuch-count.1 \
+ $(dir)/man1/notmuch-dump.1 \
+ $(dir)/man1/notmuch-restore.1 \
+ $(dir)/man1/notmuch-new.1 \
+ $(dir)/man1/notmuch-reply.1 \
+ $(dir)/man1/notmuch-search.1 \
+ $(dir)/man1/notmuch-show.1 \
+ $(dir)/man1/notmuch-tag.1
+
+MAN5 := $(dir)/man5/notmuch-hooks.5
+MAN7 := $(dir)/man7/notmuch-search-terms.7
+
+MAN1_GZ := $(addsuffix .gz,$(MAN1))
+MAN5_GZ := $(addsuffix .gz,$(MAN5))
+MAN7_GZ := $(addsuffix .gz,$(MAN7))
+
+MAN_SOURCE := $(MAN1) $(MAN5) $(MAN7)
+MAN_BACKUP := $(addsuffix .bak,$(MAN_SOURCE))
+COMPRESSED_MAN := $(MAN1_GZ) $(MAN5_GZ) $(MAN7_GZ)
+
+%.gz: %
+ gzip --stdout $^ > $@
+
+.PHONY: install-man update-man-versions verify-version-manpage
+
+install-man: $(COMPRESSED_MAN)
+ mkdir -p "$(DESTDIR)$(mandir)/man1"
+ mkdir -p "$(DESTDIR)$(mandir)/man5"
+ mkdir -p "$(DESTDIR)$(mandir)/man7"
+ install -m0644 $(MAN1_GZ) $(DESTDIR)/$(mandir)/man1
+ install -m0644 $(MAN5_GZ) $(DESTDIR)/$(mandir)/man5
+ install -m0644 $(MAN7_GZ) $(DESTDIR)/$(mandir)/man7
+ cd $(DESTDIR)/$(mandir)/man1 && ln -sf notmuch.1.gz notmuch-setup.1.gz
+
+verify-version-manpage: verify-version-components
+ @echo -n "Checking that manual page version is $(VERSION)..."
+ @[ "$(VERSION)" = $$(sed -n '/^[.]TH NOTMUCH 1/{s/.*"Notmuch //;s/".*//p;}' $(MAIN_PAGE)) ] || \
+ (echo "No." && \
+ echo "Please edit version and notmuch.1 to have consistent versions." && false)
+ @echo "Good."
+
+update-man-versions: $(MAN_SOURCE)
+ for file in $(MAN_SOURCE); do \
+ cp $$file $$file.bak ; \
+ sed "s/^.TH NOTMUCH\([^[:blank:]]*\) \([1-9]\) .*$$/.TH NOTMUCH\1 \2 ${DATE} \"Notmuch ${VERSION}\"/" \
+ < $$file.bak > $$file; \
+ done
+
+CLEAN := $(CLEAN) $(COMPRESSED_MAN) $(MAN_BACKUP)
--- /dev/null
+.TH NOTMUCH-CONFIG 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-config \- Output a single part of a multipart MIME message.
+.SH SYNOPSIS
+
+.B notmuch config get
+.RI "<" section "> . <" item ">"
+
+.B notmuch config set
+.RI "<" section "> . <" item "> [" value "]"
+
+.SH DESCRIPTION
+
+The
+.B config
+command can be used to get or set settings in the notmuch
+configuration file.
+
+.SS GET
+
+The value of the specified configuration item is printed to stdout. If
+the item has multiple values, each value is separated by a newline
+character.
+
+Available configuration items include at least
+
+ database.path
+
+ user.name
+
+ user.primary_email
+
+ user.other_email
+
+ new.tags
+
+.SS SET
+
+The specified configuration item is set to the given value. To
+specify a multiple-value item, provide each value as a separate
+command-line argument.
+
+If no values are provided, the specified configuration item will be
+removed from the configuration file.
+.RE
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-part\fR(1), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
+\fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-COUNT 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-count \- Count messages matching the given search terms.
+.SH SYNOPSIS
+
+.B notmuch count
+.RI [ options "... ] <" search-term ">..."
+
+.SH DESCRIPTION
+
+Count messages matching the search terms.
+
+The number of matching messages (or threads) is output to stdout.
+
+With no search terms, a count of all messages (or threads) in the database will
+be displayed.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+Supported options for
+.B count
+include
+.RS 4
+.TP 4
+.B \-\-output=(messages|threads)
+
+.RS 4
+.TP 4
+.B messages
+
+Output the number of matching messages. This is the default.
+.RE
+.RS 4
+.TP 4
+.B threads
+
+Output the number of matching threads.
+.RE
+.RE
+.RE
+.RE
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-dump\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-DUMP 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-dump \- Creates a plain-text dump of the tags of each message.
+
+.SH SYNOPSIS
+
+.B "notmuch dump"
+.RI "[ <" filename "> ] [--]"
+.RI "[ <" search-term ">...]"
+
+.SH DESCRIPTION
+
+Dump tags for messages matching the given search terms.
+
+Output is to the given filename, if any, or to stdout. Note that
+using the filename argument is deprecated.
+
+These tags are the only data in the notmuch database that can't be
+recreated from the messages themselves. The output of notmuch dump is
+therefore the only critical thing to backup (and much more friendly to
+incremental backup than the native database files.)
+
+With no search terms, a dump of all messages in the database will be
+generated. A "--" argument instructs notmuch that the
+remaining arguments are search terms.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+.RE
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-NEW 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-new \- Incorporate new mail into the notmuch database.
+.SH SYNOPSIS
+
+.B notmuch new
+.RB "[" --no-hooks "]"
+
+.SH DESCRIPTION
+
+Find and import any new messages to the database.
+
+The
+.B new
+command scans all sub-directories of the database, performing
+full-text indexing on new messages that are found. Each new message
+will automatically be tagged with both the
+.BR inbox " and " unread
+tags.
+
+You should run
+.B "notmuch new"
+once after first running
+.B "notmuch setup"
+to create the initial database. The first run may take a long time if
+you have a significant amount of mail (several hundred thousand
+messages or more). Subsequently, you should run
+.B "notmuch new"
+whenever new mail is delivered and you wish to incorporate it into the
+database. These subsequent runs will be much quicker than the initial
+run.
+
+Invoking
+.B notmuch
+with no command argument will run
+.B new
+if
+.B "notmuch setup"
+has previously been completed, but
+.B "notmuch new"
+has not previously been run.
+
+
+The
+.B new
+command supports hooks. See \fBnotmuch-hooks(5)\fR
+for more details on hooks.
+
+Supported options for
+.B new
+include
+.RS 4
+.TP 4
+.BR \-\-no\-hooks
+
+Prevents hooks from being run.
+.RE
+.RE
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-REPLY 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-reply \- Constructs a reply template for a set of messages.
+
+.SH SYNOPSIS
+
+.B notmuch reply
+.RI "[" options "...] <" search-term ">..."
+
+.SH DESCRIPTION
+
+Constructs a reply template for a set of messages.
+
+To make replying to email easier,
+.B notmuch reply
+takes an existing set of messages and constructs a suitable mail
+template. The Reply-to header (if any, otherwise From:) is used for
+the To: address. Vales from the To: and Cc: headers are copied, but
+not including any of the current user's email addresses (as configured
+in primary_mail or other_email in the .notmuch\-config file) in the
+recipient list
+
+It also builds a suitable new subject, including Re: at the front (if
+not already present), and adding the message IDs of the messages being
+replied to to the References list and setting the In\-Reply\-To: field
+correctly.
+
+Finally, the original contents of the emails are quoted by prefixing
+each line with '> ' and included in the body.
+
+The resulting message template is output to stdout.
+
+Supported options for
+.B reply
+include
+.RS
+.TP 4
+.BR \-\-format= ( default | headers\-only )
+.RS
+.TP 4
+.BR default
+Includes subject and quoted message body.
+.TP
+.BR headers\-only
+Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
+.RE
+.RE
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+Note: It is most common to use
+.B "notmuch reply"
+with a search string matching a single message, (such as
+id:<message-id>), but it can be useful to reply to several messages at
+once. For example, when a series of patches are sent in a single
+thread, replying to the entire thread allows for the reply to comment
+on issue found in multiple patches.
+.RE
+.RE
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-part\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-RESTORE 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-restore \- Restores the tags from the given file (see notmuch dump).
+
+.SH SYNOPSIS
+
+.B "notmuch restore"
+.RB [ "--accumulate" ]
+.RI "[ <" filename "> ]"
+
+.SH DESCRIPTION
+
+Restores the tags from the given file (see
+.BR "notmuch dump" ")."
+
+The input is read from the given filename, if any, or from stdin.
+
+Note: The dump file format is specifically chosen to be
+compatible with the format of files produced by sup-dump.
+So if you've previously been using sup for mail, then the
+.B "notmuch restore"
+command provides you a way to import all of your tags (or labels as
+sup calls them).
+
+The --accumulate switch causes the union of the existing and new tags to be
+applied, instead of replacing each message's tags as they are read in from the
+dump file.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+.RE
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-dump\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-SEARCH 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-search \- Search for messages matching the given search terms.
+.SH SYNOPSIS
+
+.B notmuch search
+.RI [ options "...] <" search-term ">..."
+
+.SH DESCRIPTION
+
+Search for messages matching the given search terms, and display as
+results the threads containing the matched messages.
+
+The output consists of one line per thread, giving a thread ID, the
+date of the newest (or oldest, depending on the sort option) matched
+message in the thread, the number of matched messages and total
+messages in the thread, the names of all participants in the thread,
+and the subject of the newest (or oldest) message.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+Supported options for
+.B search
+include
+.RS 4
+.TP 4
+.BR \-\-format= ( json | text )
+
+Presents the results in either JSON or plain-text (default).
+.RE
+
+.RS 4
+.TP 4
+.B \-\-output=(summary|threads|messages|files|tags)
+
+.RS 4
+.TP 4
+.B summary
+
+Output a summary of each thread with any message matching the search
+terms. The summary includes the thread ID, date, the number of
+messages in the thread (both the number matched and the total number),
+the authors of the thread and the subject.
+.RE
+.RS 4
+.TP 4
+.B threads
+
+Output the thread IDs of all threads with any message matching the
+search terms, either one per line (\-\-format=text) or as a JSON array
+(\-\-format=json).
+.RE
+.RS 4
+.TP 4
+.B messages
+
+Output the message IDs of all messages matching the search terms,
+either one per line (\-\-format=text) or as a JSON array
+(\-\-format=json).
+.RE
+.RS 4
+.TP 4
+.B files
+
+Output the filenames of all messages matching the search terms, either
+one per line (\-\-format=text) or as a JSON array (\-\-format=json).
+.RE
+.RS 4
+.TP 4
+.B tags
+
+Output all tags that appear on any message matching the search terms,
+either one per line (\-\-format=text) or as a JSON array
+(\-\-format=json).
+.RE
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-sort= ( newest\-first | oldest\-first )
+
+This option can be used to present results in either chronological order
+.RB ( oldest\-first )
+or reverse chronological order
+.RB ( newest\-first ).
+
+Note: The thread order will be distinct between these two options
+(beyond being simply reversed). When sorting by
+.B oldest\-first
+the threads will be sorted by the oldest message in each thread, but
+when sorting by
+.B newest\-first
+the threads will be sorted by the newest message in each thread.
+
+By default, results will be displayed in reverse chronological order,
+(that is, the newest results will be displayed first).
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-offset=[\-]N
+
+Skip displaying the first N results. With the leading '\-', start at the Nth
+result from the end.
+.RE
+
+.RS 4
+.TP 4
+.BR \-\-limit=N
+
+Limit the number of displayed results to N.
+.RE
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+notmuch.1
\ No newline at end of file
--- /dev/null
+.TH NOTMUCH-SHOW 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-show \- Show messages matching the given search terms.
+.SH SYNOPSIS
+
+.B notmuch show
+.RI "[" options "...] <" search-term ">..."
+
+.SH DESCRIPTION
+
+Shows all messages matching the search terms.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+The messages will be grouped and sorted based on the threading (all
+replies to a particular message will appear immediately after that
+message in date order). The output is not indented by default, but
+depth tags are printed so that proper indentation can be performed by
+a post-processor (such as the emacs interface to notmuch).
+
+Supported options for
+.B show
+include
+.RS 4
+.TP 4
+.B \-\-entire\-thread
+
+By default only those messages that match the search terms will be
+displayed. With this option, all messages in the same thread as any
+matched message will be displayed.
+.RE
+
+.RS 4
+.TP 4
+.B \-\-format=(text|json|mbox|raw)
+
+.RS 4
+.TP 4
+.BR text " (default for messages)"
+
+The default plain-text format has all text-content MIME parts
+decoded. Various components in the output,
+.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
+will be delimited by easily-parsed markers. Each marker consists of a
+Control-L character (ASCII decimal 12), the name of the marker, and
+then either an opening or closing brace, ('{' or '}'), to either open
+or close the component. For a multipart MIME message, these parts will
+be nested.
+.RE
+.RS 4
+.TP 4
+.B json
+
+The output is formatted with Javascript Object Notation (JSON). This
+format is more robust than the text format for automated
+processing. The nested structure of multipart MIME messages is
+reflected in nested JSON output. JSON output always includes all
+messages in a matching thread; in effect
+.B \-\-format=json
+implies
+.B \-\-entire\-thread
+
+.RE
+.RS 4
+.TP 4
+.B mbox
+
+All matching messages are output in the traditional, Unix mbox format
+with each message being prefixed by a line beginning with "From " and
+a blank line separating each message. Lines in the message content
+beginning with "From " (preceded by zero or more '>' characters) have
+an additional '>' character added. This reversible escaping
+is termed "mboxrd" format and described in detail here:
+
+.nf
+.nh
+http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
+.hy
+.fi
+.
+.RE
+.RS 4
+.TP 4
+.BR raw " (default for a single part, see \-\-part)"
+
+For a message, the original, raw content of the email message is
+output. Consumers of this format should expect to implement MIME
+decoding and similar functions.
+
+For a single part (\-\-part) the raw part content is output after
+performing any necessary MIME decoding.
+
+The raw format must only be used with search terms matching single
+message.
+.RE
+.RE
+
+.RS 4
+.TP 4
+.B \-\-part=N
+
+Output the single decoded MIME part N of a single message. The search
+terms must match only a single message. Message parts are numbered in
+a depth-first walk of the message MIME structure, and are identified
+in the 'json' or 'text' output formats.
+.RE
+
+.RS 4
+.TP 4
+.B \-\-verify
+
+Compute and report the validity of any MIME cryptographic signatures
+found in the selected content (ie. "multipart/signed" parts). Status
+of the signature will be reported (currently only supported with
+--format=json), and the multipart/signed part will be replaced by the
+signed data.
+.RE
+
+.RS 4
+.TP 4
+.B \-\-decrypt
+
+Decrypt any MIME encrypted parts found in the selected content
+(ie. "multipart/encrypted" parts). Status of the decryption will be
+reported (currently only supported with --format=json) and the
+multipart/encrypted part will be replaced by the decrypted
+content.
+.RE
+
+A common use of
+.B notmuch show
+is to display a single thread of email messages. For this, use a
+search term of "thread:<thread-id>" as can be seen in the first
+column of output from the
+.B notmuch search
+command.
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-part\fR(1), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-search-terms\fR(7), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-TAG 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch-tag \- Add/remove tags for all messages matching the search terms.
+
+.SH SYNOPSIS
+.B notmuch tag
+.RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..."
+
+.SH DESCRIPTION
+
+Add/remove tags for all messages matching the search terms.
+
+See \fBnotmuch-search-terms\fR(7)
+for details of the supported syntax for <search-terms>.
+
+Tags prefixed by '+' are added while those prefixed by '\-' are
+removed. For each message, tag removal is performed before tag
+addition.
+
+The beginning of <search-terms> is recognized by the first
+argument that begins with neither '+' nor '\-'. Support for
+an initial search term beginning with '+' or '\-' is provided
+by allowing the user to specify a "\-\-" argument to separate
+the tags from the search terms.
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-part\fR(1), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1)
--- /dev/null
+.\" notmuch - Not much of an email program, (just index, search and tagging)
+.\"
+.\" Copyright © 2009 Carl Worth
+.\"
+.\" Notmuch is free software: you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" Notmuch is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see http://www.gnu.org/licenses/ .
+.\"
+.\" Author: Carl Worth <cworth@cworth.org>
+.TH NOTMUCH 1 2011-12-04 "Notmuch 0.10.2"
+.SH NAME
+notmuch \- thread-based email index, search, and tagging
+.SH SYNOPSIS
+.B notmuch
+.IR command " [" args " ...]"
+.SH DESCRIPTION
+Notmuch is a command-line based program for indexing, searching,
+reading, and tagging large collections of email messages.
+
+This page describes how to get started using notmuch from the command
+line, and gives a brief overview of the commands available. For more
+information on e.g.
+.B notmuch show
+consult the \fBnotmuch-show\fR(1) man page, also accessible via
+.B notmuch help show
+
+The quickest way to get started with Notmuch is to simply invoke the
+.B notmuch
+command with no arguments, which will interactively guide you through
+the process of indexing your mail.
+.SH NOTE
+While the command-line program
+.B notmuch
+provides powerful functionality, it does not provide the most
+convenient interface for that functionality. More sophisticated
+interfaces are expected to be built on top of either the command-line
+interface, or more likely, on top of the notmuch library
+interface. See http://notmuchmail.org for more about alternate
+interfaces to notmuch. The emacs-based interface to notmuch (available under
+.B emacs/
+in the Notmuch source distribution) is probably the most widely used at
+this time.
+
+.SH COMMANDS
+
+
+.SS SETUP
+
+The
+.B notmuch setup
+command is used to configure Notmuch for first use, (or to reconfigure
+it later).
+
+The setup command will prompt for your full name, your primary email
+address, any alternate email addresses you use, and the directory
+containing your email archives. Your answers will be written to a
+configuration file in ${NOTMUCH_CONFIG} (if set) or
+${HOME}/.notmuch-config . This configuration file will be created with
+descriptive comments, making it easy to edit by hand later to change the
+configuration. Or you can run
+.B "notmuch setup"
+again to change the configuration.
+
+The mail directory you specify can contain any number of
+sub-directories and should primarily contain only files with individual
+email messages (eg. maildir or mh archives are perfect). If there are
+other, non-email files (such as indexes maintained by other email
+programs) then notmuch will do its best to detect those and ignore
+them.
+
+Mail storage that uses mbox format, (where one mbox file contains many
+messages), will not work with notmuch. If that's how your mail is
+currently stored, it is recommended you first convert it to maildir
+format with a utility such as mb2md before running
+.B "notmuch setup" .
+
+Invoking
+.B notmuch
+with no command argument will run
+.B setup
+if the setup command has not previously been completed.
+.RE
+
+.SS OTHER COMMANDS
+
+Several of the notmuch commands accept search terms with a common
+syntax. See \fNnotmuch-search-terms\fR(7)
+for more details on the supported syntax.
+
+The
+.BR search ", " show " and " count
+commands are used to query the email database.
+
+The
+.B reply
+command is useful for preparing a template for an email reply.
+
+The
+.B tag
+command is the only command available for manipulating database
+contents.
+
+
+The
+.BR dump " and " restore
+commands can be used to create a textual dump of email tags for backup
+purposes, and to restore from that dump.
+
+The
+.B config
+command can be used to get or set settings int the notmuch
+configuration file.
+
+.SH ENVIRONMENT
+The following environment variables can be used to control the
+behavior of notmuch.
+.TP
+.B NOTMUCH_CONFIG
+Specifies the location of the notmuch configuration file. Notmuch will
+use ${HOME}/.notmuch\-config if this variable is not set.
+.SH SEE ALSO
+
+\fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-part\fR(1), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
+\fBnotmuch-tag\fR(1)
+
+
+The notmuch website:
+.B http://notmuchmail.org
+.SH CONTACT
+Feel free to send questions, comments, or kudos to the notmuch mailing
+list <notmuch@notmuchmail.org> . Subscription is not required before
+posting, but is available from the notmuchmail.org website.
+
+Real-time interaction with the Notmuch community is available via IRC
+(server: irc.freenode.net, channel: #notmuch).
--- /dev/null
+.TH NOTMUCH-HOOKS 5 2011-12-04 "Notmuch 0.10.2"
+
+.SH NAME
+notmuch-hooks \- hooks for notmuch
+
+.SH SYNOPSIS
+ $DATABASEDIR/.notmuch/hooks/*
+
+.SH DESCRIPTION
+Hooks are scripts (or arbitrary executables or symlinks to such) that notmuch
+invokes before and after certain actions. These scripts reside in
+the .notmuch/hooks directory within the database directory and must have
+executable permissions.
+
+The currently available hooks are described below.
+.RS 4
+.TP 4
+.B pre\-new
+This hook is invoked by the
+.B new
+command before scanning or importing new messages into the database. If this
+hook exits with a non-zero status, notmuch will abort further processing of the
+.B new
+command.
+
+Typically this hook is used for fetching or delivering new mail to be imported
+into the database.
+.RE
+.RS 4
+.TP 4
+.B post\-new
+This hook is invoked by the
+.B new
+command after new messages have been imported into the database and initial tags
+have been applied. The hook will not be run if there have been any errors during
+the scan or import.
+
+Typically this hook is used to perform additional query\-based tagging on the
+imported messages.
+.RE
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search-terms\fR(7),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+.TH NOTMUCH-SEARCH-TERMS 7 2011-12-04 "Notmuch 0.10.2"
+
+.SH NAME
+notmuch-search-terms \- Syntax for notmuch queries
+
+.SH SYNOPSIS
+
+.B notmuch count
+.RI [ options... ]
+.RI < search-term ">..."
+
+.B "notmuch dump"
+.RI "[ <" filename "> ] [--]"
+.RI "[ <" search-term ">...]"
+
+.B notmuch search
+.RI [ options "...] <" search-term ">..."
+
+.B notmuch show
+.RI "[" options "...] <" search-term ">..."
+
+.B notmuch tag
+.RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..."
+
+
+.SH DESCRIPTION
+Several notmuch commands accept a common syntax for search terms.
+
+The search terms can consist of free-form text (and quoted phrases)
+which will match all messages that contain all of the given
+terms/phrases in the body, the subject, or any of the sender or
+recipient headers.
+
+As a special case, a search string consisting of exactly a single
+asterisk ("*") will match all messages.
+
+In addition to free text, the following prefixes can be used to force
+terms to match against specific portions of an email, (where
+<brackets> indicate user-supplied values):
+
+ from:<name-or-address>
+
+ to:<name-or-address>
+
+ subject:<word-or-quoted-phrase>
+
+ attachment:<word>
+
+ tag:<tag> (or is:<tag>)
+
+ id:<message-id>
+
+ thread:<thread-id>
+
+ folder:<directory-path>
+
+The
+.B from:
+prefix is used to match the name or address of the sender of an email
+message.
+
+The
+.B to:
+prefix is used to match the names or addresses of any recipient of an
+email message, (whether To, Cc, or Bcc).
+
+Any term prefixed with
+.B subject:
+will match only text from the subject of an email. Searching for a
+phrase in the subject is supported by including quotation marks around
+the phrase, immediately following
+.BR subject: .
+
+The
+.B attachment:
+prefix can be used to search for specific filenames (or extensions) of
+attachments to email messages.
+
+For
+.BR tag: " and " is:
+valid tag values include
+.BR inbox " and " unread
+by default for new messages added by
+.B notmuch new
+as well as any other tag values added manually with
+.BR "notmuch tag" .
+
+For
+.BR id: ,
+message ID values are the literal contents of the Message\-ID: header
+of email messages, but without the '<', '>' delimiters.
+
+The
+.B thread:
+prefix can be used with the thread ID values that are generated
+internally by notmuch (and do not appear in email messages). These
+thread ID values can be seen in the first column of output from
+.B "notmuch search"
+
+The
+.B folder:
+prefix can be used to search for email message files that are
+contained within particular directories within the mail store. Only
+the directory components below the top-level mail database path are
+available to be searched.
+
+In addition to individual terms, multiple terms can be
+combined with Boolean operators (
+.BR and ", " or ", " not
+, etc.). Each term in the query will be implicitly connected by a
+logical AND if no explicit operator is provided, (except that terms
+with a common prefix will be implicitly combined with OR until we get
+Xapian defect #402 fixed).
+
+Parentheses can also be used to control the combination of the Boolean
+operators, but will have to be protected from interpretation by the
+shell, (such as by putting quotation marks around any parenthesized
+expression).
+
+Finally, results can be restricted to only messages within a
+particular time range, (based on the Date: header) with a syntax of:
+
+ <initial-timestamp>..<final-timestamp>
+
+Each timestamp is a number representing the number of seconds since
+1970\-01\-01 00:00:00 UTC. This is not the most convenient means of
+expressing date ranges, but until notmuch is fixed to accept a more
+convenient form, one can use the date program to construct
+timestamps. For example, with the bash shell the following syntax would
+specify a date range to return messages from 2009\-10\-01 until the
+current time:
+
+ $(date +%s \-d 2009\-10\-01)..$(date +%s)
+
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(5), \fBnotmuch-hooks\fR(5), \fBnotmuch-part\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
+\fBnotmuch-search\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-show\fR(1), \fBnotmuch-tag\fR(1)
--- /dev/null
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2009 Carl Worth
+ * Copyright © 2009 Keith Packard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/ .
+ *
+ * Authors: Carl Worth <cworth@cworth.org>
+ * Keith Packard <keithp@keithp.com>
+ * Austin Clements <aclements@csail.mit.edu>
+ */
+
+#include "notmuch-client.h"
+
+/* Context that gets inherited from the root node. */
+typedef struct mime_node_context {
+ /* Per-message resources. These are allocated internally and must
+ * be destroyed. */
+ FILE *file;
+ GMimeStream *stream;
+ GMimeParser *parser;
+ GMimeMessage *mime_message;
+
+ /* Context provided by the caller. */
+ GMimeCipherContext *cryptoctx;
+ notmuch_bool_t decrypt;
+} mime_node_context_t;
+
+static int
+_mime_node_context_free (mime_node_context_t *res)
+{
+ if (res->mime_message)
+ g_object_unref (res->mime_message);
+
+ if (res->parser)
+ g_object_unref (res->parser);
+
+ if (res->stream)
+ g_object_unref (res->stream);
+
+ if (res->file)
+ fclose (res->file);
+
+ return 0;
+}
+
+notmuch_status_t
+mime_node_open (const void *ctx, notmuch_message_t *message,
+ GMimeCipherContext *cryptoctx, notmuch_bool_t decrypt,
+ mime_node_t **root_out)
+{
+ const char *filename = notmuch_message_get_filename (message);
+ mime_node_context_t *mctx;
+ mime_node_t *root;
+ notmuch_status_t status;
+
+ root = talloc_zero (ctx, mime_node_t);
+ if (root == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ status = NOTMUCH_STATUS_OUT_OF_MEMORY;
+ goto DONE;
+ }
+
+ /* Create the tree-wide context */
+ mctx = talloc_zero (root, mime_node_context_t);
+ if (mctx == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ status = NOTMUCH_STATUS_OUT_OF_MEMORY;
+ goto DONE;
+ }
+ talloc_set_destructor (mctx, _mime_node_context_free);
+
+ mctx->file = fopen (filename, "r");
+ if (! mctx->file) {
+ fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
+ status = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+ mctx->stream = g_mime_stream_file_new (mctx->file);
+ g_mime_stream_file_set_owner (GMIME_STREAM_FILE (mctx->stream), FALSE);
+
+ mctx->parser = g_mime_parser_new_with_stream (mctx->stream);
+
+ mctx->mime_message = g_mime_parser_construct_message (mctx->parser);
+
+ mctx->cryptoctx = cryptoctx;
+ mctx->decrypt = decrypt;
+
+ /* Create the root node */
+ root->part = GMIME_OBJECT (mctx->mime_message);
+ root->envelope_file = message;
+ root->nchildren = 1;
+ root->ctx = mctx;
+
+ *root_out = root;
+ return NOTMUCH_STATUS_SUCCESS;
+
+DONE:
+ talloc_free (root);
+ return status;
+}
+
+static int
+_signature_validity_free (GMimeSignatureValidity **proxy)
+{
+ g_mime_signature_validity_free (*proxy);
+ return 0;
+}
+
+static mime_node_t *
+_mime_node_create (const mime_node_t *parent, GMimeObject *part)
+{
+ mime_node_t *node = talloc_zero (parent, mime_node_t);
+ GError *err = NULL;
+
+ /* Set basic node properties */
+ node->part = part;
+ node->ctx = parent->ctx;
+ if (!talloc_reference (node, node->ctx)) {
+ fprintf (stderr, "Out of memory.\n");
+ talloc_free (node);
+ return NULL;
+ }
+
+ /* Deal with the different types of parts */
+ if (GMIME_IS_PART (part)) {
+ node->nchildren = 0;
+ } else if (GMIME_IS_MULTIPART (part)) {
+ node->nchildren = g_mime_multipart_get_count (GMIME_MULTIPART (part));
+ } else if (GMIME_IS_MESSAGE_PART (part)) {
+ /* Promote part to an envelope and open it */
+ GMimeMessagePart *message_part = GMIME_MESSAGE_PART (part);
+ GMimeMessage *message = g_mime_message_part_get_message (message_part);
+ node->envelope_part = message_part;
+ node->part = GMIME_OBJECT (message);
+ node->nchildren = 1;
+ } else {
+ fprintf (stderr, "Warning: Unknown mime part type: %s.\n",
+ g_type_name (G_OBJECT_TYPE (part)));
+ talloc_free (node);
+ return NULL;
+ }
+
+ /* Handle PGP/MIME parts */
+ if (GMIME_IS_MULTIPART_ENCRYPTED (part)
+ && node->ctx->cryptoctx && node->ctx->decrypt) {
+ if (node->nchildren != 2) {
+ /* this violates RFC 3156 section 4, so we won't bother with it. */
+ fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
+ "message (must be exactly 2)\n",
+ node->nchildren);
+ } else {
+ GMimeMultipartEncrypted *encrypteddata =
+ GMIME_MULTIPART_ENCRYPTED (part);
+ node->decrypt_attempted = TRUE;
+ node->decrypted_child = g_mime_multipart_encrypted_decrypt
+ (encrypteddata, node->ctx->cryptoctx, &err);
+ if (node->decrypted_child) {
+ node->decrypt_success = node->verify_attempted = TRUE;
+ node->sig_validity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);
+ } else {
+ fprintf (stderr, "Failed to decrypt part: %s\n",
+ (err ? err->message : "no error explanation given"));
+ }
+ }
+ } else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->cryptoctx) {
+ if (node->nchildren != 2) {
+ /* this violates RFC 3156 section 5, so we won't bother with it. */
+ fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
+ "(must be exactly 2)\n",
+ node->nchildren);
+ } else {
+ /* For some reason the GMimeSignatureValidity returned
+ * here is not a const (inconsistent with that
+ * returned by
+ * g_mime_multipart_encrypted_get_signature_validity,
+ * and therefore needs to be properly disposed of.
+ *
+ * In GMime 2.6, they're both non-const, so we'll be able
+ * to clean up this asymmetry. */
+ GMimeSignatureValidity *sig_validity = g_mime_multipart_signed_verify
+ (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);
+ node->verify_attempted = TRUE;
+ node->sig_validity = sig_validity;
+ if (sig_validity) {
+ GMimeSignatureValidity **proxy =
+ talloc (node, GMimeSignatureValidity *);
+ *proxy = sig_validity;
+ talloc_set_destructor (proxy, _signature_validity_free);
+ }
+ }
+ }
+
+ if (node->verify_attempted && !node->sig_validity)
+ fprintf (stderr, "Failed to verify signed part: %s\n",
+ (err ? err->message : "no error explanation given"));
+
+ if (err)
+ g_error_free (err);
+
+ return node;
+}
+
+mime_node_t *
+mime_node_child (const mime_node_t *parent, int child)
+{
+ GMimeObject *sub;
+
+ if (!parent || child < 0 || child >= parent->nchildren)
+ return NULL;
+
+ if (GMIME_IS_MULTIPART (parent->part)) {
+ if (child == 1 && parent->decrypted_child)
+ sub = parent->decrypted_child;
+ else
+ sub = g_mime_multipart_get_part
+ (GMIME_MULTIPART (parent->part), child);
+ } else if (GMIME_IS_MESSAGE (parent->part)) {
+ sub = g_mime_message_get_mime_part (GMIME_MESSAGE (parent->part));
+ } else {
+ /* This should have been caught by message_part_create */
+ INTERNAL_ERROR ("Unexpected GMimeObject type: %s",
+ g_type_name (G_OBJECT_TYPE (parent->part)));
+ }
+ return _mime_node_create (parent, sub);
+}
+
+static mime_node_t *
+_mime_node_seek_dfs_walk (mime_node_t *node, int *n)
+{
+ mime_node_t *ret = NULL;
+ int i;
+
+ if (*n == 0)
+ return node;
+
+ *n -= 1;
+ for (i = 0; i < node->nchildren && !ret; i++) {
+ mime_node_t *child = mime_node_child (node, i);
+ ret = _mime_node_seek_dfs_walk (child, n);
+ if (!ret)
+ talloc_free (child);
+ }
+ return ret;
+}
+
+mime_node_t *
+mime_node_seek_dfs (mime_node_t *node, int n)
+{
+ if (n < 0)
+ return NULL;
+ return _mime_node_seek_dfs_walk (node, &n);
+}
query_string_from_args (void *ctx, int argc, char *argv[]);
notmuch_status_t
-show_message_body (const char *filename,
+show_message_body (notmuch_message_t *message,
const notmuch_show_format_t *format,
notmuch_show_params_t *params);
notmuch_bool_t
debugger_is_active (void);
+/* mime-node.c */
+
+/* mime_node_t represents a single node in a MIME tree. A MIME tree
+ * abstracts the different ways of traversing different types of MIME
+ * parts, allowing a MIME message to be viewed as a generic tree of
+ * parts. Message-type parts have one child, multipart-type parts
+ * have multiple children, and leaf parts have zero children.
+ */
+typedef struct mime_node {
+ /* The MIME object of this part. This will be a GMimeMessage,
+ * GMimePart, GMimeMultipart, or a subclass of one of these.
+ *
+ * This will never be a GMimeMessagePart because GMimeMessagePart
+ * is structurally redundant with GMimeMessage. If this part is a
+ * message (that is, 'part' is a GMimeMessage), then either
+ * envelope_file will be set to a notmuch_message_t (for top-level
+ * messages) or envelope_part will be set to a GMimeMessagePart
+ * (for embedded message parts).
+ */
+ GMimeObject *part;
+
+ /* If part is a GMimeMessage, these record the envelope of the
+ * message: either a notmuch_message_t representing a top-level
+ * message, or a GMimeMessagePart representing a MIME part
+ * containing a message.
+ */
+ notmuch_message_t *envelope_file;
+ GMimeMessagePart *envelope_part;
+
+ /* The number of children of this part. */
+ int nchildren;
+
+ /* True if decryption of this part was attempted. */
+ notmuch_bool_t decrypt_attempted;
+ /* True if decryption of this part's child succeeded. In this
+ * case, the decrypted part is substituted for the second child of
+ * this part (which would usually be the encrypted data). */
+ notmuch_bool_t decrypt_success;
+
+ /* True if signature verification on this part was attempted. */
+ notmuch_bool_t verify_attempted;
+ /* For signed or encrypted containers, the validity of the
+ * signature. May be NULL if signature verification failed. If
+ * there are simply no signatures, this will be non-NULL with an
+ * empty signers list. */
+ const GMimeSignatureValidity *sig_validity;
+
+ /* Internal: Context inherited from the root iterator. */
+ struct mime_node_context *ctx;
+
+ /* Internal: For successfully decrypted multipart parts, the
+ * decrypted part to substitute for the second child. */
+ GMimeObject *decrypted_child;
+} mime_node_t;
+
+/* Construct a new MIME node pointing to the root message part of
+ * message. If cryptoctx is non-NULL, it will be used to verify
+ * signatures on any child parts. If decrypt is true, then cryptoctx
+ * will additionally be used to decrypt any encrypted child parts.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Root node is returned in *node_out.
+ *
+ * NOTMUCH_STATUS_FILE_ERROR: Failed to open message file.
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory.
+ */
+notmuch_status_t
+mime_node_open (const void *ctx, notmuch_message_t *message,
+ GMimeCipherContext *cryptoctx, notmuch_bool_t decrypt,
+ mime_node_t **node_out);
+
+/* Return a new MIME node for the requested child part of parent.
+ * parent will be used as the talloc context for the returned child
+ * node.
+ *
+ * In case of any failure, this function returns NULL, (after printing
+ * an error message on stderr).
+ */
+mime_node_t *
+mime_node_child (const mime_node_t *parent, int child);
+
+/* Return the nth child of node in a depth-first traversal. If n is
+ * 0, returns node itself. Returns NULL if there is no such part. */
+mime_node_t *
+mime_node_seek_dfs (mime_node_t *node, int n);
+
#include "command-line-arguments.h"
#endif
notmuch_message_get_header (message, "date"),
notmuch_message_get_header (message, "from"));
- show_message_body (notmuch_message_get_filename (message),
- format, params);
+ show_message_body (message, format, params);
notmuch_message_destroy (message);
}
return 0;
}
+enum {
+ FORMAT_DEFAULT,
+ FORMAT_HEADERS_ONLY,
+};
+
int
notmuch_reply_command (void *ctx, int argc, char *argv[])
{
notmuch_config_t *config;
notmuch_database_t *notmuch;
notmuch_query_t *query;
- char *opt, *query_string;
- int i, ret = 0;
+ char *query_string;
+ int opt_index, ret = 0;
int (*reply_format_func)(void *ctx, notmuch_config_t *config, notmuch_query_t *query, notmuch_show_params_t *params);
notmuch_show_params_t params = { .part = -1 };
+ int format = FORMAT_DEFAULT;
+ notmuch_bool_t decrypt = FALSE;
+
+ notmuch_opt_desc_t options[] = {
+ { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',
+ (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },
+ { "headers-only", FORMAT_HEADERS_ONLY },
+ { 0, 0 } } },
+ { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
+ { 0, 0, 0, 0, 0 }
+ };
- reply_format_func = notmuch_reply_format_default;
-
- argc--; argv++; /* skip subcommand argument */
+ opt_index = parse_arguments (argc, argv, options, 1);
+ if (opt_index < 0) {
+ /* diagnostics already printed */
+ return 1;
+ }
- for (i = 0; i < argc && argv[i][0] == '-'; i++) {
- if (strcmp (argv[i], "--") == 0) {
- i++;
- break;
- }
- if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
- opt = argv[i] + sizeof ("--format=") - 1;
- if (strcmp (opt, "default") == 0) {
- reply_format_func = notmuch_reply_format_default;
- } else if (strcmp (opt, "headers-only") == 0) {
- reply_format_func = notmuch_reply_format_headers_only;
- } else {
- fprintf (stderr, "Invalid value for --format: %s\n", opt);
- return 1;
- }
- } else if ((STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
- if (params.cryptoctx == NULL) {
- GMimeSession* session = g_object_new(g_mime_session_get_type(), NULL);
- if (NULL == (params.cryptoctx = g_mime_gpg_context_new(session, "gpg"))) {
- fprintf (stderr, "Failed to construct gpg context.\n");
- } else {
- params.decrypt = TRUE;
- g_mime_gpg_context_set_always_trust((GMimeGpgContext*)params.cryptoctx, FALSE);
- }
- g_object_unref (session);
- session = NULL;
- }
+ if (format == FORMAT_HEADERS_ONLY)
+ reply_format_func = notmuch_reply_format_headers_only;
+ else
+ reply_format_func = notmuch_reply_format_default;
+
+ if (decrypt) {
+ GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL);
+ params.cryptoctx = g_mime_gpg_context_new (session, "gpg");
+ if (params.cryptoctx) {
+ g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) params.cryptoctx, FALSE);
+ params.decrypt = TRUE;
} else {
- fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
- return 1;
+ fprintf (stderr, "Failed to construct gpg context.\n");
}
+ g_object_unref (session);
}
- argc -= i;
- argv += i;
-
config = notmuch_config_open (ctx, NULL, NULL);
if (config == NULL)
return 1;
- query_string = query_string_from_args (ctx, argc, argv);
+ query_string = query_string_from_args (ctx, argc-opt_index, argv+opt_index);
if (query_string == NULL) {
fprintf (stderr, "Out of memory\n");
return 1;
}
if (format->part_content)
- show_message_body (notmuch_message_get_filename (message),
- format, params);
+ show_message_body (message, format, params);
if (params->part <= 0) {
fputs (format->body_end, stdout);
+++ /dev/null
-.\" notmuch - Not much of an email program, (just index, search and tagging)
-.\"
-.\" Copyright © 2009 Carl Worth
-.\"
-.\" Notmuch is free software: you can redistribute it and/or modify
-.\" it under the terms of the GNU General Public License as published by
-.\" the Free Software Foundation, either version 3 of the License, or
-.\" (at your option) any later version.
-.\"
-.\" Notmuch is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public License
-.\" along with this program. If not, see http://www.gnu.org/licenses/ .
-.\"
-.\" Author: Carl Worth <cworth@cworth.org>
-.TH NOTMUCH 1 2012-01-13 "Notmuch 0.11"
-.SH NAME
-notmuch \- thread-based email index, search, and tagging
-.SH SYNOPSIS
-.B notmuch
-.IR command " [" args " ...]"
-.SH DESCRIPTION
-Notmuch is a command-line based program for indexing, searching,
-reading, and tagging large collections of email messages.
-
-The quickest way to get started with Notmuch is to simply invoke the
-.B notmuch
-command with no arguments, which will interactively guide you through
-the process of indexing your mail.
-.SH NOTE
-While the command-line program
-.B notmuch
-provides powerful functionality, it does not provide the most
-convenient interface for that functionality. More sophisticated
-interfaces are expected to be built on top of either the command-line
-interface, or more likely, on top of the notmuch library
-interface. See http://notmuchmail.org for more about alternate
-interfaces to notmuch.
-.SH COMMANDS
-The
-.BR setup
-command is used to configure Notmuch for first use, (or to reconfigure
-it later).
-.RS 4
-.TP 4
-.B setup
-
-Interactively sets up notmuch for first use.
-
-The setup command will prompt for your full name, your primary email
-address, any alternate email addresses you use, and the directory
-containing your email archives. Your answers will be written to a
-configuration file in ${NOTMUCH_CONFIG} (if set) or
-${HOME}/.notmuch-config . This configuration file will be created with
-descriptive comments, making it easy to edit by hand later to change the
-configuration. Or you can run
-.B "notmuch setup"
-again to change the configuration.
-
-The mail directory you specify can contain any number of
-sub-directories and should primarily contain only files with individual
-email messages (eg. maildir or mh archives are perfect). If there are
-other, non-email files (such as indexes maintained by other email
-programs) then notmuch will do its best to detect those and ignore
-them.
-
-Mail storage that uses mbox format, (where one mbox file contains many
-messages), will not work with notmuch. If that's how your mail is
-currently stored, it is recommended you first convert it to maildir
-format with a utility such as mb2md before running
-.B "notmuch setup" .
-
-Invoking
-.B notmuch
-with no command argument will run
-.B setup
-if the setup command has not previously been completed.
-.RE
-
-The
-.B new
-command is used to incorporate new mail into the notmuch database.
-.RS 4
-.TP 4
-.BR new " [options...]"
-
-Find and import any new messages to the database.
-
-The
-.B new
-command scans all sub-directories of the database, performing
-full-text indexing on new messages that are found. Each new message
-will automatically be tagged with both the
-.BR inbox " and " unread
-tags.
-
-You should run
-.B "notmuch new"
-once after first running
-.B "notmuch setup"
-to create the initial database. The first run may take a long time if
-you have a significant amount of mail (several hundred thousand
-messages or more). Subsequently, you should run
-.B "notmuch new"
-whenever new mail is delivered and you wish to incorporate it into the
-database. These subsequent runs will be much quicker than the initial
-run.
-
-Invoking
-.B notmuch
-with no command argument will run
-.B new
-if
-.B "notmuch setup"
-has previously been completed, but
-.B "notmuch new"
-has not previously been run.
-
-The
-.B new
-command supports hooks. See the
-.B "HOOKS"
-section below for more details on hooks.
-
-Supported options for
-.B new
-include
-.RS 4
-.TP 4
-.BR \-\-no\-hooks
-
-Prevents hooks from being run.
-.RE
-.RE
-
-Several of the notmuch commands accept search terms with a common
-syntax. See the
-.B "SEARCH SYNTAX"
-section below for more details on the supported syntax.
-
-The
-.BR search ", " show " and " count
-commands are used to query the email database.
-.RS 4
-.TP 4
-.BR search " [options...] <search-term>..."
-
-Search for messages matching the given search terms, and display as
-results the threads containing the matched messages.
-
-The output consists of one line per thread, giving a thread ID, the
-date of the newest (or oldest, depending on the sort option) matched
-message in the thread, the number of matched messages and total
-messages in the thread, the names of all participants in the thread,
-and the subject of the newest (or oldest) message.
-
-Supported options for
-.B search
-include
-.RS 4
-.TP 4
-.BR \-\-format= ( json | text )
-
-Presents the results in either JSON or plain-text (default).
-.RE
-
-.RS 4
-.TP 4
-.B \-\-output=(summary|threads|messages|files|tags)
-
-.RS 4
-.TP 4
-.B summary
-
-Output a summary of each thread with any message matching the search
-terms. The summary includes the thread ID, date, the number of
-messages in the thread (both the number matched and the total number),
-the authors of the thread and the subject.
-.RE
-.RS 4
-.TP 4
-.B threads
-
-Output the thread IDs of all threads with any message matching the
-search terms, either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
-.RE
-.RS 4
-.TP 4
-.B messages
-
-Output the message IDs of all messages matching the search terms,
-either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
-.RE
-.RS 4
-.TP 4
-.B files
-
-Output the filenames of all messages matching the search terms, either
-one per line (\-\-format=text) or as a JSON array (\-\-format=json).
-.RE
-.RS 4
-.TP 4
-.B tags
-
-Output all tags that appear on any message matching the search terms,
-either one per line (\-\-format=text) or as a JSON array
-(\-\-format=json).
-.RE
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-sort= ( newest\-first | oldest\-first )
-
-This option can be used to present results in either chronological order
-.RB ( oldest\-first )
-or reverse chronological order
-.RB ( newest\-first ).
-
-Note: The thread order will be distinct between these two options
-(beyond being simply reversed). When sorting by
-.B oldest\-first
-the threads will be sorted by the oldest message in each thread, but
-when sorting by
-.B newest\-first
-the threads will be sorted by the newest message in each thread.
-
-By default, results will be displayed in reverse chronological order,
-(that is, the newest results will be displayed first).
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-offset=[\-]N
-
-Skip displaying the first N results. With the leading '\-', start at the Nth
-result from the end.
-.RE
-
-.RS 4
-.TP 4
-.BR \-\-limit=N
-
-Limit the number of displayed results to N.
-.RE
-
-.RS 4
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-.RE
-.TP
-.BR show " [options...] <search-term>..."
-
-Shows all messages matching the search terms.
-
-The messages will be grouped and sorted based on the threading (all
-replies to a particular message will appear immediately after that
-message in date order). The output is not indented by default, but
-depth tags are printed so that proper indentation can be performed by
-a post-processor (such as the emacs interface to notmuch).
-
-Supported options for
-.B show
-include
-.RS 4
-.TP 4
-.B \-\-entire\-thread
-
-By default only those messages that match the search terms will be
-displayed. With this option, all messages in the same thread as any
-matched message will be displayed.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-format=(text|json|mbox|raw)
-
-.RS 4
-.TP 4
-.BR text " (default for messages)"
-
-The default plain-text format has all text-content MIME parts
-decoded. Various components in the output,
-.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
-will be delimited by easily-parsed markers. Each marker consists of a
-Control-L character (ASCII decimal 12), the name of the marker, and
-then either an opening or closing brace, ('{' or '}'), to either open
-or close the component. For a multipart MIME message, these parts will
-be nested.
-.RE
-.RS 4
-.TP 4
-.B json
-
-The output is formatted with Javascript Object Notation (JSON). This
-format is more robust than the text format for automated
-processing. The nested structure of multipart MIME messages is
-reflected in nested JSON output. JSON output always includes all
-messages in a matching thread; in effect
-.B \-\-format=json
-implies
-.B \-\-entire\-thread
-
-.RE
-.RS 4
-.TP 4
-.B mbox
-
-All matching messages are output in the traditional, Unix mbox format
-with each message being prefixed by a line beginning with "From " and
-a blank line separating each message. Lines in the message content
-beginning with "From " (preceded by zero or more '>' characters) have
-an additional '>' character added. This reversible escaping
-is termed "mboxrd" format and described in detail here:
-
-.nf
-.nh
-http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
-.hy
-.fi
-.
-.RE
-.RS 4
-.TP 4
-.BR raw " (default for a single part, see \-\-part)"
-
-For a message, the original, raw content of the email message is
-output. Consumers of this format should expect to implement MIME
-decoding and similar functions.
-
-For a single part (\-\-part) the raw part content is output after
-performing any necessary MIME decoding.
-
-The raw format must only be used with search terms matching single
-message.
-.RE
-.RE
-
-.RS 4
-.TP 4
-.B \-\-part=N
-
-Output the single decoded MIME part N of a single message. The search
-terms must match only a single message. Message parts are numbered in
-a depth-first walk of the message MIME structure, and are identified
-in the 'json' or 'text' output formats.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-verify
-
-Compute and report the validity of any MIME cryptographic signatures
-found in the selected content (ie. "multipart/signed" parts). Status
-of the signature will be reported (currently only supported with
---format=json), and the multipart/signed part will be replaced by the
-signed data.
-.RE
-
-.RS 4
-.TP 4
-.B \-\-decrypt
-
-Decrypt any MIME encrypted parts found in the selected content
-(ie. "multipart/encrypted" parts). Status of the decryption will be
-reported (currently only supported with --format=json) and the
-multipart/encrypted part will be replaced by the decrypted
-content.
-.RE
-
-A common use of
-.B notmuch show
-is to display a single thread of email messages. For this, use a
-search term of "thread:<thread-id>" as can be seen in the first
-column of output from the
-.B notmuch search
-command.
-
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-.RE
-.RS 4
-.TP 4
-.BR count " [options...] <search-term>..."
-
-Count messages matching the search terms.
-
-The number of matching messages (or threads) is output to stdout.
-
-With no search terms, a count of all messages (or threads) in the database will
-be displayed.
-
-Supported options for
-.B count
-include
-.RS 4
-.TP 4
-.B \-\-output=(messages|threads)
-
-.RS 4
-.TP 4
-.B messages
-
-Output the number of matching messages. This is the default.
-.RE
-.RS 4
-.TP 4
-.B threads
-
-Output the number of matching threads.
-.RE
-.RE
-.RE
-.RE
-
-The
-.B reply
-command is useful for preparing a template for an email reply.
-.RS 4
-.TP 4
-.BR reply " [options...] <search-term>..."
-
-Constructs a reply template for a set of messages.
-
-To make replying to email easier,
-.B notmuch reply
-takes an existing set of messages and constructs a suitable mail
-template. The Reply-to header (if any, otherwise From:) is used for
-the To: address. Vales from the To: and Cc: headers are copied, but
-not including any of the current user's email addresses (as configured
-in primary_mail or other_email in the .notmuch\-config file) in the
-recipient list
-
-It also builds a suitable new subject, including Re: at the front (if
-not already present), and adding the message IDs of the messages being
-replied to to the References list and setting the In\-Reply\-To: field
-correctly.
-
-Finally, the original contents of the emails are quoted by prefixing
-each line with '> ' and included in the body.
-
-The resulting message template is output to stdout.
-
-Supported options for
-.B reply
-include
-.RS
-.TP 4
-.BR \-\-format= ( default | headers\-only )
-.RS
-.TP 4
-.BR default
-Includes subject and quoted message body.
-.TP
-.BR headers\-only
-Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
-.RE
-
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-
-Note: It is most common to use
-.B "notmuch reply"
-with a search string matching a single message, (such as
-id:<message-id>), but it can be useful to reply to several messages at
-once. For example, when a series of patches are sent in a single
-thread, replying to the entire thread allows for the reply to comment
-on issue found in multiple patches.
-.RE
-.RE
-
-The
-.B tag
-command is the only command available for manipulating database
-contents.
-
-.RS 4
-.TP 4
-.BR tag " +<tag>|\-<tag> [...] [\-\-] <search-term>..."
-
-Add/remove tags for all messages matching the search terms.
-
-Tags prefixed by '+' are added while those prefixed by '\-' are
-removed. For each message, tag removal is performed before tag
-addition.
-
-The beginning of <search-terms> is recognized by the first
-argument that begins with neither '+' nor '\-'. Support for
-an initial search term beginning with '+' or '\-' is provided
-by allowing the user to specify a "\-\-" argument to separate
-the tags from the search terms.
-
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-.RE
-
-The
-.BR dump " and " restore
-commands can be used to create a textual dump of email tags for backup
-purposes, and to restore from that dump.
-
-.RS 4
-.TP 4
-.BR dump " [<filename>] [--] [<search-terms>]"
-
-Creates a plain-text dump of the tags of each message.
-
-Output is to the given filename, if any, or to stdout. Note that
-using the filename argument is deprecated.
-
-These tags are the only data in the notmuch database that can't be
-recreated from the messages themselves. The output of notmuch dump is
-therefore the only critical thing to backup (and much more friendly to
-incremental backup than the native database files.)
-
-With no search terms, a dump of all messages in the database will be
-generated. A "--" argument instructs notmuch that the
-remaining arguments are search terms.
-
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-.RE
-
-.TP
-.BR restore " [--accumulate] [<filename>]"
-
-Restores the tags from the given file (see
-.BR "notmuch dump" ")."
-
-The input is read from the given filename, if any, or from stdin.
-
-Note: The dump file format is specifically chosen to be
-compatible with the format of files produced by sup-dump.
-So if you've previously been using sup for mail, then the
-.B "notmuch restore"
-command provides you a way to import all of your tags (or labels as
-sup calls them).
-
-The --accumulate switch causes the union of the existing and new tags to be
-applied, instead of replacing each message's tags as they are read in from the
-dump file.
-.RE
-
-The
-.B part
-command can used to output a single part of a multipart MIME message.
-
-.RS 4
-.TP 4
-.BR part " \-\-part=<part-number> <search-term>..."
-
-Output a single MIME part of a message.
-
-A single decoded MIME part, with no encoding or framing, is output to
-stdout. The search terms must match only a single message, otherwise
-this command will fail.
-
-The part number should match the part "id" field output by the
-"\-\-format=json" option of "notmuch show". If the message specified by
-the search terms does not include a part with the specified "id" there
-will be no output.
-
-See the
-.B "SEARCH SYNTAX"
-section below for details of the supported syntax for <search-terms>.
-.RE
-
-The
-.B config
-command can be used to get or set settings int the notmuch
-configuration file.
-
-.RS 4
-.TP 4
-.BR "config get " <section> . <item>
-
-The value of the specified configuration item is printed to stdout. If
-the item has multiple values, each value is separated by a newline
-character.
-
-Available configuration items include at least
-
- database.path
-
- user.name
-
- user.primary_email
-
- user.other_email
-
- new.tags
-.RE
-
-.RS 4
-.TP 4
-.BR "config set " <section> . "<item> [values ...]"
-
-The specified configuration item is set to the given value. To
-specify a multiple-value item, provide each value as a separate
-command-line argument.
-
-If no values are provided, the specified configuration item will be
-removed from the configuration file.
-.RE
-
-.SH SEARCH SYNTAX
-Several notmuch commands accept a common syntax for search terms.
-
-The search terms can consist of free-form text (and quoted phrases)
-which will match all messages that contain all of the given
-terms/phrases in the body, the subject, or any of the sender or
-recipient headers.
-
-As a special case, a search string consisting of exactly a single
-asterisk ("*") will match all messages.
-
-In addition to free text, the following prefixes can be used to force
-terms to match against specific portions of an email, (where
-<brackets> indicate user-supplied values):
-
- from:<name-or-address>
-
- to:<name-or-address>
-
- subject:<word-or-quoted-phrase>
-
- attachment:<word>
-
- tag:<tag> (or is:<tag>)
-
- id:<message-id>
-
- thread:<thread-id>
-
- folder:<directory-path>
-
-The
-.B from:
-prefix is used to match the name or address of the sender of an email
-message.
-
-The
-.B to:
-prefix is used to match the names or addresses of any recipient of an
-email message, (whether To, Cc, or Bcc).
-
-Any term prefixed with
-.B subject:
-will match only text from the subject of an email. Searching for a
-phrase in the subject is supported by including quotation marks around
-the phrase, immediately following
-.BR subject: .
-
-The
-.B attachment:
-prefix can be used to search for specific filenames (or extensions) of
-attachments to email messages.
-
-For
-.BR tag: " and " is:
-valid tag values include
-.BR inbox " and " unread
-by default for new messages added by
-.B notmuch new
-as well as any other tag values added manually with
-.BR "notmuch tag" .
-
-For
-.BR id: ,
-message ID values are the literal contents of the Message\-ID: header
-of email messages, but without the '<', '>' delimiters.
-
-The
-.B thread:
-prefix can be used with the thread ID values that are generated
-internally by notmuch (and do not appear in email messages). These
-thread ID values can be seen in the first column of output from
-.B "notmuch search"
-
-The
-.B folder:
-prefix can be used to search for email message files that are
-contained within particular directories within the mail store. Only
-the directory components below the top-level mail database path are
-available to be searched.
-
-In addition to individual terms, multiple terms can be
-combined with Boolean operators (
-.BR and ", " or ", " not
-, etc.). Each term in the query will be implicitly connected by a
-logical AND if no explicit operator is provided, (except that terms
-with a common prefix will be implicitly combined with OR until we get
-Xapian defect #402 fixed).
-
-Parentheses can also be used to control the combination of the Boolean
-operators, but will have to be protected from interpretation by the
-shell, (such as by putting quotation marks around any parenthesized
-expression).
-
-Finally, results can be restricted to only messages within a
-particular time range, (based on the Date: header) with a syntax of:
-
- <initial-timestamp>..<final-timestamp>
-
-Each timestamp is a number representing the number of seconds since
-1970\-01\-01 00:00:00 UTC. This is not the most convenient means of
-expressing date ranges, but until notmuch is fixed to accept a more
-convenient form, one can use the date program to construct
-timestamps. For example, with the bash shell the following syntax would
-specify a date range to return messages from 2009\-10\-01 until the
-current time:
-
- $(date +%s \-d 2009\-10\-01)..$(date +%s)
-.SH HOOKS
-Hooks are scripts (or arbitrary executables or symlinks to such) that notmuch
-invokes before and after certain actions. These scripts reside in
-the .notmuch/hooks directory within the database directory and must have
-executable permissions.
-
-The currently available hooks are described below.
-.RS 4
-.TP 4
-.B pre\-new
-This hook is invoked by the
-.B new
-command before scanning or importing new messages into the database. If this
-hook exits with a non-zero status, notmuch will abort further processing of the
-.B new
-command.
-
-Typically this hook is used for fetching or delivering new mail to be imported
-into the database.
-.RE
-.RS 4
-.TP 4
-.B post\-new
-This hook is invoked by the
-.B new
-command after new messages have been imported into the database and initial tags
-have been applied. The hook will not be run if there have been any errors during
-the scan or import.
-
-Typically this hook is used to perform additional query\-based tagging on the
-imported messages.
-.RE
-.SH ENVIRONMENT
-The following environment variables can be used to control the
-behavior of notmuch.
-.TP
-.B NOTMUCH_CONFIG
-Specifies the location of the notmuch configuration file. Notmuch will
-use ${HOME}/.notmuch\-config if this variable is not set.
-.SH SEE ALSO
-The emacs-based interface to notmuch (available as
-.B notmuch.el
-in the Notmuch distribution).
-
-The notmuch website:
-.B http://notmuchmail.org
-.SH CONTACT
-Feel free to send questions, comments, or kudos to the notmuch mailing
-list <notmuch@notmuchmail.org> . Subscription is not required before
-posting, but is available from the notmuchmail.org website.
-
-Real-time interaction with the Notmuch community is available via IRC
-(server: irc.freenode.net, channel: #notmuch).
command_function_t function;
const char *arguments;
const char *summary;
- const char *documentation;
} command_t;
#define MAX_ALIAS_SUBSTITUTIONS 3
static int
notmuch_help_command (void *ctx, int argc, char *argv[]);
-static const char search_terms_help[] =
- "\tSeveral notmuch commands accept a common syntax for search\n"
- "\tterms.\n"
- "\n"
- "\tThe search terms can consist of free-form text (and quoted\n"
- "\tphrases) which will match all messages that contain all of\n"
- "\tthe given terms/phrases in the body, the subject, or any of\n"
- "\tthe sender or recipient headers.\n"
- "\n"
- "\tAs a special case, a search string consisting of exactly a\n"
- "\tsingle asterisk (\"*\") will match all messages.\n"
- "\n"
- "\tIn addition to free text, the following prefixes can be used\n"
- "\tto force terms to match against specific portions of an email,\n"
- "\t(where <brackets> indicate user-supplied values):\n"
- "\n"
- "\t\tfrom:<name-or-address>\n"
- "\t\tto:<name-or-address>\n"
- "\t\tsubject:<word-or-quoted-phrase>\n"
- "\t\tattachment:<word>\n"
- "\t\ttag:<tag> (or is:<tag>)\n"
- "\t\tid:<message-id>\n"
- "\t\tthread:<thread-id>\n"
- "\t\tfolder:<directory-path>\n"
- "\n"
- "\tThe from: prefix is used to match the name or address of\n"
- "\tthe sender of an email message.\n"
- "\n"
- "\tThe to: prefix is used to match the names or addresses of\n"
- "\tany recipient of an email message, (whether To, Cc, or Bcc).\n"
- "\n"
- "\tAny term prefixed with subject: will match only text from\n"
- "\tthe subject of an email. Quoted phrases are supported when\n"
- "\tsearching with: subject:\"this is a phrase\".\n"
- "\n"
- "\tFor tag: and is:, valid tag values include \"inbox\" and \"unread\"\n"
- "\tby default for new messages added by \"notmuch new\" as well\n"
- "\tas any other tag values added manually with \"notmuch tag\".\n"
- "\n"
- "\tFor id:, message ID values are the literal contents of the\n"
- "\tMessage-ID: header of email messages, but without the '<','>'\n"
- "\tdelimiters.\n"
- "\n"
- "\tThe thread: prefix can be used with the thread ID values that\n"
- "\tare generated internally by notmuch (and do not appear in email\n"
- "\tmessages). These thread ID values can be seen in the first\n"
- "\tcolumn of output from \"notmuch search\".\n"
- "\n"
- "\tThe folder: prefix can be used to search for email message\n"
- "\tfiles that are contained within particular directories within\n"
- "\tthe mail store. Only the directory components below the top-level\n"
- "\tmail database path are available to be searched.\n"
- "\n"
- "\tIn addition to individual terms, multiple terms can be\n"
- "\tcombined with Boolean operators (\"and\", \"or\", \"not\", etc.).\n"
- "\tEach term in the query will be implicitly connected by a\n"
- "\tlogical AND if no explicit operator is provided, (except\n"
- "\tthat terms with a common prefix will be implicitly combined\n"
- "\twith OR until we get Xapian defect #402 fixed).\n"
- "\n"
- "\tParentheses can also be used to control the combination of\n"
- "\tthe Boolean operators, but will have to be protected from\n"
- "\tinterpretation by the shell, (such as by putting quotation\n"
- "\tmarks around any parenthesized expression).\n"
- "\n"
- "\tFinally, results can be restricted to only messages within a\n"
- "\tparticular time range, (based on the Date: header) with:\n"
- "\n"
- "\t\t<intial-timestamp>..<final-timestamp>\n"
- "\n"
- "\tEach timestamp is a number representing the number of seconds\n"
- "\tsince 1970-01-01 00:00:00 UTC. This is not the most convenient\n"
- "\tmeans of expressing date ranges, but until notmuch is fixed to\n"
- "\taccept a more convenient form, one can use the date program to\n"
- "\tconstruct timestamps. For example, with the bash shell the\n"
- "\tfollowing syntax would specify a date range to return messages\n"
- "\tfrom 2009-10-01 until the current time:\n"
- "\n"
- "\t\t$(date +%%s -d 2009-10-01)..$(date +%%s)\n\n";
-
-static const char hooks_help[] =
- "\tHooks are scripts (or arbitrary executables or symlinks to such) that\n"
- "\tnotmuch invokes before and after certain actions. These scripts reside\n"
- "\tin the .notmuch/hooks directory within the database directory and must\n"
- "\thave executable permissions.\n"
- "\n"
- "\tThe currently available hooks are described below.\n"
- "\n"
- "\tpre-new\n"
- "\t\tThis hook is invoked by the new command before scanning or\n"
- "\t\timporting new messages into the database. If this hook exits\n"
- "\t\twith a non-zero status, notmuch will abort further processing\n"
- "\t\tof the new command.\n"
- "\n"
- "\t\tTypically this hook is used for fetching or delivering new\n"
- "\t\tmail to be imported into the database.\n"
- "\n"
- "\tpost-new\n"
- "\t\tThis hook is invoked by the new command after new messages\n"
- "\t\thave been imported into the database and initial tags have\n"
- "\t\tbeen applied. The hook will not be run if there have been any\n"
- "\t\terrors during the scan or import.\n"
- "\n"
- "\t\tTypically this hook is used to perform additional query-based\n"
- "\t\ttagging on the imported messages.\n\n";
-
static command_t commands[] = {
{ "setup", notmuch_setup_command,
NULL,
- "Interactively setup notmuch for first use.",
- "\tThe setup command will prompt for your full name, your primary\n"
- "\temail address, any alternate email addresses you use, and the\n"
- "\tdirectory containing your email archives. Your answers will be\n"
- "\twritten to a configuration file in ${NOTMUCH_CONFIG} (if set)\n"
- "\tor ${HOME}/.notmuch-config.\n"
- "\n"
- "\tThis configuration file will be created with descriptive\n"
- "\tcomments, making it easy to edit by hand later to change the\n"
- "\tconfiguration. Or you can run \"notmuch setup\" again.\n"
- "\n"
- "\tInvoking notmuch with no command argument will run setup if\n"
- "\tthe setup command has not previously been completed." },
+ "Interactively setup notmuch for first use." },
{ "new", notmuch_new_command,
"[options...]",
- "Find and import new messages to the notmuch database.",
- "\tScans all sub-directories of the mail directory, performing\n"
- "\tfull-text indexing on new messages that are found. Each new\n"
- "\tmessage will be tagged as both \"inbox\" and \"unread\".\n"
- "\n"
- "\tYou should run \"notmuch new\" once after first running\n"
- "\t\"notmuch setup\" to create the initial database. The first\n"
- "\trun may take a long time if you have a significant amount of\n"
- "\tmail (several hundred thousand messages or more).\n"
- "\n"
- "\tSubsequently, you should run \"notmuch new\" whenever new mail\n"
- "\tis delivered and you wish to incorporate it into the database.\n"
- "\tThese subsequent runs will be much quicker than the initial run.\n"
- "\n"
- "\tThe new command supports hooks. See \"notmuch help hooks\" for\n"
- "\tmore details on hooks.\n"
- "\n"
- "\tSupported options for new include:\n"
- "\n"
- "\t--no-hooks\n"
- "\n"
- "\t\tPrevent hooks from being run.\n"
- "\n"
- "\t--verbose\n"
- "\n"
- "\t\tVerbose operation. Shows paths of message files as\n"
- "\t\tthey are being indexed.\n"
- "\n"
- "\tInvoking notmuch with no command argument will run new if\n"
- "\tthe setup command has previously been completed, but new has\n"
- "\tnot previously been run." },
+ "Find and import new messages to the notmuch database." },
{ "search", notmuch_search_command,
"[options...] <search-terms> [...]",
- "Search for messages matching the given search terms.",
- "\tNote that the individual mail messages will be matched\n"
- "\tagainst the search terms, but the results will be the\n"
- "\tthreads (one per line) containing the matched messages.\n"
- "\n"
- "\tSupported options for search include:\n"
- "\n"
- "\t--format=(json|text)\n"
- "\n"
- "\t\tPresents the results in either JSON or\n"
- "\t\tplain-text (default)\n"
- "\n"
- "\t--output=(summary|threads|messages|files|tags)\n"
- "\n"
- "\t\tsummary (default)\n"
- "\n"
- "\t\tOutput a summary of each thread with any message matching the\n"
- "\t\tsearch terms. The summary includes the thread ID, date, the\n"
- "\t\tnumber of messages in the thread (both the number matched and\n"
- "\t\tthe total number), the authors of the thread and the subject.\n"
- "\n"
- "\t\tthreads\n"
- "\n"
- "\t\tOutput the thread IDs of all threads with any message matching\n"
- "\t\tthe search terms, either one per line (--format=text) or as a\n"
- "\t\tJSON array (--format=json).\n"
- "\n"
- "\t\tmessages\n"
- "\n"
- "\t\tOutput the message IDs of all messages matching the search\n"
- "\t\tterms, either one per line (--format=text) or as a JSON array\n"
- "\t\t(--format=json).\n"
- "\n"
- "\t\tfiles\n"
- "\n"
- "\t\tOutput the filenames of all messages matching the search\n"
- "\t\tterms, either one per line (--format=text) or as a JSON array\n"
- "\t\t(--format=json).\n"
- "\n"
- "\t\ttags\n"
- "\n"
- "\t\tOutput all tags that appear on any message matching the search\n"
- "\t\tterms, either one per line (--format=text) or as a JSON array\n"
- "\t\t(--format=json).\n"
- "\n"
- "\t--sort=(newest-first|oldest-first)\n"
- "\n"
- "\t\tPresent results in either chronological order\n"
- "\t\t(oldest-first) or reverse chronological order\n"
- "\t\t(newest-first), which is the default.\n"
- "\n"
- "\t--offset=[-]N\n"
- "\n"
- "\t\tSkip displaying the first N results. With the leading '-',\n"
- "\t\tstart at the Nth result from the end.\n"
- "\n"
- "\t--limit=N\n"
- "\n"
- "\t\tLimit the number of displayed results to N.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for details of the search\n"
- "\tterms syntax." },
+ "Search for messages matching the given search terms." },
{ "show", notmuch_show_command,
"<search-terms> [...]",
- "Show all messages matching the search terms.",
- "\tThe messages are grouped and sorted based on the threading\n"
- "\t(all replies to a particular message appear immediately\n"
- "\tafter that message in date order).\n"
- "\n"
- "\tSupported options for show include:\n"
- "\n"
- "\t--entire-thread\n"
- "\n"
- "\t\tBy default only those messages that match the\n"
- "\t\tsearch terms will be displayed. With this option,\n"
- "\t\tall messages in the same thread as any matched\n"
- "\t\tmessage will be displayed.\n"
- "\n"
- "\t--format=(text|json|mbox|raw)\n"
- "\n"
- "\t\ttext (default for messages)\n"
- "\n"
- "\t\tThe default plain-text format has all text-content MIME parts\n"
- "\t\tdecoded. Various components in the output, ('message', 'header',\n"
- "\t\t'body', 'attachment', and MIME 'part') are delimited by\n"
- "\t\teasily-parsed markers. Each marker consists of a Control-L\n"
- "\t\tcharacter (ASCII decimal 12), the name of the marker, and\n"
- "\t\tthen either an opening or closing brace, '{' or '}' to\n"
- "\t\teither open or close the component. For a multipart MIME\n"
- "\t\tmessage, these parts will be nested.\n"
- "\n"
- "\t\tjson\n"
- "\n"
- "\t\tThe output is formatted with Javascript Object Notation\n"
- "\t\t(JSON). This format is more robust than the text format\n"
- "\t\tfor automated processing. The nested structure of multipart\n"
- "\t\tMIME messages is reflected in nested JSON output. JSON\n"
- "\t\toutput always includes all messages in a matching thread;\n"
- "\t\tin effect '--format=json' implies '--entire-thread'\n"
- "\n"
- "\t\tmbox\n"
- "\n"
- "\t\tAll matching messages are output in the traditional, Unix\n"
- "\t\tmbox format with each message being prefixed by a line\n"
- "\t\tbeginning with 'From ' and a blank line separating each\n"
- "\t\tmessage. Lines in the message content beginning with 'From '\n"
- "\t\t(preceded by zero or more '>' characters) have an additional\n"
- "\t\t'>' character added. This reversible escaping is termed\n"
- "\t\t\"mboxrd\" format and described in detail here:\n"
- "\n"
- "\t\thttp://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html\n"
- "\n"
- "\t\traw (default for a single part, see --part)\n"
- "\n"
- "\t\tFor a message, the original, raw content of the email\n"
- "\t\tmessage is output. Consumers of this format should\n"
- "\t\texpect to implement MIME decoding and similar functions.\n"
- "\n"
- "\t\tFor a single part (--part) the raw part content is output\n"
- "\t\tafter performing any necessary MIME decoding.\n"
- "\n"
- "\t\tThe raw format must only be used with search terms matching\n"
- "\t\tsingle message.\n"
- "\n"
- "\t--part=N\n"
- "\n"
- "\t\tOutput the single decoded MIME part N of a single message.\n"
- "\t\tThe search terms must match only a single message.\n"
- "\t\tMessage parts are numbered in a depth-first walk of the\n"
- "\t\tmessage MIME structure, and are identified in the 'json' or\n"
- "\t\t'text' output formats.\n"
- "\n"
- "\t--verify\n"
- "\n"
- "\t\tCompute and report the validity of any MIME cryptographic\n"
- "\t\tsignatures found in the selected content (ie.\n"
- "\t\t\"multipart/signed\" parts). Status of the signature will be\n"
- "\t\treported (currently only supported with --format=json) and\n"
- "\t\tthe multipart/signed part will be replaced by the signed data.\n"
- "\n"
- "\t--decrypt\n"
- "\n"
- "\t\tDecrypt any MIME encrypted parts found in the selected content\n"
- "\t\t(ie. \"multipart/encrypted\" parts). Status of the decryption\n"
- "\t\twill be reported (currently only supported with --format=json)\n"
- "\t\tand the multipart/encrypted part will be replaced by the\n"
- "\t\tdecrypted content.\n"
- "\n"
- "\n"
- "\tA common use of \"notmuch show\" is to display a single\n"
- "\tthread of email messages. For this, use a search term of\n"
- "\t\"thread:<thread-id>\" as can be seen in the first column\n"
- "\tof output from the \"notmuch search\" command.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for details of the search\n"
- "\tterms syntax." },
+ "Show all messages matching the search terms." },
{ "count", notmuch_count_command,
"[options...] <search-terms> [...]",
- "Count messages matching the search terms.",
- "\tThe number of matching messages (or threads) is output to stdout.\n"
- "\n"
- "\tWith no search terms, a count of all messages (or threads) in\n"
- "\tthe database will be displayed.\n"
- "\n"
- "\tSupported options for count include:\n"
- "\n"
- "\t--output=(messages|threads)\n"
- "\n"
- "\t\tmessages (default)\n"
- "\n"
- "\t\tOutput the number of matching messages.\n"
- "\n"
- "\t\tthreads\n"
- "\n"
- "\t\tOutput the number of matching threads.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for details of the search\n"
- "\tterms syntax." },
+ "Count messages matching the search terms." },
{ "reply", notmuch_reply_command,
"[options...] <search-terms> [...]",
- "Construct a reply template for a set of messages.",
- "\tConstructs a new message as a reply to a set of existing\n"
- "\tmessages. The Reply-To: header (if any, otherwise From:) is\n"
- "\tused for the To: address. The To: and Cc: headers are copied,\n"
- "\tbut not including any of the user's configured addresses.\n"
- "\n"
- "\tA suitable subject is constructed. The In-Reply-to: and\n"
- "\tReferences: headers are set appropriately, and the content\n"
- "\tof the original messages is quoted and included in the body\n"
- "\t(unless --format=headers-only is given).\n"
- "\n"
- "\tThe resulting message template is output to stdout.\n"
- "\n"
- "\tSupported options for reply include:\n"
- "\n"
- "\t--format=(default|headers-only)\n"
- "\n"
- "\t\tdefault:\n"
- "\t\t\tIncludes subject and quoted message body.\n"
- "\n"
- "\t\theaders-only:\n"
- "\t\t\tOnly produces In-Reply-To, References, To\n"
- "\t\t\tCc, and Bcc headers.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for details of the search\n"
- "\tterms syntax." },
+ "Construct a reply template for a set of messages." },
{ "tag", notmuch_tag_command,
- "+<tag>|-<tag> [...] [--] <search-terms> [...]",
- "Add/remove tags for all messages matching the search terms.",
- "\tThe search terms are handled exactly as in 'search' so one\n"
- "\tcan use that command first to see what will be modified.\n"
- "\n"
- "\tTags prefixed by '+' are added while those prefixed by\n"
- "\t'-' are removed. For each message, tag removal is performed\n"
- "\tbefore tag addition.\n"
- "\n"
- "\tThe beginning of <search-terms> is recognized by the first\n"
- "\targument that begins with neither '+' nor '-'. Support for\n"
- "\tan initial search term beginning with '+' or '-' is provided\n"
- "\tby allowing the user to specify a \"--\" argument to separate\n"
- "\tthe tags from the search terms.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for details of the search\n"
- "\tterms syntax." },
+ "+<tag>|-<tag> [...] [--] <search-terms> [...]" ,
+ "Add/remove tags for all messages matching the search terms." },
{ "dump", notmuch_dump_command,
"[<filename>] [--] [<search-terms>]",
- "Create a plain-text dump of the tags for each message.",
- "\tOutput is to the given filename, if any, or to stdout.\n"
- "\tNote that using the filename argument is deprecated.\n"
- "\n"
- "\tThese tags are the only data in the notmuch database\n"
- "\tthat can't be recreated from the messages themselves.\n"
- "\tThe output of notmuch dump is therefore the only\n"
- "\tcritical thing to backup (and much more friendly to\n"
- "\tincremental backup than the native database files.)\n"
- "\n"
- "\tWith no search terms, a dump of all messages in the\n"
- "\tdatabase will be generated. A \"--\" argument instructs\n"
- "\tnotmuch that the remaining arguments are search terms.\n"
- "\n"
- "\tSee \"notmuch help search-terms\" for the search-term syntax.\n"
- },
+ "Create a plain-text dump of the tags for each message." },
{ "restore", notmuch_restore_command,
"[--accumulate] [<filename>]",
- "Restore the tags from the given dump file (see 'dump').",
- "\tInput is read from the given filename, if any, or from stdin.\n"
- "\tNote: The dump file format is specifically chosen to be\n"
- "\tcompatible with the format of files produced by sup-dump.\n"
- "\tSo if you've previously been using sup for mail, then the\n"
- "\t\"notmuch restore\" command provides you a way to import\n"
- "\tall of your tags (or labels as sup calls them).\n"
- "\tThe --accumulate switch causes the union of the existing and new\n"
- "\ttags to be applied, instead of replacing each message's tags as\n"
- "\tthey are read in from the dump file."},
+ "Restore the tags from the given dump file (see 'dump')." },
{ "config", notmuch_config_command,
"[get|set] <section>.<item> [value ...]",
- "Get or set settings in the notmuch configuration file.",
- " config get <section>.<item>\n"
- "\n"
- "\tThe value of the specified configuration item is printed\n"
- "\tto stdout. If the item has multiple values, each value\n"
- "\tis separated by a newline character.\n"
- "\n"
- "\tAvailable configuration items include at least\n"
- "\n"
- "\t\tdatabase.path\n"
- "\t\tuser.name\n"
- "\t\tuser.primary_email\n"
- "\t\tuser.other_email\n"
- "\t\tnew.tags\n"
- "\n"
- " config set <section>.<item> [value ...]\n"
- "\n"
- "\tThe specified configuration item is set to the given value.\n"
- "\tTo specify a multiple-value item, provide each value as\n"
- "\ta separate command-line argument.\n"
- "\n"
- "\tIf no values are provided, the specified configuration item\n"
- "\twill be removed from the configuration file." },
+ "Get or set settings in the notmuch configuration file." },
{ "help", notmuch_help_command,
"[<command>]",
- "This message, or more detailed help for the named command.",
- "\tExcept in this case, where there's not much more detailed\n"
- "\thelp available." }
+ "This message, or more detailed help for the named command." }
};
static void
"and \"notmuch help search-terms\" for the common search-terms syntax.\n\n");
}
+static void
+exec_man (const char *page)
+{
+ if (execlp ("man", "man", page, (char *) NULL)) {
+ perror ("exec man");
+ exit (1);
+ }
+}
+
static int
-notmuch_help_command (unused (void *ctx), int argc, char *argv[])
+notmuch_help_command (void *ctx, int argc, char *argv[])
{
command_t *command;
unsigned int i;
return 0;
}
+ if (strcmp (argv[0], "help") == 0) {
+ printf ("The notmuch help system.\n\n"
+ "\tNotmuch uses the man command to display help. In case\n"
+ "\tof difficulties check that MANPATH includes the pages\n"
+ "\tinstalled by notmuch.\n\n"
+ "\tTry \"notmuch help\" for a list of topics.\n");
+ return 0;
+ }
+
for (i = 0; i < ARRAY_SIZE (commands); i++) {
command = &commands[i];
if (strcmp (argv[0], command->name) == 0) {
- printf ("Help for \"notmuch %s\":\n\n", argv[0]);
- if (command->arguments)
- printf ("%s %s\n\n\t%s\n\n%s\n\n",
- command->name, command->arguments,
- command->summary, command->documentation);
- else
- printf ("%s\t%s\n\n%s\n\n", command->name,
- command->summary, command->documentation);
- return 0;
+ char *page = talloc_asprintf (ctx, "notmuch-%s", command->name);
+ exec_man (page);
}
}
if (strcmp (argv[0], "search-terms") == 0) {
- printf ("Help for <%s>\n\n", argv[0]);
- for (i = 0; i < ARRAY_SIZE (commands); i++) {
- command = &commands[i];
-
- if (command->arguments &&
- strstr (command->arguments, "search-terms"))
- {
- printf ("\t%s\t%s\n",
- command->name, command->arguments);
- }
- }
- printf ("\n");
- printf (search_terms_help);
- return 0;
+ exec_man ("notmuch-search-terms");
} else if (strcmp (argv[0], "hooks") == 0) {
- printf ("Help for <%s>\n\n", argv[0]);
- printf (hooks_help);
- return 0;
+ exec_man ("notmuch-hooks");
}
fprintf (stderr,
typedef struct show_message_state {
int part_count;
- int in_zone;
} show_message_state_t;
static void
-show_message_part (GMimeObject *part,
+show_message_part (mime_node_t *node,
show_message_state_t *state,
const notmuch_show_format_t *format,
- notmuch_show_params_t *params,
int first)
{
- GMimeObject *decryptedpart = NULL;
- int selected;
- state->part_count += 1;
+ /* Formatters expect the envelope for embedded message parts */
+ GMimeObject *part = node->envelope_part ?
+ GMIME_OBJECT (node->envelope_part) : node->part;
+ int i;
- if (! (GMIME_IS_PART (part) || GMIME_IS_MULTIPART (part) || GMIME_IS_MESSAGE_PART (part))) {
- fprintf (stderr, "Warning: Not displaying unknown mime part: %s.\n",
- g_type_name (G_OBJECT_TYPE (part)));
- return;
- }
+ if (!first)
+ fputs (format->part_sep, stdout);
- selected = (params->part <= 0 || state->part_count == params->part);
+ /* Format this part */
+ if (format->part_start)
+ format->part_start (part, &(state->part_count));
- if (selected || state->in_zone) {
- if (!first && (params->part <= 0 || state->in_zone))
- fputs (format->part_sep, stdout);
+ if (node->decrypt_attempted && format->part_encstatus)
+ format->part_encstatus (node->decrypt_success);
- if (format->part_start)
- format->part_start (part, &(state->part_count));
- }
+ if (node->verify_attempted && format->part_sigstatus)
+ format->part_sigstatus (node->sig_validity);
- /* handle PGP/MIME parts */
- if (GMIME_IS_MULTIPART (part) && params->cryptoctx) {
- GMimeMultipart *multipart = GMIME_MULTIPART (part);
- GError* err = NULL;
-
- if (GMIME_IS_MULTIPART_ENCRYPTED (part) && params->decrypt)
- {
- if ( g_mime_multipart_get_count (multipart) != 2 ) {
- /* this violates RFC 3156 section 4, so we won't bother with it. */
- fprintf (stderr,
- "Error: %d part(s) for a multipart/encrypted message (should be exactly 2)\n",
- g_mime_multipart_get_count (multipart));
- } else {
- GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part);
- decryptedpart = g_mime_multipart_encrypted_decrypt (encrypteddata, params->cryptoctx, &err);
- if (decryptedpart) {
- if ((selected || state->in_zone) && format->part_encstatus)
- format->part_encstatus (1);
- const GMimeSignatureValidity *sigvalidity = g_mime_multipart_encrypted_get_signature_validity (encrypteddata);
- if (!sigvalidity)
- fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));
- if ((selected || state->in_zone) && format->part_sigstatus)
- format->part_sigstatus (sigvalidity);
- } else {
- fprintf (stderr, "Failed to decrypt part: %s\n", (err ? err->message : "no error explanation given"));
- if ((selected || state->in_zone) && format->part_encstatus)
- format->part_encstatus (0);
- }
- }
- }
- else if (GMIME_IS_MULTIPART_SIGNED (part))
- {
- if ( g_mime_multipart_get_count (multipart) != 2 ) {
- /* this violates RFC 3156 section 5, so we won't bother with it. */
- fprintf (stderr,
- "Error: %d part(s) for a multipart/signed message (should be exactly 2)\n",
- g_mime_multipart_get_count (multipart));
- } else {
- /* For some reason the GMimeSignatureValidity returned
- * here is not a const (inconsistent with that
- * returned by
- * g_mime_multipart_encrypted_get_signature_validity,
- * and therefore needs to be properly disposed of.
- * Hopefully the API will become more consistent. */
- GMimeSignatureValidity *sigvalidity = g_mime_multipart_signed_verify (GMIME_MULTIPART_SIGNED (part), params->cryptoctx, &err);
- if (!sigvalidity) {
- fprintf (stderr, "Failed to verify signed part: %s\n", (err ? err->message : "no error explanation given"));
- }
- if ((selected || state->in_zone) && format->part_sigstatus)
- format->part_sigstatus (sigvalidity);
- if (sigvalidity)
- g_mime_signature_validity_free (sigvalidity);
- }
- }
-
- if (err)
- g_error_free (err);
- }
- /* end handle PGP/MIME parts */
-
- if (selected || state->in_zone)
- format->part_content (part);
-
- if (GMIME_IS_MULTIPART (part)) {
- GMimeMultipart *multipart = GMIME_MULTIPART (part);
- int i;
-
- if (selected)
- state->in_zone = 1;
-
- if (decryptedpart) {
- /* We emit the useless application/pgp-encrypted version
- * part here only to keep the emitted output as consistent
- * as possible between decrypted output and the
- * unprocessed multipart/mime. For some strange reason,
- * the actual encrypted data is the second part of the
- * multipart. */
- show_message_part (g_mime_multipart_get_part (multipart, 0), state, format, params, TRUE);
- show_message_part (decryptedpart, state, format, params, FALSE);
- } else {
- for (i = 0; i < g_mime_multipart_get_count (multipart); i++) {
- show_message_part (g_mime_multipart_get_part (multipart, i),
- state, format, params, i == 0);
- }
- }
-
- if (selected)
- state->in_zone = 0;
-
- } else if (GMIME_IS_MESSAGE_PART (part)) {
- GMimeMessage *mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));
-
- if (selected)
- state->in_zone = 1;
-
- if (selected || (!selected && state->in_zone)) {
- fputs (format->header_start, stdout);
- if (format->header_message_part)
- format->header_message_part (mime_message);
- fputs (format->header_end, stdout);
-
- fputs (format->body_start, stdout);
- }
-
- show_message_part (g_mime_message_get_mime_part (mime_message),
- state, format, params, TRUE);
-
- if (selected || (!selected && state->in_zone))
- fputs (format->body_end, stdout);
-
- if (selected)
- state->in_zone = 0;
- }
+ format->part_content (part);
- if (selected || state->in_zone) {
- if (format->part_end)
- format->part_end (part);
+ if (node->envelope_part) {
+ fputs (format->header_start, stdout);
+ if (format->header_message_part)
+ format->header_message_part (GMIME_MESSAGE (node->part));
+ fputs (format->header_end, stdout);
+
+ fputs (format->body_start, stdout);
}
+
+ /* Recurse over the children */
+ state->part_count += 1;
+ for (i = 0; i < node->nchildren; i++)
+ show_message_part (mime_node_child (node, i), state, format, i == 0);
+
+ /* Finish this part */
+ if (node->envelope_part)
+ fputs (format->body_end, stdout);
+
+ if (format->part_end)
+ format->part_end (part);
}
notmuch_status_t
-show_message_body (const char *filename,
+show_message_body (notmuch_message_t *message,
const notmuch_show_format_t *format,
notmuch_show_params_t *params)
{
- GMimeStream *stream = NULL;
- GMimeParser *parser = NULL;
- GMimeMessage *mime_message = NULL;
- notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
- FILE *file = NULL;
+ notmuch_status_t ret;
show_message_state_t state;
+ mime_node_t *root, *part;
- state.part_count = 0;
- state.in_zone = 0;
-
- file = fopen (filename, "r");
- if (! file) {
- fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
- ret = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
- stream = g_mime_stream_file_new (file);
- g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
-
- parser = g_mime_parser_new_with_stream (stream);
-
- mime_message = g_mime_parser_construct_message (parser);
-
- show_message_part (g_mime_message_get_mime_part (mime_message),
- &state,
- format,
- params,
- TRUE);
-
- DONE:
- if (mime_message)
- g_object_unref (mime_message);
+ ret = mime_node_open (NULL, message, params->cryptoctx, params->decrypt,
+ &root);
+ if (ret)
+ return ret;
- if (parser)
- g_object_unref (parser);
+ /* The caller of show_message_body has already handled the
+ * outermost envelope, so skip it. */
+ state.part_count = MAX (params->part, 1);
- if (stream)
- g_object_unref (stream);
+ part = mime_node_seek_dfs (root, state.part_count);
+ if (part)
+ show_message_part (part, &state, format, TRUE);
- if (file)
- fclose (file);
+ talloc_free (root);
- return ret;
+ return NOTMUCH_STATUS_SUCCESS;
}
make test OPTIONS="--verbose"
+You can choose an emacs binary to run the tests in one of the
+following ways.
+
+ TEST_EMACS=my-special-emacs make test
+ TEST_EMACS=my-special-emacs ./emacs
+ make test TEST_EMACS=my-special-emacs
+
Skipping Tests
--------------
If, for any reason, you need to skip one or more tests, you can do so
--- /dev/null
+Message-ID: <4EFC743A.3060609@april.org>
+Date: Thu, 29 Dec 2010 15:07:54 +0100
+From: "=?ISO-8859-1?Q?Fran=E7ois_Boulogne?=" <boulogne.f@gmail.com>
+User-Agent: Mozilla/5.0 (X11; Linux i686;
+ rv:9.0) Gecko/20111224 Thunderbird/9.0.1
+MIME-Version: 1.0
+To: Allan McRae <allan@archlinux.org>,
+ "Discussion about the Arch User Repository (AUR)" <aur-general@archlinux.org>
+References: <4EFC3931.6030007@april.org> <4EFC3D62.4030202@archlinux.org>
+In-Reply-To: <4EFC3D62.4030202@archlinux.org>
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 8bit
+Subject: Re: [aur-general] Guidelines: cp, mkdir vs install
+
+Le 29/12/2011 11:13, Allan McRae a écrit :
+> On 29/12/11 19:56, François Boulogne wrote:
+>> Hi,
+>>
+>> Looking to improve the quality of my packages, I read again the guidelines.
+>> https://wiki.archlinux.org/index.php/Arch_Packaging_Standards
+>>
+>> However, it don't see anything about the install command like
+>> install -d $pkgdir/usr/{bin,share/man/man1,share/locale}
+>>
+>> Some contributors on AUR use cp or mkdir to install files/dir (when no
+>> makefile is provided) and others use install command.
+>>
+>> What's the opinion of TU on this point?
+>>
+>
+> Use install with -m specifying the correct permissions
+>
+
+Thank you Allan
+
+
+--
+François Boulogne.
+https://www.sciunto.org
--- /dev/null
+From: Olivier Berger <olivier.berger@it-sudparis.eu>
+To: olivier.berger@it-sudparis.eu
+Subject: Essai =?iso-8859-1?Q?accentu=E9?=
+User-Agent: Notmuch/0.10.1 (http://notmuchmail.org) Emacs/23.3.1 (i486-pc-linux-gnu)
+X-Draft-From: ("nnimap+localdovecot:INBOX" 44228)
+Date: Fri, 16 Dec 2010 16:49:59 +0100
+Message-ID: <877h1wv7mg.fsf@inf-8657.int-evry.fr>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=iso-8859-1
+Content-Transfer-Encoding: quoted-printable
+
+Du texte accentu=E9 pour =E7a ...
+
+=E0 la bonne heure !
+--=20
+Olivier BERGER=20
+http://www-public.it-sudparis.eu/~berger_o/ - OpenPGP-Id: 2048R/5819D7E8
+Ingenieur Recherche - Dept INF
+Institut TELECOM, SudParis (http://www.it-sudparis.eu/), Evry (France)
+
"Invalid " From" <test_suite@notmuchmail.org> (2001-01-05) (inbox)
Subject: message-with-invalid-from
To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
This is just a test message (#1)
EOF
----- Original Message -----
From: Notmuch Test Suite <test_suite@notmuchmail.org>
To: Notmuch Test Suite <test_suite@notmuchmai.org>
-Sent: Tue, 05 Jan 2001 15:43:57 -0000
+Sent: Fri, 05 Jan 2001 15:43:57 +0000
Subject: The problem with top-posting
Q: Why is top-posting such a bad thing?
echo "Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox)
Subject: The problem with top-posting
To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
Top Poster <top@poster.com> (2001-01-05) (inbox unread)
Subject: Re: The problem with top-posting
To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
Thanks for the advice! I will be sure to put it to good use.
--- /dev/null
+#!/usr/bin/env bash
+
+test_description="emacs: mail subject to filename"
+. test-lib.sh
+
+# emacs server can't be started in a child process with $(test_emacs ...)
+test_emacs '(ignore)'
+
+# test notmuch-wash-subject-to-patch-sequence-number (subject)
+test_begin_subtest "no patch sequence number"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH] A normal patch subject without numbers")'
+)
+test_expect_equal "$output" ""
+
+test_begin_subtest "patch sequence number #1"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] A most regular patch subject")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #2"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ " [dummy list prefix] [RFC PATCH v2 13/42] Special prefixes")'
+)
+test_expect_equal "$output" 13
+
+test_begin_subtest "patch sequence number #3"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] [PATCH 032/037] use the last prefix")'
+)
+test_expect_equal "$output" 32
+
+test_begin_subtest "patch sequence number #4"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[dummy list prefix] [PATCH 2/3] PATCH 3/3] do not use a broken prefix")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #5"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[RFC][PATCH 3/5][PATCH 4/5][PATCH 5/5] A made up test")'
+)
+test_expect_equal "$output" 5
+
+test_begin_subtest "patch sequence number #6"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[PATCH 2/3] this -> [PATCH 3/3] is not a prefix anymore [nor this 4/4]")'
+)
+test_expect_equal "$output" 2
+
+test_begin_subtest "patch sequence number #7"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-sequence-number
+ "[liberally accept crapola right before123/456and after] the numbers")'
+)
+test_expect_equal "$output" 123
+
+# test notmuch-wash-subject-to-filename (subject &optional maxlen)
+test_begin_subtest "filename #1"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "just a subject line")'
+)
+test_expect_equal $output '"just-a-subject-line"'
+
+test_begin_subtest "filename #2"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ " [any] [prefixes are ] [removed!] from the subject")'
+)
+test_expect_equal $output '"from-the-subject"'
+
+test_begin_subtest "filename #3"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ " leading and trailing space ")'
+)
+test_expect_equal $output '"leading-and-trailing-space"'
+
+test_begin_subtest "filename #4"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "!# leading ()// &%, and in between_and_trailing garbage ()(&%%")'
+)
+test_expect_equal $output '"-leading-and-in-between_and_trailing-garbage"'
+
+test_begin_subtest "filename #5"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890")'
+)
+test_expect_equal $output '"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_01234567890"'
+
+test_begin_subtest "filename #6"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "sequences of ... are squashed and trailing are removed ...")'
+)
+test_expect_equal $output '"sequences-of-.-are-squashed-and-trailing-are-removed"'
+
+test_begin_subtest "filename #7"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "max length test" 1)'
+)
+test_expect_equal $output '"m"'
+
+test_begin_subtest "filename #8"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "max length test /&(/%&/%%&¤%¤" 20)'
+)
+test_expect_equal $output '"max-length-test"'
+
+test_begin_subtest "filename #9"
+output=$(test_emacs '(notmuch-wash-subject-to-filename
+ "[a prefix] [is only separated] by [spaces], so \"by\" is not okay!")'
+)
+test_expect_equal $output '"by-spaces-so-by-is-not-okay"'
+
+# test notmuch-wash-subject-to-patch-filename (subject)
+test_begin_subtest "patch filename #1"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[RFC][PATCH 099/100] rewrite notmuch")'
+)
+test_expect_equal "$output" '"0099-rewrite-notmuch.patch"'
+
+test_begin_subtest "patch filename #2"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[RFC PATCH v1] has no patch number, default to 1")'
+)
+test_expect_equal "$output" '"0001-has-no-patch-number-default-to-1.patch"'
+
+test_begin_subtest "patch filename #3"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[PATCH 4/5] the maximum length of a patch filename is 52 + patch sequence number + .patch extension")'
+)
+test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patch-s.patch"'
+
+test_begin_subtest "patch filename #4"
+output=$(test_emacs '(notmuch-wash-subject-to-patch-filename
+ "[PATCH 4/5] the maximum length of a patch filename is 52 + patchh ! sequence number + .patch extension, *before* trimming trailing - and .")'
+)
+test_expect_equal "$output" '"0004-the-maximum-length-of-a-patch-filename-is-52-patchh.patch"'
+
+test_done
- Welcome to notmuch. You have 50 messages.
+ Welcome to notmuch. You have 52 messages.
Saved searches: [edit]
- 50 inbox 50 unread
+ 52 inbox 52 unread
Search:
- Welcome to notmuch. You have 50 messages.
+ Welcome to notmuch. You have 52 messages.
Search:
2009-11-18 [1/1] Alexander Botero-Lowry [notmuch] request for pull (inbox unread)
2009-11-18 [2/2] Keith Packard, Alexander Botero-Lowry [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (inbox unread)
2009-11-18 [1/1] Chris Wilson [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+ 2010-12-16 [1/1] Olivier Berger Essai accentué (inbox unread)
+ 2010-12-29 [1/1] François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
End of search results.
- Welcome to notmuch. You have 50 messages.
+ Welcome to notmuch. You have 52 messages.
Saved searches: [edit]
- 50 inbox 50 unread 0 empty
+ 52 inbox 52 unread 0 empty
Search:
+ 2010-12-29 [1/1] François Boulogne [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+ 2010-12-16 [1/1] Olivier Berger Essai accentué (inbox unread)
2009-11-18 [1/1] Chris Wilson [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
2009-11-18 [2/2] Alex Botero-Lowry, Carl Worth [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
2009-11-18 [2/2] Ingmar Vanhassel, Carl Worth [notmuch] [PATCH] Typsos (inbox unread)
Cheers,
-[ 5-line signature. Click/Enter to show. ]
+[ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
[ multipart/signed ]
[ text/plain ]
- Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did gyre and gimble:
+ Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did
+ gyre and gimble:
LK> Resulted in 4604 lines of errors along the lines of:
LK> Error opening
- LK> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+ LK>
+ /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
LK> Too many open files
See the patch just posted here.
-- Lars
- [ 5-line signature. Click/Enter to show. ]
+ [ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:50:48 +0600
-
- Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu did gyre and gimble:
+ Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu
+ did gyre and gimble:
LK> Is the list archived anywhere? The obvious archives
LK> (http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
Type: application/pgp-signature
Size: 834 bytes
Desc: not available
- URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
-
+ URL:
+ <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
Keith Packard <keithp@keithp.com> (2009-11-17) (inbox unread)
Subject: [notmuch] Working with Maildir storage?
To: notmuch@notmuchmail.org
Date: Tue, 17 Nov 2009 13:24:13 -0800
- On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+ On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at
+ seas.harvard.edu> wrote:
> > See the patch just posted here.
I've also pushed a slightly more complicated (and complete) fix to my
Thanks to everyone for trying out notmuch!
-keith
-
Lars Kellogg-Stedman <lars@seas.harvard.edu> (2009-11-18) (inbox signed unread)
Subject: Re: [notmuch] Working with Maildir storage?
To: Keith Packard <keithp@keithp.com>
The version of lib/messages.cc in your repo doesn't build because it's
missing "#include <stdint.h>" (for the uint32_t on line 466).
- [ 5-line signature. Click/Enter to show. ]
+ [ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:08:10 -0800
- On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+ On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at
+ seas.harvard.edu> wrote:
> I saw the LWN article and decided to take a look at notmuch. I'm
> currently using mutt and mairix to index and read a collection of
> Maildir mail folders (around 40,000 messages total).
That's very interesting. So, thanks for coming and trying out notmuch.
> Error opening
- > /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+ > /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
> Too many open files
Sadly, the lwn article coincided with me having just introduced this
Happy hacking,
-Carl
-
Cheers,
-[ 5-line signature. Click/Enter to show. ]
+[ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
[ multipart/signed ]
[ text/plain ]
- Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did gyre and gimble:
+ Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did
+ gyre and gimble:
LK> Resulted in 4604 lines of errors along the lines of:
LK> Error opening
- LK> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+ LK>
+ /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
LK> Too many open files
See the patch just posted here.
-- Lars
- [ 5-line signature. Click/Enter to show. ]
+ [ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:50:48 +0600
-
- Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu did gyre and gimble:
+ Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu
+ did gyre and gimble:
LK> Is the list archived anywhere? The obvious archives
LK> (http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
Type: application/pgp-signature
Size: 834 bytes
Desc: not available
- URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
-
+ URL:
+ <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
Keith Packard <keithp@keithp.com> (2009-11-17) (inbox unread)
Subject: [notmuch] Working with Maildir storage?
To: notmuch@notmuchmail.org
Date: Tue, 17 Nov 2009 13:24:13 -0800
- On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+ On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at
+ seas.harvard.edu> wrote:
> > See the patch just posted here.
I've also pushed a slightly more complicated (and complete) fix to my
Thanks to everyone for trying out notmuch!
-keith
-
Lars Kellogg-Stedman <lars@seas.harvard.edu> (2009-11-18) (inbox signed unread)
Subject: Re: [notmuch] Working with Maildir storage?
To: Keith Packard <keithp@keithp.com>
The version of lib/messages.cc in your repo doesn't build because it's
missing "#include <stdint.h>" (for the uint32_t on line 466).
- [ 5-line signature. Click/Enter to show. ]
+ [ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:08:10 -0800
- On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+ On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at
+ seas.harvard.edu> wrote:
> I saw the LWN article and decided to take a look at notmuch. I'm
> currently using mutt and mairix to index and read a collection of
> Maildir mail folders (around 40,000 messages total).
That's very interesting. So, thanks for coming and trying out notmuch.
> Error opening
- > /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+ > /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
> Too many open files
Sadly, the lwn article coincided with me having just introduced this
Happy hacking,
-Carl
-
Cheers,
-[ 5-line signature. Click/Enter to show. ]
+[ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
[ multipart/signed ]
[ text/plain ]
-Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did gyre and gimble:
+Twas brillig at 14:00:54 17.11.2009 UTC-05 when lars@seas.harvard.edu did
+gyre and gimble:
LK> Resulted in 4604 lines of errors along the lines of:
LK> Error opening
- LK> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+ LK>
+/home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
LK> Too many open files
See the patch just posted here.
-- Lars
-[ 5-line signature. Click/Enter to show. ]
+[ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:50:48 +0600
-
-Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu did gyre and gimble:
+Twas brillig at 15:33:01 17.11.2009 UTC-05 when lars at seas.harvard.edu
+did gyre and gimble:
LK> Is the list archived anywhere? The obvious archives
LK> (http://notmuchmail.org/pipermail/notmuch/) aren't available, and I
Type: application/pgp-signature
Size: 834 bytes
Desc: not available
-URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
-
+URL:
+<http://notmuchmail.org/pipermail/notmuch/attachments/20091118/0e33d964/attachment.pgp>
Keith Packard <keithp@keithp.com> (2009-11-17) (inbox unread)
Subject: [notmuch] Working with Maildir storage?
To: notmuch@notmuchmail.org
Date: Tue, 17 Nov 2009 13:24:13 -0800
-On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+On Tue, 17 Nov 2009 15:33:01 -0500, Lars Kellogg-Stedman <lars at
+seas.harvard.edu> wrote:
> > See the patch just posted here.
I've also pushed a slightly more complicated (and complete) fix to my
Thanks to everyone for trying out notmuch!
-keith
-
Lars Kellogg-Stedman <lars@seas.harvard.edu> (2009-11-18) (inbox signed unread)
Subject: Re: [notmuch] Working with Maildir storage?
To: Keith Packard <keithp@keithp.com>
The version of lib/messages.cc in your repo doesn't build because it's
missing "#include <stdint.h>" (for the uint32_t on line 466).
-[ 5-line signature. Click/Enter to show. ]
+[ 4-line signature. Click/Enter to show. ]
--
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Senior Technologist, Computing and Information Technology
Harvard University School of Engineering and Applied Sciences
-
[ application/pgp-signature ]
[ text/plain ]
[ 4-line signature. Click/Enter to show. ]
To: notmuch@notmuchmail.org
Date: Wed, 18 Nov 2009 02:08:10 -0800
-On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at seas.harvard.edu> wrote:
+On Tue, 17 Nov 2009 14:00:54 -0500, Lars Kellogg-Stedman <lars at
+seas.harvard.edu> wrote:
> I saw the LWN article and decided to take a look at notmuch. I'm
> currently using mutt and mairix to index and read a collection of
> Maildir mail folders (around 40,000 messages total).
That's very interesting. So, thanks for coming and trying out notmuch.
> Error opening
-> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
+> /home/lars/Mail/read-messages.2008/cur/1246413773.24928_27334.hostname,U=3026:2,S:
> Too many open files
Sadly, the lwn article coincided with me having just introduced this
Happy hacking,
-Carl
-
Subject: Test message #1
From: Notmuch Test Suite <test_suite@notmuchmail.org>
To: Notmuch Test Suite <test_suite@notmuchmail.org>
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
\fheader}
\fbody{
\fpart{ ID: 1, Content-type: text/plain
"To": "Notmuch Test Suite <test_suite@notmuchmail.org>",
"Cc": "",
"Bcc": "",
-"Date": "Tue,
-05 Jan 2001 15:43:57 -0000"},
+"Date": "Fri,
+05 Jan 2001 15:43:57 +0000"},
"body": [{"id": 1,
"content-type": "text/plain",
"content": "This is just a test message (#3)\n"}]},
encoding
emacs
emacs-large-search-buffer
+ emacs-subject-to-filename
maildir-sync
crypto
symbol-hiding
test_begin_subtest "compare thread ids"
test_python <<EOF
import notmuch
-db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
q_new = notmuch.Query(db, 'tag:inbox')
+q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
for t in q_new.search_threads():
print t.get_thread_id()
EOF
-notmuch search --output=threads tag:inbox | sed s/^thread:// | sort > EXPECTED
-test_expect_equal_file <(sort OUTPUT) EXPECTED
+notmuch search --sort=oldest-first --output=threads tag:inbox | sed s/^thread:// > EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "compare message ids"
+test_python <<EOF
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
+q_new = notmuch.Query(db, 'tag:inbox')
+q_new.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
+for m in q_new.search_messages():
+ print m.get_message_id()
+EOF
+notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED
+test_expect_equal_file OUTPUT EXPECTED
+
test_done
To: Notmuch Test Suite <test_suite@notmuchmail.org>
Message-Id: <msg-001@notmuch-test-suite>
Subject: Test message #1
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
This is just a test message (#1)"
To: Notmuch Test Suite <test_suite@notmuchmail.org>
Message-Id: <msg-002@notmuch-test-suite>
Subject: Test message #2
-Date: Tue, 05 Jan 2001 15:43:57 -0000
+Date: Fri, 05 Jan 2001 15:43:57 +0000
This is just a test message (#2)"
test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)"
test_begin_subtest 'Search for all messages ("*")'
-output=$(notmuch search '*' | notmuch_search_sanitize)
-test_expect_equal "$output" "thread:XXX 2009-11-18 [1/1] Chris Wilson; [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
+notmuch search '*' | notmuch_search_sanitize > OUTPUT
+cat <<EOF >EXPECTED
+thread:XXX 2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+thread:XXX 2010-12-16 [1/1] Olivier Berger; Essai accentué (inbox unread)
+thread:XXX 2009-11-18 [1/1] Chris Wilson; [notmuch] [PATCH 1/2] Makefile: evaluate pkg-config once (inbox unread)
thread:XXX 2009-11-18 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)
thread:XXX 2009-11-18 [2/2] Ingmar Vanhassel, Carl Worth; [notmuch] [PATCH] Typsos (inbox unread)
thread:XXX 2009-11-18 [3/3] Adrian Perez de Castro, Keith Packard, Carl Worth; [notmuch] Introducing myself (inbox signed unread)
thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] count_files: sort directory in inode order before statting (inbox unread)
thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH 2/2] Read mail directory in inode number order (inbox unread)
thread:XXX 2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)
-thread:XXX 2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] \"notmuch help\" outputs to stderr? (attachment inbox signed unread)
+thread:XXX 2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
thread:XXX 2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
thread:XXX 2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)
thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; subject search test (phrase) (inbox unread)
-thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; this phrase should not match the subject search test (inbox unread)"
+thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; this phrase should not match the subject search test (inbox unread)
+EOF
+test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "Search body (utf-8):"
add_message '[subject]="utf8-message-body-subject"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="message body utf8: bödý"'
thread:THREADID
thread:THREADID
thread:THREADID
+thread:THREADID
+thread:THREADID
EOF
test_expect_equal_file OUTPUT EXPECTED
"THREADID",
"THREADID",
"THREADID",
+"THREADID",
+"THREADID",
"THREADID"]
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=messages"
notmuch search --output=messages '*' >OUTPUT
cat <<EOF >EXPECTED
+id:4EFC743A.3060609@april.org
+id:877h1wv7mg.fsf@inf-8657.int-evry.fr
id:1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk
id:877htoqdbo.fsf@yoom.home.cworth.org
id:878we4qdqf.fsf@yoom.home.cworth.org
test_begin_subtest "--output=messages --format=json"
notmuch search --format=json --output=messages '*' >OUTPUT
cat <<EOF >EXPECTED
-["1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk",
+["4EFC743A.3060609@april.org",
+"877h1wv7mg.fsf@inf-8657.int-evry.fr",
+"1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk",
"877htoqdbo.fsf@yoom.home.cworth.org",
"878we4qdqf.fsf@yoom.home.cworth.org",
"87aaykqe24.fsf@yoom.home.cworth.org",
test_begin_subtest "--output=files"
notmuch search --output=files '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
cat <<EOF >EXPECTED
+MAIL_DIR/cur/52:2,
+MAIL_DIR/cur/53:2,
MAIL_DIR/cur/50:2,
MAIL_DIR/cur/49:2,
MAIL_DIR/cur/48:2,
test_begin_subtest "--output=files --format=json"
notmuch search --format=json --output=files '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT
cat <<EOF >EXPECTED
-["MAIL_DIR/cur/50:2,",
+["MAIL_DIR/cur/52:2,",
+"MAIL_DIR/cur/53:2,",
+"MAIL_DIR/cur/50:2,",
"MAIL_DIR/cur/49:2,",
"MAIL_DIR/cur/48:2,",
"MAIL_DIR/cur/47:2,",
. ./test-lib.sh
run_test(){
- result=$(LD_LIBRARY_PATH=$TEST_DIRECTORY/../lib $TEST_DIRECTORY/symbol-test 2>&1)
+ result=$(LD_LIBRARY_PATH="$TEST_DIRECTORY/../lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" $TEST_DIRECTORY/symbol-test 2>&1)
}
output="A Xapian exception occurred opening database: Couldn't stat 'fakedb/.notmuch/xapian'
-#!/usr/bin/env bash
#
# Copyright (c) 2005 Junio C Hamano
#
TERM=dumb
export LANG LC_ALL PAGER TERM TZ
GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
+TEST_EMACS=${TEST_EMACS:-${EMACS:-emacs}}
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
fi
if [ -z "${template[date]}" ]; then
- template[date]="Tue, 05 Jan 2001 15:43:57 -0000"
+ template[date]="Fri, 05 Jan 2001 15:43:57 +0000"
fi
additional_headers=""
#
# --load Force loading of notmuch.el and test-lib.el
-exec emacs --no-init-file --no-site-file \
+exec ${TEST_EMACS} --no-init-file --no-site-file \
--directory "$TEST_DIRECTORY/../emacs" --load notmuch.el \
--directory "$TEST_DIRECTORY" --load test-lib.el \
"\$@"