[PATCH 5/5] emacs: Add a sort-order option to saved-searches

2014-04-05 Thread Mark Walters
This adds a sort-order option to saved-searches, stores it in the
saved-search buttons (widgets), and uses the stored value when the
button is pressed.

Storing the sort-order in the widget was suggested by Jani in
id:4c3876274126985683e888641b29cf18142a5eb8.1391771337.git.jani at nikula.org.
---
 emacs/notmuch-hello.el |   11 ++-
 emacs/notmuch-lib.el   |7 ++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index aa40e6f..6a28372 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -364,7 +364,8 @@ (defun notmuch-hello-reflect (list ncols)
 (defun notmuch-hello-widget-search (widget  ignore)
   (notmuch-search (widget-get widget
  :notmuch-search-terms)
- notmuch-search-oldest-first))
+ (widget-get widget
+ :notmuch-search-oldest-first)))

 (defun notmuch-saved-search-count (search)
   (car (process-lines notmuch-command "count" search)))
@@ -496,12 +497,20 @@ (defun notmuch-hello-insert-buttons (searches)
  (widget-insert (make-string column-indent ? )))
  (let* ((name (plist-get elem :name))
 (query (plist-get elem :query))
+(oldest-first (cond
+   ((eq (plist-get elem :sort-order) 
'newest-first)
+nil)
+   ((eq (plist-get elem :sort-order) 
'oldest-first)
+t)
+   (t
+notmuch-search-oldest-first)))
 (msg-count (plist-get elem :count)))
(widget-insert (format "%8s "
   (notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
   :notify #'notmuch-hello-widget-search
   :notmuch-search-terms query
+  :notmuch-search-oldest-first oldest-first
   name)
(setq column-indent
  (1+ (max 0 (- column-width (length name)))
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 8a12f91..8aa8cfc 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -125,7 +125,12 @@ (define-widget 'notmuch-saved-search-plist 'list
(group :format "%v" :inline t (const :format "  Query: " 
:query) (string :format "%v")))
  (checklist :inline t
 :format "%v"
-(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v")
+(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v"))
+(group :format "%v" :inline t (const :format "" 
:sort-order)
+   (choice :tag " Sort Order"
+   (const :tag "Default" nil)
+   (const :tag "Oldest-first" oldest-first)
+   (const :tag "Newest-first" 
newest-first))

 (defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
(:name "unread" :query "tag:unread"))
-- 
1.7.10.4



[PATCH 4/5] emacs: hello: switch notmuch-hello-insert-buttons to plists

2014-04-05 Thread Mark Walters
Switching notmuch-hello-insert-buttons to plists means we can easily
pass extra options through to the buttons.
---
 emacs/notmuch-hello.el |   33 +++--
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index c729af2..aa40e6f 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -425,7 +425,9 @@ (defun notmuch-hello-query-counts (query-list  options)
 these is a plist but other options are available for backwards
 compatibility: see notmuch-saved-search-get for details.

-The result is the list of elements of the form (NAME QUERY COUNT).
+The result is a list of plists each of which includes the
+pairs :name NAME, :query QUERY and :count COUNT, together with
+any pairs in the original saved-search.

 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
@@ -455,23 +457,26 @@ (defun notmuch-hello-query-counts (query-list  
options)
  #'identity
  (mapcar
   (lambda (elem)
-   (let ((name (notmuch-saved-search-get elem :name))
- (search-query (notmuch-saved-search-get elem :query))
- (message-count (prog1 (read (current-buffer))
+   (let* ((elem-plist (notmuch-hello-saved-search-to-plist elem))
+  (search-query (plist-get elem-plist :query))
+  (filtered-query (notmuch-hello-filtered-query
+   search-query (plist-get options :filter)))
+  (message-count (prog1 (read (current-buffer))
(forward-line 1
  (and (or (plist-get options :show-empty-searches) (> message-count 0))
-  (list name (notmuch-hello-filtered-query
-  search-query (plist-get options :filter))
-message-count
+  (setq elem-plist (plist-put elem-plist :query filtered-query))
+  (plist-put elem-plist :count message-count
   query-list

 (defun notmuch-hello-insert-buttons (searches)
   "Insert buttons for SEARCHES.

-SEARCHES must be a list containing lists of the form (NAME QUERY COUNT), where
-QUERY is the query to start when the button for the corresponding entry is
-activated. COUNT should be the number of messages matching the query.
-Such a list can be computed with `notmuch-hello-query-counts'."
+SEARCHES must be a list of plists each of which should contain at
+least pairs for :name NAME :query QUERY and :count COUNT, where
+QUERY is the query to start when the button for the corresponding
+entry is activated, and COUNT should be the number of messages
+matching the query.  Such a plist can be computed with
+`notmuch-hello-query-counts'."
   (let* ((widest (notmuch-hello-longest-label searches))
 (tags-and-width (notmuch-hello-tags-per-line widest))
 (tags-per-line (car tags-and-width))
@@ -489,9 +494,9 @@ (defun notmuch-hello-insert-buttons (searches)
(when elem
  (if (> column-indent 0)
  (widget-insert (make-string column-indent ? )))
- (let* ((name (first elem))
-(query (second elem))
-(msg-count (third elem)))
+ (let* ((name (plist-get elem :name))
+(query (plist-get elem :query))
+(msg-count (plist-get elem :count)))
(widget-insert (format "%8s "
   (notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
-- 
1.7.10.4



[PATCH 3/5] emacs: hello: add a customize for saved-searches

2014-04-05 Thread Mark Walters
Make the defcustom for notmuch-saved-searches use the new plist
format. It should still work with oldstyle saved-searches but will
write the newstyle form.
---
 emacs/notmuch-hello.el |2 +-
 emacs/notmuch-lib.el   |   28 +---
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 733208b..c729af2 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -324,7 +324,7 @@ (defun notmuch-hello-add-saved-search (widget)
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
 (add-to-list 'notmuch-saved-searches
- (cons name search) t))
+ (list :name name :query search) t))
 (message "Saved '%s' as '%s'." search name)
 (notmuch-hello-update)))

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 959764e..8a12f91 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -107,10 +107,32 @@ (defcustom notmuch-poll-script nil
 (defvar notmuch-search-history nil
   "Variable to store notmuch searches history.")

-(defcustom notmuch-saved-searches '(("inbox" . "tag:inbox")
-   ("unread" . "tag:unread"))
+(defun notmuch--saved-searches-to-plist (symbol)
+  "Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to extract old style saved
+searches so they still work in customize."
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  "A single saved search property list."
+  :tag "Saved Search"
+  :args '((list :inline t
+   :format "%v"
+   (group :format "%v" :inline t (const :format "   Name: " :name) 
(string :format "%v"))
+   (group :format "%v" :inline t (const :format "  Query: " 
:query) (string :format "%v")))
+ (checklist :inline t
+:format "%v"
+(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v")
+
+(defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
+   (:name "unread" :query "tag:unread"))
   "A list of saved searches to display."
-  :type '(alist :key-type string :value-type string)
+  :get 'notmuch--saved-searches-to-plist
+  :type '(repeat notmuch-saved-search-plist)
+  :tag "List of Saved Searches"
   :group 'notmuch-hello)

 (defcustom notmuch-archive-tags '("-inbox")
-- 
1.7.10.4



[PATCH 2/5] emacs: hello: use the saved-search helper functions

2014-04-05 Thread Mark Walters
This uses the helper functions: the saved searches format has not
changed yet but backwards compatibility means everything still works.
---
 emacs/notmuch-hello.el |   48 ++--
 emacs/notmuch.el   |6 +++---
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 0b9ed16..733208b 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -319,7 +319,7 @@ (defun notmuch-hello-add-saved-search (widget)
 (setq notmuch-saved-searches
  (loop for elem in notmuch-saved-searches
if (not (equal name
-  (car elem)))
+  (notmuch-saved-search-get elem :name)))
collect elem))
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
@@ -339,7 +339,7 @@ (defun notmuch-hello-delete-search-from-history (widget)

 (defun notmuch-hello-longest-label (searches-alist)
   (or (loop for elem in searches-alist
-   maximize (length (car elem)))
+   maximize (length (notmuch-saved-search-get elem :name)))
   0))

 (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
@@ -418,13 +418,12 @@ (defun notmuch-hello-filtered-query (query filter)
 (concat "(" query ") and (" filter ")"))
(t query)))

-(defun notmuch-hello-query-counts (query-alist  options)
-  "Compute list of counts of matched messages from QUERY-ALIST.
+(defun notmuch-hello-query-counts (query-list  options)
+  "Compute list of counts of matched messages from QUERY-LIST.

-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated query.
+QUERY-LIST must be a list of saved-searches. Ideally each of
+these is a plist but other options are available for backwards
+compatibility: see notmuch-saved-search-get for details.

 The result is the list of elements of the form (NAME QUERY COUNT).

@@ -432,11 +431,9 @@ (defun notmuch-hello-query-counts (query-alist  
options)
 options will be handled as specified for
 `notmuch-hello-insert-searches'."
   (with-temp-buffer
-(dolist (elem query-alist nil)
-  (let ((count-query (if (consp (cdr elem))
-;; do we have a different query for the message 
count?
-(third elem)
-  (cdr elem
+(dolist (elem query-list nil)
+  (let ((count-query (or (notmuch-saved-search-get elem :count-query)
+(notmuch-saved-search-get elem :query
(insert
 (replace-regexp-in-string
  "\n" " "
@@ -458,18 +455,15 @@ (defun notmuch-hello-query-counts (query-alist  
options)
  #'identity
  (mapcar
   (lambda (elem)
-   (let ((name (car elem))
- (search-query (if (consp (cdr elem))
-;; do we have a different query for the 
message count?
-(second elem)
- (cdr elem)))
+   (let ((name (notmuch-saved-search-get elem :name))
+ (search-query (notmuch-saved-search-get elem :query))
  (message-count (prog1 (read (current-buffer))
(forward-line 1
  (and (or (plist-get options :show-empty-searches) (> message-count 0))
   (list name (notmuch-hello-filtered-query
   search-query (plist-get options :filter))
 message-count
-  query-alist
+  query-list

 (defun notmuch-hello-insert-buttons (searches)
   "Insert buttons for SEARCHES.
@@ -728,13 +722,15 @@ (defun notmuch-hello-insert-recent-searches ()
   (indent-rigidly start (point) notmuch-hello-indent))
 nil))

-(defun notmuch-hello-insert-searches (title query-alist  options)
-  "Insert a section with TITLE showing a list of buttons made from QUERY-ALIST.
+(defun notmuch-hello-insert-searches (title query-list  options)
+  "Insert a section with TITLE showing a list of buttons made from QUERY-LIST.

-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated item.
+QUERY-LIST should ideally be a plist but for backwards
+compatibility other forms are also accepted (see
+`notmuch-saved-search-get' for details).  The plist should
+contain keys :name and :query; if :count-query is also present
+then it specifies an alternate query to be used to generate the
+count for the associated search.

 Supports the following entries in OPTIONS as a plist:
 :initially-hidden - if non-nil, section will be hidden on startup
@@ -768,7 +764,7 @@ (defun notmuch-hello-insert-searches (title query-alist 
 options)

[PATCH 1/5] emacs: hello: add helper functions for saved-searches

2014-04-05 Thread Mark Walters
Add helper functions to for saved searches to ease the transition to
the new plist form while maintaining backwards compatibility. They
will be used in the next patch.
---
 emacs/notmuch-hello.el |   39 +++
 1 file changed, 39 insertions(+)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index e325cd3..0b9ed16 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -269,6 +269,45 @@ (defun notmuch-hello-search ( search)
   (add-to-history 'notmuch-search-history search)))
   (notmuch-search search notmuch-search-oldest-first))

+(defun notmuch-saved-search-get (saved-search field)
+  "Get FIELD from SAVED-SEARCH.
+
+In the new style saved-search (a plist) this is just plist-get
+but, for backwards compatibility, this deals with the two
+old-style forms: cons cells (NAME . QUERY) and lists (NAME QUERY
+COUNT-QUERY)."
+  (cond
+   ((plist-get saved-search :name)
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  "Convert a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to give them in
+plist-form. In all cases a new copy is returned so it is safe to
+modify the returned value."
+  (if (and (listp (cdr saved-search)) (plist-member saved-search :name))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ (plist-search))
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
 (defun notmuch-hello-add-saved-search (widget)
   (interactive)
   (let ((search (widget-value
-- 
1.7.10.4



[PATCH 5/7] doc: Allow rst2man.py as an alternative to rst2man

2014-04-05 Thread Tomi Ollila
On Sat, Apr 05 2014, "W. Trevor King"  wrote:

> Gentoo's dev-python/docutils-0.10 installs Docutils scripts with a
> *.py extension, so I have /usr/bin/rst2man.py and no rst2man script.
> This patch supports users with both types of systems by checking for
> rst2man, falling back on rst2man.py, and giving up only if neither is
> found.  Users can also set the new RST2MAN path variable explicitly
> when they call Make:
>
>   make RST2MAN=/my/custom/rst_to_man_converter build-man
>
> I use POSIX's 'command -v' [1] to find the path to rst2man or
> rst2man.py, and save that as RST2MAN in Makefile.config.  We can use a
> non-empty RST2MAN to check for the availability of an rst2man program,
> so there's no need for a separate HAVE_RST2MAN.  Then pass the
> configured RST2MAN path through to prerst2man.py to use in its system
> call.
>
> [1]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

This series looks good to me. 

Except the reference to _POSIX_ page. One knows how consistent these
specifications are; alternative:

http://pubs.opengroup.org/onlinepubs/009695399/utilities/command.html

mentions additionally that -v flag
"(On systems supporting the User Portability Utilities option.)" 

Also, we don't give such a treatment to other command either; I'd rather
see RST2MAN=rst2man, RST2MAN=rst2man.py *and* RST2MAN= lines used
instead -- the last to set RST2MAN to empty string instead of being unset.

Tomi


> ---
>  configure  | 12 +++-
>  doc/Makefile.local |  6 +++---
>  doc/prerst2man.py  |  9 +
>  3 files changed, 15 insertions(+), 12 deletions(-)
>
> diff --git a/configure b/configure
> index 1d430b9..81c286b 100755
> --- a/configure
> +++ b/configure
> @@ -400,7 +400,6 @@ printf "Checking if sphinx is available and supports 
> nroff output... "
>  if hash sphinx-build > /dev/null 2>&1 && python -m sphinx.writers.manpage > 
> /dev/null 2>&1 ; then
>  printf "Yes.\n"
>  have_sphinx=1
> -have_rst2man=0
>  else
>  printf "No (falling back to rst2man).\n"
>  have_sphinx=0
> @@ -408,10 +407,12 @@ else
>  printf "Checking if rst2man is available... "
>  if rst2man -V > /dev/null 2>&1; then
> printf "Yes.\n"
> -   have_rst2man=1
> +   RST2MAN=$(command -v rst2man)
> +elif rst2man.py -V > /dev/null 2>&1; then
> +   printf "Yes.\n"
> +   RST2MAN=$(command -v rst2man.py)
>  else
> printf "No (so will not install man pages).\n"
> -   have_rst2man=0
>  fi
>  fi
>  
> @@ -788,8 +789,9 @@ HAVE_EMACS = ${have_emacs}
>  # Whether there's a sphinx-build binary available for building documentation
>  HAVE_SPHINX=${have_sphinx}
>  
> -# Whether there's a rst2man binary available for building documentation
> -HAVE_RST2MAN=${have_rst2man}
> +# The path to the rst2man program for building documentation.  Set to
> +# an empty string if no such program is available.
> +RST2MAN=${RST2MAN}
>  
>  # The directory to which desktop files should be installed
>  desktop_dir = \$(prefix)/share/applications
> diff --git a/doc/Makefile.local b/doc/Makefile.local
> index 0980c71..e08fc99 100644
> --- a/doc/Makefile.local
> +++ b/doc/Makefile.local
> @@ -42,8 +42,8 @@ ifeq ($(HAVE_SPHINX),1)
>   mkdir -p $(DOCBUILDDIR)/man/man$${section}; \
>   mv $(DOCBUILDDIR)/man/*.$${section} 
> $(DOCBUILDDIR)/man/man$${section}; \
>   done
> -else ifeq ($(HAVE_RST2MAN),1)
> - $(prerst2man) $(srcdir)/doc $(DOCBUILDDIR)/man
> +else ifdef RST2MAN
> + $(prerst2man) "$(RST2MAN)" $(srcdir)/doc $(DOCBUILDDIR)/man
>  else
>   @echo "Fatal: build dependency fail."
>   @false
> @@ -51,7 +51,7 @@ endif
>  
>  # Do not try to build or install man pages if a man page converter is
>  # not available.
> -ifeq ($(HAVE_SPHINX)$(HAVE_RST2MAN),00)
> +ifeq ($(HAVE_SPHINX)$(RST2MAN),0)
>  build-man:
>  install-man:
>   @echo "No sphinx or rst2man, will not install man pages."
> diff --git a/doc/prerst2man.py b/doc/prerst2man.py
> index 437dea9..81ce817 100644
> --- a/doc/prerst2man.py
> +++ b/doc/prerst2man.py
> @@ -4,8 +4,9 @@ from os.path import dirname, isdir
>  from os import makedirs, system
>  import re
>  
> -sourcedir = argv[1]
> -outdir = argv[2]
> +rst2man = argv[1]
> +sourcedir = argv[2]
> +outdir = argv[3]
>  
>  if not isdir(outdir):
>  makedirs(outdir, 0o755)
> @@ -59,5 +60,5 @@ for page in man_pages:
>  outfile.write("".join(lines))
>  outfile.close()
>  
> -system('set -x; rst2man {0} {1}/{2}.{3}'
> -   .format(filename, outdir, page[0], page[4]))
> +system('set -x; {0} {1} {2}/{3}.{4}'
> +   .format(rst2man, filename, outdir, page[0], page[4]))
> -- 
> 1.9.1.353.gc66d89d
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 2/5] emacs: hello: use the saved-search helper functions

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
> This uses the helper functions: the saved searches format has not
> changed yet but backwards compatibility means everything still works.
> ---
>  emacs/notmuch-hello.el |   48 
> ++--
>  emacs/notmuch.el   |6 +++---
>  2 files changed, 25 insertions(+), 29 deletions(-)
> 
> diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
> index 0b9ed16..733208b 100644
> --- a/emacs/notmuch-hello.el
> +++ b/emacs/notmuch-hello.el
> @@ -319,7 +319,7 @@ (defun notmuch-hello-add-saved-search (widget)
>  (setq notmuch-saved-searches
> (loop for elem in notmuch-saved-searches
>   if (not (equal name
> -(car elem)))
> +(notmuch-saved-search-get elem :name)))
>   collect elem))
>  ;; Add the new one.
>  (customize-save-variable 'notmuch-saved-searches
> @@ -339,7 +339,7 @@ (defun notmuch-hello-delete-search-from-history (widget)
>  
>  (defun notmuch-hello-longest-label (searches-alist)
>(or (loop for elem in searches-alist
> - maximize (length (car elem)))
> + maximize (length (notmuch-saved-search-get elem :name)))
>0))
>  
>  (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
> @@ -418,13 +418,12 @@ (defun notmuch-hello-filtered-query (query filter)
>  (concat "(" query ") and (" filter ")"))
> (t query)))
>  
> -(defun notmuch-hello-query-counts (query-alist  options)
> -  "Compute list of counts of matched messages from QUERY-ALIST.
> +(defun notmuch-hello-query-counts (query-list  options)
> +  "Compute list of counts of matched messages from QUERY-LIST.
>  
> -QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
> -or (NAME QUERY COUNT-QUERY). If the latter form is used,
> -COUNT-QUERY specifies an alternate query to be used to generate
> -the count for the associated query.
> +QUERY-LIST must be a list of saved-searches. Ideally each of
> +these is a plist but other options are available for backwards
> +compatibility: see notmuch-saved-search-get for details.

s/:/./  Also `'s around notmuch-saved-search-get.

Actually, the accepted formats (including the understood keys in plist
form) should be documented in `notmuch-saved-searches' and this
information should be cited elsewhere and not duplicated.

>  
>  The result is the list of elements of the form (NAME QUERY COUNT).
>  
> @@ -432,11 +431,9 @@ (defun notmuch-hello-query-counts (query-alist  
> options)
>  options will be handled as specified for
>  `notmuch-hello-insert-searches'."
>(with-temp-buffer
> -(dolist (elem query-alist nil)
> -  (let ((count-query (if (consp (cdr elem))
> -  ;; do we have a different query for the message 
> count?
> -  (third elem)
> -(cdr elem
> +(dolist (elem query-list nil)
> +  (let ((count-query (or (notmuch-saved-search-get elem :count-query)
> +  (notmuch-saved-search-get elem :query
>   (insert
>(replace-regexp-in-string
> "\n" " "
> @@ -458,18 +455,15 @@ (defun notmuch-hello-query-counts (query-alist  
> options)
>   #'identity
>   (mapcar
>(lambda (elem)
> - (let ((name (car elem))
> -   (search-query (if (consp (cdr elem))
> -  ;; do we have a different query for the 
> message count?
> -  (second elem)
> -   (cdr elem)))
> + (let ((name (notmuch-saved-search-get elem :name))
> +   (search-query (notmuch-saved-search-get elem :query))
> (message-count (prog1 (read (current-buffer))
>   (forward-line 1
> (and (or (plist-get options :show-empty-searches) (> message-count 0))
>  (list name (notmuch-hello-filtered-query
>  search-query (plist-get options :filter))
>message-count
> -  query-alist
> +  query-list
>  
>  (defun notmuch-hello-insert-buttons (searches)
>"Insert buttons for SEARCHES.
> @@ -728,13 +722,15 @@ (defun notmuch-hello-insert-recent-searches ()
>(indent-rigidly start (point) notmuch-hello-indent))
>  nil))
>  
> -(defun notmuch-hello-insert-searches (title query-alist  options)
> -  "Insert a section with TITLE showing a list of buttons made from 
> QUERY-ALIST.
> +(defun notmuch-hello-insert-searches (title query-list  options)
> +  "Insert a section with TITLE showing a list of buttons made from 
> QUERY-LIST.
>  
> -QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
> -or (NAME QUERY COUNT-QUERY). If the latter form is used,
> -COUNT-QUERY specifies an alternate query to be used to generate
> -the count for the associated item.
> +QUERY-LIST should ideally be a plist but for backwards
> +compatibility other 

Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread john.wy...@gmx.de
Jeremy Nickurak  writes:

> Off the top of my head, you could have an encrypted index too, which you
> can only search while able to decrypt. Certainly another level of
> complexity.
>

But why add so much complexity? 

If a user decides that either transport security is enough or
additionally the hard disk is encrypted (why store an encrypted index on
an encrypted hard disk?), said user could just switch on an option in
the notmuch configuration that causes notmuch to ask for the password
before or while indexing new messages and to add decrypted messages to the
normal index as well.


The level of security would be up to the user by means of said
configuration option and those that want the convenience of searching
encrypted messages could have it.

Personally I would argue that if an attacker has the means to access the
content of my hard disk either via the network or physically, there is
no difference between having whole disk encryption and storing an
encrypted index...



[PATCH 1/5] emacs: hello: add helper functions for saved-searches

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
> Add helper functions to for saved searches to ease the transition to
> the new plist form while maintaining backwards compatibility. They
> will be used in the next patch.
> ---
>  emacs/notmuch-hello.el |   39 +++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
> index e325cd3..0b9ed16 100644
> --- a/emacs/notmuch-hello.el
> +++ b/emacs/notmuch-hello.el
> @@ -269,6 +269,45 @@ (defun notmuch-hello-search ( search)
>(add-to-history 'notmuch-search-history search)))
>(notmuch-search search notmuch-search-oldest-first))
>  
> +(defun notmuch-saved-search-get (saved-search field)
> +  "Get FIELD from SAVED-SEARCH.
> +
> +In the new style saved-search (a plist) this is just plist-get

It won't be "new style" once this has been in for a while.  Perhaps
"If SAVED-SEARCH is a plist, this is just `plist-get', but for
backwards compatibility, ..."

> +but, for backwards compatibility, this deals with the two
> +old-style forms: cons cells (NAME . QUERY) and lists (NAME QUERY
> +COUNT-QUERY)."
> +  (cond
> +   ((plist-get saved-search :name)

Rather than depending on :name, maybe this should be a more generic
plist test like (keywordp (car saved-search))?

> +(plist-get saved-search field))
> +   ;; It is not a plist so it is an old-style entry.
> +   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
> +(case field
> +  (:name (car saved-search))

Use `first' for consistency with the other case cases?

> +  (:query (second saved-search))
> +  (:count-query (third saved-search))
> +  (t nil)))
> +   (t  ;; It is a cons-cell (NAME . QUERY)
> +(case field
> +  (:name (car saved-search))
> +  (:query (cdr saved-search))
> +  (t nil)
> +
> +(defun notmuch-hello-saved-search-to-plist (saved-search)
> +  "Convert a saved-search variable into plist form.

This takes a value, not a variable.  But it could be more succinct and
more accurate: "Return a copy of SAVED-SEARCH in plist form."

> +
> +The new style saved search is just a plist, but for backwards

Same comment about "new style".

> +compatatibility we use this function to give them in
> +plist-form. In all cases a new copy is returned so it is safe to

Grammar error?

> +modify the returned value."
> +  (if (and (listp (cdr saved-search)) (plist-member saved-search :name))
> +  (copy-seq saved-search)
> +(let ((fields (list :name :query :count-query))
> +   (plist-search))

Personally I prefer to either explicitly initialize nil variables or
to list them without the parenthesis at all (for some reason my brain
automatically reads this as an application), but if you prefer this,
that's fine, too.

> +  (dolist (field fields plist-search)
> + (let ((string (notmuch-saved-search-get saved-search field)))
> +   (when string
> + (setq plist-search (append plist-search (list field string)
> +
>  (defun notmuch-hello-add-saved-search (widget)
>(interactive)
>(let ((search (widget-value


[PATCH v5 1/2] lib: drop support for single-message mbox files

2014-04-05 Thread Tomi Ollila
On Sat, Apr 05 2014, David Bremner  wrote:

> Jani Nikula  writes:
>
>> We've supported mbox files containing a single message for historical
>> reasons, but the support has been deprecated, with a warning message
>> while indexing, since Notmuch 0.15. Finally drop the support, and
>> consider all mbox files non-email.
>
> series pushed.


For now, anyone who wants to check their mail storage whether this have
any effect:

$ find . -type f | xargs head -1 | grep -B1 '^From '

(I got zero results :D on this machine; have to test on another...)



Quickly crafted other test: regexp (and head -1) may be incomplete...

$ find . -type f | xargs head -1 | grep -B1 -v -e '^[a-zA-Z_-]*:' -e '==.*==' 
-e '^$'

The first one will find any emails that were found last time but would
not be found (as emails) after e.g. dump-restore-reindex. Second one
would find (some/most?) emails that weren't indexed in the first place...


> d


Tomi


[PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread David Bremner
"W. Trevor King"  writes:

>   {build|install}-man, which is backend (Sphinx/Docutils) agnostic
>   sphinx-{html|texinfo|info}, which doesn't have an install target
>
> Is that distinction intentional?  Personally I prefer the consistency
> of:
>
>   {build|install}-{man|html|texinfo|info}
>

I think the sphinx- prefix is a historical accident, from when we tried
to control backend with targets, so I don't really mind those switching
(back?) to build-

install-man is backend agnostic. Similar targets could be written for
html and info, but no-one did yet. I guess we'd need variables to
specify destinations. Installing info is a bit tricky because of the
need to use install-info(1) to update directory files


Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread john.wy...@gmx.de

Hello!

Would it be possible to add the configurable option to also decrypt
encrypted messages on the fly while indexing to make them searchable,
too?

That would be really great for people that consider gnupg  mainly an
encryption for transport or have their complete hard drive encrypted...

Best regards!
John


[PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread David Bremner
"W. Trevor King"  writes:

> The rst2man target was removed in 9d9a700 (doc: build man pages at
> build time; introduce HAVE_SPHINX, HAVE_RST2MAN, 2014-03-13), but a
> reference in the install docs slipped through.  While I was removing
> that reference, I also:
>
> * Converted doc/INSTALL to reStructuredText, so I can link to Sphinx
>   and Docutils directly.  Not everyone has access to Debian's
>   python-docutils, so it's better to be genric here.
> * Converted from an unordered list to paragraphs, because I think it
>   flows better.
> * Dropped the rst2man no-automatic-install caveat.  I don't think this
>   applies to the current code, although I haven't tried to track down
>   a commit that adds the automatic-install support.  Anyhow,
>
> $ make HAVE_SPHINX=0 RST2MAN=/usr/bin/rst2man.py DESTDIR=/tmp/ install-man
>
>   works for me.
> ---
>  doc/INSTALL | 34 --
>  1 file changed, 20 insertions(+), 14 deletions(-)
>
> diff --git a/doc/INSTALL b/doc/INSTALL
> index e37c2b9..91222f9 100644
> --- a/doc/INSTALL
> +++ b/doc/INSTALL
> @@ -1,24 +1,30 @@
>  This file contains some more detailed information about building and
>  installing the documentation.
>  
> -Building with sphinx.
> --
> +Building with Sphinx
> +
>  
> -- You need sphinx at least version 1.0.
> +With Sphinx_ version 1.0 or greater, you can build man, info, html,
> +and pdf versions of the docs (currently only the man pages) with::
>  
> -- You can build build and install man pages with 'make install-man'
> +  make build-{man|info|html|pdf}

most of those those targets now start with sphinx-
>  
> -- You can build man, info, html, and pdf versions of the docs
> -  (currently only the man pages) with
> +You can build build and install the docs (currently only the man
> +pages) with::

build build
>  
> - 'make install-{man|info|html|pdf}'
> +  make install-{man|info|html|pdf}
>  

this is not your bug per se, but while we're fixing docs, most of those
targets don't exist.

> -Building the man pages
> ---
> +Building the man Docutils
> +-
>  

+ with

> -- You can build the man pages with rst2man (from python-docutils) with
> -  'make rst2man'.
> +If you don't have Sphinx installed, you can still build the man-page
> +version of the docs using rst2man (from Docutils_)::
>  
> -- Currently there is no support to automagically install the resulting
> -  nroff files, but it should work to modify the target install-man
> -  in doc/Makefile.local.

This should mention the relevant variables, since the targets are the
same in both cases

Finally, I don't really object to rewriting doc/INSTALL in rst, but I
wonder if we should rename it to INSTALL.rst

d


[PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread W. Trevor King
On Sat, Apr 05, 2014 at 05:35:49PM -0300, David Bremner wrote:
> W. Trevor King writes:
> 
> > -- You can build build and install man pages with 'make install-man'
> > +  make build-{man|info|html|pdf}
> 
> most of those those targets now start with sphinx-

Ah, looks like that happended in with the original Sphinx code in
d736260 (doc: convert sphinx based docs, 2014-01-28).  It looks like
the current usage is (from the .PHONY entries):

  {build|install}-man, which is backend (Sphinx/Docutils) agnostic
  sphinx-{html|texinfo|info}, which doesn't have an install target

Is that distinction intentional?  Personally I prefer the consistency
of:

  {build|install}-{man|html|texinfo|info}

if the configured backend (Sphinx/Docutils) doesn't support the
requested target, we should error out.  If no backend is detected,
build-man and install-man should be pulled from the default dependency
tree (but they would still error out if you called them directly).  If
that sounds reasonable, I can work up a patch.

> > -- You can build man, info, html, and pdf versions of the docs
> > -  (currently only the man pages) with
> > +You can build build and install the docs (currently only the man
> > +pages) with::
> 
> build build

Oops, thanks.

> > -Building the man pages
> > ---
> > +Building the man Docutils
> > +-
> >  
> 
> + with

Thanks again :p.

> > -- You can build the man pages with rst2man (from python-docutils) with
> > -  'make rst2man'.
> > +If you don't have Sphinx installed, you can still build the man-page
> > +version of the docs using rst2man (from Docutils_)::
> >  
> > -- Currently there is no support to automagically install the resulting
> > -  nroff files, but it should work to modify the target install-man
> > -  in doc/Makefile.local.
> 
> This should mention the relevant variables, since the targets are
> the same in both cases

Ok.

> Finally, I don't really object to rewriting doc/INSTALL in rst, but
> I wonder if we should rename it to INSTALL.rst

Sure (I don't really mind).

Cheers,
Trevor

-- 
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
-- next part --
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20140405/b7335327/attachment-0001.pgp>


Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread David Bremner
john.wyzer at gmx.de writes:

> Would it be possible to add the configurable option to also decrypt
> encrypted messages on the fly while indexing to make them searchable,
> too?
>
> That would be really great for people that consider gnupg  mainly an
> encryption for transport or have their complete hard drive encrypted...

As far I understand an attacker could reconstruct the message from the
index, so one question is whether the extra complexity in notmuch is
worth the minimal extra security over decrypting on delivery and storing
plaintext on the (presumably encrypted) disk. Of course decrypting on
delivery may be inconvenient (or impossible). I have CCed the two people
who have implemented most of the crypto related stuff in notmuch so they
can comment.

d


[PATCH] debian: ignore performance corpus when making source package

2014-04-05 Thread David Bremner
David Bremner  writes:

> Currently "make debian-snapshot" will include the performance corpus
> tarball in the source package, which slows things down and wastes disk
> space.  tar-ignore is needed twice to keep the default exclude rules
> (e.g. to exclude .git)

Pushed this. I'm thinking it would be good to treat test databases the
same way, and have a new level of cleaning to remove them all. 

d


[PATCH v5 1/2] lib: drop support for single-message mbox files

2014-04-05 Thread David Bremner
Jani Nikula  writes:

> We've supported mbox files containing a single message for historical
> reasons, but the support has been deprecated, with a warning message
> while indexing, since Notmuch 0.15. Finally drop the support, and
> consider all mbox files non-email.

series pushed.

d


[PATCH 1/1] release-checks: removed manual page version check

2014-04-05 Thread Tomi Ollila
Manual pages are now generated and during the generation the version
string is read from `version` file, so this (currently failing) test
checking manual page versions can be removed.

While at it, changed the case pattern *[^0-9.]*
to its portable alternative *[!0-9.]*
---
 devel/release-checks.sh | 42 +-
 1 file changed, 1 insertion(+), 41 deletions(-)

diff --git a/devel/release-checks.sh b/devel/release-checks.sh
index 8938905..797d62a 100755
--- a/devel/release-checks.sh
+++ b/devel/release-checks.sh
@@ -68,7 +68,7 @@ verfail ()

 echo -n "Checking that '$VERSION' is good with digits and periods... "
 case $VERSION in
-   *[^0-9.]*)
+   *[!0-9.]*)
verfail "'$VERSION' contains other characters than digits and 
periods" ;;
.*) verfail "'$VERSION' begins with a period" ;;
*.) verfail "'$VERSION' ends with a period" ;;
@@ -196,46 +196,6 @@ case $news_date in
append_emsg "Date '$news_date' in NEWS file is not in format 
(-mm-dd)"
 esac

-readonly DATE=${news_date//[()]/} # bash feature
-manthdata ()
-{
-   set x $*
-   if [ $# != 7 ]
-   then
-   append_emsg "'$mp' has too many '.TH' lines"
-   man_mismatch=1
-   fi
-   man_date=${5-} man_version=${7-}
-}
-
-echo -n "Checking that manual page dates and versions are $DATE and 
$VERSION... "
-manfiles=`find man -type f | sort`
-man_pages_ok=Yes
-for mp in $manfiles
-do
-   case $mp in
-   *.[0-9]) ;; # fall below this 'case ... esac'
-
-   */Makefile.local | */Makefile ) continue ;;
-   */.gitignore)   continue ;;
-   *.bak)  continue ;;
-
-   *)  append_emsg "'$mp': extra file"
-   man_pages_ok=No
-   continue
-   esac
-   manthdata `sed -n '/^[.]TH NOTMUCH/ { y/"/ /; p; }' "$mp"`
-   if [ "$man_version" != "$VERSION" ]
-   thenappend_emsg "Version '$man_version' is not '$VERSION' in $mp"
-   mman_pages_ok=No
-   fi
-   if [ "$man_date" != "$DATE" ]
-   thenappend_emsg "DATE '$man_date' is not '$DATE' in $mp"
-   man_pages_ok=No
-   fi
-done
-echo $man_pages_ok.
-
 if [ -n "$emsgs" ]
 then
echo
-- 
1.8.0



[PATCH v4 0/4] nmbug-status: Python-3-compatibility and general refactoring

2014-04-05 Thread David Bremner
"W. Trevor King"  writes:

> On Sun, Feb 16, 2014 at 07:46:29PM -0400, David Bremner wrote:
>> pushed the last 4.
>
> It looks like there's still a nmbug-status branch on
> git://notmuchmail.org/git/notmuch.  It's an ancestor of debian/0.17-4,
> and nmbug-status development seems to have calmed back down, so that
> branch can probably be removed.

done.

d


[Patch v7 6/6] test: verify tag backup generated by database upgrade

2014-04-05 Thread David Bremner
'pre upgrade dump' is not much of a test, but at least this way we get
somewhat sensible behaviour if it fails.
---
 test/T530-upgrade.sh | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/test/T530-upgrade.sh b/test/T530-upgrade.sh
index d46e3d1..7d5d5aa 100755
--- a/test/T530-upgrade.sh
+++ b/test/T530-upgrade.sh
@@ -25,6 +25,8 @@ test_begin_subtest "path: search does not work with old 
database version"
 output=$(notmuch search path:foo)
 test_expect_equal "$output" ""

+test_expect_success 'pre upgrade dump' 'notmuch dump | sort > pre-upgrade-dump'
+
 test_begin_subtest "database upgrade from format version 1"
 output=$(notmuch new | sed -e 's/^Backing up tags to .*$/Backing up tags to 
FILENAME/')
 test_expect_equal "$output" "\
@@ -34,6 +36,10 @@ Backing up tags to FILENAME
 Your notmuch database has now been upgraded to database format version 2.
 No new mail."

+test_begin_subtest "tag backup matches pre-upgrade dump"
+gunzip -c ${MAIL_DIR}/.notmuch/dump-*.gz | sort > backup-dump
+test_expect_equal_file pre-upgrade-dump backup-dump
+
 test_begin_subtest "folder: no longer matches in the middle of path"
 output=$(notmuch search folder:baz)
 test_expect_equal "$output" ""
-- 
1.9.0



[Patch v7 5/6] notmuch-new: backup tags before database upgrade

2014-04-05 Thread David Bremner
All we do here is calculate the backup filename, and call the existing
dump routine.

Also take the opportity to add a message about being safe to
interrupt.
---
 notmuch-new.c| 29 -
 test/T530-upgrade.sh |  4 +++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 82acf69..d269c7c 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -989,8 +989,35 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
return EXIT_FAILURE;

if (notmuch_database_needs_upgrade (notmuch)) {
-   if (add_files_state.verbosity >= VERBOSITY_NORMAL)
+   time_t now = time (NULL);
+   struct tm *gm_time = gmtime ();
+
+   /* since dump files are written atomically, the amount of
+* harm from overwriting one within a second seems
+* relatively small. */
+
+   const char *backup_name =
+   talloc_asprintf (notmuch, 
"%s/dump-%04d%02d%02dT%02d%02d%02d.gz",
+dot_notmuch_path,
+gm_time->tm_year + 1900,
+gm_time->tm_mon + 1,
+gm_time->tm_mday,
+gm_time->tm_hour,
+gm_time->tm_min,
+gm_time->tm_sec);
+
+   if (add_files_state.verbosity >= VERBOSITY_NORMAL) {
printf ("Welcome to a new version of notmuch! Your database 
will now be upgraded.\n");
+   printf ("This process is safe to interrupt.\n");
+   printf ("Backing up tags to %s...\n", backup_name);
+   }
+
+   if (notmuch_database_dump (notmuch, backup_name, "",
+  DUMP_FORMAT_BATCH_TAG, TRUE)) {
+   fprintf (stderr, "Backup failed. Aborting upgrade.");
+   return EXIT_FAILURE;
+   }
+
gettimeofday (_files_state.tv_start, NULL);
notmuch_database_upgrade (notmuch,
  add_files_state.verbosity >= 
VERBOSITY_NORMAL ? upgrade_print_progress : NULL,
diff --git a/test/T530-upgrade.sh b/test/T530-upgrade.sh
index 67bbf31..d46e3d1 100755
--- a/test/T530-upgrade.sh
+++ b/test/T530-upgrade.sh
@@ -26,9 +26,11 @@ output=$(notmuch search path:foo)
 test_expect_equal "$output" ""

 test_begin_subtest "database upgrade from format version 1"
-output=$(notmuch new)
+output=$(notmuch new | sed -e 's/^Backing up tags to .*$/Backing up tags to 
FILENAME/')
 test_expect_equal "$output" "\
 Welcome to a new version of notmuch! Your database will now be upgraded.
+This process is safe to interrupt.
+Backing up tags to FILENAME
 Your notmuch database has now been upgraded to database format version 2.
 No new mail."

-- 
1.9.0



[Patch v7 4/6] restore: transparently support gzipped input

2014-04-05 Thread David Bremner
We rely completely on zlib to do the right thing in detecting gzipped
input. Since our dump format is chosen to be 7 bit ascii, this should
be fine.
---
 doc/man1/notmuch-restore.rst |  8 
 notmuch-restore.c| 93 +---
 test/T240-dump-restore.sh| 14 +++
 3 files changed, 92 insertions(+), 23 deletions(-)

diff --git a/doc/man1/notmuch-restore.rst b/doc/man1/notmuch-restore.rst
index d6cf19a..936b138 100644
--- a/doc/man1/notmuch-restore.rst
+++ b/doc/man1/notmuch-restore.rst
@@ -50,6 +50,14 @@ Supported options for **restore** include
 format, this heuristic, based the fact that batch-tag format
 contains no parentheses, should be accurate.

+GZIPPED INPUT
+=
+
+\ **notmuch restore** will detect if the input is compressed in
+**gzip(1)** format and automatically decompress it while reading. This
+detection does not depend on file naming and in particular works for
+standard input.
+
 SEE ALSO
 

diff --git a/notmuch-restore.c b/notmuch-restore.c
index c54d513..7abee0a 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -22,6 +22,7 @@
 #include "hex-escape.h"
 #include "tag-util.h"
 #include "string-util.h"
+#include "zlib-extra.h"

 static regex_t regex;

@@ -128,10 +129,10 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 tag_op_list_t *tag_ops;

 char *input_file_name = NULL;
-FILE *input = stdin;
+const char *name_for_error = NULL;
+gzFile input = NULL;
 char *line = NULL;
 void *line_ctx = NULL;
-size_t line_size;
 ssize_t line_len;

 int ret = 0;
@@ -157,39 +158,69 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 };

 opt_index = parse_arguments (argc, argv, options, 1);
-if (opt_index < 0)
-   return EXIT_FAILURE;
+if (opt_index < 0) {
+   ret = EXIT_FAILURE;
+   goto DONE;
+}
+
+name_for_error = input_file_name ? input_file_name : "stdin";

 if (! accumulate)
flags |= TAG_FLAG_REMOVE_ALL;

-if (input_file_name) {
-   input = fopen (input_file_name, "r");
-   if (input == NULL) {
-   fprintf (stderr, "Error opening %s for reading: %s\n",
-input_file_name, strerror (errno));
-   return EXIT_FAILURE;
+errno = 0;
+if (input_file_name)
+   input = gzopen (input_file_name, "r");
+else {
+   int infd = dup (STDIN_FILENO);
+   if (infd < 0) {
+   fprintf (stderr, "Error duping stdin: %s\n",
+strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
}
+   input = gzdopen (infd, "r");
+   if (! input)
+   close (infd);
+}
+
+if (input == NULL) {
+   fprintf (stderr, "Error opening %s for (gzip) reading: %s\n",
+name_for_error, strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 if (opt_index < argc) {
fprintf (stderr, "Unused positional parameter: %s\n", argv[opt_index]);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 do {
-   line_len = getline (, _size, input);
+   util_status_t status;
+
+   status = gz_getline (line_ctx, , _len, input);

/* empty input file not considered an error */
-   if (line_len < 0)
-   return EXIT_SUCCESS;
+   if (status == UTIL_EOF) {
+   ret = EXIT_SUCCESS;
+   goto DONE;
+   }

+   if (status) {
+   fprintf (stderr, "Error reading (gzipped) input: %s\n",
+gz_error_string(status, input));
+   ret = EXIT_FAILURE;
+   goto DONE;
+   }
 } while ((line_len == 0) ||
 (line[0] == '#') ||
 /* the cast is safe because we checked about for line_len < 0 */
@@ -254,21 +285,37 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
if (ret)
break;

-}  while ((line_len = getline (, _size, input)) != -1);
+}  while (! (ret = gz_getline (line_ctx, , _len, input)));
+

-if (line_ctx != NULL)
-   talloc_free (line_ctx);
+/* EOF is normal loop termination condition, UTIL_SUCCESS is
+ * impossible here */
+if (ret == UTIL_EOF) {
+   ret = UTIL_SUCCESS;
+} else {
+   fprintf (stderr, "Error reading (gzipped) input: %s\n",
+gz_error_string (ret, input));
+}
+
+/* currently this should not be after DONE: since we don't 
+ * know if the xregcomp was reached
+ */

 if (input_format == DUMP_FORMAT_SUP)
regfree ();

-if (line)
-   free (line);
+ DONE:
+if (line_ctx != NULL)
+   talloc_free (line_ctx);

-notmuch_database_destroy 

[Patch v7 3/6] test: restore with missing final newline

2014-04-05 Thread David Bremner
Recent proposed patches for gzipped input had a bug with handling
missing newlines that was not caught by the current test suite
---
 test/T240-dump-restore.sh | 9 +
 1 file changed, 9 insertions(+)

diff --git a/test/T240-dump-restore.sh b/test/T240-dump-restore.sh
index d79aca8..b6d8602 100755
--- a/test/T240-dump-restore.sh
+++ b/test/T240-dump-restore.sh
@@ -110,6 +110,15 @@ notmuch dump --format=batch-tag from:cworth | sed 's/^.*-- 
id://' | \
 sort > OUTPUT.$test_count
 test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count

+test_begin_subtest "format=batch-tag, missing newline"
+printf "+a_tag_without_newline -- id:20091117232137.GA7669 at griffis1.net" > 
IN
+notmuch restore --accumulate < IN
+notmuch dump id:20091117232137.GA7669 at griffis1.net > OUT
+cat < EXPECTED
++a_tag_without_newline +inbox +unread -- id:20091117232137.GA7669 at 
griffis1.net
+EOF
+test_expect_equal_file EXPECTED OUT
+
 test_begin_subtest "format=batch-tag, # round-trip"
 notmuch dump --format=sup | sort > EXPECTED.$test_count
 notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
-- 
1.9.0



[Patch v7 2/6] util: add gz_readline

2014-04-05 Thread David Bremner
The idea is to provide a more or less drop in replacement for readline
to read from zlib/gzip streams.  Take the opportunity to replace
malloc with talloc.
---
 util/Makefile.local |  3 +-
 util/util.c | 24 +++
 util/util.h | 29 ++
 util/zlib-extra.c   | 85 +
 util/zlib-extra.h   | 25 
 5 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 util/util.c
 create mode 100644 util/util.h
 create mode 100644 util/zlib-extra.c
 create mode 100644 util/zlib-extra.h

diff --git a/util/Makefile.local b/util/Makefile.local
index 29c0ce6..905f237 100644
--- a/util/Makefile.local
+++ b/util/Makefile.local
@@ -4,7 +4,8 @@ dir := util
 extra_cflags += -I$(srcdir)/$(dir)

 libutil_c_srcs := $(dir)/xutil.c $(dir)/error_util.c $(dir)/hex-escape.c \
- $(dir)/string-util.c $(dir)/talloc-extra.c
+ $(dir)/string-util.c $(dir)/talloc-extra.c 
$(dir)/zlib-extra.c \
+   $(dir)/util.c

 libutil_modules := $(libutil_c_srcs:.c=.o)

diff --git a/util/util.c b/util/util.c
new file mode 100644
index 000..3bd305d
--- /dev/null
+++ b/util/util.c
@@ -0,0 +1,24 @@
+#include "util.h"
+#include "error_util.h"
+#include 
+#include 
+
+const char *
+util_error_string (util_status_t errnum)
+{
+switch (errnum) {
+case UTIL_SUCCESS:
+   return "none";
+case UTIL_OUT_OF_MEMORY:
+   return "out of memory";
+case UTIL_EOF:
+   return "end of file";
+case UTIL_ERRNO:
+   return strerror (errno);
+case UTIL_GZERROR:
+   /* we lack context to be more informative here */
+   return "zlib error";
+default:
+   INTERNAL_ERROR("unexpected error status %d", errnum);
+}
+}
diff --git a/util/util.h b/util/util.h
new file mode 100644
index 000..d12fadb
--- /dev/null
+++ b/util/util.h
@@ -0,0 +1,29 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+typedef enum util_status {
+/**
+ * No error occurred.
+ */
+UTIL_SUCCESS = 0,
+/**
+ * Out of memory.
+ */
+UTIL_OUT_OF_MEMORY,
+/**
+ * End of stream reached while attempting to read.
+ */
+UTIL_EOF,
+/**
+ * Low level error occured, consult errno.
+ */
+UTIL_ERRNO,
+/**
+ * Zlib error occured, call gzerror for details.
+ */
+UTIL_GZERROR
+} util_status_t;
+
+const char *
+util_error_string (util_status_t status);
+#endif
diff --git a/util/zlib-extra.c b/util/zlib-extra.c
new file mode 100644
index 000..cb34845
--- /dev/null
+++ b/util/zlib-extra.c
@@ -0,0 +1,85 @@
+/* zlib-extra.c -  Extra or enhanced routines for compressed I/O.
+ *
+ * Copyright (c) 2014 David Bremner
+ *
+ * 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/ .
+ *
+ * Author: David Bremner 
+ */
+
+#include "zlib-extra.h"
+#include 
+#include 
+#include 
+
+/* mimic POSIX/glibc getline, but on a zlib gzFile stream, and using talloc */
+util_status_t
+gz_getline (void *talloc_ctx, char **bufptr, ssize_t *bytes_read, gzFile 
stream)
+{
+char *buf = *bufptr;
+unsigned int len;
+size_t offset = 0;
+
+if (buf) {
+   len = talloc_array_length (buf);
+} else {
+   /* same as getdelim from gnulib */
+   len = 120;
+   buf = talloc_array (talloc_ctx, char, len);
+   if (buf == NULL)
+   return UTIL_OUT_OF_MEMORY;
+}
+
+while (1) {
+   if (! gzgets (stream, buf + offset, len - offset)) {
+   /* Null indicates EOF or error */
+   int zlib_status = 0;
+   (void) gzerror (stream, _status);
+   switch (zlib_status) {
+   case Z_OK:
+   /* no data read before EOF */
+   if (offset == 0)
+   return UTIL_EOF;
+   else
+   goto SUCCESS;
+   case Z_ERRNO:
+   return UTIL_ERRNO;
+   default:
+   return UTIL_GZERROR;
+   }
+   }
+
+   offset += strlen (buf + offset);
+
+   if (buf[offset - 1] == '\n')
+   goto SUCCESS;
+
+   len *= 2;
+   buf = talloc_realloc (talloc_ctx, buf, char, len);
+   if (buf == NULL)
+   return UTIL_OUT_OF_MEMORY;
+}
+ SUCCESS:
+*bufptr = buf;
+*bytes_read = offset;
+return UTIL_SUCCESS;
+}
+
+const char *gz_error_string (util_status_t status, gzFile file) 
+{
+if (status 

[Patch v7 1/6] dump: support gzipped and atomic output

2014-04-05 Thread David Bremner
The main goal is to support gzipped output for future internal
calls (e.g. from notmuch-new) to notmuch_database_dump.

The additional dependency is not very heavy since xapian already pulls
in zlib.

We want the dump to be "atomic", in the sense that after running the
dump file is either present and complete, or not present.  This avoids
certain classes of mishaps involving overwriting a good backup with a
bad or partial one.
---
 INSTALL   |  20 +++--
 Makefile.local|   2 +-
 configure |  28 +++--
 doc/man1/notmuch-dump.rst |   3 ++
 notmuch-client.h  |   4 +-
 notmuch-dump.c| 101 +-
 test/T240-dump-restore.sh |  12 ++
 7 files changed, 142 insertions(+), 28 deletions(-)

diff --git a/INSTALL b/INSTALL
index 690b0ef..b543c50 100644
--- a/INSTALL
+++ b/INSTALL
@@ -20,8 +20,8 @@ configure stage.

 Dependencies
 
-Notmuch depends on three libraries: Xapian, GMime 2.4 or 2.6, and
-Talloc which are each described below:
+Notmuch depends on four libraries: Xapian, GMime 2.4 or 2.6,
+Talloc, and zlib which are each described below:

Xapian
--
@@ -60,6 +60,18 @@ Talloc which are each described below:

Talloc is available from http://talloc.samba.org/

+   zlib
+   
+
+   zlib is an extremely popular compression library. It is used
+   by Xapian, so if you installed that you will already have
+   zlib. You may need to install the zlib headers separately.
+
+   Notmuch needs the transparent write feature of zlib introduced
+   in version 1.2.5.2 (Dec. 2011).
+
+   zlib is available from http://zlib.net
+
 Building Documentation
 --

@@ -79,11 +91,11 @@ dependencies with a simple simple command line. For example:

   For Debian and similar:

-sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
python-sphinx
+sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
zlib1g-dev python-sphinx

   For Fedora and similar:

-   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
python-sphinx
+   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
zlib-devel python-sphinx

 On other systems, a similar command can be used, but the details of
 the package names may be different.
diff --git a/Makefile.local b/Makefile.local
index cb7b106..e5a20a7 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -41,7 +41,7 @@ PV_FILE=bindings/python/notmuch/version.py
 # Smash together user's values with our extra values
 FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(CPPFLAGS) $(CFLAGS) 
$(WARN_CFLAGS) $(extra_cflags) $(CONFIGURE_CFLAGS)
 FINAL_CXXFLAGS = $(CPPFLAGS) $(CXXFLAGS) $(WARN_CXXFLAGS) $(extra_cflags) 
$(extra_cxxflags) $(CONFIGURE_CXXFLAGS)
-FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch 
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS)
+FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch 
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS) $(ZLIB_LDFLAGS)
 FINAL_NOTMUCH_LINKER = CC
 ifneq ($(LINKER_RESOLVES_LIBRARY_DEPENDENCIES),1)
 FINAL_NOTMUCH_LDFLAGS += $(CONFIGURE_LDFLAGS)
diff --git a/configure b/configure
index 1d430b9..83b4af7 100755
--- a/configure
+++ b/configure
@@ -340,6 +340,18 @@ else
 errors=$((errors + 1))
 fi

+printf "Checking for zlib (>= 1.2.5.2)... "
+have_zlib=0
+if pkg-config --atleast-version=1.2.5.2 zlib; then
+printf "Yes.\n"
+have_zlib=1
+zlib_cflags=$(pkg-config --cflags zlib)
+zlib_ldflags=$(pkg-config --libs zlib)
+else
+printf "No.\n"
+errors=$((errors + 1))
+fi
+
 printf "Checking for talloc development files... "
 if pkg-config --exists talloc; then
 printf "Yes.\n"
@@ -496,6 +508,11 @@ EOF
echo "  Xapian library (including development files such as headers)"
echo "  http://xapian.org/;
 fi
+if [ $have_zlib -eq 0 ]; then
+   echo "  zlib library (>= version 1.2.5.2, including development files 
such as headers)"
+   echo "  http://zlib.net/;
+   echo
+fi
 if [ $have_gmime -eq 0 ]; then
echo "  Either GMime 2.4 library" $GMIME_24_VERSION_CTR "or GMime 2.6 
library" $GMIME_26_VERSION_CTR
echo "  (including development files such as headers)"
@@ -519,11 +536,11 @@ case a simple command will install everything you need. 
For example:

 On Debian and similar systems:

-   sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
+   sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
zlib1g-dev

 Or on Fedora and similar systems:

-   sudo yum install xapian-core-devel gmime-devel libtalloc-devel
+   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
zlib-devel

 On other systems, similar commands can be used, but the details of the
 package names may be different.
@@ -844,6 +861,10 @@ XAPIAN_LDFLAGS = ${xapian_ldflags}
 

v7 gzip dump restore patches

2014-04-05 Thread David Bremner
Supercedes 

  id:1396554083-3892-2-git-send-email-david at tethera.net

- adds new analogues of strerror
  - util_error_string
  - gz_error_string

Interdiff:

diff --git a/configure b/configure
index 1d624f7..83b4af7 100755
--- a/configure
+++ b/configure
@@ -509,7 +509,7 @@ EOF
echo "  http://xapian.org/;
 fi
 if [ $have_zlib -eq 0 ]; then
-   echo "  zlib library (including development files such as headers)"
+   echo "  zlib library (>= version 1.2.5.2, including development files 
such as headers)"
echo "  http://zlib.net/;
echo
 fi
diff --git a/notmuch-dump.c b/notmuch-dump.c
index 2a7252a..2849eab 100644
--- a/notmuch-dump.c
+++ b/notmuch-dump.c
@@ -127,7 +127,7 @@ notmuch_database_dump (notmuch_database_t *notmuch,
   dump_format_t output_format,
   notmuch_bool_t gzip_output)
 {
-gzFile output;
+gzFile output = NULL;
 const char *mode = gzip_output ? "w9" : "wT";
 const char *name_for_error = output_file_name ? output_file_name : 
"stdout";

@@ -178,7 +178,10 @@ notmuch_database_dump (notmuch_database_t *notmuch,
 }

 if (gzclose_w (output) != Z_OK) {
+   fprintf (stderr, "Error closing %s: %s\n", name_for_error,
+gzerror (output, NULL));
ret = EXIT_FAILURE;
+   output = NULL;
goto DONE;
 }

@@ -192,6 +195,9 @@ notmuch_database_dump (notmuch_database_t *notmuch,

 }
  DONE:
+if (ret != EXIT_SUCCESS && output)
+   (void) gzclose_w (output);
+
 if (ret != EXIT_SUCCESS && output_file_name)
(void) unlink (tempname);

diff --git a/notmuch-restore.c b/notmuch-restore.c
index eb5b7b2..7abee0a 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -129,7 +129,8 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 tag_op_list_t *tag_ops;

 char *input_file_name = NULL;
-gzFile input;
+const char *name_for_error = NULL;
+gzFile input = NULL;
 char *line = NULL;
 void *line_ctx = NULL;
 ssize_t line_len;
@@ -157,19 +158,26 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 };

 opt_index = parse_arguments (argc, argv, options, 1);
-if (opt_index < 0)
-   return EXIT_FAILURE;
+if (opt_index < 0) {
+   ret = EXIT_FAILURE;
+   goto DONE;
+}
+
+name_for_error = input_file_name ? input_file_name : "stdin";

 if (! accumulate)
flags |= TAG_FLAG_REMOVE_ALL;

+errno = 0;
 if (input_file_name)
input = gzopen (input_file_name, "r");
 else {
int infd = dup (STDIN_FILENO);
if (infd < 0) {
-   fprintf (stderr, "Error duping stdin\n");
-   return EXIT_FAILURE;
+   fprintf (stderr, "Error duping stdin: %s\n",
+strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
}
input = gzdopen (infd, "r");
if (! input)
@@ -178,19 +186,22 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])

 if (input == NULL) {
fprintf (stderr, "Error opening %s for (gzip) reading: %s\n",
-input_file_name ? input_file_name : "stdin", strerror (errno));
-   return EXIT_FAILURE;
+name_for_error, strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 if (opt_index < argc) {
fprintf (stderr, "Unused positional parameter: %s\n", argv[opt_index]);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }

 do {
@@ -199,12 +210,17 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
status = gz_getline (line_ctx, , _len, input);

/* empty input file not considered an error */
-   if (status == UTIL_EOF)
-   return EXIT_SUCCESS;
-
-   if (status)
-   return EXIT_FAILURE;
+   if (status == UTIL_EOF) {
+   ret = EXIT_SUCCESS;
+   goto DONE;
+   }

+   if (status) {
+   fprintf (stderr, "Error reading (gzipped) input: %s\n",
+gz_error_string(status, input));
+   ret = EXIT_FAILURE;
+   goto DONE;
+   }
 } while ((line_len == 0) ||
 (line[0] == '#') ||
 /* the cast is safe because we checked about for line_len < 0 */
@@ -269,17 +285,37 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
if (ret)
break;

-}  while (gz_getline (line_ctx, , _len, input) == UTIL_SUCCESS);
+}  while (! (ret = gz_getline (line_ctx, , _len, input)));
+

-if (line_ctx != NULL)
-   talloc_free (line_ctx);
+/* EOF is normal loop termination condition, UTIL_SUCCESS is
+ * impossible here 

Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread Jeremy Nickurak
Off the top of my head, you could have an encrypted index too, which you
can only search while able to decrypt. Certainly another level of
complexity.


On Sat, Apr 5, 2014 at 11:10 AM, David Bremner  wrote:

> john.wyzer at gmx.de writes:
>
> > Would it be possible to add the configurable option to also decrypt
> > encrypted messages on the fly while indexing to make them searchable,
> > too?
> >
> > That would be really great for people that consider gnupg  mainly an
> > encryption for transport or have their complete hard drive encrypted...
>
> As far I understand an attacker could reconstruct the message from the
> index, so one question is whether the extra complexity in notmuch is
> worth the minimal extra security over decrypting on delivery and storing
> plaintext on the (presumably encrypted) disk. Of course decrypting on
> delivery may be inconvenient (or impossible). I have CCed the two people
> who have implemented most of the crypto related stuff in notmuch so they
> can comment.
>
> d
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
>
-- next part --
An HTML attachment was scrubbed...
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20140405/4cbd66bf/attachment-0001.html>


[PATCH 5/7] doc: Allow rst2man.py as an alternative to rst2man

2014-04-05 Thread W. Trevor King
On Sat, Apr 05, 2014 at 10:05:31PM +0300, Tomi Ollila wrote:
> On Sat, Apr 05 2014, W. Trevor King wrote:
> > I use POSIX's 'command -v' [1] to find the path to rst2man?
> >
> > [1]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
> 
> ?
> Except the reference to _POSIX_ page. One knows how consistent these
> specifications are; alternative:
> 
> http://pubs.opengroup.org/onlinepubs/009695399/utilities/command.html
> 
> mentions additionally that -v flag
> "(On systems supporting the User Portability Utilities option.)" 

It's been a decade since POSIX 2004 ;).  I'm not sure when the ?User
Portability Utilities? caveat was removed, but I imagine most
POSIX-aspiring shells have -v support.  Short of citing POSIX 2013, I
think I'd have to survey likely shells, and that seems even less
reliable.  Maybe I'm missunderstanding your suggested change?

> Also, we don't give such a treatment to other command either; I'd rather
> see RST2MAN=rst2man, RST2MAN=rst2man.py *and* RST2MAN= lines used
> instead -- the last to set RST2MAN to empty string instead of being unset.

I'm fine with that.  Alternatively, we could add an:

  if -n "${RST2MAN}"

clause to the front of the detection code to allow users with oddball
scripts (maybe a null set) to override RST2MAN at configure time:

  $ RST2MAN=/my/custom/rst_to_man_converter ./configure
  $ make

instead of at make-invocation time:

  $ ./configure
  $ make RST2MAN=/my/custom/rst_to_man_converter

That would consolidate configuration around the 'config' call, and
make explicitly emptying the RST2MAN variable more clearly superfluous
(although I'm still fine with an explicit empty).

Thoughts?

Trevor

-- 
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
-- next part --
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20140405/2de77e22/attachment.pgp>


Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread Jameson Graef Rollins
On Sat, Apr 05 2014, David Bremner  wrote:
> john.wyzer at gmx.de writes:
>
>> Would it be possible to add the configurable option to also decrypt
>> encrypted messages on the fly while indexing to make them searchable,
>> too?
>>
>> That would be really great for people that consider gnupg  mainly an
>> encryption for transport or have their complete hard drive encrypted...
>
> As far I understand an attacker could reconstruct the message from the
> index, so one question is whether the extra complexity in notmuch is
> worth the minimal extra security over decrypting on delivery and storing
> plaintext on the (presumably encrypted) disk. Of course decrypting on
> delivery may be inconvenient (or impossible). I have CCed the two people
> who have implemented most of the crypto related stuff in notmuch so they
> can comment.

Indexing encrypted email is a bit of a foot-gun, since, as David
mentions, it is apparently possible to reconstruct encrypted messages


[PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread W. Trevor King
The rst2man target was removed in 9d9a700 (doc: build man pages at
build time; introduce HAVE_SPHINX, HAVE_RST2MAN, 2014-03-13), but a
reference in the install docs slipped through.  While I was removing
that reference, I also:

* Converted doc/INSTALL to reStructuredText, so I can link to Sphinx
  and Docutils directly.  Not everyone has access to Debian's
  python-docutils, so it's better to be genric here.
* Converted from an unordered list to paragraphs, because I think it
  flows better.
* Dropped the rst2man no-automatic-install caveat.  I don't think this
  applies to the current code, although I haven't tried to track down
  a commit that adds the automatic-install support.  Anyhow,

$ make HAVE_SPHINX=0 RST2MAN=/usr/bin/rst2man.py DESTDIR=/tmp/ install-man

  works for me.
---
 doc/INSTALL | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/doc/INSTALL b/doc/INSTALL
index e37c2b9..91222f9 100644
--- a/doc/INSTALL
+++ b/doc/INSTALL
@@ -1,24 +1,30 @@
 This file contains some more detailed information about building and
 installing the documentation.

-Building with sphinx.
--
+Building with Sphinx
+

-- You need sphinx at least version 1.0.
+With Sphinx_ version 1.0 or greater, you can build man, info, html,
+and pdf versions of the docs (currently only the man pages) with::

-- You can build build and install man pages with 'make install-man'
+  make build-{man|info|html|pdf}

-- You can build man, info, html, and pdf versions of the docs
-  (currently only the man pages) with
+You can build build and install the docs (currently only the man
+pages) with::

- 'make install-{man|info|html|pdf}'
+  make install-{man|info|html|pdf}

-Building the man pages
---
+Building the man Docutils
+-

-- You can build the man pages with rst2man (from python-docutils) with
-  'make rst2man'.
+If you don't have Sphinx installed, you can still build the man-page
+version of the docs using rst2man (from Docutils_)::

-- Currently there is no support to automagically install the resulting
-  nroff files, but it should work to modify the target install-man
-  in doc/Makefile.local.
+  make build-man
+
+and install with::
+
+  make install-man
+
+.. _Sphinx: http://sphinx-doc.org/
+.. _Docutils: http://docutils.sourceforge.net/
-- 
1.9.1.353.gc66d89d



[PATCH 6/7] doc/prerst2man.py: Convert execfile to import

2014-04-05 Thread W. Trevor King
excefile is gone in Python 3 [1].  Instead of exec-ing the
configuration, it's easier to insert the source directory in Python's
path [2], and just import the configuration.  With this change,
prerst2man.py is compatible with both Python 2 and 3.

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#builtins
[2]: https://docs.python.org/3/library/sys.html#sys.path
---
 doc/prerst2man.py | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 81ce817..7d78e9b 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -1,18 +1,20 @@
-from sys import argv
+import sys
 from datetime import date
 from os.path import dirname, isdir
 from os import makedirs, system
 import re

-rst2man = argv[1]
-sourcedir = argv[2]
-outdir = argv[3]
+rst2man = sys.argv[1]
+sourcedir = sys.argv[2]
+outdir = sys.argv[3]
+
+sys.path.insert(0, sourcedir)
+import conf
+

 if not isdir(outdir):
 makedirs(outdir, 0o755)

-execfile(sourcedir + "/conf.py")
-

 def header(file, startdocname, command, description, authors, section):
 file.write("""
@@ -29,10 +31,10 @@ def header(file, startdocname, command, description, 
authors, section):
 '-' * len(description),
 description,
 '-' * len(description),
-date.today().isoformat(), release, section, project))
+date.today().isoformat(), conf.release, section, conf.project))

 blankre = re.compile("^\s*$")
-for page in man_pages:
+for page in conf.man_pages:
 outdirname = outdir + '/' + dirname(page[0])
 if not isdir(outdirname):
 makedirs(outdirname, 0o755)
-- 
1.9.1.353.gc66d89d



[PATCH 5/7] doc: Allow rst2man.py as an alternative to rst2man

2014-04-05 Thread W. Trevor King
Gentoo's dev-python/docutils-0.10 installs Docutils scripts with a
*.py extension, so I have /usr/bin/rst2man.py and no rst2man script.
This patch supports users with both types of systems by checking for
rst2man, falling back on rst2man.py, and giving up only if neither is
found.  Users can also set the new RST2MAN path variable explicitly
when they call Make:

  make RST2MAN=/my/custom/rst_to_man_converter build-man

I use POSIX's 'command -v' [1] to find the path to rst2man or
rst2man.py, and save that as RST2MAN in Makefile.config.  We can use a
non-empty RST2MAN to check for the availability of an rst2man program,
so there's no need for a separate HAVE_RST2MAN.  Then pass the
configured RST2MAN path through to prerst2man.py to use in its system
call.

[1]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
---
 configure  | 12 +++-
 doc/Makefile.local |  6 +++---
 doc/prerst2man.py  |  9 +
 3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/configure b/configure
index 1d430b9..81c286b 100755
--- a/configure
+++ b/configure
@@ -400,7 +400,6 @@ printf "Checking if sphinx is available and supports nroff 
output... "
 if hash sphinx-build > /dev/null 2>&1 && python -m sphinx.writers.manpage > 
/dev/null 2>&1 ; then
 printf "Yes.\n"
 have_sphinx=1
-have_rst2man=0
 else
 printf "No (falling back to rst2man).\n"
 have_sphinx=0
@@ -408,10 +407,12 @@ else
 printf "Checking if rst2man is available... "
 if rst2man -V > /dev/null 2>&1; then
printf "Yes.\n"
-   have_rst2man=1
+   RST2MAN=$(command -v rst2man)
+elif rst2man.py -V > /dev/null 2>&1; then
+   printf "Yes.\n"
+   RST2MAN=$(command -v rst2man.py)
 else
printf "No (so will not install man pages).\n"
-   have_rst2man=0
 fi
 fi

@@ -788,8 +789,9 @@ HAVE_EMACS = ${have_emacs}
 # Whether there's a sphinx-build binary available for building documentation
 HAVE_SPHINX=${have_sphinx}

-# Whether there's a rst2man binary available for building documentation
-HAVE_RST2MAN=${have_rst2man}
+# The path to the rst2man program for building documentation.  Set to
+# an empty string if no such program is available.
+RST2MAN=${RST2MAN}

 # The directory to which desktop files should be installed
 desktop_dir = \$(prefix)/share/applications
diff --git a/doc/Makefile.local b/doc/Makefile.local
index 0980c71..e08fc99 100644
--- a/doc/Makefile.local
+++ b/doc/Makefile.local
@@ -42,8 +42,8 @@ ifeq ($(HAVE_SPHINX),1)
mkdir -p $(DOCBUILDDIR)/man/man$${section}; \
mv $(DOCBUILDDIR)/man/*.$${section} 
$(DOCBUILDDIR)/man/man$${section}; \
done
-else ifeq ($(HAVE_RST2MAN),1)
-   $(prerst2man) $(srcdir)/doc $(DOCBUILDDIR)/man
+else ifdef RST2MAN
+   $(prerst2man) "$(RST2MAN)" $(srcdir)/doc $(DOCBUILDDIR)/man
 else
@echo "Fatal: build dependency fail."
@false
@@ -51,7 +51,7 @@ endif

 # Do not try to build or install man pages if a man page converter is
 # not available.
-ifeq ($(HAVE_SPHINX)$(HAVE_RST2MAN),00)
+ifeq ($(HAVE_SPHINX)$(RST2MAN),0)
 build-man:
 install-man:
@echo "No sphinx or rst2man, will not install man pages."
diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 437dea9..81ce817 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -4,8 +4,9 @@ from os.path import dirname, isdir
 from os import makedirs, system
 import re

-sourcedir = argv[1]
-outdir = argv[2]
+rst2man = argv[1]
+sourcedir = argv[2]
+outdir = argv[3]

 if not isdir(outdir):
 makedirs(outdir, 0o755)
@@ -59,5 +60,5 @@ for page in man_pages:
 outfile.write("".join(lines))
 outfile.close()

-system('set -x; rst2man {0} {1}/{2}.{3}'
-   .format(filename, outdir, page[0], page[4]))
+system('set -x; {0} {1} {2}/{3}.{4}'
+   .format(rst2man, filename, outdir, page[0], page[4]))
-- 
1.9.1.353.gc66d89d



[PATCH 4/7] doc/prerst2man.py: Fix 'os.system' -> 'system' typo

2014-04-05 Thread W. Trevor King
Avoid:

  $ make HAVE_SPHINX=0 HAVE_RST2MAN=1 build-man
  python ./doc/prerst2man.py ./doc doc/_build/man
  Traceback (most recent call last):
File "./doc/prerst2man.py", line 65, in 
  os.system('set -x; rst2man {0} {1}/{2}.{3}'
  NameError: name 'os' is not defined
  make: *** [doc/_build/man/man1/notmuch.1] Error 1

by using system directly.  We don't need the 'os.' namespacing,
because the function was imported with:

  from os import makedirs, system
---
 doc/prerst2man.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 108f4a3..437dea9 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -59,5 +59,5 @@ for page in man_pages:
 outfile.write("".join(lines))
 outfile.close()

-os.system('set -x; rst2man {0} {1}/{2}.{3}'
-  .format(filename, outdir, page[0],page[4]))
+system('set -x; rst2man {0} {1}/{2}.{3}'
+   .format(filename, outdir, page[0], page[4]))
-- 
1.9.1.353.gc66d89d



[PATCH 3/7] doc/prerst2man.py: Use Python-3-compatible octal notation

2014-04-05 Thread W. Trevor King
Python 3 only supports the 0oXXX notation for octal literals [1,2],
which have also been supported in 2.x since 2.6 [2].

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#integers
[2]: http://legacy.python.org/dev/peps/pep-3127/
---
 doc/prerst2man.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 4591264..108f4a3 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -8,7 +8,7 @@ sourcedir = argv[1]
 outdir = argv[2]

 if not isdir(outdir):
-makedirs(outdir, 0755)
+makedirs(outdir, 0o755)

 execfile(sourcedir + "/conf.py")

@@ -34,7 +34,7 @@ blankre = re.compile("^\s*$")
 for page in man_pages:
 outdirname = outdir + '/' + dirname(page[0])
 if not isdir(outdirname):
-makedirs(outdirname, 0755)
+makedirs(outdirname, 0o755)
 filename = outdir + '/' + page[0] + '.rst'
 outfile = open(filename, 'w')
 infile = open(sourcedir + '/' + page[0] + '.rst', 'r')
-- 
1.9.1.353.gc66d89d



[PATCH 2/7] doc/mkdocdeps.py: Use "with" statement for the output file

2014-04-05 Thread W. Trevor King
Before this patch, the open was unnecessarily early and relied on the
process cleanup to close.  Neither one of these was a real problem,
but PEP 343's context managers (which landed in Python 2.5) make
proper cleanup very easy.

[1]: http://legacy.python.org/dev/peps/pep-0343/
---
 doc/mkdocdeps.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/mkdocdeps.py b/doc/mkdocdeps.py
index de1cbb8..b87fe3e 100644
--- a/doc/mkdocdeps.py
+++ b/doc/mkdocdeps.py
@@ -9,10 +9,10 @@ import conf

 roff_files = []
 rst_files = []
-out=open(outfile,'w')
 for page in conf.man_pages:
 rst_files = rst_files + ["{0:s}/{1:s}.rst".format(srcdir,page[0])]
 roff_files = roff_files + 
["{0:s}/man/{1:s}.{2:d}".format(builddir,page[0],page[4])]

-out.write ('MAN_ROFF_FILES := ' + ' \\\n\t'.join(roff_files)+'\n')
-out.write ('MAN_RST_FILES := ' + ' \\\n\t'.join(rst_files)+'\n')
+with open(outfile, 'w') as out:
+out.write('MAN_ROFF_FILES := ' + ' \\\n\t'.join(roff_files) + '\n')
+out.write('MAN_RST_FILES := ' + ' \\\n\t'.join(rst_files) + '\n')
-- 
1.9.1.353.gc66d89d



[PATCH 1/7] doc/mkdocdeps.py: Convert execfile to import

2014-04-05 Thread W. Trevor King
excefile is gone in Python 3 [1].  Instead of exec-ing the
configuration, it's easier to insert the source directory in Python's
path [2], and just import the configuration.  With this change,
mkdocdeps.py is compatible with both Python 2 and 3.

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#builtins
[2]: https://docs.python.org/3/library/sys.html#sys.path
---
 doc/mkdocdeps.py | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/doc/mkdocdeps.py b/doc/mkdocdeps.py
index 71bd135..de1cbb8 100644
--- a/doc/mkdocdeps.py
+++ b/doc/mkdocdeps.py
@@ -1,15 +1,16 @@
-from sys import argv
-srcdir = argv[1]
-builddir = argv[2]
-outfile = argv[3]
+import sys

-execfile(srcdir + '/conf.py')
+srcdir = sys.argv[1]
+builddir = sys.argv[2]
+outfile = sys.argv[3]

+sys.path.insert(0, srcdir)
+import conf

 roff_files = []
 rst_files = []
 out=open(outfile,'w')
-for page in man_pages:
+for page in conf.man_pages:
 rst_files = rst_files + ["{0:s}/{1:s}.rst".format(srcdir,page[0])]
 roff_files = roff_files + 
["{0:s}/man/{1:s}.{2:d}".format(builddir,page[0],page[4])]

-- 
1.9.1.353.gc66d89d



[PATCH 0/7] doc: Python 3 compat, rst2man.py support, etc.

2014-04-05 Thread W. Trevor King
I just bumped into this today while testing v2 of my
content-description series:

  $ ./configure
  ?
  $ make
  ?
  python ./doc/mkdocdeps.py ./doc doc/_build doc/docdeps.mk
  Traceback (most recent call last):
File "./doc/mkdocdeps.py", line 6, in 
  execfile(srcdir + '/conf.py')
  NameError: name 'execfile' is not defined
  ?

The first patch in this series fixes that issue, and the rest of the
series fixes some other issues I bumped into while working on that.
Sorry I missed these in the initial series.

Note that while mkdocdeps.py and prerst2man.py are now Python 3
compatible (with this series), the build will fail for Python's 3.0
through 3.2 because of the explicit unicode literals in conf.py [1].
It's likely that conf.py could use [2]

  from __future__ import unicode_literals

drop the u'' prefixes, and be compatible with all Python's ?2.6
(including all 3s).  I haven't checked the logic though, and I'm not
running 3.2 locally anymore, so it's not a big priority for me.

Cheers,
Trevor

[1]: 
https://docs.python.org/3/whatsnew/3.3.html#pep-414-explicit-unicode-literals
[2]: from __future__ import unicode_literals

W. Trevor King (7):
  doc/mkdocdeps.py: Convert execfile to import
  doc/mkdocdeps.py: Use "with" statement for the output file
  doc/prerst2man.py: Use Python-3-compatible octal notation
  doc/prerst2man.py: Fix 'os.system' -> 'system' typo
  doc: Allow rst2man.py as an alternative to rst2man
  doc/prerst2man.py: Convert execfile to import
  doc/INSTALL: Remove rst2man reference and other updates

 configure  | 12 +++-
 doc/INSTALL| 34 --
 doc/Makefile.local |  6 +++---
 doc/mkdocdeps.py   | 19 ++-
 doc/prerst2man.py  | 25 ++---
 5 files changed, 54 insertions(+), 42 deletions(-)

-- 
1.9.1.353.gc66d89d



[PATCH v4 0/4] nmbug-status: Python-3-compatibility and general refactoring

2014-04-05 Thread W. Trevor King
On Sun, Feb 16, 2014 at 07:46:29PM -0400, David Bremner wrote:
> pushed the last 4.

It looks like there's still a nmbug-status branch on
git://notmuchmail.org/git/notmuch.  It's an ancestor of debian/0.17-4,
and nmbug-status development seems to have calmed back down, so that
branch can probably be removed.

Cheers,
Trevor

-- 
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
-- next part --
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20140405/97ea6436/attachment.pgp>


[PATCH] emacs: sign/encrypt replies to signed/encrypted messages

2014-04-05 Thread Jani Nikula
This is a simple approach to improving security when replying to
signed or encrypted messages. If the message being replied to was
signed, add mml tag to sign the reply. If the message being replied to
was encrypted, add mml tag to sign and encrypt the reply.

This may need configuration; I for one might want to encrypt replies
to encrypted messages, but not always sign replies to signed messages.

This still includes a slight bug: if any mml tags are added, they are
included in the region containing the quoted parts. Killing the region
will kill the mml tags too.
---
 emacs/notmuch-mua.el | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index ba3ef275ec5e..9fb84b57b030 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -115,6 +115,15 @@ list.
(push header message-hidden-headers)))
notmuch-mua-hidden-headers))
 
+(defun notmuch-mua-reply-crypto (parts)
+  (loop for part in parts
+   if (notmuch-match-content-type (plist-get part :content-type) 
multipart/signed)
+ do (mml-secure-message-sign)
+   else if (notmuch-match-content-type (plist-get part :content-type) 
multipart/encrypted)
+ do (mml-secure-message-sign-encrypt)
+   else if (notmuch-match-content-type (plist-get part :content-type) 
multipart/*)
+ do (notmuch-mua-reply-crypto (plist-get part :content
+
 (defun notmuch-mua-get-quotable-parts (parts)
   (loop for part in parts
if (notmuch-match-content-type (plist-get part :content-type) 
multipart/alternative)
@@ -224,7 +233,10 @@ list.
(set-mark (point))
(goto-char start)
;; Quote the original message according to the user's configured style.
-   (message-cite-original
+   (message-cite-original)))
+
+;; Sign and/or encrypt replies to signed and/or encrypted messages.
+(notmuch-mua-reply-crypto (plist-get original :body)))
 
   ;; Push mark right before signature, if any.
   (message-goto-signature)
-- 
1.9.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/1] release-checks: removed manual page version check

2014-04-05 Thread Tomi Ollila
Manual pages are now generated and during the generation the version
string is read from `version` file, so this (currently failing) test
checking manual page versions can be removed.

While at it, changed the case pattern *[^0-9.]*
to its portable alternative *[!0-9.]*
---
 devel/release-checks.sh | 42 +-
 1 file changed, 1 insertion(+), 41 deletions(-)

diff --git a/devel/release-checks.sh b/devel/release-checks.sh
index 8938905..797d62a 100755
--- a/devel/release-checks.sh
+++ b/devel/release-checks.sh
@@ -68,7 +68,7 @@ verfail ()
 
 echo -n Checking that '$VERSION' is good with digits and periods... 
 case $VERSION in
-   *[^0-9.]*)
+   *[!0-9.]*)
verfail '$VERSION' contains other characters than digits and 
periods ;;
.*) verfail '$VERSION' begins with a period ;;
*.) verfail '$VERSION' ends with a period ;;
@@ -196,46 +196,6 @@ case $news_date in
append_emsg Date '$news_date' in NEWS file is not in format 
(-mm-dd)
 esac
 
-readonly DATE=${news_date//[()]/} # bash feature
-manthdata ()
-{
-   set x $*
-   if [ $# != 7 ]
-   then
-   append_emsg '$mp' has too many '.TH' lines
-   man_mismatch=1
-   fi
-   man_date=${5-} man_version=${7-}
-}
-
-echo -n Checking that manual page dates and versions are $DATE and 
$VERSION... 
-manfiles=`find man -type f | sort`
-man_pages_ok=Yes
-for mp in $manfiles
-do
-   case $mp in
-   *.[0-9]) ;; # fall below this 'case ... esac'
-
-   */Makefile.local | */Makefile ) continue ;;
-   */.gitignore)   continue ;;
-   *.bak)  continue ;;
-
-   *)  append_emsg '$mp': extra file
-   man_pages_ok=No
-   continue
-   esac
-   manthdata `sed -n '/^[.]TH NOTMUCH/ { y// /; p; }' $mp`
-   if [ $man_version != $VERSION ]
-   thenappend_emsg Version '$man_version' is not '$VERSION' in $mp
-   mman_pages_ok=No
-   fi
-   if [ $man_date != $DATE ]
-   thenappend_emsg DATE '$man_date' is not '$DATE' in $mp
-   man_pages_ok=No
-   fi
-done
-echo $man_pages_ok.
-
 if [ -n $emsgs ]
 then
echo
-- 
1.8.0

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 0/4] nmbug-status: Python-3-compatibility and general refactoring

2014-04-05 Thread W. Trevor King
On Sun, Feb 16, 2014 at 07:46:29PM -0400, David Bremner wrote:
 pushed the last 4.

It looks like there's still a nmbug-status branch on
git://notmuchmail.org/git/notmuch.  It's an ancestor of debian/0.17-4,
and nmbug-status development seems to have calmed back down, so that
branch can probably be removed.

Cheers,
Trevor

-- 
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy


signature.asc
Description: OpenPGP digital signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


v7 gzip dump restore patches

2014-04-05 Thread David Bremner
Supercedes 

  id:1396554083-3892-2-git-send-email-da...@tethera.net

- adds new analogues of strerror
  - util_error_string
  - gz_error_string

Interdiff:

diff --git a/configure b/configure
index 1d624f7..83b4af7 100755
--- a/configure
+++ b/configure
@@ -509,7 +509,7 @@ EOF
echo   http://xapian.org/;
 fi
 if [ $have_zlib -eq 0 ]; then
-   echo   zlib library (including development files such as headers)
+   echo   zlib library (= version 1.2.5.2, including development files 
such as headers)
echo   http://zlib.net/;
echo
 fi
diff --git a/notmuch-dump.c b/notmuch-dump.c
index 2a7252a..2849eab 100644
--- a/notmuch-dump.c
+++ b/notmuch-dump.c
@@ -127,7 +127,7 @@ notmuch_database_dump (notmuch_database_t *notmuch,
   dump_format_t output_format,
   notmuch_bool_t gzip_output)
 {
-gzFile output;
+gzFile output = NULL;
 const char *mode = gzip_output ? w9 : wT;
 const char *name_for_error = output_file_name ? output_file_name : 
stdout;
 
@@ -178,7 +178,10 @@ notmuch_database_dump (notmuch_database_t *notmuch,
 }
 
 if (gzclose_w (output) != Z_OK) {
+   fprintf (stderr, Error closing %s: %s\n, name_for_error,
+gzerror (output, NULL));
ret = EXIT_FAILURE;
+   output = NULL;
goto DONE;
 }
 
@@ -192,6 +195,9 @@ notmuch_database_dump (notmuch_database_t *notmuch,
 
 }
  DONE:
+if (ret != EXIT_SUCCESS  output)
+   (void) gzclose_w (output);
+
 if (ret != EXIT_SUCCESS  output_file_name)
(void) unlink (tempname);
 
diff --git a/notmuch-restore.c b/notmuch-restore.c
index eb5b7b2..7abee0a 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -129,7 +129,8 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 tag_op_list_t *tag_ops;
 
 char *input_file_name = NULL;
-gzFile input;
+const char *name_for_error = NULL;
+gzFile input = NULL;
 char *line = NULL;
 void *line_ctx = NULL;
 ssize_t line_len;
@@ -157,19 +158,26 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 };
 
 opt_index = parse_arguments (argc, argv, options, 1);
-if (opt_index  0)
-   return EXIT_FAILURE;
+if (opt_index  0) {
+   ret = EXIT_FAILURE;
+   goto DONE;
+}
+
+name_for_error = input_file_name ? input_file_name : stdin;
 
 if (! accumulate)
flags |= TAG_FLAG_REMOVE_ALL;
 
+errno = 0;
 if (input_file_name)
input = gzopen (input_file_name, r);
 else {
int infd = dup (STDIN_FILENO);
if (infd  0) {
-   fprintf (stderr, Error duping stdin\n);
-   return EXIT_FAILURE;
+   fprintf (stderr, Error duping stdin: %s\n,
+strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
}
input = gzdopen (infd, r);
if (! input)
@@ -178,19 +186,22 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 
 if (input == NULL) {
fprintf (stderr, Error opening %s for (gzip) reading: %s\n,
-input_file_name ? input_file_name : stdin, strerror (errno));
-   return EXIT_FAILURE;
+name_for_error, strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 if (opt_index  argc) {
fprintf (stderr, Unused positional parameter: %s\n, argv[opt_index]);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, Out of memory.\n);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 do {
@@ -199,12 +210,17 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
status = gz_getline (line_ctx, line, line_len, input);
 
/* empty input file not considered an error */
-   if (status == UTIL_EOF)
-   return EXIT_SUCCESS;
-
-   if (status)
-   return EXIT_FAILURE;
+   if (status == UTIL_EOF) {
+   ret = EXIT_SUCCESS;
+   goto DONE;
+   }
 
+   if (status) {
+   fprintf (stderr, Error reading (gzipped) input: %s\n,
+gz_error_string(status, input));
+   ret = EXIT_FAILURE;
+   goto DONE;
+   }
 } while ((line_len == 0) ||
 (line[0] == '#') ||
 /* the cast is safe because we checked about for line_len  0 */
@@ -269,17 +285,37 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
if (ret)
break;
 
-}  while (gz_getline (line_ctx, line, line_len, input) == UTIL_SUCCESS);
+}  while (! (ret = gz_getline (line_ctx, line, line_len, input)));
+
 
-if (line_ctx != NULL)
-   talloc_free (line_ctx);
+/* EOF is normal loop termination condition, UTIL_SUCCESS is
+ * impossible here */
+  

[Patch v7 5/6] notmuch-new: backup tags before database upgrade

2014-04-05 Thread David Bremner
All we do here is calculate the backup filename, and call the existing
dump routine.

Also take the opportity to add a message about being safe to
interrupt.
---
 notmuch-new.c| 29 -
 test/T530-upgrade.sh |  4 +++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 82acf69..d269c7c 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -989,8 +989,35 @@ notmuch_new_command (notmuch_config_t *config, int argc, 
char *argv[])
return EXIT_FAILURE;
 
if (notmuch_database_needs_upgrade (notmuch)) {
-   if (add_files_state.verbosity = VERBOSITY_NORMAL)
+   time_t now = time (NULL);
+   struct tm *gm_time = gmtime (now);
+
+   /* since dump files are written atomically, the amount of
+* harm from overwriting one within a second seems
+* relatively small. */
+
+   const char *backup_name =
+   talloc_asprintf (notmuch, 
%s/dump-%04d%02d%02dT%02d%02d%02d.gz,
+dot_notmuch_path,
+gm_time-tm_year + 1900,
+gm_time-tm_mon + 1,
+gm_time-tm_mday,
+gm_time-tm_hour,
+gm_time-tm_min,
+gm_time-tm_sec);
+
+   if (add_files_state.verbosity = VERBOSITY_NORMAL) {
printf (Welcome to a new version of notmuch! Your database 
will now be upgraded.\n);
+   printf (This process is safe to interrupt.\n);
+   printf (Backing up tags to %s...\n, backup_name);
+   }
+
+   if (notmuch_database_dump (notmuch, backup_name, ,
+  DUMP_FORMAT_BATCH_TAG, TRUE)) {
+   fprintf (stderr, Backup failed. Aborting upgrade.);
+   return EXIT_FAILURE;
+   }
+
gettimeofday (add_files_state.tv_start, NULL);
notmuch_database_upgrade (notmuch,
  add_files_state.verbosity = 
VERBOSITY_NORMAL ? upgrade_print_progress : NULL,
diff --git a/test/T530-upgrade.sh b/test/T530-upgrade.sh
index 67bbf31..d46e3d1 100755
--- a/test/T530-upgrade.sh
+++ b/test/T530-upgrade.sh
@@ -26,9 +26,11 @@ output=$(notmuch search path:foo)
 test_expect_equal $output 
 
 test_begin_subtest database upgrade from format version 1
-output=$(notmuch new)
+output=$(notmuch new | sed -e 's/^Backing up tags to .*$/Backing up tags to 
FILENAME/')
 test_expect_equal $output \
 Welcome to a new version of notmuch! Your database will now be upgraded.
+This process is safe to interrupt.
+Backing up tags to FILENAME
 Your notmuch database has now been upgraded to database format version 2.
 No new mail.
 
-- 
1.9.0

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[Patch v7 3/6] test: restore with missing final newline

2014-04-05 Thread David Bremner
Recent proposed patches for gzipped input had a bug with handling
missing newlines that was not caught by the current test suite
---
 test/T240-dump-restore.sh | 9 +
 1 file changed, 9 insertions(+)

diff --git a/test/T240-dump-restore.sh b/test/T240-dump-restore.sh
index d79aca8..b6d8602 100755
--- a/test/T240-dump-restore.sh
+++ b/test/T240-dump-restore.sh
@@ -110,6 +110,15 @@ notmuch dump --format=batch-tag from:cworth | sed 's/^.*-- 
id://' | \
 sort  OUTPUT.$test_count
 test_expect_equal_file EXPECTED.$test_count OUTPUT.$test_count
 
+test_begin_subtest format=batch-tag, missing newline
+printf +a_tag_without_newline -- id:20091117232137.ga7...@griffis1.net  IN
+notmuch restore --accumulate  IN
+notmuch dump id:20091117232137.ga7...@griffis1.net  OUT
+cat EOF  EXPECTED
++a_tag_without_newline +inbox +unread -- id:20091117232137.ga7...@griffis1.net
+EOF
+test_expect_equal_file EXPECTED OUT
+
 test_begin_subtest format=batch-tag, # round-trip
 notmuch dump --format=sup | sort  EXPECTED.$test_count
 notmuch dump --format=batch-tag | notmuch restore --format=batch-tag
-- 
1.9.0

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[Patch v7 4/6] restore: transparently support gzipped input

2014-04-05 Thread David Bremner
We rely completely on zlib to do the right thing in detecting gzipped
input. Since our dump format is chosen to be 7 bit ascii, this should
be fine.
---
 doc/man1/notmuch-restore.rst |  8 
 notmuch-restore.c| 93 +---
 test/T240-dump-restore.sh| 14 +++
 3 files changed, 92 insertions(+), 23 deletions(-)

diff --git a/doc/man1/notmuch-restore.rst b/doc/man1/notmuch-restore.rst
index d6cf19a..936b138 100644
--- a/doc/man1/notmuch-restore.rst
+++ b/doc/man1/notmuch-restore.rst
@@ -50,6 +50,14 @@ Supported options for **restore** include
 format, this heuristic, based the fact that batch-tag format
 contains no parentheses, should be accurate.
 
+GZIPPED INPUT
+=
+
+\ **notmuch restore** will detect if the input is compressed in
+**gzip(1)** format and automatically decompress it while reading. This
+detection does not depend on file naming and in particular works for
+standard input.
+
 SEE ALSO
 
 
diff --git a/notmuch-restore.c b/notmuch-restore.c
index c54d513..7abee0a 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -22,6 +22,7 @@
 #include hex-escape.h
 #include tag-util.h
 #include string-util.h
+#include zlib-extra.h
 
 static regex_t regex;
 
@@ -128,10 +129,10 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 tag_op_list_t *tag_ops;
 
 char *input_file_name = NULL;
-FILE *input = stdin;
+const char *name_for_error = NULL;
+gzFile input = NULL;
 char *line = NULL;
 void *line_ctx = NULL;
-size_t line_size;
 ssize_t line_len;
 
 int ret = 0;
@@ -157,39 +158,69 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
 };
 
 opt_index = parse_arguments (argc, argv, options, 1);
-if (opt_index  0)
-   return EXIT_FAILURE;
+if (opt_index  0) {
+   ret = EXIT_FAILURE;
+   goto DONE;
+}
+
+name_for_error = input_file_name ? input_file_name : stdin;
 
 if (! accumulate)
flags |= TAG_FLAG_REMOVE_ALL;
 
-if (input_file_name) {
-   input = fopen (input_file_name, r);
-   if (input == NULL) {
-   fprintf (stderr, Error opening %s for reading: %s\n,
-input_file_name, strerror (errno));
-   return EXIT_FAILURE;
+errno = 0;
+if (input_file_name)
+   input = gzopen (input_file_name, r);
+else {
+   int infd = dup (STDIN_FILENO);
+   if (infd  0) {
+   fprintf (stderr, Error duping stdin: %s\n,
+strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
}
+   input = gzdopen (infd, r);
+   if (! input)
+   close (infd);
+}
+
+if (input == NULL) {
+   fprintf (stderr, Error opening %s for (gzip) reading: %s\n,
+name_for_error, strerror (errno));
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 if (opt_index  argc) {
fprintf (stderr, Unused positional parameter: %s\n, argv[opt_index]);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, Out of memory.\n);
-   return EXIT_FAILURE;
+   ret = EXIT_FAILURE;
+   goto DONE;
 }
 
 do {
-   line_len = getline (line, line_size, input);
+   util_status_t status;
+
+   status = gz_getline (line_ctx, line, line_len, input);
 
/* empty input file not considered an error */
-   if (line_len  0)
-   return EXIT_SUCCESS;
+   if (status == UTIL_EOF) {
+   ret = EXIT_SUCCESS;
+   goto DONE;
+   }
 
+   if (status) {
+   fprintf (stderr, Error reading (gzipped) input: %s\n,
+gz_error_string(status, input));
+   ret = EXIT_FAILURE;
+   goto DONE;
+   }
 } while ((line_len == 0) ||
 (line[0] == '#') ||
 /* the cast is safe because we checked about for line_len  0 */
@@ -254,21 +285,37 @@ notmuch_restore_command (notmuch_config_t *config, int 
argc, char *argv[])
if (ret)
break;
 
-}  while ((line_len = getline (line, line_size, input)) != -1);
+}  while (! (ret = gz_getline (line_ctx, line, line_len, input)));
+
 
-if (line_ctx != NULL)
-   talloc_free (line_ctx);
+/* EOF is normal loop termination condition, UTIL_SUCCESS is
+ * impossible here */
+if (ret == UTIL_EOF) {
+   ret = UTIL_SUCCESS;
+} else {
+   fprintf (stderr, Error reading (gzipped) input: %s\n,
+gz_error_string (ret, input));
+}
+
+/* currently this should not be after DONE: since we don't 
+ * know if the xregcomp was reached
+ */
 
 if (input_format == DUMP_FORMAT_SUP)
regfree (regex);
 
-if (line)
-   free (line);
+ DONE:
+if (line_ctx != NULL)
+   talloc_free (line_ctx);
 
-

[Patch v7 6/6] test: verify tag backup generated by database upgrade

2014-04-05 Thread David Bremner
'pre upgrade dump' is not much of a test, but at least this way we get
somewhat sensible behaviour if it fails.
---
 test/T530-upgrade.sh | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/test/T530-upgrade.sh b/test/T530-upgrade.sh
index d46e3d1..7d5d5aa 100755
--- a/test/T530-upgrade.sh
+++ b/test/T530-upgrade.sh
@@ -25,6 +25,8 @@ test_begin_subtest path: search does not work with old 
database version
 output=$(notmuch search path:foo)
 test_expect_equal $output 
 
+test_expect_success 'pre upgrade dump' 'notmuch dump | sort  pre-upgrade-dump'
+
 test_begin_subtest database upgrade from format version 1
 output=$(notmuch new | sed -e 's/^Backing up tags to .*$/Backing up tags to 
FILENAME/')
 test_expect_equal $output \
@@ -34,6 +36,10 @@ Backing up tags to FILENAME
 Your notmuch database has now been upgraded to database format version 2.
 No new mail.
 
+test_begin_subtest tag backup matches pre-upgrade dump
+gunzip -c ${MAIL_DIR}/.notmuch/dump-*.gz | sort  backup-dump
+test_expect_equal_file pre-upgrade-dump backup-dump
+
 test_begin_subtest folder: no longer matches in the middle of path
 output=$(notmuch search folder:baz)
 test_expect_equal $output 
-- 
1.9.0

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[Patch v7 1/6] dump: support gzipped and atomic output

2014-04-05 Thread David Bremner
The main goal is to support gzipped output for future internal
calls (e.g. from notmuch-new) to notmuch_database_dump.

The additional dependency is not very heavy since xapian already pulls
in zlib.

We want the dump to be atomic, in the sense that after running the
dump file is either present and complete, or not present.  This avoids
certain classes of mishaps involving overwriting a good backup with a
bad or partial one.
---
 INSTALL   |  20 +++--
 Makefile.local|   2 +-
 configure |  28 +++--
 doc/man1/notmuch-dump.rst |   3 ++
 notmuch-client.h  |   4 +-
 notmuch-dump.c| 101 +-
 test/T240-dump-restore.sh |  12 ++
 7 files changed, 142 insertions(+), 28 deletions(-)

diff --git a/INSTALL b/INSTALL
index 690b0ef..b543c50 100644
--- a/INSTALL
+++ b/INSTALL
@@ -20,8 +20,8 @@ configure stage.
 
 Dependencies
 
-Notmuch depends on three libraries: Xapian, GMime 2.4 or 2.6, and
-Talloc which are each described below:
+Notmuch depends on four libraries: Xapian, GMime 2.4 or 2.6,
+Talloc, and zlib which are each described below:
 
Xapian
--
@@ -60,6 +60,18 @@ Talloc which are each described below:
 
Talloc is available from http://talloc.samba.org/
 
+   zlib
+   
+
+   zlib is an extremely popular compression library. It is used
+   by Xapian, so if you installed that you will already have
+   zlib. You may need to install the zlib headers separately.
+
+   Notmuch needs the transparent write feature of zlib introduced
+   in version 1.2.5.2 (Dec. 2011).
+
+   zlib is available from http://zlib.net
+
 Building Documentation
 --
 
@@ -79,11 +91,11 @@ dependencies with a simple simple command line. For example:
 
   For Debian and similar:
 
-sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
python-sphinx
+sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
zlib1g-dev python-sphinx
 
   For Fedora and similar:
 
-   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
python-sphinx
+   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
zlib-devel python-sphinx
 
 On other systems, a similar command can be used, but the details of
 the package names may be different.
diff --git a/Makefile.local b/Makefile.local
index cb7b106..e5a20a7 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -41,7 +41,7 @@ PV_FILE=bindings/python/notmuch/version.py
 # Smash together user's values with our extra values
 FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(CPPFLAGS) $(CFLAGS) 
$(WARN_CFLAGS) $(extra_cflags) $(CONFIGURE_CFLAGS)
 FINAL_CXXFLAGS = $(CPPFLAGS) $(CXXFLAGS) $(WARN_CXXFLAGS) $(extra_cflags) 
$(extra_cxxflags) $(CONFIGURE_CXXFLAGS)
-FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch 
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS)
+FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Lutil -lutil -Llib -lnotmuch 
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS) $(ZLIB_LDFLAGS)
 FINAL_NOTMUCH_LINKER = CC
 ifneq ($(LINKER_RESOLVES_LIBRARY_DEPENDENCIES),1)
 FINAL_NOTMUCH_LDFLAGS += $(CONFIGURE_LDFLAGS)
diff --git a/configure b/configure
index 1d430b9..83b4af7 100755
--- a/configure
+++ b/configure
@@ -340,6 +340,18 @@ else
 errors=$((errors + 1))
 fi
 
+printf Checking for zlib (= 1.2.5.2)... 
+have_zlib=0
+if pkg-config --atleast-version=1.2.5.2 zlib; then
+printf Yes.\n
+have_zlib=1
+zlib_cflags=$(pkg-config --cflags zlib)
+zlib_ldflags=$(pkg-config --libs zlib)
+else
+printf No.\n
+errors=$((errors + 1))
+fi
+
 printf Checking for talloc development files... 
 if pkg-config --exists talloc; then
 printf Yes.\n
@@ -496,6 +508,11 @@ EOF
echo   Xapian library (including development files such as headers)
echo   http://xapian.org/;
 fi
+if [ $have_zlib -eq 0 ]; then
+   echo   zlib library (= version 1.2.5.2, including development files 
such as headers)
+   echo   http://zlib.net/;
+   echo
+fi
 if [ $have_gmime -eq 0 ]; then
echo   Either GMime 2.4 library $GMIME_24_VERSION_CTR or GMime 2.6 
library $GMIME_26_VERSION_CTR
echo   (including development files such as headers)
@@ -519,11 +536,11 @@ case a simple command will install everything you need. 
For example:
 
 On Debian and similar systems:
 
-   sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev
+   sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev 
zlib1g-dev
 
 Or on Fedora and similar systems:
 
-   sudo yum install xapian-core-devel gmime-devel libtalloc-devel
+   sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
zlib-devel
 
 On other systems, similar commands can be used, but the details of the
 package names may be different.
@@ -844,6 +861,10 @@ XAPIAN_LDFLAGS = ${xapian_ldflags}
 GMIME_CFLAGS = 

[Patch v7 2/6] util: add gz_readline

2014-04-05 Thread David Bremner
The idea is to provide a more or less drop in replacement for readline
to read from zlib/gzip streams.  Take the opportunity to replace
malloc with talloc.
---
 util/Makefile.local |  3 +-
 util/util.c | 24 +++
 util/util.h | 29 ++
 util/zlib-extra.c   | 85 +
 util/zlib-extra.h   | 25 
 5 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 util/util.c
 create mode 100644 util/util.h
 create mode 100644 util/zlib-extra.c
 create mode 100644 util/zlib-extra.h

diff --git a/util/Makefile.local b/util/Makefile.local
index 29c0ce6..905f237 100644
--- a/util/Makefile.local
+++ b/util/Makefile.local
@@ -4,7 +4,8 @@ dir := util
 extra_cflags += -I$(srcdir)/$(dir)
 
 libutil_c_srcs := $(dir)/xutil.c $(dir)/error_util.c $(dir)/hex-escape.c \
- $(dir)/string-util.c $(dir)/talloc-extra.c
+ $(dir)/string-util.c $(dir)/talloc-extra.c 
$(dir)/zlib-extra.c \
+   $(dir)/util.c
 
 libutil_modules := $(libutil_c_srcs:.c=.o)
 
diff --git a/util/util.c b/util/util.c
new file mode 100644
index 000..3bd305d
--- /dev/null
+++ b/util/util.c
@@ -0,0 +1,24 @@
+#include util.h
+#include error_util.h
+#include string.h
+#include errno.h
+
+const char *
+util_error_string (util_status_t errnum)
+{
+switch (errnum) {
+case UTIL_SUCCESS:
+   return none;
+case UTIL_OUT_OF_MEMORY:
+   return out of memory;
+case UTIL_EOF:
+   return end of file;
+case UTIL_ERRNO:
+   return strerror (errno);
+case UTIL_GZERROR:
+   /* we lack context to be more informative here */
+   return zlib error;
+default:
+   INTERNAL_ERROR(unexpected error status %d, errnum);
+}
+}
diff --git a/util/util.h b/util/util.h
new file mode 100644
index 000..d12fadb
--- /dev/null
+++ b/util/util.h
@@ -0,0 +1,29 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+typedef enum util_status {
+/**
+ * No error occurred.
+ */
+UTIL_SUCCESS = 0,
+/**
+ * Out of memory.
+ */
+UTIL_OUT_OF_MEMORY,
+/**
+ * End of stream reached while attempting to read.
+ */
+UTIL_EOF,
+/**
+ * Low level error occured, consult errno.
+ */
+UTIL_ERRNO,
+/**
+ * Zlib error occured, call gzerror for details.
+ */
+UTIL_GZERROR
+} util_status_t;
+
+const char *
+util_error_string (util_status_t status);
+#endif
diff --git a/util/zlib-extra.c b/util/zlib-extra.c
new file mode 100644
index 000..cb34845
--- /dev/null
+++ b/util/zlib-extra.c
@@ -0,0 +1,85 @@
+/* zlib-extra.c -  Extra or enhanced routines for compressed I/O.
+ *
+ * Copyright (c) 2014 David Bremner
+ *
+ * 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/ .
+ *
+ * Author: David Bremner da...@tethera.net
+ */
+
+#include zlib-extra.h
+#include talloc.h
+#include stdio.h
+#include string.h
+
+/* mimic POSIX/glibc getline, but on a zlib gzFile stream, and using talloc */
+util_status_t
+gz_getline (void *talloc_ctx, char **bufptr, ssize_t *bytes_read, gzFile 
stream)
+{
+char *buf = *bufptr;
+unsigned int len;
+size_t offset = 0;
+
+if (buf) {
+   len = talloc_array_length (buf);
+} else {
+   /* same as getdelim from gnulib */
+   len = 120;
+   buf = talloc_array (talloc_ctx, char, len);
+   if (buf == NULL)
+   return UTIL_OUT_OF_MEMORY;
+}
+
+while (1) {
+   if (! gzgets (stream, buf + offset, len - offset)) {
+   /* Null indicates EOF or error */
+   int zlib_status = 0;
+   (void) gzerror (stream, zlib_status);
+   switch (zlib_status) {
+   case Z_OK:
+   /* no data read before EOF */
+   if (offset == 0)
+   return UTIL_EOF;
+   else
+   goto SUCCESS;
+   case Z_ERRNO:
+   return UTIL_ERRNO;
+   default:
+   return UTIL_GZERROR;
+   }
+   }
+
+   offset += strlen (buf + offset);
+
+   if (buf[offset - 1] == '\n')
+   goto SUCCESS;
+
+   len *= 2;
+   buf = talloc_realloc (talloc_ctx, buf, char, len);
+   if (buf == NULL)
+   return UTIL_OUT_OF_MEMORY;
+}
+ SUCCESS:
+*bufptr = buf;
+*bytes_read = offset;
+return UTIL_SUCCESS;
+}
+
+const char *gz_error_string 

Re: [PATCH v4 0/4] nmbug-status: Python-3-compatibility and general refactoring

2014-04-05 Thread David Bremner
W. Trevor King wk...@tremily.us writes:

 On Sun, Feb 16, 2014 at 07:46:29PM -0400, David Bremner wrote:
 pushed the last 4.

 It looks like there's still a nmbug-status branch on
 git://notmuchmail.org/git/notmuch.  It's an ancestor of debian/0.17-4,
 and nmbug-status development seems to have calmed back down, so that
 branch can probably be removed.

done.

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v5 1/2] lib: drop support for single-message mbox files

2014-04-05 Thread David Bremner
Jani Nikula j...@nikula.org writes:

 We've supported mbox files containing a single message for historical
 reasons, but the support has been deprecated, with a warning message
 while indexing, since Notmuch 0.15. Finally drop the support, and
 consider all mbox files non-email.

series pushed.

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] debian: ignore performance corpus when making source package

2014-04-05 Thread David Bremner
David Bremner da...@tethera.net writes:

 Currently make debian-snapshot will include the performance corpus
 tarball in the source package, which slows things down and wastes disk
 space.  tar-ignore is needed twice to keep the default exclude rules
 (e.g. to exclude .git)

Pushed this. I'm thinking it would be good to treat test databases the
same way, and have a new level of cleaning to remove them all. 

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread john . wyzer

Hello!

Would it be possible to add the configurable option to also decrypt
encrypted messages on the fly while indexing to make them searchable,
too?

That would be really great for people that consider gnupg  mainly an
encryption for transport or have their complete hard drive encrypted...

Best regards!
John
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread David Bremner
john.wy...@gmx.de writes:

 Would it be possible to add the configurable option to also decrypt
 encrypted messages on the fly while indexing to make them searchable,
 too?

 That would be really great for people that consider gnupg  mainly an
 encryption for transport or have their complete hard drive encrypted...

As far I understand an attacker could reconstruct the message from the
index, so one question is whether the extra complexity in notmuch is
worth the minimal extra security over decrypting on delivery and storing
plaintext on the (presumably encrypted) disk. Of course decrypting on
delivery may be inconvenient (or impossible). I have CCed the two people
who have implemented most of the crypto related stuff in notmuch so they
can comment.

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 0/7] doc: Python 3 compat, rst2man.py support, etc.

2014-04-05 Thread W. Trevor King
I just bumped into this today while testing v2 of my
content-description series:

  $ ./configure
  …
  $ make
  …
  python ./doc/mkdocdeps.py ./doc doc/_build doc/docdeps.mk
  Traceback (most recent call last):
File ./doc/mkdocdeps.py, line 6, in module
  execfile(srcdir + '/conf.py')
  NameError: name 'execfile' is not defined
  …

The first patch in this series fixes that issue, and the rest of the
series fixes some other issues I bumped into while working on that.
Sorry I missed these in the initial series.

Note that while mkdocdeps.py and prerst2man.py are now Python 3
compatible (with this series), the build will fail for Python's 3.0
through 3.2 because of the explicit unicode literals in conf.py [1].
It's likely that conf.py could use [2]

  from __future__ import unicode_literals

drop the u'' prefixes, and be compatible with all Python's ≥2.6
(including all 3s).  I haven't checked the logic though, and I'm not
running 3.2 locally anymore, so it's not a big priority for me.

Cheers,
Trevor

[1]: 
https://docs.python.org/3/whatsnew/3.3.html#pep-414-explicit-unicode-literals
[2]: from __future__ import unicode_literals

W. Trevor King (7):
  doc/mkdocdeps.py: Convert execfile to import
  doc/mkdocdeps.py: Use with statement for the output file
  doc/prerst2man.py: Use Python-3-compatible octal notation
  doc/prerst2man.py: Fix 'os.system' - 'system' typo
  doc: Allow rst2man.py as an alternative to rst2man
  doc/prerst2man.py: Convert execfile to import
  doc/INSTALL: Remove rst2man reference and other updates

 configure  | 12 +++-
 doc/INSTALL| 34 --
 doc/Makefile.local |  6 +++---
 doc/mkdocdeps.py   | 19 ++-
 doc/prerst2man.py  | 25 ++---
 5 files changed, 54 insertions(+), 42 deletions(-)

-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/7] doc/mkdocdeps.py: Convert execfile to import

2014-04-05 Thread W. Trevor King
excefile is gone in Python 3 [1].  Instead of exec-ing the
configuration, it's easier to insert the source directory in Python's
path [2], and just import the configuration.  With this change,
mkdocdeps.py is compatible with both Python 2 and 3.

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#builtins
[2]: https://docs.python.org/3/library/sys.html#sys.path
---
 doc/mkdocdeps.py | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/doc/mkdocdeps.py b/doc/mkdocdeps.py
index 71bd135..de1cbb8 100644
--- a/doc/mkdocdeps.py
+++ b/doc/mkdocdeps.py
@@ -1,15 +1,16 @@
-from sys import argv
-srcdir = argv[1]
-builddir = argv[2]
-outfile = argv[3]
+import sys
 
-execfile(srcdir + '/conf.py')
+srcdir = sys.argv[1]
+builddir = sys.argv[2]
+outfile = sys.argv[3]
 
+sys.path.insert(0, srcdir)
+import conf
 
 roff_files = []
 rst_files = []
 out=open(outfile,'w')
-for page in man_pages:
+for page in conf.man_pages:
 rst_files = rst_files + [{0:s}/{1:s}.rst.format(srcdir,page[0])]
 roff_files = roff_files + 
[{0:s}/man/{1:s}.{2:d}.format(builddir,page[0],page[4])]
 
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 4/7] doc/prerst2man.py: Fix 'os.system' - 'system' typo

2014-04-05 Thread W. Trevor King
Avoid:

  $ make HAVE_SPHINX=0 HAVE_RST2MAN=1 build-man
  python ./doc/prerst2man.py ./doc doc/_build/man
  Traceback (most recent call last):
File ./doc/prerst2man.py, line 65, in module
  os.system('set -x; rst2man {0} {1}/{2}.{3}'
  NameError: name 'os' is not defined
  make: *** [doc/_build/man/man1/notmuch.1] Error 1

by using system directly.  We don't need the 'os.' namespacing,
because the function was imported with:

  from os import makedirs, system
---
 doc/prerst2man.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 108f4a3..437dea9 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -59,5 +59,5 @@ for page in man_pages:
 outfile.write(.join(lines))
 outfile.close()
 
-os.system('set -x; rst2man {0} {1}/{2}.{3}'
-  .format(filename, outdir, page[0],page[4]))
+system('set -x; rst2man {0} {1}/{2}.{3}'
+   .format(filename, outdir, page[0], page[4]))
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 2/7] doc/mkdocdeps.py: Use with statement for the output file

2014-04-05 Thread W. Trevor King
Before this patch, the open was unnecessarily early and relied on the
process cleanup to close.  Neither one of these was a real problem,
but PEP 343's context managers (which landed in Python 2.5) make
proper cleanup very easy.

[1]: http://legacy.python.org/dev/peps/pep-0343/
---
 doc/mkdocdeps.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/mkdocdeps.py b/doc/mkdocdeps.py
index de1cbb8..b87fe3e 100644
--- a/doc/mkdocdeps.py
+++ b/doc/mkdocdeps.py
@@ -9,10 +9,10 @@ import conf
 
 roff_files = []
 rst_files = []
-out=open(outfile,'w')
 for page in conf.man_pages:
 rst_files = rst_files + [{0:s}/{1:s}.rst.format(srcdir,page[0])]
 roff_files = roff_files + 
[{0:s}/man/{1:s}.{2:d}.format(builddir,page[0],page[4])]
 
-out.write ('MAN_ROFF_FILES := ' + ' \\\n\t'.join(roff_files)+'\n')
-out.write ('MAN_RST_FILES := ' + ' \\\n\t'.join(rst_files)+'\n')
+with open(outfile, 'w') as out:
+out.write('MAN_ROFF_FILES := ' + ' \\\n\t'.join(roff_files) + '\n')
+out.write('MAN_RST_FILES := ' + ' \\\n\t'.join(rst_files) + '\n')
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread W. Trevor King
The rst2man target was removed in 9d9a700 (doc: build man pages at
build time; introduce HAVE_SPHINX, HAVE_RST2MAN, 2014-03-13), but a
reference in the install docs slipped through.  While I was removing
that reference, I also:

* Converted doc/INSTALL to reStructuredText, so I can link to Sphinx
  and Docutils directly.  Not everyone has access to Debian's
  python-docutils, so it's better to be genric here.
* Converted from an unordered list to paragraphs, because I think it
  flows better.
* Dropped the rst2man no-automatic-install caveat.  I don't think this
  applies to the current code, although I haven't tried to track down
  a commit that adds the automatic-install support.  Anyhow,

$ make HAVE_SPHINX=0 RST2MAN=/usr/bin/rst2man.py DESTDIR=/tmp/ install-man

  works for me.
---
 doc/INSTALL | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/doc/INSTALL b/doc/INSTALL
index e37c2b9..91222f9 100644
--- a/doc/INSTALL
+++ b/doc/INSTALL
@@ -1,24 +1,30 @@
 This file contains some more detailed information about building and
 installing the documentation.
 
-Building with sphinx.
--
+Building with Sphinx
+
 
-- You need sphinx at least version 1.0.
+With Sphinx_ version 1.0 or greater, you can build man, info, html,
+and pdf versions of the docs (currently only the man pages) with::
 
-- You can build build and install man pages with 'make install-man'
+  make build-{man|info|html|pdf}
 
-- You can build man, info, html, and pdf versions of the docs
-  (currently only the man pages) with
+You can build build and install the docs (currently only the man
+pages) with::
 
- 'make install-{man|info|html|pdf}'
+  make install-{man|info|html|pdf}
 
-Building the man pages
---
+Building the man Docutils
+-
 
-- You can build the man pages with rst2man (from python-docutils) with
-  'make rst2man'.
+If you don't have Sphinx installed, you can still build the man-page
+version of the docs using rst2man (from Docutils_)::
 
-- Currently there is no support to automagically install the resulting
-  nroff files, but it should work to modify the target install-man
-  in doc/Makefile.local.
+  make build-man
+
+and install with::
+
+  make install-man
+
+.. _Sphinx: http://sphinx-doc.org/
+.. _Docutils: http://docutils.sourceforge.net/
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 6/7] doc/prerst2man.py: Convert execfile to import

2014-04-05 Thread W. Trevor King
excefile is gone in Python 3 [1].  Instead of exec-ing the
configuration, it's easier to insert the source directory in Python's
path [2], and just import the configuration.  With this change,
prerst2man.py is compatible with both Python 2 and 3.

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#builtins
[2]: https://docs.python.org/3/library/sys.html#sys.path
---
 doc/prerst2man.py | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 81ce817..7d78e9b 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -1,18 +1,20 @@
-from sys import argv
+import sys
 from datetime import date
 from os.path import dirname, isdir
 from os import makedirs, system
 import re
 
-rst2man = argv[1]
-sourcedir = argv[2]
-outdir = argv[3]
+rst2man = sys.argv[1]
+sourcedir = sys.argv[2]
+outdir = sys.argv[3]
+
+sys.path.insert(0, sourcedir)
+import conf
+
 
 if not isdir(outdir):
 makedirs(outdir, 0o755)
 
-execfile(sourcedir + /conf.py)
-
 
 def header(file, startdocname, command, description, authors, section):
 file.write(
@@ -29,10 +31,10 @@ def header(file, startdocname, command, description, 
authors, section):
 '-' * len(description),
 description,
 '-' * len(description),
-date.today().isoformat(), release, section, project))
+date.today().isoformat(), conf.release, section, conf.project))
 
 blankre = re.compile(^\s*$)
-for page in man_pages:
+for page in conf.man_pages:
 outdirname = outdir + '/' + dirname(page[0])
 if not isdir(outdirname):
 makedirs(outdirname, 0o755)
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 3/7] doc/prerst2man.py: Use Python-3-compatible octal notation

2014-04-05 Thread W. Trevor King
Python 3 only supports the 0oXXX notation for octal literals [1,2],
which have also been supported in 2.x since 2.6 [2].

[1]: https://docs.python.org/3.0/whatsnew/3.0.html#integers
[2]: http://legacy.python.org/dev/peps/pep-3127/
---
 doc/prerst2man.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/prerst2man.py b/doc/prerst2man.py
index 4591264..108f4a3 100644
--- a/doc/prerst2man.py
+++ b/doc/prerst2man.py
@@ -8,7 +8,7 @@ sourcedir = argv[1]
 outdir = argv[2]
 
 if not isdir(outdir):
-makedirs(outdir, 0755)
+makedirs(outdir, 0o755)
 
 execfile(sourcedir + /conf.py)
 
@@ -34,7 +34,7 @@ blankre = re.compile(^\s*$)
 for page in man_pages:
 outdirname = outdir + '/' + dirname(page[0])
 if not isdir(outdirname):
-makedirs(outdirname, 0755)
+makedirs(outdirname, 0o755)
 filename = outdir + '/' + page[0] + '.rst'
 outfile = open(filename, 'w')
 infile = open(sourcedir + '/' + page[0] + '.rst', 'r')
-- 
1.9.1.353.gc66d89d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v5 1/2] lib: drop support for single-message mbox files

2014-04-05 Thread Tomi Ollila
On Sat, Apr 05 2014, David Bremner da...@tethera.net wrote:

 Jani Nikula j...@nikula.org writes:

 We've supported mbox files containing a single message for historical
 reasons, but the support has been deprecated, with a warning message
 while indexing, since Notmuch 0.15. Finally drop the support, and
 consider all mbox files non-email.

 series pushed.


For now, anyone who wants to check their mail storage whether this have
any effect:

$ find . -type f | xargs head -1 | grep -B1 '^From '

(I got zero results :D on this machine; have to test on another...)



Quickly crafted other test: regexp (and head -1) may be incomplete...

$ find . -type f | xargs head -1 | grep -B1 -v -e '^[a-zA-Z_-]*:' -e '==.*==' 
-e '^$'

The first one will find any emails that were found last time but would
not be found (as emails) after e.g. dump-restore-reindex. Second one
would find (some/most?) emails that weren't indexed in the first place...


 d


Tomi
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread Jeremy Nickurak
Off the top of my head, you could have an encrypted index too, which you
can only search while able to decrypt. Certainly another level of
complexity.


On Sat, Apr 5, 2014 at 11:10 AM, David Bremner da...@tethera.net wrote:

 john.wy...@gmx.de writes:

  Would it be possible to add the configurable option to also decrypt
  encrypted messages on the fly while indexing to make them searchable,
  too?
 
  That would be really great for people that consider gnupg  mainly an
  encryption for transport or have their complete hard drive encrypted...

 As far I understand an attacker could reconstruct the message from the
 index, so one question is whether the extra complexity in notmuch is
 worth the minimal extra security over decrypting on delivery and storing
 plaintext on the (presumably encrypted) disk. Of course decrypting on
 delivery may be inconvenient (or impossible). I have CCed the two people
 who have implemented most of the crypto related stuff in notmuch so they
 can comment.

 d
 ___
 notmuch mailing list
 notmuch@notmuchmail.org
 http://notmuchmail.org/mailman/listinfo/notmuch

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread john . wyzer
Jeremy Nickurak not-m...@trk.nickurak.ca writes:

 Off the top of my head, you could have an encrypted index too, which you
 can only search while able to decrypt. Certainly another level of
 complexity.


But why add so much complexity? 

If a user decides that either transport security is enough or
additionally the hard disk is encrypted (why store an encrypted index on
an encrypted hard disk?), said user could just switch on an option in
the notmuch configuration that causes notmuch to ask for the password
before or while indexing new messages and to add decrypted messages to the
normal index as well.


The level of security would be up to the user by means of said
configuration option and those that want the convenience of searching
encrypted messages could have it.

Personally I would argue that if an attacker has the means to access the
content of my hard disk either via the network or physically, there is
no difference between having whole disk encryption and storing an
encrypted index...

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Feature suggestion. Indexing encrypted mail?

2014-04-05 Thread Jameson Graef Rollins
On Sat, Apr 05 2014, David Bremner da...@tethera.net wrote:
 john.wy...@gmx.de writes:

 Would it be possible to add the configurable option to also decrypt
 encrypted messages on the fly while indexing to make them searchable,
 too?

 That would be really great for people that consider gnupg  mainly an
 encryption for transport or have their complete hard drive encrypted...

 As far I understand an attacker could reconstruct the message from the
 index, so one question is whether the extra complexity in notmuch is
 worth the minimal extra security over decrypting on delivery and storing
 plaintext on the (presumably encrypted) disk. Of course decrypting on
 delivery may be inconvenient (or impossible). I have CCed the two people
 who have implemented most of the crypto related stuff in notmuch so they
 can comment.

Indexing encrypted email is a bit of a foot-gun, since, as David
mentions, it is apparently possible to reconstruct encrypted messages
From the index.  It therefore needs to be approached with care.

I think decrypting on delivery (or mail fetch or whatever) sounds
difficult and unwieldy.  In either event, it seems out of the scope of
notmuch.  If a user figured out how to have that done, no changes to
notmuch would be needed afaict.
 
I don't think it would be difficult modify notmuch new to decrypt at
indexing time.  Given that gnupg agent would be used for accessing the
users private key for decryption, the interface would be fairly
straightforward.

A couple of decryption options could be added to notmuch new:

* don't decrypt: don't attempt to decrypt and index any encrypted
  message (default)

* decrypt always: fail if any encrypted message could not be decrypted

* decrypt opportunistically: attempt to decrypt, but continue indexing
  if an encrypted message could not be decrypted

If something like this is enabled, we should make sure we make the
dangers clear to the users.

jamie.


pgpBorqLfuOX2.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread David Bremner
W. Trevor King wk...@tremily.us writes:

 The rst2man target was removed in 9d9a700 (doc: build man pages at
 build time; introduce HAVE_SPHINX, HAVE_RST2MAN, 2014-03-13), but a
 reference in the install docs slipped through.  While I was removing
 that reference, I also:

 * Converted doc/INSTALL to reStructuredText, so I can link to Sphinx
   and Docutils directly.  Not everyone has access to Debian's
   python-docutils, so it's better to be genric here.
 * Converted from an unordered list to paragraphs, because I think it
   flows better.
 * Dropped the rst2man no-automatic-install caveat.  I don't think this
   applies to the current code, although I haven't tried to track down
   a commit that adds the automatic-install support.  Anyhow,

 $ make HAVE_SPHINX=0 RST2MAN=/usr/bin/rst2man.py DESTDIR=/tmp/ install-man

   works for me.
 ---
  doc/INSTALL | 34 --
  1 file changed, 20 insertions(+), 14 deletions(-)

 diff --git a/doc/INSTALL b/doc/INSTALL
 index e37c2b9..91222f9 100644
 --- a/doc/INSTALL
 +++ b/doc/INSTALL
 @@ -1,24 +1,30 @@
  This file contains some more detailed information about building and
  installing the documentation.
  
 -Building with sphinx.
 --
 +Building with Sphinx
 +
  
 -- You need sphinx at least version 1.0.
 +With Sphinx_ version 1.0 or greater, you can build man, info, html,
 +and pdf versions of the docs (currently only the man pages) with::
  
 -- You can build build and install man pages with 'make install-man'
 +  make build-{man|info|html|pdf}

most of those those targets now start with sphinx-
  
 -- You can build man, info, html, and pdf versions of the docs
 -  (currently only the man pages) with
 +You can build build and install the docs (currently only the man
 +pages) with::

build build
  
 - 'make install-{man|info|html|pdf}'
 +  make install-{man|info|html|pdf}
  

this is not your bug per se, but while we're fixing docs, most of those
targets don't exist.

 -Building the man pages
 ---
 +Building the man Docutils
 +-
  

+ with

 -- You can build the man pages with rst2man (from python-docutils) with
 -  'make rst2man'.
 +If you don't have Sphinx installed, you can still build the man-page
 +version of the docs using rst2man (from Docutils_)::
  
 -- Currently there is no support to automagically install the resulting
 -  nroff files, but it should work to modify the target install-man
 -  in doc/Makefile.local.

This should mention the relevant variables, since the targets are the
same in both cases

Finally, I don't really object to rewriting doc/INSTALL in rst, but I
wonder if we should rename it to INSTALL.rst

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread W. Trevor King
On Sat, Apr 05, 2014 at 05:35:49PM -0300, David Bremner wrote:
 W. Trevor King writes:
 
  -- You can build build and install man pages with 'make install-man'
  +  make build-{man|info|html|pdf}
 
 most of those those targets now start with sphinx-

Ah, looks like that happended in with the original Sphinx code in
d736260 (doc: convert sphinx based docs, 2014-01-28).  It looks like
the current usage is (from the .PHONY entries):

  {build|install}-man, which is backend (Sphinx/Docutils) agnostic
  sphinx-{html|texinfo|info}, which doesn't have an install target

Is that distinction intentional?  Personally I prefer the consistency
of:

  {build|install}-{man|html|texinfo|info}

if the configured backend (Sphinx/Docutils) doesn't support the
requested target, we should error out.  If no backend is detected,
build-man and install-man should be pulled from the default dependency
tree (but they would still error out if you called them directly).  If
that sounds reasonable, I can work up a patch.

  -- You can build man, info, html, and pdf versions of the docs
  -  (currently only the man pages) with
  +You can build build and install the docs (currently only the man
  +pages) with::
 
 build build

Oops, thanks.

  -Building the man pages
  ---
  +Building the man Docutils
  +-
   
 
 + with

Thanks again :p.

  -- You can build the man pages with rst2man (from python-docutils) with
  -  'make rst2man'.
  +If you don't have Sphinx installed, you can still build the man-page
  +version of the docs using rst2man (from Docutils_)::
   
  -- Currently there is no support to automagically install the resulting
  -  nroff files, but it should work to modify the target install-man
  -  in doc/Makefile.local.
 
 This should mention the relevant variables, since the targets are
 the same in both cases

Ok.

 Finally, I don't really object to rewriting doc/INSTALL in rst, but
 I wonder if we should rename it to INSTALL.rst

Sure (I don't really mind).

Cheers,
Trevor

-- 
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy


signature.asc
Description: OpenPGP digital signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 0/5] emacs: hello: convert saved-searches to plists

2014-04-05 Thread Mark Walters
This series converts the saved-search format to plists. This should
make it much easier to extend their functionality. The final patch
illustrates this by adding a sort-order option to the saved
searches. It also exposes the count-query functionality that is
already present internally, and could be used to store keyboard
shortcuts for searches.

The series tries hard to be backwardly compatible and seems to work in
most cases. However, notmuch-hello is very interconnected so some
corner cases may fail: for example if people are doing strange things
with notmuch-saved-search-sort-function then it may break.

Also note that the functions used for saved-searches are also used for
the all tags section: I have not converted them as they are purely
internal. Since we have backwards compatibility they still work.

Best wishes

Mark







Mark Walters (5):
  emacs: hello: add helper functions for saved-searches
  emacs: hello: use the saved-search helper functions
  emacs: hello: add a customize for saved-searches
  emacs: hello: switch notmuch-hello-insert-buttons to plists
  emacs: Add a sort-order option to saved-searches

 emacs/notmuch-hello.el |  129 +---
 emacs/notmuch-lib.el   |   33 +++--
 emacs/notmuch.el   |6 +--
 3 files changed, 122 insertions(+), 46 deletions(-)

-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/5] emacs: hello: add helper functions for saved-searches

2014-04-05 Thread Mark Walters
Add helper functions to for saved searches to ease the transition to
the new plist form while maintaining backwards compatibility. They
will be used in the next patch.
---
 emacs/notmuch-hello.el |   39 +++
 1 file changed, 39 insertions(+)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index e325cd3..0b9ed16 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -269,6 +269,45 @@ (defun notmuch-hello-search (optional search)
   (add-to-history 'notmuch-search-history search)))
   (notmuch-search search notmuch-search-oldest-first))
 
+(defun notmuch-saved-search-get (saved-search field)
+  Get FIELD from SAVED-SEARCH.
+
+In the new style saved-search (a plist) this is just plist-get
+but, for backwards compatibility, this deals with the two
+old-style forms: cons cells (NAME . QUERY) and lists (NAME QUERY
+COUNT-QUERY).
+  (cond
+   ((plist-get saved-search :name)
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  Convert a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to give them in
+plist-form. In all cases a new copy is returned so it is safe to
+modify the returned value.
+  (if (and (listp (cdr saved-search)) (plist-member saved-search :name))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ (plist-search))
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
 (defun notmuch-hello-add-saved-search (widget)
   (interactive)
   (let ((search (widget-value
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 4/5] emacs: hello: switch notmuch-hello-insert-buttons to plists

2014-04-05 Thread Mark Walters
Switching notmuch-hello-insert-buttons to plists means we can easily
pass extra options through to the buttons.
---
 emacs/notmuch-hello.el |   33 +++--
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index c729af2..aa40e6f 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -425,7 +425,9 @@ (defun notmuch-hello-query-counts (query-list rest options)
 these is a plist but other options are available for backwards
 compatibility: see notmuch-saved-search-get for details.
 
-The result is the list of elements of the form (NAME QUERY COUNT).
+The result is a list of plists each of which includes the
+pairs :name NAME, :query QUERY and :count COUNT, together with
+any pairs in the original saved-search.
 
 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
@@ -455,23 +457,26 @@ (defun notmuch-hello-query-counts (query-list rest 
options)
  #'identity
  (mapcar
   (lambda (elem)
-   (let ((name (notmuch-saved-search-get elem :name))
- (search-query (notmuch-saved-search-get elem :query))
- (message-count (prog1 (read (current-buffer))
+   (let* ((elem-plist (notmuch-hello-saved-search-to-plist elem))
+  (search-query (plist-get elem-plist :query))
+  (filtered-query (notmuch-hello-filtered-query
+   search-query (plist-get options :filter)))
+  (message-count (prog1 (read (current-buffer))
(forward-line 1
  (and (or (plist-get options :show-empty-searches) ( message-count 0))
-  (list name (notmuch-hello-filtered-query
-  search-query (plist-get options :filter))
-message-count
+  (setq elem-plist (plist-put elem-plist :query filtered-query))
+  (plist-put elem-plist :count message-count
   query-list
 
 (defun notmuch-hello-insert-buttons (searches)
   Insert buttons for SEARCHES.
 
-SEARCHES must be a list containing lists of the form (NAME QUERY COUNT), where
-QUERY is the query to start when the button for the corresponding entry is
-activated. COUNT should be the number of messages matching the query.
-Such a list can be computed with `notmuch-hello-query-counts'.
+SEARCHES must be a list of plists each of which should contain at
+least pairs for :name NAME :query QUERY and :count COUNT, where
+QUERY is the query to start when the button for the corresponding
+entry is activated, and COUNT should be the number of messages
+matching the query.  Such a plist can be computed with
+`notmuch-hello-query-counts'.
   (let* ((widest (notmuch-hello-longest-label searches))
 (tags-and-width (notmuch-hello-tags-per-line widest))
 (tags-per-line (car tags-and-width))
@@ -489,9 +494,9 @@ (defun notmuch-hello-insert-buttons (searches)
(when elem
  (if ( column-indent 0)
  (widget-insert (make-string column-indent ? )))
- (let* ((name (first elem))
-(query (second elem))
-(msg-count (third elem)))
+ (let* ((name (plist-get elem :name))
+(query (plist-get elem :query))
+(msg-count (plist-get elem :count)))
(widget-insert (format %8s 
   (notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 2/5] emacs: hello: use the saved-search helper functions

2014-04-05 Thread Mark Walters
This uses the helper functions: the saved searches format has not
changed yet but backwards compatibility means everything still works.
---
 emacs/notmuch-hello.el |   48 ++--
 emacs/notmuch.el   |6 +++---
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 0b9ed16..733208b 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -319,7 +319,7 @@ (defun notmuch-hello-add-saved-search (widget)
 (setq notmuch-saved-searches
  (loop for elem in notmuch-saved-searches
if (not (equal name
-  (car elem)))
+  (notmuch-saved-search-get elem :name)))
collect elem))
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
@@ -339,7 +339,7 @@ (defun notmuch-hello-delete-search-from-history (widget)
 
 (defun notmuch-hello-longest-label (searches-alist)
   (or (loop for elem in searches-alist
-   maximize (length (car elem)))
+   maximize (length (notmuch-saved-search-get elem :name)))
   0))
 
 (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
@@ -418,13 +418,12 @@ (defun notmuch-hello-filtered-query (query filter)
 (concat ( query ) and ( filter )))
(t query)))
 
-(defun notmuch-hello-query-counts (query-alist rest options)
-  Compute list of counts of matched messages from QUERY-ALIST.
+(defun notmuch-hello-query-counts (query-list rest options)
+  Compute list of counts of matched messages from QUERY-LIST.
 
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated query.
+QUERY-LIST must be a list of saved-searches. Ideally each of
+these is a plist but other options are available for backwards
+compatibility: see notmuch-saved-search-get for details.
 
 The result is the list of elements of the form (NAME QUERY COUNT).
 
@@ -432,11 +431,9 @@ (defun notmuch-hello-query-counts (query-alist rest 
options)
 options will be handled as specified for
 `notmuch-hello-insert-searches'.
   (with-temp-buffer
-(dolist (elem query-alist nil)
-  (let ((count-query (if (consp (cdr elem))
-;; do we have a different query for the message 
count?
-(third elem)
-  (cdr elem
+(dolist (elem query-list nil)
+  (let ((count-query (or (notmuch-saved-search-get elem :count-query)
+(notmuch-saved-search-get elem :query
(insert
 (replace-regexp-in-string
  \n  
@@ -458,18 +455,15 @@ (defun notmuch-hello-query-counts (query-alist rest 
options)
  #'identity
  (mapcar
   (lambda (elem)
-   (let ((name (car elem))
- (search-query (if (consp (cdr elem))
-;; do we have a different query for the 
message count?
-(second elem)
- (cdr elem)))
+   (let ((name (notmuch-saved-search-get elem :name))
+ (search-query (notmuch-saved-search-get elem :query))
  (message-count (prog1 (read (current-buffer))
(forward-line 1
  (and (or (plist-get options :show-empty-searches) ( message-count 0))
   (list name (notmuch-hello-filtered-query
   search-query (plist-get options :filter))
 message-count
-  query-alist
+  query-list
 
 (defun notmuch-hello-insert-buttons (searches)
   Insert buttons for SEARCHES.
@@ -728,13 +722,15 @@ (defun notmuch-hello-insert-recent-searches ()
   (indent-rigidly start (point) notmuch-hello-indent))
 nil))
 
-(defun notmuch-hello-insert-searches (title query-alist rest options)
-  Insert a section with TITLE showing a list of buttons made from QUERY-ALIST.
+(defun notmuch-hello-insert-searches (title query-list rest options)
+  Insert a section with TITLE showing a list of buttons made from QUERY-LIST.
 
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated item.
+QUERY-LIST should ideally be a plist but for backwards
+compatibility other forms are also accepted (see
+`notmuch-saved-search-get' for details).  The plist should
+contain keys :name and :query; if :count-query is also present
+then it specifies an alternate query to be used to generate the
+count for the associated search.
 
 Supports the following entries in OPTIONS as a plist:
 :initially-hidden - if non-nil, section will be hidden on startup
@@ -768,7 +764,7 @@ (defun notmuch-hello-insert-searches (title 

[PATCH 3/5] emacs: hello: add a customize for saved-searches

2014-04-05 Thread Mark Walters
Make the defcustom for notmuch-saved-searches use the new plist
format. It should still work with oldstyle saved-searches but will
write the newstyle form.
---
 emacs/notmuch-hello.el |2 +-
 emacs/notmuch-lib.el   |   28 +---
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 733208b..c729af2 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -324,7 +324,7 @@ (defun notmuch-hello-add-saved-search (widget)
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
 (add-to-list 'notmuch-saved-searches
- (cons name search) t))
+ (list :name name :query search) t))
 (message Saved '%s' as '%s'. search name)
 (notmuch-hello-update)))
 
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 959764e..8a12f91 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -107,10 +107,32 @@ (defcustom notmuch-poll-script nil
 (defvar notmuch-search-history nil
   Variable to store notmuch searches history.)
 
-(defcustom notmuch-saved-searches '((inbox . tag:inbox)
-   (unread . tag:unread))
+(defun notmuch--saved-searches-to-plist (symbol)
+  Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to extract old style saved
+searches so they still work in customize.
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  A single saved search property list.
+  :tag Saved Search
+  :args '((list :inline t
+   :format %v
+   (group :format %v :inline t (const :formatName:  :name) 
(string :format %v))
+   (group :format %v :inline t (const :format   Query:  
:query) (string :format %v)))
+ (checklist :inline t
+:format %v
+(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v)
+
+(defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
+   (:name unread :query tag:unread))
   A list of saved searches to display.
-  :type '(alist :key-type string :value-type string)
+  :get 'notmuch--saved-searches-to-plist
+  :type '(repeat notmuch-saved-search-plist)
+  :tag List of Saved Searches
   :group 'notmuch-hello)
 
 (defcustom notmuch-archive-tags '(-inbox)
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 5/5] emacs: Add a sort-order option to saved-searches

2014-04-05 Thread Mark Walters
This adds a sort-order option to saved-searches, stores it in the
saved-search buttons (widgets), and uses the stored value when the
button is pressed.

Storing the sort-order in the widget was suggested by Jani in
id:4c3876274126985683e888641b29cf18142a5eb8.1391771337.git.j...@nikula.org.
---
 emacs/notmuch-hello.el |   11 ++-
 emacs/notmuch-lib.el   |7 ++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index aa40e6f..6a28372 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -364,7 +364,8 @@ (defun notmuch-hello-reflect (list ncols)
 (defun notmuch-hello-widget-search (widget rest ignore)
   (notmuch-search (widget-get widget
  :notmuch-search-terms)
- notmuch-search-oldest-first))
+ (widget-get widget
+ :notmuch-search-oldest-first)))
 
 (defun notmuch-saved-search-count (search)
   (car (process-lines notmuch-command count search)))
@@ -496,12 +497,20 @@ (defun notmuch-hello-insert-buttons (searches)
  (widget-insert (make-string column-indent ? )))
  (let* ((name (plist-get elem :name))
 (query (plist-get elem :query))
+(oldest-first (cond
+   ((eq (plist-get elem :sort-order) 
'newest-first)
+nil)
+   ((eq (plist-get elem :sort-order) 
'oldest-first)
+t)
+   (t
+notmuch-search-oldest-first)))
 (msg-count (plist-get elem :count)))
(widget-insert (format %8s 
   (notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
   :notify #'notmuch-hello-widget-search
   :notmuch-search-terms query
+  :notmuch-search-oldest-first oldest-first
   name)
(setq column-indent
  (1+ (max 0 (- column-width (length name)))
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 8a12f91..8aa8cfc 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -125,7 +125,12 @@ (define-widget 'notmuch-saved-search-plist 'list
(group :format %v :inline t (const :format   Query:  
:query) (string :format %v)))
  (checklist :inline t
 :format %v
-(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v)
+(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v))
+(group :format %v :inline t (const :format  
:sort-order)
+   (choice :tag  Sort Order
+   (const :tag Default nil)
+   (const :tag Oldest-first oldest-first)
+   (const :tag Newest-first 
newest-first))
 
 (defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
(:name unread :query tag:unread))
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 7/7] doc/INSTALL: Remove rst2man reference and other updates

2014-04-05 Thread David Bremner
W. Trevor King wk...@tremily.us writes:

   {build|install}-man, which is backend (Sphinx/Docutils) agnostic
   sphinx-{html|texinfo|info}, which doesn't have an install target

 Is that distinction intentional?  Personally I prefer the consistency
 of:

   {build|install}-{man|html|texinfo|info}


I think the sphinx- prefix is a historical accident, from when we tried
to control backend with targets, so I don't really mind those switching
(back?) to build-

install-man is backend agnostic. Similar targets could be written for
html and info, but no-one did yet. I guess we'd need variables to
specify destinations. Installing info is a bit tricky because of the
need to use install-info(1) to update directory files
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/5] emacs: hello: add helper functions for saved-searches

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
 Add helper functions to for saved searches to ease the transition to
 the new plist form while maintaining backwards compatibility. They
 will be used in the next patch.
 ---
  emacs/notmuch-hello.el |   39 +++
  1 file changed, 39 insertions(+)
 
 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
 index e325cd3..0b9ed16 100644
 --- a/emacs/notmuch-hello.el
 +++ b/emacs/notmuch-hello.el
 @@ -269,6 +269,45 @@ (defun notmuch-hello-search (optional search)
(add-to-history 'notmuch-search-history search)))
(notmuch-search search notmuch-search-oldest-first))
  
 +(defun notmuch-saved-search-get (saved-search field)
 +  Get FIELD from SAVED-SEARCH.
 +
 +In the new style saved-search (a plist) this is just plist-get

It won't be new style once this has been in for a while.  Perhaps
If SAVED-SEARCH is a plist, this is just `plist-get', but for
backwards compatibility, ...

 +but, for backwards compatibility, this deals with the two
 +old-style forms: cons cells (NAME . QUERY) and lists (NAME QUERY
 +COUNT-QUERY).
 +  (cond
 +   ((plist-get saved-search :name)

Rather than depending on :name, maybe this should be a more generic
plist test like (keywordp (car saved-search))?

 +(plist-get saved-search field))
 +   ;; It is not a plist so it is an old-style entry.
 +   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
 +(case field
 +  (:name (car saved-search))

Use `first' for consistency with the other case cases?

 +  (:query (second saved-search))
 +  (:count-query (third saved-search))
 +  (t nil)))
 +   (t  ;; It is a cons-cell (NAME . QUERY)
 +(case field
 +  (:name (car saved-search))
 +  (:query (cdr saved-search))
 +  (t nil)
 +
 +(defun notmuch-hello-saved-search-to-plist (saved-search)
 +  Convert a saved-search variable into plist form.

This takes a value, not a variable.  But it could be more succinct and
more accurate: Return a copy of SAVED-SEARCH in plist form.

 +
 +The new style saved search is just a plist, but for backwards

Same comment about new style.

 +compatatibility we use this function to give them in
 +plist-form. In all cases a new copy is returned so it is safe to

Grammar error?

 +modify the returned value.
 +  (if (and (listp (cdr saved-search)) (plist-member saved-search :name))
 +  (copy-seq saved-search)
 +(let ((fields (list :name :query :count-query))
 +   (plist-search))

Personally I prefer to either explicitly initialize nil variables or
to list them without the parenthesis at all (for some reason my brain
automatically reads this as an application), but if you prefer this,
that's fine, too.

 +  (dolist (field fields plist-search)
 + (let ((string (notmuch-saved-search-get saved-search field)))
 +   (when string
 + (setq plist-search (append plist-search (list field string)
 +
  (defun notmuch-hello-add-saved-search (widget)
(interactive)
(let ((search (widget-value
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 2/5] emacs: hello: use the saved-search helper functions

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
 This uses the helper functions: the saved searches format has not
 changed yet but backwards compatibility means everything still works.
 ---
  emacs/notmuch-hello.el |   48 
 ++--
  emacs/notmuch.el   |6 +++---
  2 files changed, 25 insertions(+), 29 deletions(-)
 
 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
 index 0b9ed16..733208b 100644
 --- a/emacs/notmuch-hello.el
 +++ b/emacs/notmuch-hello.el
 @@ -319,7 +319,7 @@ (defun notmuch-hello-add-saved-search (widget)
  (setq notmuch-saved-searches
 (loop for elem in notmuch-saved-searches
   if (not (equal name
 -(car elem)))
 +(notmuch-saved-search-get elem :name)))
   collect elem))
  ;; Add the new one.
  (customize-save-variable 'notmuch-saved-searches
 @@ -339,7 +339,7 @@ (defun notmuch-hello-delete-search-from-history (widget)
  
  (defun notmuch-hello-longest-label (searches-alist)
(or (loop for elem in searches-alist
 - maximize (length (car elem)))
 + maximize (length (notmuch-saved-search-get elem :name)))
0))
  
  (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
 @@ -418,13 +418,12 @@ (defun notmuch-hello-filtered-query (query filter)
  (concat ( query ) and ( filter )))
 (t query)))
  
 -(defun notmuch-hello-query-counts (query-alist rest options)
 -  Compute list of counts of matched messages from QUERY-ALIST.
 +(defun notmuch-hello-query-counts (query-list rest options)
 +  Compute list of counts of matched messages from QUERY-LIST.
  
 -QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
 -or (NAME QUERY COUNT-QUERY). If the latter form is used,
 -COUNT-QUERY specifies an alternate query to be used to generate
 -the count for the associated query.
 +QUERY-LIST must be a list of saved-searches. Ideally each of
 +these is a plist but other options are available for backwards
 +compatibility: see notmuch-saved-search-get for details.

s/:/./  Also `'s around notmuch-saved-search-get.

Actually, the accepted formats (including the understood keys in plist
form) should be documented in `notmuch-saved-searches' and this
information should be cited elsewhere and not duplicated.

  
  The result is the list of elements of the form (NAME QUERY COUNT).
  
 @@ -432,11 +431,9 @@ (defun notmuch-hello-query-counts (query-alist rest 
 options)
  options will be handled as specified for
  `notmuch-hello-insert-searches'.
(with-temp-buffer
 -(dolist (elem query-alist nil)
 -  (let ((count-query (if (consp (cdr elem))
 -  ;; do we have a different query for the message 
 count?
 -  (third elem)
 -(cdr elem
 +(dolist (elem query-list nil)
 +  (let ((count-query (or (notmuch-saved-search-get elem :count-query)
 +  (notmuch-saved-search-get elem :query
   (insert
(replace-regexp-in-string
 \n  
 @@ -458,18 +455,15 @@ (defun notmuch-hello-query-counts (query-alist rest 
 options)
   #'identity
   (mapcar
(lambda (elem)
 - (let ((name (car elem))
 -   (search-query (if (consp (cdr elem))
 -  ;; do we have a different query for the 
 message count?
 -  (second elem)
 -   (cdr elem)))
 + (let ((name (notmuch-saved-search-get elem :name))
 +   (search-query (notmuch-saved-search-get elem :query))
 (message-count (prog1 (read (current-buffer))
   (forward-line 1
 (and (or (plist-get options :show-empty-searches) ( message-count 0))
  (list name (notmuch-hello-filtered-query
  search-query (plist-get options :filter))
message-count
 -  query-alist
 +  query-list
  
  (defun notmuch-hello-insert-buttons (searches)
Insert buttons for SEARCHES.
 @@ -728,13 +722,15 @@ (defun notmuch-hello-insert-recent-searches ()
(indent-rigidly start (point) notmuch-hello-indent))
  nil))
  
 -(defun notmuch-hello-insert-searches (title query-alist rest options)
 -  Insert a section with TITLE showing a list of buttons made from 
 QUERY-ALIST.
 +(defun notmuch-hello-insert-searches (title query-list rest options)
 +  Insert a section with TITLE showing a list of buttons made from 
 QUERY-LIST.
  
 -QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
 -or (NAME QUERY COUNT-QUERY). If the latter form is used,
 -COUNT-QUERY specifies an alternate query to be used to generate
 -the count for the associated item.
 +QUERY-LIST should ideally be a plist but for backwards
 +compatibility other forms are also accepted (see
 +`notmuch-saved-search-get' for details).  The plist should
 +contain 

Re: [PATCH 4/5] emacs: hello: switch notmuch-hello-insert-buttons to plists

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
 Switching notmuch-hello-insert-buttons to plists means we can easily
 pass extra options through to the buttons.
 ---
  emacs/notmuch-hello.el |   33 +++--
  1 file changed, 19 insertions(+), 14 deletions(-)
 
 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
 index c729af2..aa40e6f 100644
 --- a/emacs/notmuch-hello.el
 +++ b/emacs/notmuch-hello.el
 @@ -425,7 +425,9 @@ (defun notmuch-hello-query-counts (query-list rest 
 options)
  these is a plist but other options are available for backwards
  compatibility: see notmuch-saved-search-get for details.
  
 -The result is the list of elements of the form (NAME QUERY COUNT).
 +The result is a list of plists each of which includes the
 +pairs :name NAME, :query QUERY and :count COUNT, together with
 +any pairs in the original saved-search.

Pair can be synonymous with cons, which is not what you mean here.
Properties?

  
  The values :show-empty-searches, :filter and :filter-count from
  options will be handled as specified for
 @@ -455,23 +457,26 @@ (defun notmuch-hello-query-counts (query-list rest 
 options)
   #'identity
   (mapcar
(lambda (elem)
 - (let ((name (notmuch-saved-search-get elem :name))
 -   (search-query (notmuch-saved-search-get elem :query))
 -   (message-count (prog1 (read (current-buffer))
 + (let* ((elem-plist (notmuch-hello-saved-search-to-plist elem))
 +(search-query (plist-get elem-plist :query))
 +(filtered-query (notmuch-hello-filtered-query
 + search-query (plist-get options :filter)))
 +(message-count (prog1 (read (current-buffer))
   (forward-line 1
 (and (or (plist-get options :show-empty-searches) ( message-count 0))
 -(list name (notmuch-hello-filtered-query
 -search-query (plist-get options :filter))
 -  message-count
 +(setq elem-plist (plist-put elem-plist :query filtered-query))

This technically works, but `setq' is a strange thing to see in an
`and'.  But the problem isn't the `setq'; it's that crazy `and'.  I'd
replace the `and' with `when', keep the `setq' and `plist-put' in the
body, and squint a lot less at this code.

 +(plist-put elem-plist :count message-count
query-list
  
  (defun notmuch-hello-insert-buttons (searches)
Insert buttons for SEARCHES.
  
 -SEARCHES must be a list containing lists of the form (NAME QUERY COUNT), 
 where
 -QUERY is the query to start when the button for the corresponding entry is
 -activated. COUNT should be the number of messages matching the query.
 -Such a list can be computed with `notmuch-hello-query-counts'.
 +SEARCHES must be a list of plists each of which should contain at
 +least pairs for :name NAME :query QUERY and :count COUNT, where

Same comment about pairs.

 +QUERY is the query to start when the button for the corresponding
 +entry is activated, and COUNT should be the number of messages
 +matching the query.  Such a plist can be computed with
 +`notmuch-hello-query-counts'.
(let* ((widest (notmuch-hello-longest-label searches))
(tags-and-width (notmuch-hello-tags-per-line widest))
(tags-per-line (car tags-and-width))
 @@ -489,9 +494,9 @@ (defun notmuch-hello-insert-buttons (searches)
   (when elem
 (if ( column-indent 0)
 (widget-insert (make-string column-indent ? )))
 -   (let* ((name (first elem))
 -  (query (second elem))
 -  (msg-count (third elem)))
 +   (let* ((name (plist-get elem :name))
 +  (query (plist-get elem :query))
 +  (msg-count (plist-get elem :count)))
   (widget-insert (format %8s 
  (notmuch-hello-nice-number msg-count)))
   (widget-create 'push-button
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 5/5] emacs: Add a sort-order option to saved-searches

2014-04-05 Thread Austin Clements
Quoth Mark Walters on Apr 05 at 10:24 pm:
 This adds a sort-order option to saved-searches, stores it in the
 saved-search buttons (widgets), and uses the stored value when the
 button is pressed.
 
 Storing the sort-order in the widget was suggested by Jani in
 id:4c3876274126985683e888641b29cf18142a5eb8.1391771337.git.j...@nikula.org.
 ---
  emacs/notmuch-hello.el |   11 ++-
  emacs/notmuch-lib.el   |7 ++-
  2 files changed, 16 insertions(+), 2 deletions(-)
 
 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
 index aa40e6f..6a28372 100644
 --- a/emacs/notmuch-hello.el
 +++ b/emacs/notmuch-hello.el
 @@ -364,7 +364,8 @@ (defun notmuch-hello-reflect (list ncols)
  (defun notmuch-hello-widget-search (widget rest ignore)
(notmuch-search (widget-get widget
 :notmuch-search-terms)
 -   notmuch-search-oldest-first))
 +   (widget-get widget
 +   :notmuch-search-oldest-first)))
  
  (defun notmuch-saved-search-count (search)
(car (process-lines notmuch-command count search)))
 @@ -496,12 +497,20 @@ (defun notmuch-hello-insert-buttons (searches)
 (widget-insert (make-string column-indent ? )))
 (let* ((name (plist-get elem :name))
(query (plist-get elem :query))
 +  (oldest-first (cond
 + ((eq (plist-get elem :sort-order) 
 'newest-first)
 +  nil)
 + ((eq (plist-get elem :sort-order) 
 'oldest-first)
 +  t)
 + (t
 +  notmuch-search-oldest-first)))

(case (plist-get elem :sort-order)
  (newest-first nil)
  (oldest-first t)
  (otherwise notmuch-search-oldest-first))

(msg-count (plist-get elem :count)))
   (widget-insert (format %8s 
  (notmuch-hello-nice-number msg-count)))
   (widget-create 'push-button
  :notify #'notmuch-hello-widget-search
  :notmuch-search-terms query
 +:notmuch-search-oldest-first oldest-first
  name)
   (setq column-indent
 (1+ (max 0 (- column-width (length name)))
 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
 index 8a12f91..8aa8cfc 100644
 --- a/emacs/notmuch-lib.el
 +++ b/emacs/notmuch-lib.el
 @@ -125,7 +125,12 @@ (define-widget 'notmuch-saved-search-plist 'list
   (group :format %v :inline t (const :format   Query:  
 :query) (string :format %v)))
 (checklist :inline t
:format %v
 -  (group :format %v :inline t (const :format Count-Query: 
  :count-query) (string :format %v)
 +  (group :format %v :inline t (const :format Count-Query: 
  :count-query) (string :format %v))
 +  (group :format %v :inline t (const :format  
 :sort-order)
 + (choice :tag  Sort Order

Should there be a colon?  (I haven't applied the patches and I'm
afraid this is beyond my mental implementation of define-widget!)

 + (const :tag Default nil)
 + (const :tag Oldest-first oldest-first)
 + (const :tag Newest-first 
 newest-first))
  
  (defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
   (:name unread :query tag:unread))
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 0/5] emacs: hello: convert saved-searches to plists

2014-04-05 Thread David Bremner
Mark Walters markwalters1...@gmail.com writes:

 This series converts the saved-search format to plists. This should
 make it much easier to extend their functionality. The final patch
 illustrates this by adding a sort-order option to the saved
 searches. It also exposes the count-query functionality that is
 already present internally, and could be used to store keyboard
 shortcuts for searches.

Not necessarily an issue for this series, but I'd like start thinking
about a front-end-independent representation for saved searches; perhaps
json for want of better ideas.  

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


build and install doxygen api docs

2014-04-05 Thread David Bremner
I'm not sure if we really want to install the API docs yet, but I was
reviewing Tomi's patch and it occured to me that this was one more
place where we could stop hardcoding the version number.

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/2] doc: move doxgen config from devel/ to doc/

2014-04-05 Thread David Bremner
a first step towards actually instally the API docs
---
 devel/doxygen.cfg | 304 --
 doc/doxygen.cfg   | 304 ++
 2 files changed, 304 insertions(+), 304 deletions(-)
 delete mode 100644 devel/doxygen.cfg
 create mode 100644 doc/doxygen.cfg

diff --git a/devel/doxygen.cfg b/devel/doxygen.cfg
deleted file mode 100644
index 65d5fb5..000
--- a/devel/doxygen.cfg
+++ /dev/null
@@ -1,304 +0,0 @@
-# Doxyfile 1.8.4
-
-#---
-# Project related configuration options
-#---
-DOXYFILE_ENCODING  = UTF-8
-PROJECT_NAME   = Notmuch 0.17
-PROJECT_NUMBER =
-PROJECT_BRIEF  =
-PROJECT_LOGO   =
-OUTPUT_DIRECTORY   =
-CREATE_SUBDIRS = NO
-OUTPUT_LANGUAGE= English
-BRIEF_MEMBER_DESC  = YES
-REPEAT_BRIEF   = YES
-ABBREVIATE_BRIEF   =
-ALWAYS_DETAILED_SEC= NO
-INLINE_INHERITED_MEMB  = NO
-FULL_PATH_NAMES= NO
-STRIP_FROM_PATH=
-STRIP_FROM_INC_PATH=
-SHORT_NAMES= NO
-JAVADOC_AUTOBRIEF  = YES
-QT_AUTOBRIEF   = NO
-MULTILINE_CPP_IS_BRIEF = NO
-INHERIT_DOCS   = YES
-SEPARATE_MEMBER_PAGES  = NO
-TAB_SIZE   = 8
-ALIASES=
-TCL_SUBST  =
-OPTIMIZE_OUTPUT_FOR_C  = YES
-OPTIMIZE_OUTPUT_JAVA   = NO
-OPTIMIZE_FOR_FORTRAN   = NO
-OPTIMIZE_OUTPUT_VHDL   = NO
-EXTENSION_MAPPING  =
-MARKDOWN_SUPPORT   = YES
-AUTOLINK_SUPPORT   = YES
-BUILTIN_STL_SUPPORT= NO
-CPP_CLI_SUPPORT= NO
-SIP_SUPPORT= NO
-IDL_PROPERTY_SUPPORT   = YES
-DISTRIBUTE_GROUP_DOC   = NO
-SUBGROUPING= YES
-INLINE_GROUPED_CLASSES = NO
-INLINE_SIMPLE_STRUCTS  = NO
-TYPEDEF_HIDES_STRUCT   = YES
-LOOKUP_CACHE_SIZE  = 0
-#---
-# Build related configuration options
-#---
-EXTRACT_ALL= NO
-EXTRACT_PRIVATE= NO
-EXTRACT_PACKAGE= NO
-EXTRACT_STATIC = NO
-EXTRACT_LOCAL_CLASSES  = YES
-EXTRACT_LOCAL_METHODS  = NO
-EXTRACT_ANON_NSPACES   = NO
-HIDE_UNDOC_MEMBERS = NO
-HIDE_UNDOC_CLASSES = NO
-HIDE_FRIEND_COMPOUNDS  = NO
-HIDE_IN_BODY_DOCS  = NO
-INTERNAL_DOCS  = NO
-CASE_SENSE_NAMES   = YES
-HIDE_SCOPE_NAMES   = NO
-SHOW_INCLUDE_FILES = NO
-FORCE_LOCAL_INCLUDES   = NO
-INLINE_INFO= YES
-SORT_MEMBER_DOCS   = NO
-SORT_BRIEF_DOCS= NO
-SORT_MEMBERS_CTORS_1ST = NO
-SORT_GROUP_NAMES   = NO
-SORT_BY_SCOPE_NAME = NO
-STRICT_PROTO_MATCHING  = NO
-GENERATE_TODOLIST  = NO
-GENERATE_TESTLIST  = NO
-GENERATE_BUGLIST   = NO
-GENERATE_DEPRECATEDLIST= NO
-ENABLED_SECTIONS   =
-MAX_INITIALIZER_LINES  = 30
-SHOW_USED_FILES= NO
-SHOW_FILES = NO
-SHOW_NAMESPACES= NO
-FILE_VERSION_FILTER=
-LAYOUT_FILE=
-CITE_BIB_FILES =
-#---
-# configuration options related to warning and progress messages
-#---
-QUIET  = YES
-WARNINGS   = YES
-WARN_IF_UNDOCUMENTED   = YES
-WARN_IF_DOC_ERROR  = YES
-WARN_NO_PARAMDOC   = NO
-WARN_FORMAT= $file:$line: $text
-WARN_LOGFILE   =
-#---
-# configuration options related to the input files
-#---
-INPUT  = lib/notmuch.h
-INPUT_ENCODING = UTF-8
-FILE_PATTERNS  =
-RECURSIVE  = NO
-EXCLUDE=
-EXCLUDE_SYMLINKS   = NO
-EXCLUDE_PATTERNS   =
-EXCLUDE_SYMBOLS=
-EXAMPLE_PATH   =
-EXAMPLE_PATTERNS   =
-EXAMPLE_RECURSIVE  = NO
-IMAGE_PATH =
-INPUT_FILTER   =
-FILTER_PATTERNS=
-FILTER_SOURCE_FILES= NO
-FILTER_SOURCE_PATTERNS =
-USE_MDFILE_AS_MAINPAGE =
-#---
-# configuration options related to source browsing
-#---
-SOURCE_BROWSER = NO
-INLINE_SOURCES = NO
-STRIP_CODE_COMMENTS= YES
-REFERENCED_BY_RELATION = NO
-REFERENCES_RELATION= NO
-REFERENCES_LINK_SOURCE = YES
-USE_HTAGS  = NO
-VERBATIM_HEADERS   = NO
-#---
-# configuration options related to the alphabetical class index
-#---
-ALPHABETICAL_INDEX = NO
-COLS_IN_ALPHA_INDEX= 5
-IGNORE_PREFIX 

Re: [PATCH 4/5] emacs: hello: switch notmuch-hello-insert-buttons to plists

2014-04-05 Thread Mark Walters

Hello

 @@ -455,23 +457,26 @@ (defun notmuch-hello-query-counts (query-list rest 
 options)
   #'identity
   (mapcar
(lambda (elem)
 -(let ((name (notmuch-saved-search-get elem :name))
 -  (search-query (notmuch-saved-search-get elem :query))
 -  (message-count (prog1 (read (current-buffer))
 +(let* ((elem-plist (notmuch-hello-saved-search-to-plist elem))
 +   (search-query (plist-get elem-plist :query))
 +   (filtered-query (notmuch-hello-filtered-query
 +search-query (plist-get options :filter)))
 +   (message-count (prog1 (read (current-buffer))
  (forward-line 1
(and (or (plist-get options :show-empty-searches) ( message-count 0))
 -   (list name (notmuch-hello-filtered-query
 -   search-query (plist-get options :filter))
 - message-count
 +   (setq elem-plist (plist-put elem-plist :query filtered-query))

 This technically works, but `setq' is a strange thing to see in an
 `and'.  But the problem isn't the `setq'; it's that crazy `and'.  I'd
 replace the `and' with `when', keep the `setq' and `plist-put' in the
 body, and squint a lot less at this code.

This was actually a bug on my part: the filtered query can be nil (which
is used to mean hide this search); in earlier versions having a setq
inside the `and' achieved this but obviously not in this plist form. I
have switched to the when as suggested and added a test for
filtered-query being nil.

Best wishes

Mark

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 5/5] emacs: Add a sort-order option to saved-searches

2014-04-05 Thread Mark Walters

Hi

On Sun, 06 Apr 2014, Austin Clements amdra...@mit.edu wrote:
 Quoth Mark Walters on Apr 05 at 10:24 pm:
 This adds a sort-order option to saved-searches, stores it in the
 saved-search buttons (widgets), and uses the stored value when the
 button is pressed.
 
 Storing the sort-order in the widget was suggested by Jani in
 id:4c3876274126985683e888641b29cf18142a5eb8.1391771337.git.j...@nikula.org.
 ---
  emacs/notmuch-hello.el |   11 ++-
  emacs/notmuch-lib.el   |7 ++-
  2 files changed, 16 insertions(+), 2 deletions(-)
 
 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
 index aa40e6f..6a28372 100644
 --- a/emacs/notmuch-hello.el
 +++ b/emacs/notmuch-hello.el
 @@ -364,7 +364,8 @@ (defun notmuch-hello-reflect (list ncols)
  (defun notmuch-hello-widget-search (widget rest ignore)
(notmuch-search (widget-get widget
:notmuch-search-terms)
 -  notmuch-search-oldest-first))
 +  (widget-get widget
 +  :notmuch-search-oldest-first)))
  
  (defun notmuch-saved-search-count (search)
(car (process-lines notmuch-command count search)))
 @@ -496,12 +497,20 @@ (defun notmuch-hello-insert-buttons (searches)
(widget-insert (make-string column-indent ? )))
(let* ((name (plist-get elem :name))
   (query (plist-get elem :query))
 + (oldest-first (cond
 +((eq (plist-get elem :sort-order) 
 'newest-first)
 + nil)
 +((eq (plist-get elem :sort-order) 
 'oldest-first)
 + t)
 +(t
 + notmuch-search-oldest-first)))

 (case (plist-get elem :sort-order)
   (newest-first nil)
   (oldest-first t)
   (otherwise notmuch-search-oldest-first))

This is much better.


   (msg-count (plist-get elem :count)))
  (widget-insert (format %8s 
 (notmuch-hello-nice-number msg-count)))
  (widget-create 'push-button
 :notify #'notmuch-hello-widget-search
 :notmuch-search-terms query
 +   :notmuch-search-oldest-first oldest-first
 name)
  (setq column-indent
(1+ (max 0 (- column-width (length name)))
 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
 index 8a12f91..8aa8cfc 100644
 --- a/emacs/notmuch-lib.el
 +++ b/emacs/notmuch-lib.el
 @@ -125,7 +125,12 @@ (define-widget 'notmuch-saved-search-plist 'list
  (group :format %v :inline t (const :format   Query:  
 :query) (string :format %v)))
(checklist :inline t
   :format %v
 - (group :format %v :inline t (const :format Count-Query: 
  :count-query) (string :format %v)
 + (group :format %v :inline t (const :format Count-Query: 
  :count-query) (string :format %v))
 + (group :format %v :inline t (const :format  
 :sort-order)
 +(choice :tag  Sort Order

 Should there be a colon?  (I haven't applied the patches and I'm
 afraid this is beyond my mental implementation of define-widget!)

I think it is OK without: since this is using :tag rather than :format
the colon is supplied automatically.

Many thanks

Mark


 +(const :tag Default nil)
 +(const :tag Oldest-first oldest-first)
 +(const :tag Newest-first 
 newest-first))
  
  (defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
  (:name unread :query tag:unread))
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 0/5] emacs: hello: convert saved-searches to plists

2014-04-05 Thread Mark Walters

On Sun, 06 Apr 2014, David Bremner da...@tethera.net wrote:
 Mark Walters markwalters1...@gmail.com writes:

 This series converts the saved-search format to plists. This should
 make it much easier to extend their functionality. The final patch
 illustrates this by adding a sort-order option to the saved
 searches. It also exposes the count-query functionality that is
 already present internally, and could be used to store keyboard
 shortcuts for searches.

 Not necessarily an issue for this series, but I'd like start thinking
 about a front-end-independent representation for saved searches; perhaps
 json for want of better ideas.  

Yes that sounds good. I think it would be natural to parse the JSON (or
sexp if we allow both formats) into a plist for the saved search so that
could fit in quite neatly.

Best wishes

Mark


___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 0/5] emacs: hello: convert saved-searches to plists

2014-04-05 Thread Mark Walters
This is v2 of the series; v1 is at
id:1396733065-32602-1-git-send-email-markwalters1...@gmail.com

I have made all the changes suggested by Austin in his review of v1. I
include the diff from v1 below.

There is now one slight oddity in the patch ordering: the
documentation for the plist form appears in patch 3 while the users
and references to that documentation appear in patch 2.

Best wishes

Mark

Mark Walters (5):
  emacs: hello: add helper functions for saved-searches
  emacs: hello: use the saved-search helper functions
  emacs: hello: add a customize for saved-searches
  emacs: hello: switch notmuch-hello-insert-buttons to plists
  emacs: Add a sort-order option to saved-searches

 emacs/notmuch-hello.el |  127 
 emacs/notmuch-lib.el   |   54 ++--
 emacs/notmuch.el   |6 +--
 3 files changed, 139 insertions(+), 48 deletions(-)


diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 6a28372..f0675f2 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -272,17 +272,17 @@ (defun notmuch-hello-search (optional search)
 (defun notmuch-saved-search-get (saved-search field)
   Get FIELD from SAVED-SEARCH.
 
-In the new style saved-search (a plist) this is just plist-get
-but, for backwards compatibility, this deals with the two
-old-style forms: cons cells (NAME . QUERY) and lists (NAME QUERY
-COUNT-QUERY).
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY).
   (cond
-   ((plist-get saved-search :name)
+   ((keywordp (car saved-search))
 (plist-get saved-search field))
;; It is not a plist so it is an old-style entry.
((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
 (case field
-  (:name (car saved-search))
+  (:name (first saved-search))
   (:query (second saved-search))
   (:count-query (third saved-search))
   (t nil)))
@@ -293,16 +293,15 @@ (defun notmuch-saved-search-get (saved-search field)
   (t nil)
 
 (defun notmuch-hello-saved-search-to-plist (saved-search)
-  Convert a saved-search variable into plist form.
+  Return a copy of SAVED-SEARCH in plist form.
 
-The new style saved search is just a plist, but for backwards
-compatatibility we use this function to give them in
-plist-form. In all cases a new copy is returned so it is safe to
-modify the returned value.
-  (if (and (listp (cdr saved-search)) (plist-member saved-search :name))
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatability, convert to plist form and
+return that.
+  (if (keywordp (car saved-search))
   (copy-seq saved-search)
 (let ((fields (list :name :query :count-query))
- (plist-search))
+ plist-search)
   (dolist (field fields plist-search)
(let ((string (notmuch-saved-search-get saved-search field)))
  (when string
@@ -424,11 +423,11 @@ (defun notmuch-hello-query-counts (query-list rest 
options)
 
 QUERY-LIST must be a list of saved-searches. Ideally each of
 these is a plist but other options are available for backwards
-compatibility: see notmuch-saved-search-get for details.
+compatibility: see `notmuch-saved-searches' for details.
 
 The result is a list of plists each of which includes the
-pairs :name NAME, :query QUERY and :count COUNT, together with
-any pairs in the original saved-search.
+properties :name NAME, :query QUERY and :count COUNT, together
+with any properties in the original saved-search.
 
 The values :show-empty-searches, :filter and :filter-count from
 options will be handled as specified for
@@ -464,20 +463,20 @@ (defun notmuch-hello-query-counts (query-list rest 
options)
search-query (plist-get options :filter)))
   (message-count (prog1 (read (current-buffer))
(forward-line 1
- (and (or (plist-get options :show-empty-searches) ( message-count 0))
-  (setq elem-plist (plist-put elem-plist :query filtered-query))
-  (plist-put elem-plist :count message-count
+ (when (and filtered-query (or (plist-get options 
:show-empty-searches) ( message-count 0)))
+   (setq elem-plist (plist-put elem-plist :query filtered-query))
+   (plist-put elem-plist :count message-count
   query-list
 
 (defun notmuch-hello-insert-buttons (searches)
   Insert buttons for SEARCHES.
 
 SEARCHES must be a list of plists each of which should contain at
-least pairs for :name NAME :query QUERY and :count COUNT, where
-QUERY is the query to start when the button for the corresponding
-entry is activated, and COUNT should be the number of messages
-matching the query.  Such a plist can be computed with
-`notmuch-hello-query-counts'.
+least the properties :name 

[PATCH v2 3/5] emacs: hello: add a customize for saved-searches

2014-04-05 Thread Mark Walters
Make the defcustom for notmuch-saved-searches use the new plist
format. It should still work with oldstyle saved-searches but will
write the newstyle form.
---
 emacs/notmuch-hello.el |2 +-
 emacs/notmuch-lib.el   |   46 ++
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 568ae47..30f26db 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -323,7 +323,7 @@ (defun notmuch-hello-add-saved-search (widget)
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
 (add-to-list 'notmuch-saved-searches
- (cons name search) t))
+ (list :name name :query search) t))
 (message Saved '%s' as '%s'. search name)
 (notmuch-hello-update)))
 
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 959764e..a54a055 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -107,10 +107,48 @@ (defcustom notmuch-poll-script nil
 (defvar notmuch-search-history nil
   Variable to store notmuch searches history.)
 
-(defcustom notmuch-saved-searches '((inbox . tag:inbox)
-   (unread . tag:unread))
-  A list of saved searches to display.
-  :type '(alist :key-type string :value-type string)
+(defun notmuch--saved-searches-to-plist (symbol)
+  Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to extract old style saved
+searches so they still work in customize.
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  A single saved search property list.
+  :tag Saved Search
+  :args '((list :inline t
+   :format %v
+   (group :format %v :inline t (const :formatName:  :name) 
(string :format %v))
+   (group :format %v :inline t (const :format   Query:  
:query) (string :format %v)))
+ (checklist :inline t
+:format %v
+(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v)
+
+(defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
+   (:name unread :query tag:unread))
+  A list of saved searches to display.
+
+The saved search can be given in 3 forms. The preferred way is as
+a plist. Supported properties are
+
+  :nameName of the search (required).
+  :query   Search to run (required).
+  :count-query Optional extra query to generate the count
+   shown. If not present then the :query property
+   is used.
+
+Other accepted forms are a cons cell of the form (NAME . QUERY)
+or a list of the form (NAME QUERY COUNT-QUERY).
+;; The saved-search format is also used by the all-tags notmuch-hello
+;; section. This section generates its own saved-search list in one of
+;; the latter two forms.
+
+  :get 'notmuch--saved-searches-to-plist
+  :type '(repeat notmuch-saved-search-plist)
+  :tag List of Saved Searches
   :group 'notmuch-hello)
 
 (defcustom notmuch-archive-tags '(-inbox)
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 2/5] emacs: hello: use the saved-search helper functions

2014-04-05 Thread Mark Walters
This uses the helper functions: the saved searches format has not
changed yet but backwards compatibility means everything still works.
---
 emacs/notmuch-hello.el |   48 ++--
 emacs/notmuch.el   |6 +++---
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index f81ec27..568ae47 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -318,7 +318,7 @@ (defun notmuch-hello-add-saved-search (widget)
 (setq notmuch-saved-searches
  (loop for elem in notmuch-saved-searches
if (not (equal name
-  (car elem)))
+  (notmuch-saved-search-get elem :name)))
collect elem))
 ;; Add the new one.
 (customize-save-variable 'notmuch-saved-searches
@@ -338,7 +338,7 @@ (defun notmuch-hello-delete-search-from-history (widget)
 
 (defun notmuch-hello-longest-label (searches-alist)
   (or (loop for elem in searches-alist
-   maximize (length (car elem)))
+   maximize (length (notmuch-saved-search-get elem :name)))
   0))
 
 (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
@@ -417,13 +417,12 @@ (defun notmuch-hello-filtered-query (query filter)
 (concat ( query ) and ( filter )))
(t query)))
 
-(defun notmuch-hello-query-counts (query-alist rest options)
-  Compute list of counts of matched messages from QUERY-ALIST.
+(defun notmuch-hello-query-counts (query-list rest options)
+  Compute list of counts of matched messages from QUERY-LIST.
 
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated query.
+QUERY-LIST must be a list of saved-searches. Ideally each of
+these is a plist but other options are available for backwards
+compatibility: see `notmuch-saved-searches' for details.
 
 The result is the list of elements of the form (NAME QUERY COUNT).
 
@@ -431,11 +430,9 @@ (defun notmuch-hello-query-counts (query-alist rest 
options)
 options will be handled as specified for
 `notmuch-hello-insert-searches'.
   (with-temp-buffer
-(dolist (elem query-alist nil)
-  (let ((count-query (if (consp (cdr elem))
-;; do we have a different query for the message 
count?
-(third elem)
-  (cdr elem
+(dolist (elem query-list nil)
+  (let ((count-query (or (notmuch-saved-search-get elem :count-query)
+(notmuch-saved-search-get elem :query
(insert
 (replace-regexp-in-string
  \n  
@@ -457,18 +454,15 @@ (defun notmuch-hello-query-counts (query-alist rest 
options)
  #'identity
  (mapcar
   (lambda (elem)
-   (let ((name (car elem))
- (search-query (if (consp (cdr elem))
-;; do we have a different query for the 
message count?
-(second elem)
- (cdr elem)))
+   (let ((name (notmuch-saved-search-get elem :name))
+ (search-query (notmuch-saved-search-get elem :query))
  (message-count (prog1 (read (current-buffer))
(forward-line 1
  (and (or (plist-get options :show-empty-searches) ( message-count 0))
   (list name (notmuch-hello-filtered-query
   search-query (plist-get options :filter))
 message-count
-  query-alist
+  query-list
 
 (defun notmuch-hello-insert-buttons (searches)
   Insert buttons for SEARCHES.
@@ -727,13 +721,15 @@ (defun notmuch-hello-insert-recent-searches ()
   (indent-rigidly start (point) notmuch-hello-indent))
 nil))
 
-(defun notmuch-hello-insert-searches (title query-alist rest options)
-  Insert a section with TITLE showing a list of buttons made from QUERY-ALIST.
+(defun notmuch-hello-insert-searches (title query-list rest options)
+  Insert a section with TITLE showing a list of buttons made from QUERY-LIST.
 
-QUERY-ALIST must be a list containing elements of the form (NAME . QUERY)
-or (NAME QUERY COUNT-QUERY). If the latter form is used,
-COUNT-QUERY specifies an alternate query to be used to generate
-the count for the associated item.
+QUERY-LIST should ideally be a plist but for backwards
+compatibility other forms are also accepted (see
+`notmuch-saved-searches' for details).  The plist should
+contain keys :name and :query; if :count-query is also present
+then it specifies an alternate query to be used to generate the
+count for the associated search.
 
 Supports the following entries in OPTIONS as a plist:
 :initially-hidden - if non-nil, section will be hidden on startup
@@ -767,7 +763,7 @@ (defun notmuch-hello-insert-searches (title 

[PATCH v2 1/5] emacs: hello: add helper functions for saved-searches

2014-04-05 Thread Mark Walters
Add helper functions to for saved searches to ease the transition to
the new plist form while maintaining backwards compatibility. They
will be used in the next patch.
---
 emacs/notmuch-hello.el |   38 ++
 1 file changed, 38 insertions(+)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index e325cd3..f81ec27 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -269,6 +269,44 @@ (defun notmuch-hello-search (optional search)
   (add-to-history 'notmuch-search-history search)))
   (notmuch-search search notmuch-search-oldest-first))
 
+(defun notmuch-saved-search-get (saved-search field)
+  Get FIELD from SAVED-SEARCH.
+
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY).
+  (cond
+   ((keywordp (car saved-search))
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (first saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  Return a copy of SAVED-SEARCH in plist form.
+
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatability, convert to plist form and
+return that.
+  (if (keywordp (car saved-search))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ plist-search)
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
 (defun notmuch-hello-add-saved-search (widget)
   (interactive)
   (let ((search (widget-value
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 5/5] emacs: Add a sort-order option to saved-searches

2014-04-05 Thread Mark Walters
This adds a sort-order option to saved-searches, stores it in the
saved-search buttons (widgets), and uses the stored value when the
button is pressed.

Storing the sort-order in the widget was suggested by Jani in
id:4c3876274126985683e888641b29cf18142a5eb8.1391771337.git.j...@nikula.org.
---
 emacs/notmuch-hello.el |8 +++-
 emacs/notmuch-lib.el   |   10 +-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index f440352..f0675f2 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -363,7 +363,8 @@ (defun notmuch-hello-reflect (list ncols)
 (defun notmuch-hello-widget-search (widget rest ignore)
   (notmuch-search (widget-get widget
  :notmuch-search-terms)
- notmuch-search-oldest-first))
+ (widget-get widget
+ :notmuch-search-oldest-first)))
 
 (defun notmuch-saved-search-count (search)
   (car (process-lines notmuch-command count search)))
@@ -495,12 +496,17 @@ (defun notmuch-hello-insert-buttons (searches)
  (widget-insert (make-string column-indent ? )))
  (let* ((name (plist-get elem :name))
 (query (plist-get elem :query))
+(oldest-first (case (plist-get elem :sort-order)
+(newest-first nil)
+(oldest-first t)
+(otherwise notmuch-search-oldest-first)))
 (msg-count (plist-get elem :count)))
(widget-insert (format %8s 
   (notmuch-hello-nice-number msg-count)))
(widget-create 'push-button
   :notify #'notmuch-hello-widget-search
   :notmuch-search-terms query
+  :notmuch-search-oldest-first oldest-first
   name)
(setq column-indent
  (1+ (max 0 (- column-width (length name)))
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index a54a055..3a3c69d 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -125,7 +125,12 @@ (define-widget 'notmuch-saved-search-plist 'list
(group :format %v :inline t (const :format   Query:  
:query) (string :format %v)))
  (checklist :inline t
 :format %v
-(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v)
+(group :format %v :inline t (const :format Count-Query: 
 :count-query) (string :format %v))
+(group :format %v :inline t (const :format  
:sort-order)
+   (choice :tag  Sort Order
+   (const :tag Default nil)
+   (const :tag Oldest-first oldest-first)
+   (const :tag Newest-first 
newest-first))
 
 (defcustom notmuch-saved-searches '((:name inbox :query tag:inbox)
(:name unread :query tag:unread))
@@ -139,6 +144,9 @@ (defcustom notmuch-saved-searches '((:name inbox :query 
tag:inbox)
   :count-query Optional extra query to generate the count
shown. If not present then the :query property
is used.
+  :sort-order  Specify the sort order to be used for the search.
+   Possible values are 'oldest-first 'newest-first or
+   nil. Nil means use the default sort order.
 
 Other accepted forms are a cons cell of the form (NAME . QUERY)
 or a list of the form (NAME QUERY COUNT-QUERY).
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch