]> git.notmuchmail.org Git - notmuch/commitdiff
Merge branch 'release'
authorDavid Bremner <bremner@debian.org>
Sat, 14 Jan 2012 00:52:01 +0000 (20:52 -0400)
committerDavid Bremner <bremner@debian.org>
Sat, 14 Jan 2012 00:52:01 +0000 (20:52 -0400)
Conflicts:
notmuch-reply.c
notmuch.1

62 files changed:
Makefile
Makefile.local
bindings/python/notmuch.py
bindings/python/notmuch/database.py
bindings/python/notmuch/filename.py
bindings/python/notmuch/globals.py
bindings/python/notmuch/message.py
bindings/python/notmuch/tag.py
bindings/python/notmuch/thread.py
bindings/python/setup.py
debian/notmuch.install
emacs/notmuch-hello.el
emacs/notmuch-mua.el
emacs/notmuch-show.el
emacs/notmuch-wash.el
emacs/notmuch.el
lib/index.cc
lib/messages.c
man/Makefile [new file with mode: 0644]
man/Makefile.local [new file with mode: 0644]
man/man1/notmuch-config.1 [new file with mode: 0644]
man/man1/notmuch-count.1 [new file with mode: 0644]
man/man1/notmuch-dump.1 [new file with mode: 0644]
man/man1/notmuch-new.1 [new file with mode: 0644]
man/man1/notmuch-reply.1 [new file with mode: 0644]
man/man1/notmuch-restore.1 [new file with mode: 0644]
man/man1/notmuch-search.1 [new file with mode: 0644]
man/man1/notmuch-setup.1 [new symlink]
man/man1/notmuch-show.1 [new file with mode: 0644]
man/man1/notmuch-tag.1 [new file with mode: 0644]
man/man1/notmuch.1 [new file with mode: 0644]
man/man5/notmuch-hooks.5 [new file with mode: 0644]
man/man7/notmuch-search-terms.7 [new file with mode: 0644]
mime-node.c [new file with mode: 0644]
notmuch-client.h
notmuch-reply.c
notmuch-show.c
notmuch.1 [deleted file]
notmuch.c
show-message.c
test/README
test/corpus/cur/52:2, [new file with mode: 0644]
test/corpus/cur/53:2, [new file with mode: 0644]
test/emacs
test/emacs-subject-to-filename [new file with mode: 0755]
test/emacs.expected-output/notmuch-hello
test/emacs.expected-output/notmuch-hello-no-saved-searches
test/emacs.expected-output/notmuch-hello-view-inbox
test/emacs.expected-output/notmuch-hello-with-empty
test/emacs.expected-output/notmuch-search-tag-inbox
test/emacs.expected-output/notmuch-show-thread-maildir-storage
test/emacs.expected-output/notmuch-show-thread-maildir-storage-with-fourfold-indentation
test/emacs.expected-output/notmuch-show-thread-maildir-storage-without-indentation
test/encoding
test/maildir-sync
test/notmuch-test
test/python
test/raw
test/search
test/search-output
test/symbol-hiding
test/test-lib.sh

index 2fb2a61354c7bbd3ca75219150e7ebaf1b0e7944..e5e2e3a3ac67a9e515411c7e03d449db59d9a5c0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 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 \
index 97f397ff2d238ca99bbb735488ccd06dd0c40d4b..d3bf9478b3f75ac165693c03522436de8efcafde 100644 (file)
@@ -53,7 +53,7 @@ endif
 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
@@ -95,8 +95,7 @@ dist: $(TAR_FILE)
 
 .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
@@ -221,14 +220,6 @@ verify-version-python: verify-version-components
                 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..."
@@ -315,6 +306,7 @@ notmuch_client_srcs =               \
        notmuch-time.c          \
        query-string.c          \
        show-message.c          \
+       mime-node.c             \
        json.c
 
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
@@ -325,13 +317,8 @@ notmuch: $(notmuch_client_modules) lib/libnotmuch.a util/libutil.a
 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)
@@ -362,4 +349,4 @@ install-desktop:
        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
index 8d1185953b5ccd50c9032b1220624873857701af..3ff53ec8c60ed6459a9eb36b03bf81e246eca838 100755 (executable)
@@ -17,7 +17,12 @@ import stat
 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+):(.*$)')
index 7923f768b1f78caec831c3018b5280367feb9712..24da8e99f1b715d43ffd8136e10ca4a7ed921b72 100644 (file)
@@ -430,7 +430,7 @@ class Database(object):
                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
@@ -543,7 +543,13 @@ class Database(object):
         """ 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'))
@@ -919,7 +925,7 @@ class Filenames(object):
     _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)
 
@@ -927,9 +933,10 @@ class Filenames(object):
             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
index a7cd7e63d44bf03076b5e21087e77ae425761a7a..51dae202d5d656963a977739ae053ef55b35adb5 100644 (file)
@@ -18,10 +18,10 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
 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
@@ -93,14 +93,11 @@ class Filenames(object):
             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
 
index 54a49b2d3f16895a8a8ce0b9ffc459b58a7cadf2..32ed9ae40181ece3632fa2175a5569c89dd69e2c 100644 (file)
@@ -16,7 +16,7 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 
 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
-
+import sys
 from ctypes import CDLL, c_char_p, c_int, Structure, POINTER
 
 #-----------------------------------------------------------------------------
@@ -27,6 +27,16 @@ except:
     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):
@@ -51,7 +61,7 @@ class Status(Enum):
         """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',
@@ -89,7 +99,7 @@ argument to receive a human readable string"""
 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
@@ -133,16 +143,13 @@ class NotmuchError(Exception):
         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
index ce8e7181b2743f162843c8f2d387baf3515d3f9c..d40a575d92d8587e355935abbb312117e2ec0a0c 100644 (file)
@@ -21,7 +21,8 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 
 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
@@ -158,7 +159,7 @@ class Messages(object):
     _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)
 
@@ -169,6 +170,7 @@ class Messages(object):
         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):
         """
@@ -186,14 +188,17 @@ class Messages(object):
         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 = ""
@@ -207,38 +212,61 @@ class Messages(object):
 
         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*
@@ -336,7 +364,7 @@ class Message(object):
         """
         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
@@ -354,7 +382,7 @@ class Message(object):
         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`
@@ -368,10 +396,9 @@ class Message(object):
             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.
         """
@@ -381,7 +408,7 @@ class Message(object):
         msgs_p = Message._get_replies(self._msg)
 
         if msgs_p is None:
-            return None
+            return EmptyMessagesResult(self)
 
         return Messages(msgs_p, self)
 
@@ -424,10 +451,10 @@ class Message(object):
             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
@@ -438,7 +465,7 @@ class Message(object):
         """
         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'
@@ -795,9 +822,6 @@ class Message(object):
         """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'),
index 2fb7d3287a8413e295b1e9b5b2840d9d06bdb476..ceb724410606a729bd042a394b2937816afc30ed 100644 (file)
@@ -17,10 +17,10 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 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
@@ -89,7 +89,7 @@ class Tags(object):
     _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):
@@ -98,6 +98,7 @@ class Tags(object):
         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
@@ -110,9 +111,6 @@ class Tags(object):
             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
 
index 5058846d7ce89d4bbd0cbef5fb6bab06079e3047..e81ff1bdea305de55fada9a308508c4a5e6bd5d2 100644 (file)
@@ -20,13 +20,13 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 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
@@ -116,7 +116,7 @@ class Threads(object):
     _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)
 
@@ -127,6 +127,7 @@ class Threads(object):
         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
@@ -245,7 +246,7 @@ class Thread(object):
         """
         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]
@@ -325,7 +326,7 @@ class Thread(object):
         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'
@@ -338,7 +339,7 @@ class Thread(object):
         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
@@ -391,9 +392,6 @@ class Thread(object):
             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)"
 
index 286fd1962187b6351036d54d547e69dd9c0b1016..2e58dab1d6a6cc3a6193031f2410b082e385b9eb 100644 (file)
@@ -7,7 +7,7 @@ from distutils.core import setup
 # 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',
index fff498d20f55896121a232da5a46a877e6f04005..86e891d4aefc5ad6a593b68f81981dfa85bbcf45 100644 (file)
@@ -1,3 +1,3 @@
 usr/bin
-usr/share/man/man1
+usr/share/man
 etc/bash_completion.d
index 333d4c1ea633749cabb7dcf0e31f78241b1eadd2..02017ce59a0ea1fa107aea832b770405274eb429 100644 (file)
@@ -299,15 +299,17 @@ should be. Returns a cons cell `(tags-per-line width)'."
                               :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")))
index 7114e48a4b8ca94223c969cefebcb5f50fde55fa..32e2e30bfd938d96a37ad6014768810006e0e737 100644 (file)
@@ -108,7 +108,8 @@ list."
     (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))
index 82d11c925bab4b5ecc6b225579e430514b8fce44..2806879e53cfff412e07c4b175478f8ed728998e 100644 (file)
@@ -75,7 +75,10 @@ any given message."
   :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
@@ -585,6 +588,10 @@ current buffer, if possible."
                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))
index 1f420b25a05d770556cd19e4e737f522b7e18098..5c1e83009eec56a4d5073806be2d9ea93c2d4a94 100644 (file)
@@ -290,6 +290,44 @@ When doing so, maintaining citation leaders in the wrapped text."
 
 (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.
 
@@ -313,10 +351,13 @@ for error."
              (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))))))
 
index fde23779d7cf8f4a8853fd16da6940779cd48820..1e617752ad3174ec081bb4935999b376bf30a126 100644 (file)
@@ -164,16 +164,23 @@ For a mouse binding, return nil."
                "\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))
 
@@ -438,7 +445,7 @@ Complete list of currently available key bindings:
                                 "*")
                         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."
index e8e9922b408a4d59a771aedf6783fc73126b0ad0..d8f8b2bf516247ccc14aec8927dc5ae703a830d3 100644 (file)
@@ -339,6 +339,10 @@ _index_mime_part (notmuch_message_t *message,
                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));
        }
index 7bcd1abfb4ce16791c6306c444215e1ae25418be..11218648f8c15f86f5a5dd6c5c0ece696577e46a 100644 (file)
@@ -127,8 +127,10 @@ notmuch_messages_get (notmuch_messages_t *messages)
 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;
diff --git a/man/Makefile b/man/Makefile
new file mode 100644 (file)
index 0000000..fa25832
--- /dev/null
@@ -0,0 +1,5 @@
+all:
+       $(MAKE) -C .. all
+
+.DEFAULT:
+       $(MAKE) -C .. $@
diff --git a/man/Makefile.local b/man/Makefile.local
new file mode 100644 (file)
index 0000000..d43a949
--- /dev/null
@@ -0,0 +1,60 @@
+# -*- 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)
diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1
new file mode 100644 (file)
index 0000000..cb3234f
--- /dev/null
@@ -0,0 +1,54 @@
+.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)
diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
new file mode 100644 (file)
index 0000000..25fe329
--- /dev/null
@@ -0,0 +1,50 @@
+.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)
diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1
new file mode 100644 (file)
index 0000000..9ccf35d
--- /dev/null
@@ -0,0 +1,37 @@
+.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)
diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1
new file mode 100644 (file)
index 0000000..77d4776
--- /dev/null
@@ -0,0 +1,65 @@
+.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)
diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
new file mode 100644 (file)
index 0000000..db464d8
--- /dev/null
@@ -0,0 +1,68 @@
+.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)
diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1
new file mode 100644 (file)
index 0000000..2191df0
--- /dev/null
@@ -0,0 +1,39 @@
+.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)
diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
new file mode 100644 (file)
index 0000000..0bc3f40
--- /dev/null
@@ -0,0 +1,121 @@
+.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)
diff --git a/man/man1/notmuch-setup.1 b/man/man1/notmuch-setup.1
new file mode 120000 (symlink)
index 0000000..5c78dc8
--- /dev/null
@@ -0,0 +1 @@
+notmuch.1
\ No newline at end of file
diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
new file mode 100644 (file)
index 0000000..b2301d8
--- /dev/null
@@ -0,0 +1,145 @@
+.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)
diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1
new file mode 100644 (file)
index 0000000..993911b
--- /dev/null
@@ -0,0 +1,32 @@
+.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)
diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1
new file mode 100644 (file)
index 0000000..424ca36
--- /dev/null
@@ -0,0 +1,148 @@
+.\" 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).
diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5
new file mode 100644 (file)
index 0000000..2c4e552
--- /dev/null
@@ -0,0 +1,48 @@
+.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)
diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7
new file mode 100644 (file)
index 0000000..a53565b
--- /dev/null
@@ -0,0 +1,141 @@
+.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)
diff --git a/mime-node.c b/mime-node.c
new file mode 100644 (file)
index 0000000..d26bb44
--- /dev/null
@@ -0,0 +1,265 @@
+/* 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);
+}
index c602e2e08c28fd2d2d9011c2eacb3f7dac8f1d75..517c010a5db1dafef2e2817f753b9b4e33254398 100644 (file)
@@ -162,7 +162,7 @@ char *
 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);
 
@@ -241,5 +241,93 @@ notmuch_run_hook (const char *db_path, const char *hook);
 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
index 7242310a7ec5f376872ac065044cbfc0e7c1fedb..000f6dada171fef07e3b42985934656172e989b5 100644 (file)
@@ -546,8 +546,7 @@ notmuch_reply_format_default(void *ctx,
                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);
     }
@@ -613,62 +612,61 @@ notmuch_reply_format_headers_only(void *ctx,
     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;
index 19fb49f29b89172b63eed772ab79297e986904a1..0200b9c4a4cd28fe7126d83b5b0045c82037e9bb 100644 (file)
@@ -758,8 +758,7 @@ show_message (void *ctx,
     }
 
     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);
diff --git a/notmuch.1 b/notmuch.1
deleted file mode 100644 (file)
index a5828bc..0000000
--- a/notmuch.1
+++ /dev/null
@@ -1,776 +0,0 @@
-.\" 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).
index c0ce026a14ff904d29fbf53ca53b40975855bf52..477a09cf05dd1bd803e8d68bfadf0e3c82660a65 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -29,7 +29,6 @@ typedef struct command {
     command_function_t function;
     const char *arguments;
     const char *summary;
-    const char *documentation;
 } command_t;
 
 #define MAX_ALIAS_SUBSTITUTIONS 3
@@ -47,447 +46,40 @@ alias_t aliases[] = {
 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
@@ -517,8 +109,17 @@ usage (FILE *out)
     "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;
@@ -531,41 +132,28 @@ notmuch_help_command (unused (void *ctx), int argc, char *argv[])
        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,
index d83f04ecc553264bd42b28867e5154c33966b4f2..8768889efddd11ed665e84f788bf0864bd6da3c3 100644 (file)
 
 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;
 }
index 7b2e96d466a7a1403fa78f03940ffacf15abdd14..bde6db0c04a4979ea29ac1451e5d0e6b80b8fb50 100644 (file)
@@ -56,6 +56,13 @@ can be specified as follows:
 
        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
diff --git a/test/corpus/cur/52:2, b/test/corpus/cur/52:2,
new file mode 100644 (file)
index 0000000..6028340
--- /dev/null
@@ -0,0 +1,39 @@
+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
diff --git a/test/corpus/cur/53:2, b/test/corpus/cur/53:2,
new file mode 100644 (file)
index 0000000..7a1e2e5
--- /dev/null
@@ -0,0 +1,20 @@
+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)
+
index f36718e73e450728f51e26c08f9e8a46e2be1646..ac47b161f837be4f325101c8305ab499867e376f 100755 (executable)
@@ -81,7 +81,7 @@ cat <<EOF >EXPECTED
 "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
@@ -320,7 +320,7 @@ add_message '[from]="Top Poster <top@poster.com>"' \
 ----- 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?
@@ -331,7 +331,7 @@ test_emacs "(notmuch-show \"top-posting\")
 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?
@@ -340,7 +340,7 @@ Q: What is the most annoying thing in e-mail?
 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.
 
diff --git a/test/emacs-subject-to-filename b/test/emacs-subject-to-filename
new file mode 100755 (executable)
index 0000000..176e685
--- /dev/null
@@ -0,0 +1,138 @@
+#!/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
index 48143bd73055a07f7f3394ca95f9f16ca053335f..de57de250b2c938cf5fc4f68e2954b1f9c319240 100644 (file)
@@ -1,8 +1,8 @@
-   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:                                                                      
 
index 7c09e40bcef121d778fcf72f7a1676269e7fcf93..f1fc4d6a956051b2778c7a5638ce92b839519beb 100644 (file)
@@ -1,4 +1,4 @@
-   Welcome to notmuch. You have 50 messages.
+   Welcome to notmuch. You have 52 messages.
 
 Search:                                                                      
 
index 894ae5fadb72763a2fc556458f909da1494a0aab..1688d6745c51ba6f3393acd8703860be8944ea7c 100644 (file)
@@ -20,4 +20,6 @@
   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.
index 2a267c92580a8c39979cbd7a5c6e4c515d38cb54..dd8728b17cfc35438f9a086acc08eac8bb3e5103 100644 (file)
@@ -1,8 +1,8 @@
-   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:                                                                      
 
index 9456ccfd247ab6c78fc8c62cdee045f39fd89cd0..8a53555afb40d5a5eec1662dfcd622c32087123c 100644 (file)
@@ -1,3 +1,5 @@
+  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)
index 8ba64b270a050e460c4aac20ca34995e379485e0..cdbfa1d7e18476c32ca8483936b061bacf09d674 100644 (file)
@@ -26,12 +26,11 @@ with Maildir) or if something else is going on.
 
 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. ]
@@ -48,12 +47,14 @@ http://notmuchmail.org/mailman/listinfo/notmuch
  [ 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.
@@ -88,12 +89,11 @@ http://notmuchmail.org/mailman/listinfo/notmuch
 
   -- 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. ]
@@ -106,8 +106,8 @@ http://notmuchmail.org/mailman/listinfo/notmuch
    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
@@ -127,14 +127,15 @@ http://notmuchmail.org/mailman/listinfo/notmuch
    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
@@ -150,7 +151,6 @@ http://notmuchmail.org/mailman/listinfo/notmuch
    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>
@@ -166,12 +166,11 @@ http://notmuchmail.org/mailman/listinfo/notmuch
     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. ]
@@ -184,7 +183,8 @@ http://notmuchmail.org/mailman/listinfo/notmuch
  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).
@@ -195,7 +195,7 @@ http://notmuchmail.org/mailman/listinfo/notmuch
  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
@@ -212,4 +212,3 @@ http://notmuchmail.org/mailman/listinfo/notmuch
  Happy hacking,
 
  -Carl
-
index 41e2aaa33e065604b268319c359551f6d135d2ba..b0bf93edc99146050a21e6b1e8ab3bc354b4ff15 100644 (file)
@@ -26,12 +26,11 @@ with Maildir) or if something else is going on.
 
 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. ]
@@ -48,12 +47,14 @@ http://notmuchmail.org/mailman/listinfo/notmuch
     [ 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.
@@ -88,12 +89,11 @@ http://notmuchmail.org/mailman/listinfo/notmuch
 
        -- 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. ]
@@ -106,8 +106,8 @@ http://notmuchmail.org/mailman/listinfo/notmuch
            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
@@ -127,14 +127,15 @@ http://notmuchmail.org/mailman/listinfo/notmuch
            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
@@ -150,7 +151,6 @@ http://notmuchmail.org/mailman/listinfo/notmuch
            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>
@@ -166,12 +166,11 @@ http://notmuchmail.org/mailman/listinfo/notmuch
                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. ]
@@ -184,7 +183,8 @@ http://notmuchmail.org/mailman/listinfo/notmuch
     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).
@@ -195,7 +195,7 @@ http://notmuchmail.org/mailman/listinfo/notmuch
     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
@@ -212,4 +212,3 @@ http://notmuchmail.org/mailman/listinfo/notmuch
     Happy hacking,
 
     -Carl
-
index fa2108ef2efbfe0bdadcf68112a7204c146de5da..08de8b5da86a9fd9cb2b873e02b59744018f70f6 100644 (file)
@@ -26,12 +26,11 @@ with Maildir) or if something else is going on.
 
 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. ]
@@ -48,12 +47,14 @@ Date: Wed, 18 Nov 2009 01:02:38 +0600
 [ 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.
@@ -88,12 +89,11 @@ It doesn't look like the patch is in git yet.
 
 -- 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. ]
@@ -106,8 +106,8 @@ Subject: [notmuch] Working with Maildir storage?
 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
@@ -127,14 +127,15 @@ Name: not available
 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
@@ -150,7 +151,6 @@ Barcelona today and so it won't get fixed for a while.
 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>
@@ -166,12 +166,11 @@ Date: Tue, 17 Nov 2009 19:50:40 -0500
 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. ]
@@ -184,7 +183,8 @@ Subject: [notmuch] Working with Maildir storage?
 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).
@@ -195,7 +195,7 @@ I hadn't even seen that Keith's blog post had been picked up by lwn.net.
 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
@@ -212,4 +212,3 @@ likes the best.
 Happy hacking,
 
 -Carl
-
index 673b0394860548a379b58733dba2823aa93cec9f..e875c8b1f4f8348f0e2156d2a9938b1e1f659ef1 100755 (executable)
@@ -12,7 +12,7 @@ Notmuch Test Suite <test_suite@notmuchmail.org> (2001-01-05) (inbox unread)
 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
index a60854f8f59f311294effaa3690c80bc50703158..d5872a53589ccd106420190af66b71f8e5be4979 100755 (executable)
@@ -55,8 +55,8 @@ test_expect_equal "$output" '[[[{"id": "adding-replied-tag@notmuch-test-suite",
 "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"}]},
index ded79e8f703283fa1934add756babb8009d99198..e40ef86a8764427434957f76f5cf29dbaf7ac9ae 100755 (executable)
@@ -42,6 +42,7 @@ TESTS="
   encoding
   emacs
   emacs-large-search-buffer
+  emacs-subject-to-filename
   maildir-sync
   crypto
   symbol-hiding
index c3aa7266e285f0e6b6f4b2671ffed07663eab805..6018c2d0ad134e1b1bdad765e62b235e48afa618 100755 (executable)
@@ -7,11 +7,25 @@ add_email_corpus
 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
index 99d3a3bf0460ee55009c72dcba1814cc59995ff8..0171e641efd624917a4f55fed4c9d39581384bfa 100755 (executable)
--- a/test/raw
+++ b/test/raw
@@ -19,7 +19,7 @@ test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.or
 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)"
 
@@ -29,7 +29,7 @@ test_expect_equal "$output" "From: Notmuch Test Suite <test_suite@notmuchmail.or
 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)"
 
index e7c8c54b8331d15502c52d161ca6d10ccd8227b0..a7a0b18d2e48d21f09890aca61cc63f3eb8bd2f6 100755 (executable)
@@ -79,8 +79,11 @@ output=$(notmuch search 'subject:"subject search test (phrase)"' | notmuch_searc
 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)
@@ -99,7 +102,7 @@ thread:XXX   2009-11-18 [1/1] Jan Janak; [notmuch] [PATCH] notmuch new: Support
 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)
@@ -117,7 +120,9 @@ thread:XXX   2000-01-01 [1/1] Search By From Name; search by from (name) (inbox
 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ý"'
index 10291c3b79d8d711c9fa8206fea601235eed61c2..8b57a432438e06ea6de9e8aebb8e29b2d01e29a7 100755 (executable)
@@ -29,6 +29,8 @@ thread:THREADID
 thread:THREADID
 thread:THREADID
 thread:THREADID
+thread:THREADID
+thread:THREADID
 EOF
 test_expect_equal_file OUTPUT EXPECTED
 
@@ -56,6 +58,8 @@ cat <<EOF >EXPECTED
 "THREADID",
 "THREADID",
 "THREADID",
+"THREADID",
+"THREADID",
 "THREADID"]
 EOF
 test_expect_equal_file OUTPUT EXPECTED
@@ -63,6 +67,8 @@ 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
@@ -119,7 +125,9 @@ test_expect_equal_file OUTPUT EXPECTED
 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",
@@ -175,6 +183,8 @@ test_expect_equal_file OUTPUT EXPECTED
 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,
@@ -232,7 +242,9 @@ test_expect_equal_file OUTPUT EXPECTED
 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,",
index 68f0d1b183c9acd29f90721ced1960fd1eac4ffa..7fa7b2aaac5635945a7162e086f577d023951878 100755 (executable)
@@ -12,7 +12,7 @@ test_description='exception symbol hiding'
 . ./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'
index b5e346c0c544abdfdfe7700b7b14385123d72719..82767c07ccf41ac3eb6cd964ce6bb783ba39dea9 100644 (file)
@@ -1,4 +1,3 @@
-#!/usr/bin/env bash
 #
 # Copyright (c) 2005 Junio C Hamano
 #
@@ -50,6 +49,7 @@ TZ=UTC
 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
@@ -322,7 +322,7 @@ generate_message ()
     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=""
@@ -897,7 +897,7 @@ export NOTMUCH_CONFIG=$NOTMUCH_CONFIG
 #
 # --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 \
        "\$@"