[PATCH v4 0/5] reply to sender

2012-01-12 Thread Jani Nikula
Hi all, changes since v3:

Split the first patch into two, the first one refactoring the reply/from address
scanning, and the second one adding the actual reply-to-sender feature. This
addresses Austins comments in id:"20120112033146.gu20...@mit.edu" (and does
improve the code).

Patches 3-5 remain unchanged.


BR,
Jani.


Jani Nikula (4):
  cli: slightly refactor "notmuch reply" address scanning functions
  cli: add support for replying just to the sender in "notmuch reply"
  emacs: add support for replying just to the sender
  emacs: bind 'r' to reply-to-sender and 'R' to reply-to-all

Mark Walters (1):
  test: add tests for "notmuch reply" --reply-to=sender

 emacs/notmuch-mua.el |9 ++-
 emacs/notmuch-show.el|   12 ++-
 emacs/notmuch.el |   11 ++-
 man/man1/notmuch-reply.1 |   28 +-
 notmuch-reply.c  |  122 +--
 test/notmuch-test|1 +
 test/reply-to-sender |  209 ++
 7 files changed, 335 insertions(+), 57 deletions(-)
 create mode 100755 test/reply-to-sender

-- 
1.7.5.4

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


[PATCH v4 1/5] cli: slightly refactor "notmuch reply" address scanning functions

2012-01-12 Thread Jani Nikula
Slightly refactor "notmuch reply" recipient and user from address scanning
functions in preparation for reply-to-sender feature.

Add support for not adding messages at all (just scan for user from
address), and returning the number of messages added.

No externally visible functional changes.

Signed-off-by: Jani Nikula 
---
 notmuch-reply.c |   74 --
 1 files changed, 38 insertions(+), 36 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 000f6da..4fae66f 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -168,22 +168,28 @@ address_is_users (const char *address, notmuch_config_t 
*config)
 return 0;
 }
 
-/* For each address in 'list' that is not configured as one of the
- * user's addresses in 'config', add that address to 'message' as an
- * address of 'type'.
+/* Scan addresses in 'list'.
  *
- * The first address encountered that *is* the user's address will be
- * returned, (otherwise NULL is returned).
+ * If 'message' is non-NULL, then for each address in 'list' that is not
+ * configured as one of the user's addresses in 'config', add that address to
+ * 'message' as an address of 'type'.
+ *
+ * If 'user_from' is non-NULL and *user_from is NULL, the first address
+ * encountered in 'list' that *is* the user's address will be set to 
*user_from.
+ *
+ * Return the number of addresses added to 'message'. (If 'message' is NULL, 
the
+ * function returns 0 by definition.)
  */
-static const char *
-add_recipients_for_address_list (GMimeMessage *message,
-notmuch_config_t *config,
-GMimeRecipientType type,
-InternetAddressList *list)
+static unsigned int
+scan_address_list (InternetAddressList *list,
+  notmuch_config_t *config,
+  GMimeMessage *message,
+  GMimeRecipientType type,
+  const char **user_from)
 {
 InternetAddress *address;
 int i;
-const char *ret = NULL;
+unsigned int n = 0;
 
 for (i = 0; i < internet_address_list_length (list); i++) {
address = internet_address_list_get_address (list, i);
@@ -196,8 +202,7 @@ add_recipients_for_address_list (GMimeMessage *message,
if (group_list == NULL)
continue;
 
-   add_recipients_for_address_list (message, config,
-type, group_list);
+   n += scan_address_list (group_list, config, message, type, NULL);
} else {
InternetAddressMailbox *mailbox;
const char *name;
@@ -209,40 +214,40 @@ add_recipients_for_address_list (GMimeMessage *message,
addr = internet_address_mailbox_get_addr (mailbox);
 
if (address_is_users (addr, config)) {
-   if (ret == NULL)
-   ret = addr;
-   } else {
+   if (user_from && *user_from == NULL)
+   *user_from = addr;
+   } else if (message) {
g_mime_message_add_recipient (message, type, name, addr);
+   n++;
}
}
 }
 
-return ret;
+return n;
 }
 
-/* For each address in 'recipients' that is not configured as one of
- * the user's addresses in 'config', add that address to 'message' as
- * an address of 'type'.
+/* Scan addresses in 'recipients'.
  *
- * The first address encountered that *is* the user's address will be
- * returned, (otherwise NULL is returned).
+ * See the documentation of scan_address_list() above. This function does
+ * exactly the same, but converts 'recipients' to an InternetAddressList first.
  */
-static const char *
-add_recipients_for_string (GMimeMessage *message,
-  notmuch_config_t *config,
-  GMimeRecipientType type,
-  const char *recipients)
+static unsigned int
+scan_address_string (const char *recipients,
+notmuch_config_t *config,
+GMimeMessage *message,
+GMimeRecipientType type,
+const char **user_from)
 {
 InternetAddressList *list;
 
 if (recipients == NULL)
-   return NULL;
+   return 0;
 
 list = internet_address_list_parse_string (recipients);
 if (list == NULL)
-   return NULL;
+   return 0;
 
-return add_recipients_for_address_list (message, config, type, list);
+return scan_address_list (list, config, message, type, user_from);
 }
 
 /* Does the address in the Reply-To header of 'message' already appear
@@ -324,7 +329,7 @@ add_recipients_from_message (GMimeMessage *reply,
 }
 
 for (i = 0;

[PATCH v4 2/5] cli: add support for replying just to the sender in "notmuch reply"

2012-01-12 Thread Jani Nikula
Add new option --reply-to=(all|sender) to "notmuch reply" to select whether
to reply to all (sender and all recipients), or just sender. Reply to all
remains the default.

Credits to Mark Walters  for his similar earlier
work where I picked up the basic idea of handling reply-to-sender in
add_recipients_from_message(). All bugs are mine, though.

Signed-off-by: Jani Nikula 

---

Settled on --reply-to=(all|sender) per Carl's earlier suggestion
(id:87pqn5cg4g@yoom.home.cworth.org) and David's approval on IRC.
---
 man/man1/notmuch-reply.1 |   28 
 notmuch-reply.c  |   52 +
 2 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index db464d8..5160ece 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -14,11 +14,13 @@ Constructs a reply template for a set of messages.
 To make replying to email easier,
 .B notmuch reply
 takes an existing set of messages and constructs a suitable mail
-template. The Reply-to header (if any, otherwise From:) is used for
-the To: address. Vales from the To: and Cc: headers are copied, but
-not including any of the current user's email addresses (as configured
-in primary_mail or other_email in the .notmuch\-config file) in the
-recipient list
+template. The Reply-to: header (if any, otherwise From:) is used for
+the To: address. Unless
+.BR \-\-reply-to=sender
+is specified, values from the To: and Cc: headers are copied, but not
+including any of the current user's email addresses (as configured in
+primary_mail or other_email in the .notmuch\-config file) in the
+recipient list.
 
 It also builds a suitable new subject, including Re: at the front (if
 not already present), and adding the message IDs of the messages being
@@ -45,6 +47,22 @@ Includes subject and quoted message body.
 Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
 .RE
 .RE
+.RS
+.TP 4
+.BR \-\-reply\-to= ( all | sender )
+.RS
+.TP 4
+.BR all " (default)"
+Replies to all addresses.
+.TP 4
+.BR sender
+Replies only to the sender. If replying to user's own message
+(Reply-to: or From: header is one of the user's configured email
+addresses), try To:, Cc:, and Bcc: headers in this order, and copy
+values from the first that contains something other than only the
+user's addresses.
+.RE
+.RE
 
 See \fBnotmuch-search-terms\fR(7)
 for details of the supported syntax for .
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 4fae66f..b4c81de 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -289,7 +289,14 @@ reply_to_header_is_redundant (notmuch_message_t *message)
 return 0;
 }
 
-/* Augments the recipients of reply from the headers of message.
+/* Augment the recipients of 'reply' from the "Reply-to:", "From:", "To:",
+ * "Cc:", and "Bcc:" headers of 'message'.
+ *
+ * If 'reply_all' is true, use sender and all recipients, otherwise scan the
+ * headers for the first that contains something other than the user's 
addresses
+ * and add the recipients from this header (typically this would be
+ * reply-to-sender, but also handles reply to user's own message in a sensible
+ * way).
  *
  * If any of the user's addresses were found in these headers, the first
  * of these returned, otherwise NULL is returned.
@@ -297,7 +304,8 @@ reply_to_header_is_redundant (notmuch_message_t *message)
 static const char *
 add_recipients_from_message (GMimeMessage *reply,
 notmuch_config_t *config,
-notmuch_message_t *message)
+notmuch_message_t *message,
+notmuch_bool_t reply_all)
 {
 struct {
const char *header;
@@ -311,6 +319,7 @@ add_recipients_from_message (GMimeMessage *reply,
 };
 const char *from_addr = NULL;
 unsigned int i;
+unsigned int n = 0;
 
 /* Some mailing lists munge the Reply-To header despite it being A Bad
  * Thing, see http://www.unicom.com/pw/reply-to-harmful.html
@@ -337,8 +346,23 @@ add_recipients_from_message (GMimeMessage *reply,
recipients = notmuch_message_get_header (message,
 reply_to_map[i].fallback);
 
-   scan_address_string (recipients, config, reply,
-reply_to_map[i].recipient_type, &from_addr);
+   n += scan_address_string (recipients, config, reply,
+ reply_to_map[i].recipient_type, &from_addr);
+
+   if (!reply_all && n) {
+   /* Stop adding new recipients in reply-to-sender mode if we have
+* added some recipient(s) above.
+*
+* This also handles the case of user replying to his own message,
+* where re

[PATCH v4 3/5] emacs: add support for replying just to the sender

2012-01-12 Thread Jani Nikula
Provide reply to sender counterparts to the search and show reply
functions. Add key binding 'R' to reply to sender, while keeping 'r' as
reply to all, both in search and show views.

Signed-off-by: Jani Nikula 
---
 emacs/notmuch-mua.el  |9 ++---
 emacs/notmuch-show.el |   10 --
 emacs/notmuch.el  |9 -
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index 32e2e30..d8ab822 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -71,12 +71,15 @@ list."
(push header message-hidden-headers)))
notmuch-mua-hidden-headers))
 
-(defun notmuch-mua-reply (query-string &optional sender)
+(defun notmuch-mua-reply (query-string &optional sender reply-all)
   (let (headers
body
(args '("reply")))
 (if notmuch-show-process-crypto
(setq args (append args '("--decrypt"
+(if reply-all
+   (setq args (append args '("--reply-to=all")))
+  (setq args (append args '("--reply-to=sender"
 (setq args (append args (list query-string)))
 ;; This make assumptions about the output of `notmuch reply', but
 ;; really only that the headers come first followed by a blank
@@ -218,13 +221,13 @@ the From: address first."
(notmuch-mua-forward-message))
 (notmuch-mua-forward-message)))
 
-(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender)
+(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender 
reply-all)
   "Invoke the notmuch reply window."
   (interactive "P")
   (let ((sender
 (when prompt-for-sender
   (notmuch-mua-prompt-for-sender
-(notmuch-mua-reply query-string sender)))
+(notmuch-mua-reply query-string sender reply-all)))
 
 (defun notmuch-mua-send-and-exit (&optional arg)
   (interactive "P")
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 5502efd..96eea19 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -933,6 +933,7 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "m" 'notmuch-mua-new-mail)
(define-key map "f" 'notmuch-show-forward-message)
(define-key map "r" 'notmuch-show-reply)
+   (define-key map "R" 'notmuch-show-reply-sender)
(define-key map "|" 'notmuch-show-pipe-message)
(define-key map "w" 'notmuch-show-save-attachments)
(define-key map "V" 'notmuch-show-view-raw-message)
@@ -1237,9 +1238,14 @@ any effects from previous calls to
   (notmuch-show-previous-message)
 
 (defun notmuch-show-reply (&optional prompt-for-sender)
-  "Reply to the current message."
+  "Reply to the sender and all recipients of the current message."
   (interactive "P")
-  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender))
+  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender t))
+
+(defun notmuch-show-reply-sender (&optional prompt-for-sender)
+  "Reply to the sender of the current message."
+  (interactive "P")
+  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender nil))
 
 (defun notmuch-show-forward-message (&optional prompt-for-sender)
   "Forward the current message."
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 1e61775..9ac2888 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -214,6 +214,7 @@ For a mouse binding, return nil."
 (define-key map "p" 'notmuch-search-previous-thread)
 (define-key map "n" 'notmuch-search-next-thread)
 (define-key map "r" 'notmuch-search-reply-to-thread)
+(define-key map "R" 'notmuch-search-reply-to-thread-sender)
 (define-key map "m" 'notmuch-mua-new-mail)
 (define-key map "s" 'notmuch-search)
 (define-key map "o" 'notmuch-search-toggle-order)
@@ -448,10 +449,16 @@ Complete list of currently available key bindings:
   (message "End of search results."
 
 (defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
+  "Begin composing a reply-all to the entire current thread in a new buffer."
+  (interactive "P")
+  (let ((message-id (notmuch-search-find-thread-id)))
+(notmuch-mua-new-reply message-id prompt-for-sender t)))
+
+(defun notmuch-search-reply-to-thread-sender (&optional prompt-for-sender)
   "Begin composing a reply to the entire current thread in a new buffer."
   (interactive "P")
   (let ((message-id (notmuch-search-find-thread-id)))
-(notmuch-mua-new-reply message-id prompt-for-sender)))
+(notmuch-mua-new-reply message-id prompt-for-sender nil)))
 
 (defun notmuch-call-notmuch-process (&rest args)
   "Synchronously invoke \"notmuch\" with the given list of arguments.
-- 
1.7.5.4

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


[PATCH v4 4/5] emacs: bind 'r' to reply-to-sender and 'R' to reply-to-all

2012-01-12 Thread Jani Nikula
Change the default reply key bindings, making 'r' reply-to-sender and 'R'
reply-to-all.

Signed-off-by: Jani Nikula 

---

There were mixed feelings about this. This as a separate patch so it's easy
to drop if needed.
---
 emacs/notmuch-show.el |4 ++--
 emacs/notmuch.el  |4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 96eea19..8f8ea93 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -932,8 +932,8 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "s" 'notmuch-search)
(define-key map "m" 'notmuch-mua-new-mail)
(define-key map "f" 'notmuch-show-forward-message)
-   (define-key map "r" 'notmuch-show-reply)
-   (define-key map "R" 'notmuch-show-reply-sender)
+   (define-key map "r" 'notmuch-show-reply-sender)
+   (define-key map "R" 'notmuch-show-reply)
(define-key map "|" 'notmuch-show-pipe-message)
(define-key map "w" 'notmuch-show-save-attachments)
(define-key map "V" 'notmuch-show-view-raw-message)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 9ac2888..d952c41 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -213,8 +213,8 @@ For a mouse binding, return nil."
 (define-key map ">" 'notmuch-search-last-thread)
 (define-key map "p" 'notmuch-search-previous-thread)
 (define-key map "n" 'notmuch-search-next-thread)
-(define-key map "r" 'notmuch-search-reply-to-thread)
-(define-key map "R" 'notmuch-search-reply-to-thread-sender)
+(define-key map "r" 'notmuch-search-reply-to-thread-sender)
+(define-key map "R" 'notmuch-search-reply-to-thread)
 (define-key map "m" 'notmuch-mua-new-mail)
 (define-key map "s" 'notmuch-search)
 (define-key map "o" 'notmuch-search-toggle-order)
-- 
1.7.5.4

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


[PATCH v4 5/5] test: add tests for "notmuch reply" --reply-to=sender

2012-01-12 Thread Jani Nikula
From: Mark Walters 

---
 test/notmuch-test|1 +
 test/reply-to-sender |  209 ++
 2 files changed, 210 insertions(+), 0 deletions(-)
 create mode 100755 test/reply-to-sender

diff --git a/test/notmuch-test b/test/notmuch-test
index e40ef86..6a99ae3 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -33,6 +33,7 @@ TESTS="
   thread-naming
   raw
   reply
+  reply-to-sender
   dump-restore
   uuencode
   thread-order
diff --git a/test/reply-to-sender b/test/reply-to-sender
new file mode 100755
index 000..c7d15bb
--- /dev/null
+++ b/test/reply-to-sender
@@ -0,0 +1,209 @@
+#!/usr/bin/env bash
+test_description="\"notmuch reply --reply-to=sender\" in several variations"
+. ./test-lib.sh
+
+test_begin_subtest "Basic reply-to-sender"
+add_message '[from]="Sender "' \
+ [to]=test_su...@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="basic reply-to-sender test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> basic reply-to-sender test"
+
+test_begin_subtest "From Us, Basic reply to message"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="basic reply-to-from-us test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> basic reply-to-from-us test"
+
+test_begin_subtest "Multiple recipients"
+add_message '[from]="Sender "' \
+'[to]="test_su...@notmuchmail.org, Someone Else 
"' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="Multiple recipients"'
+
+output=$(notmuch reply  --reply-to=sender  id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> Multiple recipients"
+
+test_begin_subtest "From Us, Multiple TO recipients"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient , Someone Else 
"' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="From Us, Multiple TO recipients"'
+
+output=$(notmuch reply  --reply-to=sender  id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient , Someone Else 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> From Us, Multiple TO recipients"
+
+test_begin_subtest "Reply with CC"
+add_message '[from]="Sender "' \
+ [to]=test_su...@notmuchmail.org \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply with CC"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient "' \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply no TO but with CC"
+add_message '[from]="Notmuch Test Suite "' \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+Cc: Other Parties 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuc

Re: [PATCH v4 1/5] cli: slightly refactor "notmuch reply" address scanning functions

2012-01-14 Thread Jani Nikula
On Thu, 12 Jan 2012 16:59:05 -0500, Austin Clements  wrote:
> LGTM.  One thing you could fix below (and a few comments), but not
> enough alone to warrant a new version.
> 
> Quoth Jani Nikula on Jan 12 at 11:40 pm:
> > Slightly refactor "notmuch reply" recipient and user from address scanning
> > functions in preparation for reply-to-sender feature.
> > 
> > Add support for not adding messages at all (just scan for user from
> > address), and returning the number of messages added.
> > 
> > No externally visible functional changes.
> > 
> > Signed-off-by: Jani Nikula 
> > ---
> >  notmuch-reply.c |   74 
> > --
> >  1 files changed, 38 insertions(+), 36 deletions(-)
> > 
> > diff --git a/notmuch-reply.c b/notmuch-reply.c
> > index 000f6da..4fae66f 100644
> > --- a/notmuch-reply.c
> > +++ b/notmuch-reply.c
> > @@ -168,22 +168,28 @@ address_is_users (const char *address, 
> > notmuch_config_t *config)
> >  return 0;
> >  }
> >  
> > -/* For each address in 'list' that is not configured as one of the
> > - * user's addresses in 'config', add that address to 'message' as an
> > - * address of 'type'.
> > +/* Scan addresses in 'list'.
> >   *
> > - * The first address encountered that *is* the user's address will be
> > - * returned, (otherwise NULL is returned).
> > + * If 'message' is non-NULL, then for each address in 'list' that is not
> > + * configured as one of the user's addresses in 'config', add that address 
> > to
> > + * 'message' as an address of 'type'.
> > + *
> > + * If 'user_from' is non-NULL and *user_from is NULL, the first address
> > + * encountered in 'list' that *is* the user's address will be set to 
> > *user_from.
> > + *
> > + * Return the number of addresses added to 'message'. (If 'message' is 
> > NULL, the
> > + * function returns 0 by definition.)
> 
> Ah, I like the return value.  Better than adding an umpteenth argument
> like I was suggesting.
> 
> >   */
> > -static const char *
> > -add_recipients_for_address_list (GMimeMessage *message,
> > -notmuch_config_t *config,
> > -GMimeRecipientType type,
> > -InternetAddressList *list)
> > +static unsigned int
> > +scan_address_list (InternetAddressList *list,
> > +  notmuch_config_t *config,
> > +  GMimeMessage *message,
> > +  GMimeRecipientType type,
> > +  const char **user_from)
> >  {
> >  InternetAddress *address;
> >  int i;
> > -const char *ret = NULL;
> > +unsigned int n = 0;
> >  
> >  for (i = 0; i < internet_address_list_length (list); i++) {
> > address = internet_address_list_get_address (list, i);
> > @@ -196,8 +202,7 @@ add_recipients_for_address_list (GMimeMessage *message,
> > if (group_list == NULL)
> > continue;
> >  
> > -   add_recipients_for_address_list (message, config,
> > -type, group_list);
> > +   n += scan_address_list (group_list, config, message, type, NULL);
> 
> Should the NULL above be user_from?  You're being compatible with the
> original code, which is the right thing to do in this patch, but the
> new-found explicitness made me wonder if this is actually a bug.

I didn't even know what a group list was, and if [1] is accurate, I
don't think I've ever seen one either. This does smell like a bug, but
I'm doubtful if anyone would ever notice... Anyway, as you say, it
should be another patch, and independent of this series.

BR,
Jani.

[1] http://www.cs.tut.fi/~jkorpela/rfc/822addr.html

> 
> > } else {
> > InternetAddressMailbox *mailbox;
> > const char *name;
> > @@ -209,40 +214,40 @@ add_recipients_for_address_list (GMimeMessage 
> > *message,
> > addr = internet_address_mailbox_get_addr (mailbox);
> >  
> > if (address_is_users (addr, config)) {
> > -   if (ret == NULL)
> > -   ret = addr;
> > -   } else {
> > +   if (user_from && *user_from == NULL)
> > +   *user_from = addr;
> > +   } else if (message) {
> > g_mime_message_add_recipient (message, type, name, addr);
> > + 

[PATCH v5 0/5] reply to sender

2012-01-14 Thread Jani Nikula
Hi all, hopefully the final round with only the comment and commit
message fixes to issues in patches 1 and 2 spotted by Austin and
Mark. Thanks again for a thorough review!

BR,
Jani.

Jani Nikula (4):
  cli: slightly refactor "notmuch reply" address scanning functions
  cli: add support for replying just to the sender in "notmuch reply"
  emacs: add support for replying just to the sender
  emacs: bind 'r' to reply-to-sender and 'R' to reply-to-all

Mark Walters (1):
  test: add tests for "notmuch reply" --reply-to=sender

 emacs/notmuch-mua.el |9 ++-
 emacs/notmuch-show.el|   12 ++-
 emacs/notmuch.el |   11 ++-
 man/man1/notmuch-reply.1 |   28 +-
 notmuch-reply.c  |  129 ++--
 test/notmuch-test|1 +
 test/reply-to-sender |  209 ++
 7 files changed, 340 insertions(+), 59 deletions(-)
 create mode 100755 test/reply-to-sender

-- 
1.7.5.4

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


[PATCH v5 1/5] cli: slightly refactor "notmuch reply" address scanning functions

2012-01-14 Thread Jani Nikula
Slightly refactor "notmuch reply" recipient and user from address scanning
functions in preparation for reply-to-sender feature.

Add support for not adding recipients at all (just scan for user from
address), and returning the number of recipients added.

No externally visible functional changes.

Signed-off-by: Jani Nikula 
---
 notmuch-reply.c |   76 +--
 1 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 000f6da..a8d6a94 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -168,22 +168,29 @@ address_is_users (const char *address, notmuch_config_t 
*config)
 return 0;
 }
 
-/* For each address in 'list' that is not configured as one of the
- * user's addresses in 'config', add that address to 'message' as an
- * address of 'type'.
+/* Scan addresses in 'list'.
  *
- * The first address encountered that *is* the user's address will be
- * returned, (otherwise NULL is returned).
+ * If 'message' is non-NULL, then for each address in 'list' that is
+ * not configured as one of the user's addresses in 'config', add that
+ * address to 'message' as an address of 'type'.
+ *
+ * If 'user_from' is non-NULL and *user_from is NULL, *user_from will
+ * be set to the first address encountered in 'list' that is the
+ * user's address.
+ *
+ * Return the number of addresses added to 'message'. (If 'message' is
+ * NULL, the function returns 0 by definition.)
  */
-static const char *
-add_recipients_for_address_list (GMimeMessage *message,
-notmuch_config_t *config,
-GMimeRecipientType type,
-InternetAddressList *list)
+static unsigned int
+scan_address_list (InternetAddressList *list,
+  notmuch_config_t *config,
+  GMimeMessage *message,
+  GMimeRecipientType type,
+  const char **user_from)
 {
 InternetAddress *address;
 int i;
-const char *ret = NULL;
+unsigned int n = 0;
 
 for (i = 0; i < internet_address_list_length (list); i++) {
address = internet_address_list_get_address (list, i);
@@ -196,8 +203,7 @@ add_recipients_for_address_list (GMimeMessage *message,
if (group_list == NULL)
continue;
 
-   add_recipients_for_address_list (message, config,
-type, group_list);
+   n += scan_address_list (group_list, config, message, type, NULL);
} else {
InternetAddressMailbox *mailbox;
const char *name;
@@ -209,40 +215,41 @@ add_recipients_for_address_list (GMimeMessage *message,
addr = internet_address_mailbox_get_addr (mailbox);
 
if (address_is_users (addr, config)) {
-   if (ret == NULL)
-   ret = addr;
-   } else {
+   if (user_from && *user_from == NULL)
+   *user_from = addr;
+   } else if (message) {
g_mime_message_add_recipient (message, type, name, addr);
+   n++;
}
}
 }
 
-return ret;
+return n;
 }
 
-/* For each address in 'recipients' that is not configured as one of
- * the user's addresses in 'config', add that address to 'message' as
- * an address of 'type'.
+/* Scan addresses in 'recipients'.
  *
- * The first address encountered that *is* the user's address will be
- * returned, (otherwise NULL is returned).
+ * See the documentation of scan_address_list() above. This function
+ * does exactly the same, but converts 'recipients' to an
+ * InternetAddressList first.
  */
-static const char *
-add_recipients_for_string (GMimeMessage *message,
-  notmuch_config_t *config,
-  GMimeRecipientType type,
-  const char *recipients)
+static unsigned int
+scan_address_string (const char *recipients,
+notmuch_config_t *config,
+GMimeMessage *message,
+GMimeRecipientType type,
+const char **user_from)
 {
 InternetAddressList *list;
 
 if (recipients == NULL)
-   return NULL;
+   return 0;
 
 list = internet_address_list_parse_string (recipients);
 if (list == NULL)
-   return NULL;
+   return 0;
 
-return add_recipients_for_address_list (message, config, type, list);
+return scan_address_list (list, config, message, type, user_from);
 }
 
 /* Does the address in the Reply-To header of 'message' already appear
@@ -324,7 +331,7 @@ add_recipients_from_message (GMimeMessage *reply,
 }
 
 for (i = 0;

[PATCH v5 2/5] cli: add support for replying just to the sender in "notmuch reply"

2012-01-14 Thread Jani Nikula
Add new option --reply-to=(all|sender) to "notmuch reply" to select whether
to reply to all (sender and all recipients), or just sender. Reply to all
remains the default.

Credits to Mark Walters  for his similar earlier
work where I picked up the basic idea of handling reply-to-sender in
add_recipients_from_message(). All bugs are mine, though.

Signed-off-by: Jani Nikula 

---

Settled on --reply-to=(all|sender) per Carl's earlier suggestion
(id:87pqn5cg4g@yoom.home.cworth.org) and David's approval on IRC.
---
 man/man1/notmuch-reply.1 |   28 ++
 notmuch-reply.c  |   57 -
 2 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index db464d8..5160ece 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -14,11 +14,13 @@ Constructs a reply template for a set of messages.
 To make replying to email easier,
 .B notmuch reply
 takes an existing set of messages and constructs a suitable mail
-template. The Reply-to header (if any, otherwise From:) is used for
-the To: address. Vales from the To: and Cc: headers are copied, but
-not including any of the current user's email addresses (as configured
-in primary_mail or other_email in the .notmuch\-config file) in the
-recipient list
+template. The Reply-to: header (if any, otherwise From:) is used for
+the To: address. Unless
+.BR \-\-reply-to=sender
+is specified, values from the To: and Cc: headers are copied, but not
+including any of the current user's email addresses (as configured in
+primary_mail or other_email in the .notmuch\-config file) in the
+recipient list.
 
 It also builds a suitable new subject, including Re: at the front (if
 not already present), and adding the message IDs of the messages being
@@ -45,6 +47,22 @@ Includes subject and quoted message body.
 Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
 .RE
 .RE
+.RS
+.TP 4
+.BR \-\-reply\-to= ( all | sender )
+.RS
+.TP 4
+.BR all " (default)"
+Replies to all addresses.
+.TP 4
+.BR sender
+Replies only to the sender. If replying to user's own message
+(Reply-to: or From: header is one of the user's configured email
+addresses), try To:, Cc:, and Bcc: headers in this order, and copy
+values from the first that contains something other than only the
+user's addresses.
+.RE
+.RE
 
 See \fBnotmuch-search-terms\fR(7)
 for details of the supported syntax for .
diff --git a/notmuch-reply.c b/notmuch-reply.c
index a8d6a94..da3acce 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -291,15 +291,23 @@ reply_to_header_is_redundant (notmuch_message_t *message)
 return 0;
 }
 
-/* Augments the recipients of reply from the headers of message.
+/* Augment the recipients of 'reply' from the "Reply-to:", "From:",
+ * "To:", "Cc:", and "Bcc:" headers of 'message'.
  *
- * If any of the user's addresses were found in these headers, the first
- * of these returned, otherwise NULL is returned.
+ * If 'reply_all' is true, use sender and all recipients, otherwise
+ * scan the headers for the first that contains something other than
+ * the user's addresses and add the recipients from this header
+ * (typically this would be reply-to-sender, but also handles reply to
+ * user's own message in a sensible way).
+ *
+ * If any of the user's addresses were found in these headers, the
+ * first of these returned, otherwise NULL is returned.
  */
 static const char *
 add_recipients_from_message (GMimeMessage *reply,
 notmuch_config_t *config,
-notmuch_message_t *message)
+notmuch_message_t *message,
+notmuch_bool_t reply_all)
 {
 struct {
const char *header;
@@ -313,6 +321,7 @@ add_recipients_from_message (GMimeMessage *reply,
 };
 const char *from_addr = NULL;
 unsigned int i;
+unsigned int n = 0;
 
 /* Some mailing lists munge the Reply-To header despite it being A Bad
  * Thing, see http://www.unicom.com/pw/reply-to-harmful.html
@@ -339,8 +348,24 @@ add_recipients_from_message (GMimeMessage *reply,
recipients = notmuch_message_get_header (message,
 reply_to_map[i].fallback);
 
-   scan_address_string (recipients, config, reply,
-reply_to_map[i].recipient_type, &from_addr);
+   n += scan_address_string (recipients, config, reply,
+ reply_to_map[i].recipient_type, &from_addr);
+
+   if (!reply_all && n) {
+   /* Stop adding new recipients in reply-to-sender mode if
+* we have added some recipient(s) above.
+*
+* This also handles the case of user repl

[PATCH v5 3/5] emacs: add support for replying just to the sender

2012-01-14 Thread Jani Nikula
Provide reply to sender counterparts to the search and show reply
functions. Add key binding 'R' to reply to sender, while keeping 'r' as
reply to all, both in search and show views.

Signed-off-by: Jani Nikula 
---
 emacs/notmuch-mua.el  |9 ++---
 emacs/notmuch-show.el |   10 --
 emacs/notmuch.el  |9 -
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index 32e2e30..d8ab822 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -71,12 +71,15 @@ list."
(push header message-hidden-headers)))
notmuch-mua-hidden-headers))
 
-(defun notmuch-mua-reply (query-string &optional sender)
+(defun notmuch-mua-reply (query-string &optional sender reply-all)
   (let (headers
body
(args '("reply")))
 (if notmuch-show-process-crypto
(setq args (append args '("--decrypt"
+(if reply-all
+   (setq args (append args '("--reply-to=all")))
+  (setq args (append args '("--reply-to=sender"
 (setq args (append args (list query-string)))
 ;; This make assumptions about the output of `notmuch reply', but
 ;; really only that the headers come first followed by a blank
@@ -218,13 +221,13 @@ the From: address first."
(notmuch-mua-forward-message))
 (notmuch-mua-forward-message)))
 
-(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender)
+(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender 
reply-all)
   "Invoke the notmuch reply window."
   (interactive "P")
   (let ((sender
 (when prompt-for-sender
   (notmuch-mua-prompt-for-sender
-(notmuch-mua-reply query-string sender)))
+(notmuch-mua-reply query-string sender reply-all)))
 
 (defun notmuch-mua-send-and-exit (&optional arg)
   (interactive "P")
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 034db87..9031b82 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -934,6 +934,7 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "m" 'notmuch-mua-new-mail)
(define-key map "f" 'notmuch-show-forward-message)
(define-key map "r" 'notmuch-show-reply)
+   (define-key map "R" 'notmuch-show-reply-sender)
(define-key map "|" 'notmuch-show-pipe-message)
(define-key map "w" 'notmuch-show-save-attachments)
(define-key map "V" 'notmuch-show-view-raw-message)
@@ -1238,9 +1239,14 @@ any effects from previous calls to
   (notmuch-show-previous-message)
 
 (defun notmuch-show-reply (&optional prompt-for-sender)
-  "Reply to the current message."
+  "Reply to the sender and all recipients of the current message."
   (interactive "P")
-  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender))
+  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender t))
+
+(defun notmuch-show-reply-sender (&optional prompt-for-sender)
+  "Reply to the sender of the current message."
+  (interactive "P")
+  (notmuch-mua-new-reply (notmuch-show-get-message-id) prompt-for-sender nil))
 
 (defun notmuch-show-forward-message (&optional prompt-for-sender)
   "Forward the current message."
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 1e61775..9ac2888 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -214,6 +214,7 @@ For a mouse binding, return nil."
 (define-key map "p" 'notmuch-search-previous-thread)
 (define-key map "n" 'notmuch-search-next-thread)
 (define-key map "r" 'notmuch-search-reply-to-thread)
+(define-key map "R" 'notmuch-search-reply-to-thread-sender)
 (define-key map "m" 'notmuch-mua-new-mail)
 (define-key map "s" 'notmuch-search)
 (define-key map "o" 'notmuch-search-toggle-order)
@@ -448,10 +449,16 @@ Complete list of currently available key bindings:
   (message "End of search results."
 
 (defun notmuch-search-reply-to-thread (&optional prompt-for-sender)
+  "Begin composing a reply-all to the entire current thread in a new buffer."
+  (interactive "P")
+  (let ((message-id (notmuch-search-find-thread-id)))
+(notmuch-mua-new-reply message-id prompt-for-sender t)))
+
+(defun notmuch-search-reply-to-thread-sender (&optional prompt-for-sender)
   "Begin composing a reply to the entire current thread in a new buffer."
   (interactive "P")
   (let ((message-id (notmuch-search-find-thread-id)))
-(notmuch-mua-new-reply message-id prompt-for-sender)))
+(notmuch-mua-new-reply message-id prompt-for-sender nil)))
 
 (defun notmuch-call-notmuch-process (&rest args)
   "Synchronously invoke \"notmuch\" with the given list of arguments.
-- 
1.7.5.4

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


[PATCH v5 4/5] emacs: bind 'r' to reply-to-sender and 'R' to reply-to-all

2012-01-14 Thread Jani Nikula
Change the default reply key bindings, making 'r' reply-to-sender and 'R'
reply-to-all.

Signed-off-by: Jani Nikula 

---

There were mixed feelings about this. This as a separate patch so it's easy
to drop if needed.
---
 emacs/notmuch-show.el |4 ++--
 emacs/notmuch.el  |4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 9031b82..03c1f6b 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -933,8 +933,8 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "s" 'notmuch-search)
(define-key map "m" 'notmuch-mua-new-mail)
(define-key map "f" 'notmuch-show-forward-message)
-   (define-key map "r" 'notmuch-show-reply)
-   (define-key map "R" 'notmuch-show-reply-sender)
+   (define-key map "r" 'notmuch-show-reply-sender)
+   (define-key map "R" 'notmuch-show-reply)
(define-key map "|" 'notmuch-show-pipe-message)
(define-key map "w" 'notmuch-show-save-attachments)
(define-key map "V" 'notmuch-show-view-raw-message)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 9ac2888..d952c41 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -213,8 +213,8 @@ For a mouse binding, return nil."
 (define-key map ">" 'notmuch-search-last-thread)
 (define-key map "p" 'notmuch-search-previous-thread)
 (define-key map "n" 'notmuch-search-next-thread)
-(define-key map "r" 'notmuch-search-reply-to-thread)
-(define-key map "R" 'notmuch-search-reply-to-thread-sender)
+(define-key map "r" 'notmuch-search-reply-to-thread-sender)
+(define-key map "R" 'notmuch-search-reply-to-thread)
 (define-key map "m" 'notmuch-mua-new-mail)
 (define-key map "s" 'notmuch-search)
 (define-key map "o" 'notmuch-search-toggle-order)
-- 
1.7.5.4

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


[PATCH v5 5/5] test: add tests for "notmuch reply" --reply-to=sender

2012-01-14 Thread Jani Nikula
From: Mark Walters 

---
 test/notmuch-test|1 +
 test/reply-to-sender |  209 ++
 2 files changed, 210 insertions(+), 0 deletions(-)
 create mode 100755 test/reply-to-sender

diff --git a/test/notmuch-test b/test/notmuch-test
index e40ef86..6a99ae3 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -33,6 +33,7 @@ TESTS="
   thread-naming
   raw
   reply
+  reply-to-sender
   dump-restore
   uuencode
   thread-order
diff --git a/test/reply-to-sender b/test/reply-to-sender
new file mode 100755
index 000..c7d15bb
--- /dev/null
+++ b/test/reply-to-sender
@@ -0,0 +1,209 @@
+#!/usr/bin/env bash
+test_description="\"notmuch reply --reply-to=sender\" in several variations"
+. ./test-lib.sh
+
+test_begin_subtest "Basic reply-to-sender"
+add_message '[from]="Sender "' \
+ [to]=test_su...@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="basic reply-to-sender test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> basic reply-to-sender test"
+
+test_begin_subtest "From Us, Basic reply to message"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="basic reply-to-from-us test"'
+
+output=$(notmuch reply --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> basic reply-to-from-us test"
+
+test_begin_subtest "Multiple recipients"
+add_message '[from]="Sender "' \
+'[to]="test_su...@notmuchmail.org, Someone Else 
"' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="Multiple recipients"'
+
+output=$(notmuch reply  --reply-to=sender  id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> Multiple recipients"
+
+test_begin_subtest "From Us, Multiple TO recipients"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient , Someone Else 
"' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="From Us, Multiple TO recipients"'
+
+output=$(notmuch reply  --reply-to=sender  id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient , Someone Else 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> From Us, Multiple TO recipients"
+
+test_begin_subtest "Reply with CC"
+add_message '[from]="Sender "' \
+ [to]=test_su...@notmuchmail.org \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply with CC"
+add_message '[from]="Notmuch Test Suite "' \
+'[to]="Recipient "' \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Recipient 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuch Test Suite 
 wrote:
+> reply with CC"
+
+test_begin_subtest "From Us, Reply no TO but with CC"
+add_message '[from]="Notmuch Test Suite "' \
+'[cc]="Other Parties "' \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="reply with CC"'
+
+output=$(notmuch reply  --reply-to=sender id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+Cc: Other Parties 
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Notmuc

[PATCH] NEWS: add news items for reply to sender

2012-01-14 Thread Jani Nikula
---
 NEWS |   23 +++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index bf21e64..1161c22 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,26 @@
+Notmuch 0.12 (2012-xx-xx)
+=
+
+Command-Line Interface
+--
+
+Reply to sender
+
+  "notmuch reply" has gained the ability to create a reply template
+  for replying just to the sender of the message, in addition to reply
+  to all. The feature is available through the new command line option
+  --reply-to=(all|sender).
+
+Emacs Interface
+---
+
+Reply to sender
+
+  The Emacs interface has, with the new CLI support, gained the
+  ability to reply to sender in addition to reply to all. In both show
+  and search modes, 'r' has been bound to reply to sender, replacing
+  reply to all, which now has key binding 'R'.
+
 Notmuch 0.11 (2012-01-13)
 =
 
-- 
1.7.5.4

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


Re: [PATCH v5 1/5] cli: slightly refactor "notmuch reply" address scanning functions

2012-01-14 Thread Jani Nikula

For those not on IRC:

On Sat, 14 Jan 2012 11:31:16 -0400, David Bremner  wrote:
> This series definitely needs a NEWS item. 

id:"1326559168-29178-1-git-send-email-j...@nikula.org"

> Perhaps some kind soul could add a wiki entry explaining to people how
> to swap the bindings, just in case there people who don't like the
> "one-true-reply-bindings" (cough).

http://notmuchmail.org/emacstips/#index7h2


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


Re: [PATCH 2/4] reply: Add a JSON reply format.

2012-01-14 Thread Jani Nikula
On Sun,  8 Jan 2012 00:52:40 -0700, Adam Wolfe Gordon  
wrote:
> From: Adam Wolfe Gordon 
> 
> This new JSON format for replies includes headers generated for a reply
> message as well as the headers and all text parts of the original message.
> Using this data, a client can intelligently create a reply. For example,
> the emacs client will be able to create replies with quoted HTML parts by
> parsing the HTML parts using w3m.

Hi Adam, this is a drive-by-review on some things I spotted, but can't
say I would've thought the whole thing through. I'm pretty ignorant
about MIME parts etc. Please find comments inline.

The reply-to-sender set was just merged. You'll have conflicts both here
and in emacs code, but they should be trivial to sort out.


BR,
Jani.


> ---
>  notmuch-reply.c |  269 
> +++
>  1 files changed, 230 insertions(+), 39 deletions(-)
> 
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index f8d5f64..82df396 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -30,6 +30,15 @@ reply_headers_message_part (GMimeMessage *message);
>  static void
>  reply_part_content (GMimeObject *part);
>  
> +static void
> +reply_part_start_json (GMimeObject *part, int *part_count);
> +
> +static void
> +reply_part_content_json (GMimeObject *part);
> +
> +static void
> +reply_part_end_json (GMimeObject *part);
> +

I know there are existing forward declarations like this, but would it
be much trouble to arrange the code so that they were not needed at all?

>  static const notmuch_show_format_t format_reply = {
>  "",
>   "", NULL,
> @@ -46,6 +55,22 @@ static const notmuch_show_format_t format_reply = {
>  ""
>  };
>  
> +static const notmuch_show_format_t format_json = {
> +"",
> + "", NULL,
> + "", NULL, NULL, "",
> + "",
> + reply_part_start_json,
> + NULL,
> + NULL,
> + reply_part_content_json,
> + reply_part_end_json,
> + "",
> + "",
> + "", "",
> +""
> +};
> +
>  static void
>  show_reply_headers (GMimeMessage *message)
>  {
> @@ -147,6 +172,78 @@ reply_part_content (GMimeObject *part)
>  }
>  }
>  
> +static void
> +reply_part_start_json (GMimeObject *part, unused(int *part_count))
> +{
> +GMimeContentType *content_type = g_mime_object_get_content_type 
> (GMIME_OBJECT (part));
> +GMimeContentDisposition *disposition = 
> g_mime_object_get_content_disposition (part);
> +
> +if (g_mime_content_type_is_type (content_type, "text", "*") &&
> + (!disposition ||
> +  strcmp (disposition->disposition, GMIME_DISPOSITION_INLINE) == 0))
> +{
> + printf("{ ");
> +}
> +}
> +
> +static void
> +reply_part_end_json (GMimeObject *part)
> +{
> +GMimeContentType *content_type = g_mime_object_get_content_type 
> (GMIME_OBJECT (part));
> +GMimeContentDisposition *disposition = 
> g_mime_object_get_content_disposition (part);
> +
> +if (g_mime_content_type_is_type (content_type, "text", "*") &&
> + (!disposition ||
> +  strcmp (disposition->disposition, GMIME_DISPOSITION_INLINE) == 0))
> + printf ("}, ");
> +}

The two functions above, while small, are almost identical. Please move
the common stuff to a common helper, and you can have something like
this:

if (the_common_function (part))
printf ("}, ");

> +
> +static void
> +reply_part_content_json (GMimeObject *part)
> +{
> +GMimeContentType *content_type = g_mime_object_get_content_type 
> (GMIME_OBJECT (part));
> +GMimeContentDisposition *disposition = 
> g_mime_object_get_content_disposition (part);
> +
> +void *ctx = talloc_new (NULL);
> +
> +/* We only care about inline text parts for reply purposes */
> +if (g_mime_content_type_is_type (content_type, "text", "*") &&
> + (!disposition ||
> +  strcmp (disposition->disposition, GMIME_DISPOSITION_INLINE) == 0))

Oh, you can use the common helper here too.

> +{
> + GMimeStream *stream_memory = NULL, *stream_filter = NULL;

No need to initialize stream_memory here.

> + GMimeDataWrapper *wrapper;
> + GByteArray *part_content;
> + const char *charset;
> +
> + printf("\"content-type\": %s, \"content\": ",
> +json_quote_str(ctx, 
> g_mime_content_type_to_string(content_type)));

The style in notmuch is to have a space before the opening brace in
function calls. Check elsewhere also. I always forget that too. :)

> +
> + charset = g_mime_object_get_content_type_parameter (part, "charset");

AFAICT charset declaration and the above call could be moved inside "if
(stream_memory)" below.

> + stream_memory = g_mime_stream_mem_new ();
> + if (stream_memory) {
> + stream_filter = g_mime_stream_filter_new(stream_memory);
> + if (charset) {
> + g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
> +  g_mime_filter_charse

[PATCH 1/2] test: add known broken test for reply from address in named group list

2012-01-14 Thread Jani Nikula
If a message was received to the user's address that was in a named
group list, notmuch reply does not use that address for picking the
from address.

Groups lists are of the form: foo:b...@example.com,b...@example.com;

Signed-off-by: Jani Nikula 
---
 test/reply |   19 +++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/test/reply b/test/reply
index c0b8e26..196535a 100755
--- a/test/reply
+++ b/test/reply
@@ -72,6 +72,25 @@ References: <${gen_msg_id}>
 On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
 > reply from alternate address"
 
+test_begin_subtest "Reply from address in named group list"
+test_subtest_known_broken
+add_message '[from]="Sender "' \
+'[to]=group:test_su...@notmuchmail.org,some...@example.com\;' \
+ [cc]=test_suite_ot...@notmuchmail.org \
+ [subject]=notmuch-reply-test \
+'[date]="Tue, 05 Jan 2010 15:43:56 -"' \
+'[body]="Reply from address in named group list"'
+
+output=$(notmuch reply id:${gen_msg_id})
+test_expect_equal "$output" "From: Notmuch Test Suite 

+Subject: Re: notmuch-reply-test
+To: Sender , some...@example.com
+In-Reply-To: <${gen_msg_id}>
+References: <${gen_msg_id}>
+
+On Tue, 05 Jan 2010 15:43:56 -, Sender  wrote:
+> Reply from address in named group list"
+
 test_begin_subtest "Support for Reply-To"
 add_message '[from]="Sender "' \
  [to]=test_su...@notmuchmail.org \
-- 
1.7.5.4

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


[PATCH 2/2] cli: pick the user's address in a group list as from address

2012-01-14 Thread Jani Nikula
Messages received to a group list were not replied to using the from
address in the list. Fix it.

Signed-off-by: Jani Nikula 
---
 notmuch-reply.c |2 +-
 test/reply  |1 -
 2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index da3acce..0f682db 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -203,7 +203,7 @@ scan_address_list (InternetAddressList *list,
if (group_list == NULL)
continue;
 
-   n += scan_address_list (group_list, config, message, type, NULL);
+   n += scan_address_list (group_list, config, message, type, 
user_from);
} else {
InternetAddressMailbox *mailbox;
const char *name;
diff --git a/test/reply b/test/reply
index 196535a..e4e16eb 100755
--- a/test/reply
+++ b/test/reply
@@ -73,7 +73,6 @@ On Tue, 05 Jan 2010 15:43:56 -, Sender 
 wrote:
 > reply from alternate address"
 
 test_begin_subtest "Reply from address in named group list"
-test_subtest_known_broken
 add_message '[from]="Sender "' \
 '[to]=group:test_su...@notmuchmail.org,some...@example.com\;' \
  [cc]=test_suite_ot...@notmuchmail.org \
-- 
1.7.5.4

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


Re: [PATCH v3 09/10] random-dump.c: new test-binary to generate dump files

2012-01-15 Thread Jani Nikula
On Jan 15, 2012 3:41 AM, "David Bremner"  wrote:
>
> From: David Bremner 
>
> This binary creates a "torture test" dump file for the new dump
> format.
> ---
>  test/Makefile.local |4 ++
>  test/basic  |2 +-
>  test/random-dump.c  |  144
+++
>  3 files changed, 149 insertions(+), 1 deletions(-)
>  create mode 100644 test/random-dump.c
>
> diff --git a/test/Makefile.local b/test/Makefile.local
> index ba697f4..b59f837 100644
> --- a/test/Makefile.local
> +++ b/test/Makefile.local
> @@ -16,6 +16,9 @@ $(dir)/arg-test: $(dir)/arg-test.o
command-line-arguments.o util/libutil.a
>  $(dir)/hex-xcode: $(dir)/hex-xcode.o command-line-arguments.o
util/libutil.a
>$(call quiet,CC) -I. $^ -o $@ -ltalloc
>
> +$(dir)/random-dump:  $(dir)/random-dump.o command-line-arguments.o
util/libutil.a
> +   $(call quiet,CC) -I. $^ -o $@ -ltalloc -lm
> +
>  $(dir)/smtp-dummy: $(smtp_dummy_modules)
>$(call quiet,CC) $^ -o $@
>
> @@ -25,6 +28,7 @@ $(dir)/symbol-test: $(dir)/symbol-test.o
>  .PHONY: test check
>
>  test-binaries: $(dir)/arg-test $(dir)/hex-xcode \
> +   $(dir)/random-dump \
> $(dir)/smtp-dummy $(dir)/symbol-test
>
>  test:  all test-binaries
> diff --git a/test/basic b/test/basic
> index af57026..e3a6cef 100755
> --- a/test/basic
> +++ b/test/basic
> @@ -54,7 +54,7 @@ test_begin_subtest 'Ensure that all available tests
will be run by notmuch-test'
>  eval $(sed -n -e '/^TESTS="$/,/^"$/p' $TEST_DIRECTORY/notmuch-test)
>  tests_in_suite=$(for i in $TESTS; do echo $i; done | sort)
>  available=$(find "$TEST_DIRECTORY" -maxdepth 1 -type f -executable
-printf '%f\n' | \
> -sed -r -e
"/^(aggregate-results.sh|notmuch-test|smtp-dummy|test-verbose|symbol-test|arg-test|hex-xcode)$/d"
| \
> +sed -r -e
"/^(aggregate-results.sh|notmuch-test|smtp-dummy|test-verbose|symbol-test|arg-test|hex-xcode|random-dump)$/d"
| \
> sort)
>  test_expect_equal "$tests_in_suite" "$available"
>
> diff --git a/test/random-dump.c b/test/random-dump.c
> new file mode 100644
> index 000..1949425
> --- /dev/null
> +++ b/test/random-dump.c
> @@ -0,0 +1,144 @@
> +/*
> +   Generate a random dump file in 'notmuch' format.
> +   Generated message-id's and tags are intentionally nasty.
> +
> +   We restrict ourselves to 7 bit message-ids, because generating
> +   random valid UTF-8 seems like work. And invalid UTF-8 can't be
> +   round-tripped via Xapian.
> +
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include "math.h"
> +#include "hex-escape.h"
> +#include "command-line-arguments.h"
> +
> +static void
> +hex_out (void *ctx, char *buf)
> +{
> +static char *encoded_buf = NULL;
> +static size_t encoded_buf_size = 0;
> +
> +if (hex_encode (ctx, buf, &encoded_buf, &encoded_buf_size) !=
HEX_SUCCESS) {
> +   fprintf (stderr, "Hex encoding failed");
> +   exit (1);
> +}
> +
> +fputs (encoded_buf, stdout);
> +}
> +
> +static void
> +random_chars (char *buf, int from, int stop, int max_char,
> + const char *blacklist)
> +{
> +int i;
> +
> +for (i = from; i < stop; i++) {
> +   do {
> +   buf[i] = ' ' + (random () % (max_char - ' '));
> +   } while (blacklist && strchr (blacklist, buf[i]));
> +}
> +}
> +
> +static void
> +random_tag (void *ctx, size_t len)
> +{
> +static char *buf = NULL;
> +static size_t buf_len = 0;
> +
> +int use = (random () % (len - 1)) + 1;
> +
> +if (len > buf_len) {
> +   buf = talloc_realloc (ctx, buf, char, len);
> +   buf_len = len;
> +}
> +
> +random_chars (buf, 0, use, 255, NULL);
> +
> +buf[use] = '\0';
> +
> +hex_out (ctx, buf);
> +}
> +
> +static void
> +random_message_id (void *ctx, size_t len)
> +{
> +static char *buf = NULL;
> +static size_t buf_len = 0;
> +
> +int lhs_len = (random () % (len / 2 - 1)) + 1;
> +
> +int rhs_len = (random () % len / 2) + 1;
> +
> +const char *blacklist = "\n\r@<>[]()";
> +
> +if (len > buf_len) {
> +   buf = talloc_realloc (ctx, buf, char, len);
> +   buf_len = len;
> +}
> +
> +random_chars (buf, 0, lhs_len, 127, blacklist);
> +
> +buf[lhs_len] = '@';
> +
> +random_chars (buf, lhs_len + 1, lhs_len + rhs_len + 1, 127,
blacklist);
> +
> +hex_out (ctx, buf);
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> +
> +void *ctx = talloc_new (NULL);
> +int num_lines = 500;
> +int max_tags = 10;
> +int message_id_len = 100;
> +int tag_len = 50;
> +int seed = 734569;
> +
> +int pad_tag = 0, pad_mid = 0;
> +
> +notmuch_opt_desc_t options[] = {
> +   { NOTMUCH_OPT_INT, &num_lines, "num-lines", 'n', 0 },
> +   { NOTMUCH_OPT_INT, &max_tags, "max-tags", 'm', 0 },
> +   { NOTMUCH_OPT_INT, &message_id_len, "message-id-len", 'M', 0 },
> +   { NOTMUCH_OPT_INT, &tag_len, "tag-len", 't', 0 },
> +   { NOTMUCH_OPT_INT, &seed, "tag-len", 't', 0 },

s/tag-len/seed/

> +   { 0, 0, 0,

Re: [PATCH 1/4] emacs: unify search mechanisms

2012-01-16 Thread Jani Nikula
On Mon, 16 Jan 2012 15:39:14 +0400, Dmitry Kurochkin 
 wrote:
> On Mon, 16 Jan 2012 11:35:37 +, David Edmondson  wrote:
> > On Sun, 25 Dec 2011 08:14:52 +0400, Dmitry Kurochkin 
> >  wrote:
> > > Before the change, there were two ways to do search in Emacs UI:
> > > search widget in notmuch-hello buffer and `notmuch-search'
> > > function bound to "s".  Internally, notmuch-hello search widget
> > > uses `notmuch-search' function.  But it uses widget field input
> > > instead of minibuffer.  Such duplication is a major issue for
> > > notmuch-hello usability: search interface is inconsistent and
> > > lacks features that are available in minibuffer (e.g. history and
> > > auto completion).  Some of these features may be relatively easy
> > > to implement for notmuch-hello search, others would be much more
> > > tricky.  So to avoid duplication, make UI more consistent, bring
> > > notmuch-hello search to feature parity with the minibuffer
> > > search, the patch replaces notmuch-hello search widget and with a
> > > button that works the same way as "s" key binding.
> > 
> > Dmitry, if Daniel re-submits his patches to allow the construction of
> > `notmuch-hello' buffers to be configured, it seems that this patchset
> > would become unnecessary. Is that correct?
> 
> Right.  We will just need to fix the 's' key binding.  Looking forward
> for that.

Isn't (something like) this still needed to merge the search histories:

id:"1324698436-8532-1-git-send-email-dmitry.kuroch...@gmail.com"


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


Re: [PATCH] v2 [RFC] emacs: merge overhauled `notmuch-cycle-notmuch-buffers' into `notmuch'

2012-01-16 Thread Jani Nikula
On Mon, 16 Jan 2012 17:46:55 +0100, Pieter Praet  wrote:
> Make `notmuch-cycle-notmuch-buffers' more Lispy and merge into `notmuch',
> eliminating the need to hog yet another keybind.

What does "merge" mean here? Will it still be possible for me to hit one
key to unconditionally get to notmuch-hello, and another to cycle
through the buffers? I wouldn't want to lose that ability.

> ---
>  emacs/notmuch.el |   40 ++--
>  1 files changed, 14 insertions(+), 26 deletions(-)
> 
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index ef4dcc7..539b3a0 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -1067,7 +1067,20 @@ current search results AND that are tagged with the 
> given tag."
>  (defun notmuch ()
>"Run notmuch and display saved searches, known tags, etc."
>(interactive)
> -  (notmuch-hello))
> +  (let* ((old-buffer (current-buffer))
> +  (interesting-buffers
> +   (delq nil (mapcar (lambda (b)
> +   (if (notmuch-interesting-buffer b) b))
> + (buffer-list
> +  (next-buffer (first
> +   (delq nil (mapcar (lambda (b)
> +   (unless (eq old-buffer b) b))
> + interesting-buffers)
> +(if next-buffer
> + (progn
> +   (switch-to-buffer next-buffer)
> +   (bury-buffer old-buffer))
> +  (notmuch-hello

notmuch-cycle-notmuch-buffers pretty much explains in the name what it
does, but additionally it has documentation, and explanatory
comments. Please don't drop those.

BR,
Jani



>  
>  (defun notmuch-interesting-buffer (b)
>"Is the current buffer of interest to a notmuch user?"
> @@ -1078,31 +1091,6 @@ current search results AND that are tagged with the 
> given tag."
>  message-mode
>  
>  ;;;###autoload
> -(defun notmuch-cycle-notmuch-buffers ()
> -  "Cycle through any existing notmuch buffers (search, show or hello).
> -
> -If the current buffer is the only notmuch buffer, bury it. If no
> -notmuch buffers exist, run `notmuch'."
> -  (interactive)
> -
> -  (let (start first)
> -;; If the current buffer is a notmuch buffer, remember it and then
> -;; bury it.
> -(when (notmuch-interesting-buffer (current-buffer))
> -  (setq start (current-buffer))
> -  (bury-buffer))
> -
> -;; Find the first notmuch buffer.
> -(setq first (loop for buffer in (buffer-list)
> -  if (notmuch-interesting-buffer buffer)
> -  return buffer))
> -
> -(if first
> - ;; If the first one we found is any other than the starting
> - ;; buffer, switch to it.
> - (unless (eq first start)
> -   (switch-to-buffer first))
> -  (notmuch
>  
>  (setq mail-user-agent 'notmuch-user-agent)
>  
> -- 
> 1.7.8.1
> 
> ___
> 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: [PATCH v2] Document external dependencies in the test suite

2012-01-16 Thread Jani Nikula
On Mon, 16 Jan 2012 22:09:55 +0100, Xavier Maillard  wrote:
> Hi,
> 
> On Mon, 16 Jan 2012 13:52:47 -0500, Ethan Glasser-Camp  
> wrote:
> 
> [...]
> 
> > +Prerequisites
> > +-
> > +Some tests require external dependencies to run. Without them, they
> > +will be skipped, or (rarely) marked failed. Please install these, so
> > +that you know if you break anything.
> > +
> > +  - dtach(1)
> > +  - emacs(1)
> > +  - emacsclient(1)
> > +  - gdb(1)
> > +  - gpg(1)
> > +  - python(1)
> 
> Looks good but just a nit: what is the meaning of the '1' ?

It's the man page section. See 'man man'.

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


Re: [PATCH] emacs: Don't attempt to colour tags in `notmuch-show-mode'.

2012-01-16 Thread Jani Nikula
On Mon, 16 Jan 2012 15:51:30 -0500, Aaron Ecay  wrote:
> On Mon, 16 Jan 2012 11:22:27 +, David Edmondson  wrote:
> > On Mon, 16 Jan 2012 12:17:03 +0100, Pieter Praet  wrote:
> > > Alas, those text properties actually *were* effective (and I liked them :)
> > 
> > Well, not in emacs 24. My reading of the source was that overlays were
> > intended to stomp on text properties, but that could have been wrong.
> > 
> > Do they look correct when you add/remove tags?
> 
> The tags look nice and yellow-green for me too on a trunk build of emacs
> (which is one flavor of emacs 24).  Adding and removing tags works as
> expected – the tags dis/appear and are the right color.
> 
> I haven’t reloaded the notmuch *.el files since this change landed, but
> I agree with Pieter that the overlays were nice.

Missing them too. Emacs 23.3.1.

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


Re: Partial words on notmuch search?

2012-01-17 Thread Jani Nikula
On Mon, 16 Jan 2012 21:34:31 -0500, Austin Clements  wrote:
> Quoth Andrei Popescu on Jan 16 at 10:21 pm:
> > This is also interesting:
> > $ notmuch count 'debian'
> > 65888
> > $ notmuch count 'dEbian'
> > 65888
> > $ notmuch count 'Debian'
> > 65887
> 
> The first two will match stemmed versions of "debian" such as
> "debian's" and "debianed".  However, starting a term with a capital
> letter suppresses stemming (because it suggests that it's a name,
> which you wouldn't want to modify), so your last query matches only
> the term "debian".  This is probably documented somewhere, though I
> don't know where.

Interesting. Is this done when adding the terms to the database, or when
searching? I presume the latter. How much control does notmuch have over
this?

The assumption that one wouldn't want to have stemming for names is very
much language dependent. [1]

BR,
Jani.


[1] http://en.wikipedia.org/wiki/Finnish_noun_cases (the same works for
names as well as nouns)
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] fix .gitignore for gzipped man pages

2012-01-17 Thread Jani Nikula
---
 .gitignore |1 -
 man/.gitignore |2 ++
 2 files changed, 2 insertions(+), 1 deletions(-)
 create mode 100644 man/.gitignore

diff --git a/.gitignore b/.gitignore
index d64ec9f..d428290 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,6 @@ tags
 /notmuch
 notmuch.sym
 notmuch-shared
-notmuch.1.gz
 libnotmuch.so*
 libnotmuch*.dylib
 *.[ao]
diff --git a/man/.gitignore b/man/.gitignore
new file mode 100644
index 000..26ead20
--- /dev/null
+++ b/man/.gitignore
@@ -0,0 +1,2 @@
+# ignore gzipped man pages
+*.[0-9].gz
-- 
1.7.5.4

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


Re: on deleting messages

2012-01-17 Thread Jani Nikula
On Tue, 17 Jan 2012 11:01:45 -0800, Jameson Graef Rollins 
 wrote:
> Now that Austin's excellent tag exclusion patch set [0] has been pushed,
> the question remains if we want to support any delete-handling key
> bindings in emacs.
> 
> Based on the show-mode improvements I recently sent [1], the following
> patch set implements thread and message delete keys.
> 
> This is the last I'm going to comment on this issue.  If we don't want
> to support this, we should put together something on the wiki that
> states we don't want to support it and that users should just bind it
> themselves (with a nice explanation how), so that we can try to reduce
> the number of future patches on the issue.
> 
> Given the number of patches we've had on this issue, though, it's clear
> that a lot of people expect this functionality, so we may want to
> seriously consider supporting it.  Given Austin's tag exclusion stuff,
> and the fact that "deleted" tags are excluded by default, we now have
> the functionality that Carl originally wanted to see, so it's not so
> unreasonable to support this functionality anymore.

I think it's reasonable to consider having key bindings (or other
special handling) for pretty much *any* tags that are special to
notmuch: inbox, unread, draft, flagged, etc. (An exhaustive list should
be documented somewhere.)

Looking at the source and history, I have to admit there has been
intent, and code, to have support for "deleted" tag. See for example
TODO or [1].

And I agree there has been demand for this.

I say let's have this.

But make it clear that "deleted" is just a tag; that the messages aren't
going away, not by notmuch anyway.


BR,
Jani.

[1] commit 2c262042ac174d7bc96d6035ab9c88bd0abe7f35
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/3] emacs: bind "s" to `notmuch-search' in notmuch-hello buffer

2012-01-17 Thread Jani Nikula
On Tue, 17 Jan 2012 23:34:08 +0400, Dmitry Kurochkin 
 wrote:
> Before the change, "s" in notmuch-hello buffer would jump to the
> search box.  The patch changes the binding to `notmuch-search' which
> is consistent with all other notmuch buffers.
> ---
>  emacs/notmuch-hello.el |   19 ++-
>  1 files changed, 6 insertions(+), 13 deletions(-)
> 
> diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
> index 02017ce..08fcd22 100644
> --- a/emacs/notmuch-hello.el
> +++ b/emacs/notmuch-hello.el
> @@ -29,9 +29,6 @@
>  (declare-function notmuch-search "notmuch" (query &optional oldest-first 
> target-thread target-line continuation))
>  (declare-function notmuch-poll "notmuch" ())
>  
> -(defvar notmuch-hello-search-bar-marker nil
> -  "The position of the search bar within the notmuch-hello buffer.")
> -
>  (defcustom notmuch-recent-searches-max 10
>"The number of recent searches to store and display."
>:type 'integer
> @@ -321,11 +318,6 @@ should be. Returns a cons cell `(tags-per-line width)'."
>   (widget-insert "\n"))
>  found-target-pos))
>  
> -(defun notmuch-hello-goto-search ()
> -  "Put point inside the `search' widget."
> -  (interactive)
> -  (goto-char notmuch-hello-search-bar-marker))

After this, what would the user have to do to bind some key to put the
point in the search box? If someone wants to restore old behaviour for
themselves.

Also, it's perhaps out of scope for this patch, but it will become more
evident now that notmuch-search does not respect
notmuch-search-oldest-first when called without parameters like the new
's' keybinding does. This is the same in search view.


BR,
Jani.


> -
>  (defimage notmuch-hello-logo ((:type png :file "notmuch-logo.png")))
>  
>  (defun notmuch-hello-search-continuation()
> @@ -355,7 +347,7 @@ should be. Returns a cons cell `(tags-per-line width)'."
>  (define-key map "G" 'notmuch-hello-poll-and-update)
>  (define-key map (kbd "") 'widget-backward)
>  (define-key map "m" 'notmuch-mua-new-mail)
> -(define-key map "s" 'notmuch-hello-goto-search)
> +(define-key map "s" 'notmuch-search)
>  map)
>"Keymap for \"notmuch hello\" buffers.")
>  (fset 'notmuch-hello-mode-map notmuch-hello-mode-map)
> @@ -468,7 +460,8 @@ Complete list of currently available key bindings:
>(widget-insert " messages.\n"))
>  
>  (let ((found-target-pos nil)
> -   (final-target-pos nil))
> +   (final-target-pos nil)
> +   (search-bar-pos))
>(let* ((saved-alist
> ;; Filter out empty saved searches if required.
> (if notmuch-show-empty-saved-searches
> @@ -500,7 +493,7 @@ Complete list of currently available key bindings:
>   (indent-rigidly start (point) notmuch-hello-indent)))
>  
>   (widget-insert "\nSearch: ")
> - (setq notmuch-hello-search-bar-marker (point-marker))
> + (setq search-bar-pos (point-marker))
>   (widget-create 'editable-field
>  ;; Leave some space at the start and end of the
>  ;; search boxes.
> @@ -589,7 +582,7 @@ Complete list of currently available key bindings:
>   (when notmuch-saved-searches
> (widget-insert "Edit saved searches with the `edit' button.\n"))
>   (widget-insert "Hit RET or click on a saved search or tag name to view 
> matching threads.\n")
> - (widget-insert "`=' refreshes this screen. `s' jumps to the search box. 
> `q' to quit.\n")
> + (widget-insert "`=' refreshes this screen. `s' to search messages. `q' 
> to quit.\n")
>   (let ((fill-column (- (window-width) notmuch-hello-indent)))
> (center-region start (point
>  
> @@ -601,7 +594,7 @@ Complete list of currently available key bindings:
> (widget-forward 1)))
>  
>(unless (widget-at)
> - (notmuch-hello-goto-search
> + (goto-char search-bar-pos
>  
>(run-hooks 'notmuch-hello-refresh-hook))
>  
> -- 
> 1.7.8.3
> 
> ___
> 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: [PATCH 1/3] mime node: Record depth-first part numbers

2012-01-18 Thread Jani Nikula
On Wed, 18 Jan 2012 15:28:25 -0500, Austin Clements  wrote:
> This makes the part numbers readily accessible to formatters.
> Hierarchical part numbering would be a more natural and efficient fit
> for MIME and may be the way to go in the future, but depth-first
> numbering maintains compatibility with what we currently do.

Hi, please find a few things to consider below. If you disagree after
considering, it's quite all right, as they're largely style matters. :)

BR,
Jani.


> ---
>  mime-node.c  |   33 -
>  notmuch-client.h |   11 +++
>  2 files changed, 43 insertions(+), 1 deletions(-)
> 
> diff --git a/mime-node.c b/mime-node.c
> index d26bb44..30b542f 100644
> --- a/mime-node.c
> +++ b/mime-node.c
> @@ -104,6 +104,10 @@ mime_node_open (const void *ctx, notmuch_message_t 
> *message,
>  root->nchildren = 1;
>  root->ctx = mctx;
>  
> +root->part_num = 0;
> +root->next_child = 0;
> +root->next_part_num = 1;
> +
>  *root_out = root;
>  return NOTMUCH_STATUS_SUCCESS;
>  
> @@ -133,6 +137,8 @@ _mime_node_create (const mime_node_t *parent, GMimeObject 
> *part)
>   talloc_free (node);
>   return NULL;
>  }
> +node->parent = parent;
> +node->part_num = node->next_part_num = -1;
>  
>  /* Deal with the different types of parts */
>  if (GMIME_IS_PART (part)) {
> @@ -217,6 +223,7 @@ mime_node_t *
>  mime_node_child (const mime_node_t *parent, int child)
>  {
>  GMimeObject *sub;
> +mime_node_t *node;
>  
>  if (!parent || child < 0 || child >= parent->nchildren)
>   return NULL;
> @@ -234,7 +241,31 @@ mime_node_child (const mime_node_t *parent, int child)
>   INTERNAL_ERROR ("Unexpected GMimeObject type: %s",
>   g_type_name (G_OBJECT_TYPE (parent->part)));
>  }
> -return _mime_node_create (parent, sub);
> +node = _mime_node_create (parent, sub);
> +
> +if (child == parent->next_child && parent->next_part_num != -1) {
> + /* We're traversing in depth-first order.  Record the child's
> +  * depth-first numbering. */
> + node->part_num = parent->next_part_num;
> + node->next_part_num = node->part_num + 1;
> +
> + /* Drop the const qualifier because these are internal fields
> +  * whose mutability doesn't affect the interface. */

FWIW, I'm not a big fan of casting away const. Either it is const, or it
isn't. Not very many places would be affected if you dropped the const
qualifier from the related interface(s) altogether, and things would
look cleaner here. But I suppose this is a matter of taste.

> + ((mime_node_t*)parent)->next_child++;
> + ((mime_node_t*)parent)->next_part_num = -1;
> +
> + if (node->nchildren == 0) {
> + /* We've reached a leaf, so find the parent that has more
> +  * children and set it up to number its next child. */
> + const mime_node_t *it = node;
> + while (it && it->next_child == it->nchildren)
> + it = it->parent;
> + if (it)
> + ((mime_node_t*)it)->next_part_num = node->part_num + 1;
> + }
> +}

Following the constness around made me wonder why the above if block
isn't within _mime_node_create(). It does have a feel of initialization
related to creation in it. (You'd have to pass more info to it though.)

> +
> +return node;
>  }
>  
>  static mime_node_t *
> diff --git a/notmuch-client.h b/notmuch-client.h
> index 62ede28..b3dcb6b 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -281,6 +281,13 @@ typedef struct mime_node {
>  /* The number of children of this part. */
>  int nchildren;
>  
> +/* The parent of this node or NULL if this is the root node. */
> +const struct mime_node *parent;
> +
> +/* The depth-first part number of this child if the MIME tree is
> + * being traversed in depth-first order, or -1 otherwise. */
> +int part_num;
> +
>  /* True if decryption of this part was attempted. */
>  notmuch_bool_t decrypt_attempted;
>  /* True if decryption of this part's child succeeded.  In this
> @@ -302,6 +309,10 @@ typedef struct mime_node {
>  /* Internal: For successfully decrypted multipart parts, the
>   * decrypted part to substitute for the second child. */
>  GMimeObject *decrypted_child;
> +
> +/* Internal: The next child for depth-first traversal and the part
> + * number to assign it (or -1 if unknown). */
> +int next_child, next_part_num;

A matter of taste again, but I wouldn't use "int foo, bar" in struct
declarations.

>  } mime_node_t;
>  
>  /* Construct a new MIME node pointing to the root message part of
> -- 
> 1.7.7.3
> 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 3/3] show: Introduce mime_node formatter callback

2012-01-18 Thread Jani Nikula
On Wed, 18 Jan 2012 15:28:27 -0500, Austin Clements  wrote:
> This callback is the gateway to the new mime_node_t-based formatters.
> This maintains backwards compatibility so the formatters can be
> transitioned one at a time.  Once all formatters are converted, the
> formatter structure can be reduced to only message_set_{start,sep,end}
> and part, most of show_message can be deleted, and all of
> show-message.c can be deleted.
> ---
>  notmuch-client.h |6 ++
>  notmuch-reply.c  |2 +-
>  notmuch-show.c   |   22 ++
>  3 files changed, 25 insertions(+), 5 deletions(-)
> 
> diff --git a/notmuch-client.h b/notmuch-client.h
> index b3dcb6b..3ccdfad 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -54,8 +54,14 @@
>  #define STRINGIFY(s) STRINGIFY_(s)
>  #define STRINGIFY_(s) #s
>  
> +struct mime_node;
> +struct notmuch_show_params;
> +
>  typedef struct notmuch_show_format {
>  const char *message_set_start;
> +void (*part) (const void *ctx,
> +   struct mime_node *node, int indent,
> +   struct notmuch_show_params *params);
>  const char *message_start;
>  void (*message) (const void *ctx,
>notmuch_message_t *message,
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index 0f682db..9a224e2 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -31,7 +31,7 @@ static void
>  reply_part_content (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_reply = {
> -"",
> +"", NULL,
>   "", NULL,
>   "", NULL, reply_headers_message_part, ">\n",
>   "",
> diff --git a/notmuch-show.c b/notmuch-show.c
> index ecadfa8..46eef44 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -42,7 +42,7 @@ static void
>  format_part_end_text (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_text = {
> -"",
> +"", NULL,
>   "\fmessage{ ", format_message_text,
>   "\fheader{\n", format_headers_text, 
> format_headers_message_part_text, "\fheader}\n",
>   "\fbody{\n",
> @@ -85,7 +85,7 @@ static void
>  format_part_end_json (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_json = {
> -"[",
> +"[", NULL,
>   "{", format_message_json,
>   "\"headers\": {", format_headers_json, 
> format_headers_message_part_json, "}",
>   ", \"body\": [",
> @@ -106,7 +106,7 @@ format_message_mbox (const void *ctx,
>unused (int indent));
>  
>  static const notmuch_show_format_t format_mbox = {
> -"",
> +"", NULL,
>  "", format_message_mbox,
>  "", NULL, NULL, "",
>  "",
> @@ -125,7 +125,7 @@ static void
>  format_part_content_raw (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_raw = {
> -"",
> +"", NULL,
>   "", NULL,
>   "", NULL, format_headers_message_part_text, "\n",
>  "",
> @@ -762,6 +762,20 @@ show_message (void *ctx,
> int indent,
> notmuch_show_params_t *params)
>  {
> +if (format->part) {
> + void *local = talloc_new (ctx);
> + mime_node_t *root, *part;
> +
> + if (mime_node_open (local, message, params->cryptoctx, params->decrypt,
> + &root) != NOTMUCH_STATUS_SUCCESS)

I'm new to talloc, I think I like it, but I always find it confusing
when some code paths free the contexts, and some don't. Like here.

Are you not freeing the local context here because it's just an empty
context, and freeing below because it's no longer empty?

No need to change anything, I guess, just asking...

BR,
Jani.

> + return;
> + part = mime_node_seek_dfs (root, params->part < 0 ? 0 : params->part);
> + if (part)
> + format->part (local, part, indent, params);
> + talloc_free (local);
> + return;
> +}
> +
>  if (params->part <= 0) {
>   fputs (format->message_start, stdout);
>   if (format->message)
> -- 
> 1.7.7.3
> 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v2 2/4] reply: Add a JSON reply format.

2012-01-18 Thread Jani Nikula
On Mon, 16 Jan 2012 11:13:21 -0700, Adam Wolfe Gordon  
wrote:
> This new JSON format for replies includes headers generated for a reply
> message as well as the headers and all text parts of the original message.
> Using this data, a client can intelligently create a reply. For example,
> the emacs client will be able to create replies with quoted HTML parts by
> parsing the HTML parts using w3m.

Hi, admittedly not a very thorough review, but please find a couple of
comments below.

BR,
Jani.


> ---
>  notmuch-reply.c |  313 
> ---
>  1 files changed, 253 insertions(+), 60 deletions(-)
> 
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index da3acce..f5a5dcf 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -30,6 +30,15 @@ reply_headers_message_part (GMimeMessage *message);
>  static void
>  reply_part_content (GMimeObject *part);
>  
> +static void
> +reply_part_start_json (GMimeObject *part, int *part_count);
> +
> +static void
> +reply_part_content_json (GMimeObject *part);
> +
> +static void
> +reply_part_end_json (GMimeObject *part);
> +
>  static const notmuch_show_format_t format_reply = {
>  "",
>   "", NULL,
> @@ -46,6 +55,22 @@ static const notmuch_show_format_t format_reply = {
>  ""
>  };
>  
> +static const notmuch_show_format_t format_json = {
> +"",
> + "", NULL,
> + "", NULL, NULL, "",
> + "",
> + reply_part_start_json,
> + NULL,
> + NULL,
> + reply_part_content_json,
> + reply_part_end_json,
> + "",
> + "",
> + "", "",
> +""
> +};
> +
>  static void
>  show_reply_headers (GMimeMessage *message)
>  {
> @@ -54,14 +79,14 @@ show_reply_headers (GMimeMessage *message)
>  stream_stdout = g_mime_stream_file_new (stdout);
>  if (stream_stdout) {
>   g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
> - stream_filter = g_mime_stream_filter_new(stream_stdout);
> + stream_filter = g_mime_stream_filter_new (stream_stdout);
>   if (stream_filter) {
> - g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
> -  g_mime_filter_headers_new());
> - g_mime_object_write_to_stream(GMIME_OBJECT(message), 
> stream_filter);
> - g_object_unref(stream_filter);
> + g_mime_stream_filter_add (GMIME_STREAM_FILTER(stream_filter),
> +   g_mime_filter_headers_new());
> + g_mime_object_write_to_stream (GMIME_OBJECT(message), 
> stream_filter);
> + g_object_unref (stream_filter);
>   }
> - g_object_unref(stream_stdout);
> + g_object_unref (stream_stdout);

I know I asked you to adhere to notmuch coding style like above, but I
meant in the context of your patch, not elsewhere. Cleanups like this
should really be separate patches. Sorry if I was ambiguous.

>  }
>  }
>  
> @@ -86,6 +111,17 @@ reply_headers_message_part (GMimeMessage *message)
>  printf ("> Date: %s\n", g_mime_message_get_date_as_string (message));
>  }
>  
> +static notmuch_bool_t
> +reply_check_part_type (GMimeObject *part, const char *type, const char 
> *subtype,
> +const char *disposition)
> +{
> +GMimeContentType *content_type = g_mime_object_get_content_type 
> (GMIME_OBJECT (part));
> +GMimeContentDisposition *part_disposition = 
> g_mime_object_get_content_disposition (part);
> +
> +return (g_mime_content_type_is_type (content_type, type, subtype) &&
> + (!part_disposition ||
> +  strcmp (part_disposition->disposition, disposition) == 0));
> +}
>  
>  static void
>  reply_part_content (GMimeObject *part)
> @@ -108,32 +144,29 @@ reply_part_content (GMimeObject *part)
>  {
>   GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
>   GMimeDataWrapper *wrapper;
> - const char *charset;
> -
> - charset = g_mime_object_get_content_type_parameter (part, "charset");
>   stream_stdout = g_mime_stream_file_new (stdout);
>   if (stream_stdout) {
>   g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), 
> FALSE);
> - stream_filter = g_mime_stream_filter_new(stream_stdout);
> - if (charset) {
> - g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
> -  g_mime_filter_charset_new(charset, 
> "UTF-8"));
> - }
> + stream_filter = g_mime_stream_filter_new (stream_stdout);
> +
> + const char *charset = g_mime_object_get_content_type_parameter 
> (part, "charset");
> + if (charset)
> + g_mime_stream_filter_add(GMIME_STREAM_FILTER (stream_filter),
> +  g_mime_filter_charset_new (charset, 
> "UTF-8"));
>   }
> - g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
> -  g_mime_f

Re: [PATCH 0/2] Fix or silence "unused result" warnings

2012-01-19 Thread Jani Nikula
On Wed, 18 Jan 2012 19:40:09 -0500, Austin Clements  wrote:
> I'm afraid I bikeshedded dme's original patch for this into oblivion
> (id:"1324503532-5799-1-git-send-email-...@dme.org") and we still have
> these warnings on the buildbot.  Tomi convinced me that dme was right
> and I was wrong, so I'm bringing dme's patch back.

I'm afraid I contributed to the bikeshedding... My apologies to dme. The
series looks good.

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


Re: [PATCH] lib: Save filenames for files detected as "not an email file" in the database.

2012-01-21 Thread Jani Nikula
On Fri, 20 Jan 2012 17:00:27 -0500, Austin Clements  wrote:
> Later runs of "notmuch new" won't scan these files again and won't
> print warnings.
> 
> Various programs (Dovecot, in my case) store indexes and caches and
> such in the maildir.  Without this, notmuch persistently complains
> about such files.

Overall, sounds good and doing this automagically is nice. Superficially
the code looks sensible, but I didn't really dig into it. A few nasty
questions instead:

What happens if you delete a non-email file? Does the entry stay in the
database?

What happens if you replace a non-email file with an email file?

Does it matter what happens above?

These are corner cases, but what remains in TODO suggests that it would
be difficult to debug and figure out if the above ever did happen to
someone.


BR,
Jani.


> ---
> Every time I run notmuch new I get a slew of these warnings.  It was
> starting to get on my nerves, so I implemented the solution suggested
> by the TODO file.
> 
>  devel/TODO  |9 +++--
>  lib/database.cc |   41 +
>  test/new|   23 +++
>  3 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/devel/TODO b/devel/TODO
> index 4dda6f4..b64a26e 100644
> --- a/devel/TODO
> +++ b/devel/TODO
> @@ -260,12 +260,9 @@ existing messages at the next database upgrade).
>  Add support for the user to specify custom headers to be indexed (and
>  re-index these for existing messages at the next database upgrade).
>  
> -Save filenames for files detected as "not an email file" in the
> -database. This would allow for two things: 1. Optimizing "notmuch new"
> -to not have to look at these files again (since they are potentially
> -large so the detection could be potentially slow). 2. A "notmuch
> -search" syntax could be added to allow the user to find these files,
> -(and perhaps delete them or move them away as appropriate).
> +Add a "notmuch search" syntax to allow uses to find files recorded as
> +non-emails in the database (and perhaps delete them or move them away
> +as appropriate).
>  
>  Fix filesystem/notmuch-new race condition by not updating database
>  mtime for a directory if it is the same as the current mtime.
> diff --git a/lib/database.cc b/lib/database.cc
> index 8103bd9..fd1ec6e 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -1618,6 +1618,43 @@ _notmuch_database_link_message (notmuch_database_t 
> *notmuch,
>  return NOTMUCH_STATUS_SUCCESS;
>  }
>  
> +static notmuch_status_t
> +_notmuch_database_add_nonemail (notmuch_database_t *notmuch,
> + const char *filename)
> +{
> +notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
> +void *local = talloc_new (notmuch);
> +char *term, *direntry;
> +Xapian::docid id;
> +
> +if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)
> + INTERNAL_ERROR ("Failure to ensure database is writable");
> +
> +Xapian::WritableDatabase *db =
> + static_cast  (notmuch->xapian_db);
> +
> +/* Create a document to record the non-email */
> +Xapian::Document nonemail;
> +term = talloc_asprintf (local, "%s%s", _find_prefix ("type"), 
> "nonemail");
> +nonemail.add_term (term, 0);
> +
> +status = _notmuch_database_filename_to_direntry (local, notmuch,
> +  filename, &direntry);
> +if (status)
> + goto DONE;
> +term = talloc_asprintf (local, "%s%s", _find_prefix ("file-direntry"),
> + direntry);
> +nonemail.add_term (term, 0);
> +
> +/* Add it to the database */
> +id = _notmuch_database_generate_doc_id (notmuch);
> +db->replace_document (id, nonemail);
> +
> +  DONE:
> +talloc_free (local);
> +return status;
> +}
> +
>  notmuch_status_t
>  notmuch_database_add_message (notmuch_database_t *notmuch,
> const char *filename,
> @@ -1673,6 +1710,10 @@ notmuch_database_add_message (notmuch_database_t 
> *notmuch,
>   (subject == NULL || *subject == '\0') &&
>   (to == NULL || *to == '\0'))
>   {
> + /* The file is not an email.  Record it so we don't
> +  * reconsider this file in the future, which prevents
> +  * potentially expensive scans and annoying warnings. */
> + _notmuch_database_add_nonemail (notmuch, filename);
>   ret = NOTMUCH_STATUS_FILE_NOT_EMAIL;
>   goto DONE;
>   }
> diff --git a/test/new b/test/new
> index 49f390d..346d453 100755
> --- a/test/new
> +++ b/test/new
> @@ -153,4 +153,27 @@ rm -rf "${MAIL_DIR}"/two
>  output=$(NOTMUCH_NEW)
>  test_expect_equal "$output" "No new mail. Removed 3 messages."
>  
> +
> +test_begin_subtest "Skips non-email"
> +PRE_COUNT=$(notmuch search '*' | wc -l)
> +echo "I am not an email" > "${MAIL_DIR}"/nonemail
> +output=$(NOTMUCH_NEW 2>&1 | sed -n '/^Note:/p;$p' | sed 's/\(file:\) .*/\1 
> XXX/')
> +test_expect_equal "$output" "Note: Ignorin

Re: [PATCH] lib: Save filenames for files detected as "not an email file" in the database.

2012-01-22 Thread Jani Nikula
On Sat, 21 Jan 2012 18:49:19 -0500, Austin Clements  wrote:
> Quoth Jani Nikula on Jan 22 at  1:00 am:
> > On Fri, 20 Jan 2012 17:00:27 -0500, Austin Clements  
> > wrote:
> > > Later runs of "notmuch new" won't scan these files again and won't
> > > print warnings.
> > > 
> > > Various programs (Dovecot, in my case) store indexes and caches and
> > > such in the maildir.  Without this, notmuch persistently complains
> > > about such files.
> > 
> > Overall, sounds good and doing this automagically is nice. Superficially
> > the code looks sensible, but I didn't really dig into it. A few nasty
> > questions instead:
> > 
> > What happens if you delete a non-email file? Does the entry stay in the
> > database?
> 
> Phooey.  I thought this worked, but you're right that it doesn't (I
> even wrote a test for this, but the test was based on a false
> assumption).  Non-email files do get returned by the directory
> iterator, so without any changes, notmuch new will notice that they're
> gone.  What I missed is that it then uses
> notmuch_database_find_message_by_filename to find the "message" and
> remove the filename, which won't work since there's no message to
> find.
> 
> I'll have to think about this more.

Sorry about that...

This feature has considerable overlap with file/subdirectory exclusion,
most recently referred to in id:"20120122113212.GA7084@X200". I like the
way your approach is automatic, but doing it manually with configurable
exclusions has certain explicitness to it, and altogether avoids the
problems here, don't you think? There apparently also are people who
wouldn't want notmuch to index some valid email files for one reason or
another.

I haven't thought this through, but what if the exclude/ignore feature
had both the option to specify explicit files/subdirs (patterns like
.gitignore?) that are ignored, and some sort of "auto" option you could
enable to ignore all non-email files without warnings? This would
obviously all happen in the cli.

That probably does not make your thinking any easier, I'm afraid... but
perhaps it provides another angle.


BR,
Jani.


> 
> > What happens if you replace a non-email file with an email file?
> 
> It will not notice because notmuch new only inspects directory mtimes.
> This would require checking the mtimes of every non-email in the
> database on every notmuch new.
> 
> > Does it matter what happens above?
> > 
> > These are corner cases, but what remains in TODO suggests that it would
> > be difficult to debug and figure out if the above ever did happen to
> > someone.
> 
> Yes.  It's possible this needs to get a search syntax before it is
> acceptable for general use.
> 
> > BR,
> > Jani.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 3/4] config: only set search.exclude_tags to "deleted; spam; " during setup

2012-01-22 Thread Jani Nikula
On Mon, 23 Jan 2012 06:05:27 +0100, Pieter Praet  wrote:
> On Sun, 22 Jan 2012 14:53:41 -0800, Jameson Graef Rollins 
>  wrote:
> > On Sun, 22 Jan 2012 23:14:13 +0100, Xavier Maillard  
> > wrote:
> > > 
> > > On Thu, 19 Jan 2012 20:19:03 +0100, Pieter Praet  wrote:
> > > > If the 'search.exclude_tags' option is missing from the config file,
> > > > its value is automatically set to "deleted;spam;".  Taking PoLS/DWIM
> > > > into account, this should probably only happen during setup.
> > > > 
> > > > This patch is actually Austin Clements' work:
> > > >   id:"20120117203211.gq16...@mit.edu"
> > > 
> > > I do not think this is a sane default. As I told it in another post. I
> > > do not expect notmuch to skew my search queries not that I specifically
> > > asked.
> > 
> > Hi, Xavier.  Do you currently mark things as "deleted" or "spam"?  If
> > not, this would have no affect on your search results.  If you do, do
> > you currently expect those messages to show up in searches?  If so, why
> > did you mark them as "deleted" or "spam" to begin with?
> > 
> > I agree with your point in principle (ie. I don't generally want my
> > searches tampered with behind the scenes) but the issue here is about
> > messages that have been explicitly tagged as a form of "trash".  Trash
> > is by it's nature something you're trying to get rid of.  If you wanted
> > to find something in the future, why would you put it in the trash in
> > the first place?
> > 
> 
> You definitely have a point, but then again, who are we to assume that
> the terms "deleted" and "spam" have the *exact* same meaning for
> everyone?  (also see id:"8739bbo0br@praet.org")

"deleted" used to be a tag recognized by notmuch, and it used to sync to
the T (trashed) maildir flag. Even if notmuch won't delete any of your
mails now, I don't think you should use "deleted" on messages you want
to see again. Please let's not split hairs about this.

There really should be a definitive list of tags that are special to
lib/cli/emacs (like "inbox", "unread", "deleted", ...), or are
recommended for specific purposes (like "new" as an intermediate tag
before more sophisticated tagging), to avoid prolonged discussions like
this.

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


Re: [PATCH 3/4] config: only set search.exclude_tags to "deleted; spam; " during setup

2012-01-23 Thread Jani Nikula
On Sun, 22 Jan 2012 23:38:40 -0800, Jameson Graef Rollins 
 wrote:
> On Mon, 23 Jan 2012 07:22:25 +0000, Jani Nikula  wrote:
> > There really should be a definitive list of tags that are special to
> > lib/cli/emacs (like "inbox", "unread", "deleted", ...), or are
> > recommended for specific purposes (like "new" as an intermediate tag
> > before more sophisticated tagging), to avoid prolonged discussions like
> > this.
> 
> Just to be clear: the lib doesn't assign any special meaning to any tag
> (as it shouldn't).  The cli does, but only in the sense that it creates
> config files that designate certain tags for certain operations by
> default.  It's really in emacs where certain tags currently have
> unconfigurable meanings ("inbox").

The lib *does* assign special meaning to the tags it syncs to maildir
flags: draft, flagged, passed, replied, unread. (deleted used to be part
of the list.) The cli does have to request the syncing, but the mapping
is in the lib (flag2tag array in lib/message.cc).

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


Re: [PATCH 3/4] config: only set search.exclude_tags to "deleted; spam; " during setup

2012-01-23 Thread Jani Nikula
On Mon, 23 Jan 2012 09:03:42 +0100, Pieter Praet  wrote:
> On Mon, 23 Jan 2012 07:22:25 +0000, Jani Nikula  wrote:
> > On Mon, 23 Jan 2012 06:05:27 +0100, Pieter Praet  wrote:
> > > On Sun, 22 Jan 2012 14:53:41 -0800, Jameson Graef Rollins 
> > >  wrote:
> > > > On Sun, 22 Jan 2012 23:14:13 +0100, Xavier Maillard 
> > > >  wrote:
> > > > > 
> > > > > On Thu, 19 Jan 2012 20:19:03 +0100, Pieter Praet  
> > > > > wrote:
> > > > > > If the 'search.exclude_tags' option is missing from the config file,
> > > > > > its value is automatically set to "deleted;spam;".  Taking PoLS/DWIM
> > > > > > into account, this should probably only happen during setup.
> > > > > > 
> > > > > > This patch is actually Austin Clements' work:
> > > > > >   id:"20120117203211.gq16...@mit.edu"
> > > > > 
> > > > > I do not think this is a sane default. As I told it in another post. I
> > > > > do not expect notmuch to skew my search queries not that I 
> > > > > specifically
> > > > > asked.
> > > > 
> > > > Hi, Xavier.  Do you currently mark things as "deleted" or "spam"?  If
> > > > not, this would have no affect on your search results.  If you do, do
> > > > you currently expect those messages to show up in searches?  If so, why
> > > > did you mark them as "deleted" or "spam" to begin with?
> > > > 
> > > > I agree with your point in principle (ie. I don't generally want my
> > > > searches tampered with behind the scenes) but the issue here is about
> > > > messages that have been explicitly tagged as a form of "trash".  Trash
> > > > is by it's nature something you're trying to get rid of.  If you wanted
> > > > to find something in the future, why would you put it in the trash in
> > > > the first place?
> > > > 
> > > 
> > > You definitely have a point, but then again, who are we to assume that
> > > the terms "deleted" and "spam" have the *exact* same meaning for
> > > everyone?  (also see id:"8739bbo0br@praet.org")
> > 
> > "deleted" used to be a tag recognized by notmuch, and it used to sync to
> > the T (trashed) maildir flag. Even if notmuch won't delete any of your
> > mails now, I don't think you should use "deleted" on messages you want
> > to see again. Please let's not split hairs about this.
> > 
> 
> Agreed, but it might be nice to make a clear distinction between
> concepts and the actual tags mapped to them.  I'm not suggestion we
> redefine the term "deleted", but from an internationalization
> standpoint, we shouldn't prevent users from mapping e.g. "verwijderd",
> "supprimé", "gelöscht", ... to the concept "deleted".
> 
> > There really should be a definitive list of tags that are special to
> > lib/cli/emacs (like "inbox", "unread", "deleted", ...), or are
> > recommended for specific purposes (like "new" as an intermediate tag
> > before more sophisticated tagging), to avoid prolonged discussions like
> > this.
> > 
> 
> A list of recommended tags would definitely be nice, as long as they
> remain recommendations (as opposed to obligations), especially since
> there's really no reason to designate certain tags as being "special".

Whether there's reason or not, certain tags are special, for a fact, and
they are not just recommendations. Perhaps one day someone will
contribute patches to make them configurable, and separate the concepts
from the actual tags, but in the mean time it will be easier to just
document them for what they are.

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


Re: [PATCH v2 1/3] mime node: Record depth-first part numbers

2012-01-24 Thread Jani Nikula
On Sun, 22 Jan 2012 21:31:11 -0500, Austin Clements  wrote:
> This makes the part numbers readily accessible to formatters.
> Hierarchical part numbering would be a more natural and efficient fit
> for MIME and may be the way to go in the future, but depth-first
> numbering maintains compatibility with what we currently do.
> ---
>  mime-node.c  |   37 ++---
>  notmuch-client.h |   14 +-
>  2 files changed, 47 insertions(+), 4 deletions(-)
> 
> diff --git a/mime-node.c b/mime-node.c
> index 27077f7..025c537 100644
> --- a/mime-node.c
> +++ b/mime-node.c
> @@ -112,6 +112,10 @@ mime_node_open (const void *ctx, notmuch_message_t 
> *message,
>  root->nchildren = 1;
>  root->ctx = mctx;
>  
> +root->part_num = 0;
> +root->next_child = 0;
> +root->next_part_num = 1;
> +
>  *root_out = root;
>  return NOTMUCH_STATUS_SUCCESS;
>  
> @@ -137,7 +141,7 @@ _signature_validity_free (GMimeSignatureValidity **proxy)
>  #endif
>  
>  static mime_node_t *
> -_mime_node_create (const mime_node_t *parent, GMimeObject *part)
> +_mime_node_create (mime_node_t *parent, GMimeObject *part)
>  {
>  mime_node_t *node = talloc_zero (parent, mime_node_t);
>  GError *err = NULL;
> @@ -150,6 +154,8 @@ _mime_node_create (const mime_node_t *parent, GMimeObject 
> *part)
>   talloc_free (node);
>   return NULL;
>  }
> +node->parent = parent;
> +node->part_num = node->next_part_num = -1;
>  
>  /* Deal with the different types of parts */
>  if (GMIME_IS_PART (part)) {
> @@ -267,9 +273,10 @@ _mime_node_create (const mime_node_t *parent, 
> GMimeObject *part)
>  }
>  
>  mime_node_t *
> -mime_node_child (const mime_node_t *parent, int child)
> +mime_node_child (mime_node_t *parent, int child)
>  {
>  GMimeObject *sub;
> +mime_node_t *node;
>  
>  if (!parent || child < 0 || child >= parent->nchildren)
>   return NULL;
> @@ -287,7 +294,31 @@ mime_node_child (const mime_node_t *parent, int child)
>   INTERNAL_ERROR ("Unexpected GMimeObject type: %s",
>   g_type_name (G_OBJECT_TYPE (parent->part)));
>  }
> -return _mime_node_create (parent, sub);
> +node = _mime_node_create (parent, sub);
> +
> +if (child == parent->next_child && parent->next_part_num != -1) {
> + /* We're traversing in depth-first order.  Record the child's
> +  * depth-first numbering. */
> + node->part_num = parent->next_part_num;
> + node->next_part_num = node->part_num + 1;
> +
> + /* Drop the const qualifier because these are internal fields
> +  * whose mutability doesn't affect the interface. */

Leftover comment from the old version.

Otherwise, the code looks good, with the disclaimer that I don't know
much about MIME or gmime.

BR,
Jani.


> + parent->next_child++;
> + parent->next_part_num = -1;
> +
> + if (node->nchildren == 0) {
> + /* We've reached a leaf, so find the parent that has more
> +  * children and set it up to number its next child. */
> + mime_node_t *it = node;
> + while (it && it->next_child == it->nchildren)
> + it = it->parent;
> + if (it)
> + it->next_part_num = node->part_num + 1;
> + }
> +}
> +
> +return node;
>  }
>  
>  static mime_node_t *
> diff --git a/notmuch-client.h b/notmuch-client.h
> index 9c1d383..abfe5d3 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -297,6 +297,13 @@ typedef struct mime_node {
>  /* The number of children of this part. */
>  int nchildren;
>  
> +/* The parent of this node or NULL if this is the root node. */
> +struct mime_node *parent;
> +
> +/* The depth-first part number of this child if the MIME tree is
> + * being traversed in depth-first order, or -1 otherwise. */
> +int part_num;
> +
>  /* True if decryption of this part was attempted. */
>  notmuch_bool_t decrypt_attempted;
>  /* True if decryption of this part's child succeeded.  In this
> @@ -324,6 +331,11 @@ typedef struct mime_node {
>  /* Internal: For successfully decrypted multipart parts, the
>   * decrypted part to substitute for the second child. */
>  GMimeObject *decrypted_child;
> +
> +/* Internal: The next child for depth-first traversal and the part
> + * number to assign it (or -1 if unknown). */
> +int next_child;
> +int next_part_num;
>  } mime_node_t;
>  
>  /* Construct a new MIME node pointing to the root message part of
> @@ -356,7 +368,7 @@ mime_node_open (const void *ctx, notmuch_message_t 
> *message,
>   * an error message on stderr).
>   */
>  mime_node_t *
> -mime_node_child (const mime_node_t *parent, int child);
> +mime_node_child (mime_node_t *parent, int child);
>  
>  /* Return the nth child of node in a depth-first traversal.  If n is
>   * 0, returns node itself.  Returns NULL if there is no such part. */
> -- 
> 1.7.7.3
> 
> __

Re: [PATCH v5 2/2] show: Introduce mime_node formatter callback

2012-01-24 Thread Jani Nikula
On Mon, 23 Jan 2012 18:33:10 -0500, Austin Clements  wrote:
> This callback is the gateway to the new mime_node_t-based formatters.
> This maintains backwards compatibility so the formatters can be
> transitioned one at a time.  Once all formatters are converted, the
> formatter structure can be reduced to only message_set_{start,sep,end}
> and part, most of show_message can be deleted, and all of
> show-message.c can be deleted.
> ---
>  notmuch-client.h |6 ++
>  notmuch-reply.c  |2 +-
>  notmuch-show.c   |   21 +
>  3 files changed, 24 insertions(+), 5 deletions(-)
> 
> diff --git a/notmuch-client.h b/notmuch-client.h
> index abfe5d3..093c789 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -62,8 +62,14 @@
>  #define STRINGIFY(s) STRINGIFY_(s)
>  #define STRINGIFY_(s) #s
>  
> +struct mime_node;
> +struct notmuch_show_params;
> +
>  typedef struct notmuch_show_format {
>  const char *message_set_start;
> +void (*part) (const void *ctx,
> +   struct mime_node *node, int indent,
> +   const struct notmuch_show_params *params);
>  const char *message_start;
>  void (*message) (const void *ctx,
>notmuch_message_t *message,
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index bf67960..f55b1d2 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -31,7 +31,7 @@ static void
>  reply_part_content (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_reply = {
> -"",
> +"", NULL,
>   "", NULL,
>   "", NULL, reply_headers_message_part, ">\n",
>   "",
> diff --git a/notmuch-show.c b/notmuch-show.c
> index 682aa71..dec799c 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -42,7 +42,7 @@ static void
>  format_part_end_text (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_text = {
> -"",
> +"", NULL,
>   "\fmessage{ ", format_message_text,
>   "\fheader{\n", format_headers_text, 
> format_headers_message_part_text, "\fheader}\n",
>   "\fbody{\n",
> @@ -89,7 +89,7 @@ static void
>  format_part_end_json (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_json = {
> -"[",
> +"[", NULL,
>   "{", format_message_json,
>   "\"headers\": {", format_headers_json, 
> format_headers_message_part_json, "}",
>   ", \"body\": [",
> @@ -110,7 +110,7 @@ format_message_mbox (const void *ctx,
>unused (int indent));
>  
>  static const notmuch_show_format_t format_mbox = {
> -"",
> +"", NULL,
>  "", format_message_mbox,
>  "", NULL, NULL, "",
>  "",
> @@ -129,7 +129,7 @@ static void
>  format_part_content_raw (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_raw = {
> -"",
> +"", NULL,
>   "", NULL,
>   "", NULL, format_headers_message_part_text, "\n",
>  "",
> @@ -850,6 +850,19 @@ show_message (void *ctx,
> int indent,
> notmuch_show_params_t *params)
>  {
> +if (format->part) {
> + void *local = talloc_new (ctx);
> + mime_node_t *root, *part;
> +
> + if (mime_node_open (local, message, params->cryptoctx, params->decrypt,
> + &root) == NOTMUCH_STATUS_SUCCESS &&
> + (part = mime_node_seek_dfs (root, (params->part < 0 ?
> +0 : params->part
> + format->part (local, part, indent, params);

I know you did this because Dmitry asked to remove the goto, but I'd
argue this is *much* less readable than the original with goto. There's
just way too much going on in the if. Two calls, an assignment, a
ternary operator. KISS.

BR,
Jani.





> + talloc_free (local);
> + return;
> +}
> +
>  if (params->part <= 0) {
>   fputs (format->message_start, stdout);
>   if (format->message)
> -- 
> 1.7.7.3
> 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [RFC PATCH] bikeshed uncrustify options

2012-01-25 Thread Jani Nikula

Coding style bikeshedding, wonderful. :)

On Wed, 25 Jan 2012 17:21:26 +0200, Tomi Ollila  wrote:
> Is (generally) using *INDENT-(OFF|ON)*  ok ? 

Obviously I wish we could do without.

You should cook up a wrapper for uncrustify that takes a patch, applies
it, and checks if it introduces new coding style issues, but ignores the
existing ones. ;)

> Would it be ok to have
> #define STRINGIFY(s) STRINGIFY_ (s)

Why not, it's the notmuch style?

> (now such expansion disabled by INDENT-OFF)
> When used, it is still thought as function call,
> and whitespace added.
> 
> What about enum { } \n format_sel change below ?

See comment inline below.

> After applying this patch and running:
> 
> $ uncrustify --replace -c devel/uncrustify.cfg *.[ch]
> 
> one can discuss (at least):
> 
> * should there be space after '!'

That's like having space in '- foo' or '~ foo', isn't it? I'd prefer no
space after unary operators.

> * should there be space after (cast)

Yes, please.

> 
> ---
>  devel/uncrustify.cfg |3 ++-
>  notmuch-client.h |5 -
>  notmuch-reply.c  |2 ++
>  notmuch-search.c |   13 +
>  notmuch-show.c   |8 
>  notmuch-time.c   |3 +++
>  6 files changed, 28 insertions(+), 6 deletions(-)
> 
> diff --git a/devel/uncrustify.cfg b/devel/uncrustify.cfg
> index d8075ba..a752fae 100644
> --- a/devel/uncrustify.cfg
> +++ b/devel/uncrustify.cfg
> @@ -58,7 +58,8 @@ nl_after_struct = 0
>  # Extra types used in notmuch source.
>  # (add more on demand)
>  
> -type GMimeObject mime_node_t
> +type GMimeObject GMimeCryptoContext GMimeCipherContext
> +type mime_node_t notmuch_message_t
>  
>  #
>  # inter-character spacing options
> diff --git a/notmuch-client.h b/notmuch-client.h
> index e0eb594..131e453 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -59,8 +59,10 @@
>  
>  #define unused(x) x __attribute__ ((unused))
>  
> +/* *INDENT-OFF* */
>  #define STRINGIFY(s) STRINGIFY_(s)
>  #define STRINGIFY_(s) #s
> +/* *INDENT-ON* */
>  
>  struct mime_node;
>  struct notmuch_show_params;
> @@ -377,7 +379,8 @@ mime_node_t *
>  mime_node_child (mime_node_t *parent, int child);
>  
>  /* Return the nth child of node in a depth-first traversal.  If n is
> - * 0, returns node itself.  Returns NULL if there is no such part. */
> + * 0, returns node itself.  Returns NULL if there is no such part.
> + */
>  mime_node_t *
>  mime_node_seek_dfs (mime_node_t *node, int n);
>  
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index f55b1d2..57742c4 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -31,6 +31,7 @@ static void
>  reply_part_content (GMimeObject *part);
>  
>  static const notmuch_show_format_t format_reply = {
> +/* *INDENT-OFF* */

What does it do here without the comment?

>  "", NULL,
>   "", NULL,
>   "", NULL, reply_headers_message_part, ">\n",
> @@ -44,6 +45,7 @@ static const notmuch_show_format_t format_reply = {
>   "",
>   "", "",
>  ""
> +/* *INDENT-ON* */
>  };
>  
>  static void
> diff --git a/notmuch-search.c b/notmuch-search.c
> index d504051..57ec603 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -65,6 +65,7 @@ format_thread_text (const void *ctx,
>   const char *authors,
>   const char *subject);
>  static const search_format_t format_text = {
> +/* *INDENT-OFF* */
>  "",
>   "",
>   format_item_id_text,
> @@ -75,6 +76,7 @@ static const search_format_t format_text = {
>   "",
>  "\n",
>  "",
> +/* *INDENT-ON* */
>  };
>  
>  static void
> @@ -91,6 +93,7 @@ format_thread_json (const void *ctx,
>   const char *authors,
>   const char *subject);
>  static const search_format_t format_json = {
> +/* *INDENT-OFF* */
>  "[",
>   "{",
>   format_item_id_json,
> @@ -101,6 +104,7 @@ static const search_format_t format_json = {
>   "}",
>  "]\n",
>  "]\n",
> +/* *INDENT-ON* */
>  };
>  
>  static void
> @@ -160,7 +164,7 @@ format_item_id_json (const void *ctx,
>  printf ("%s", json_quote_str (ctx_quote, item_id));
>  
>  talloc_free (ctx_quote);
> -
> +
>  }
>  
>  static void
> @@ -333,7 +337,7 @@ do_search_messages (const search_format_t *format,
>  
>   first_message = 0;
>   }
> - 
> +
>   notmuch_filenames_destroy( filenames );
>  
>   } else { /* output == OUTPUT_MESSAGES */
> @@ -427,8 +431,9 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
>  size_t search_exclude_tags_length;
>  unsigned int i;
>  
> -enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }
> - format_sel = NOTMUCH_FORMAT_TEXT;
> +enum { /* note: also emacs indents this wrongly if not like this. */
> + NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT
> +} format_sel = NOTMUCH_FORMAT_TEXT;

I prefer this style anyway. Compare with:

struct { int foo; int bar; } baz;

which I think would be frowned upon.

> 

Re: [PATCH 1/2] moved _notmuch_get_list () and _notmuch_set_list () up in file

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 12:11:57 +0200, Tomi Ollila  wrote:
> Moved _notmuch_get_list () and _notmuch_set_list () to a location
> in notmuch-config.c so that new functions that will be located 
> before the old location of those functions can also use these.

Parse error. ;)

You mean something along the lines of: "Move _notmuch_get_list () and
_notmuch_set_list () earlier in the file to avoid forward declarations
in further work. No functional changes."

I'm sure native speakers can bikeshed that further. ;)

BR,
Jani.


> ---
> 
> This patch is independent of the next one (just required by it)
> and can (should) be pushed early.
> 
>  notmuch-config.c |   84 
> +++---
>  1 files changed, 42 insertions(+), 42 deletions(-)
> 
> diff --git a/notmuch-config.c b/notmuch-config.c
> index 0ded6d7..a124e34 100644
> --- a/notmuch-config.c
> +++ b/notmuch-config.c
> @@ -467,6 +467,48 @@ notmuch_config_save (notmuch_config_t *config)
>  return 0;
>  }
>  
> +static const char **
> +_config_get_list (notmuch_config_t *config,
> +   const char *section, const char *key,
> +   const char ***outlist, size_t *list_length, size_t 
> *ret_length)
> +{
> +assert(outlist);
> +
> +if (*outlist == NULL) {
> +
> + char **inlist = g_key_file_get_string_list (config->key_file,
> +  section, key, list_length, NULL);
> + if (inlist) {
> + unsigned int i;
> +
> + *outlist = talloc_size (config, sizeof (char *) * (*list_length + 
> 1));
> +
> + for (i = 0; i < *list_length; i++)
> + (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
> +
> + (*outlist)[i] = NULL;
> +
> + g_strfreev (inlist);
> + }
> +}
> +
> +if (ret_length)
> + *ret_length = *list_length;
> +
> +return *outlist;
> +}
> +
> +static void
> +_config_set_list (notmuch_config_t *config,
> +   const char *group, const char *name,
> +   const char *list[],
> +   size_t length, const char ***config_var )
> +{
> +g_key_file_set_string_list (config->key_file, group, name, list, length);
> +talloc_free (*config_var);
> +*config_var = NULL;
> +}
> +
>  const char *
>  notmuch_config_get_database_path (notmuch_config_t *config)
>  {
> @@ -551,37 +593,6 @@ notmuch_config_set_user_primary_email (notmuch_config_t 
> *config,
>  config->user_primary_email = NULL;
>  }
>  
> -static const char **
> -_config_get_list (notmuch_config_t *config,
> -   const char *section, const char *key,
> -   const char ***outlist, size_t *list_length, size_t 
> *ret_length)
> -{
> -assert(outlist);
> -
> -if (*outlist == NULL) {
> -
> - char **inlist = g_key_file_get_string_list (config->key_file,
> -  section, key, list_length, NULL);
> - if (inlist) {
> - unsigned int i;
> -
> - *outlist = talloc_size (config, sizeof (char *) * (*list_length + 
> 1));
> -
> - for (i = 0; i < *list_length; i++)
> - (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
> -
> - (*outlist)[i] = NULL;
> -
> - g_strfreev (inlist);
> - }
> -}
> -
> -if (ret_length)
> - *ret_length = *list_length;
> -
> -return *outlist;
> -}
> -
>  const char **
>  notmuch_config_get_user_other_email (notmuch_config_t *config,   size_t 
> *length)
>  {
> @@ -598,17 +609,6 @@ notmuch_config_get_new_tags (notmuch_config_t *config,   
> size_t *length)
>&(config->new_tags_length), length);
>  }
>  
> -static void
> -_config_set_list (notmuch_config_t *config,
> -   const char *group, const char *name,
> -   const char *list[],
> -   size_t length, const char ***config_var )
> -{
> -g_key_file_set_string_list (config->key_file, group, name, list, length);
> -talloc_free (*config_var);
> -*config_var = NULL;
> -}
> -
>  void
>  notmuch_config_set_user_other_email (notmuch_config_t *config,
>const char *list[],
> -- 
> 1.7.6.4
> 
> ___
> 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: [PATCH 2/2] added support for user-specified directories to exclude

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 12:11:58 +0200, Tomi Ollila  wrote:
> A new configuration key 'database.exclude' is used to determine
> which directories user wants not to be scanned for new mails.
> 
> ---
> 
> Notes (from 2011-09-13):
> 
> 1) Currently the comments for newly created configuration file are not
> updated, so for not this is 'undocumented feature'. Should there be an
> empty configuration line as a placeholder ... ?
> 
> 2) Whenever some already existing directory is added to the exclude list
> and the parent directory timestamp has not changed, notmuch new will not
> notice the directory has gone (as it still is there), user needs to 'touch'
> the parent directory before next 'notmuch new' no make notmuch notice.
> 
> 2012-01-26: could notmuch track mtime of the configuration file and if
> that changes, ignore mail directory timestamps ?
> 
> 3) count_files() function is not touched. The functionality there has fallen
> behind of add_files_recursive (maildir+tmp check and following symlinks).
> The question there should it be updated, or attempted to merge with
> add_files (as the comment says). count_files() is only called at the beginning
> when database is not yet initialised.
> ---
>  notmuch-client.h |3 +++
>  notmuch-config.c |   13 +
>  notmuch-new.c|   22 --
>  3 files changed, 36 insertions(+), 2 deletions(-)
> 
> diff --git a/notmuch-client.h b/notmuch-client.h
> index e0eb594..78460fc 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -219,6 +219,9 @@ void
>  notmuch_config_set_database_path (notmuch_config_t *config,
> const char *database_path);
>  
> +const char **
> +notmuch_config_get_database_exclude (notmuch_config_t *config,
> +  size_t *length);
>  const char *
>  notmuch_config_get_user_name (notmuch_config_t *config);
>  
> diff --git a/notmuch-config.c b/notmuch-config.c
> index a124e34..e236114 100644
> --- a/notmuch-config.c
> +++ b/notmuch-config.c
> @@ -99,6 +99,8 @@ struct _notmuch_config {
>  GKeyFile *key_file;
>  
>  char *database_path;
> +const char **database_exclude;
> +size_t database_exclude_length;
>  char *user_name;
>  char *user_primary_email;
>  const char **user_other_email;
> @@ -258,6 +260,8 @@ notmuch_config_open (void *ctx,
>  config->key_file = g_key_file_new ();
>  
>  config->database_path = NULL;
> +config->database_exclude = NULL;
> +config->database_exclude_length = 0;
>  config->user_name = NULL;
>  config->user_primary_email = NULL;
>  config->user_other_email = NULL;
> @@ -537,6 +541,15 @@ notmuch_config_set_database_path (notmuch_config_t 
> *config,
>  config->database_path = NULL;
>  }
>  
> +const char **
> +notmuch_config_get_database_exclude (notmuch_config_t *config,
> +  size_t *length)
> +{
> +return _config_get_list (config, "database", "exclude",
> +  &(config->database_exclude),
> +  &(config->database_exclude_length), length);
> +}
> +
>  const char *
>  notmuch_config_get_user_name (notmuch_config_t *config)
>  {
> diff --git a/notmuch-new.c b/notmuch-new.c
> index a569a54..d607f5b 100644
> --- a/notmuch-new.c
> +++ b/notmuch-new.c
> @@ -39,6 +39,8 @@ typedef struct {
>  int verbose;
>  const char **new_tags;
>  size_t new_tags_length;
> +const char **database_exclude;
> +size_t database_exclude_length;
>  
>  int total_files;
>  int processed_files;
> @@ -300,6 +302,8 @@ add_files_recursive (notmuch_database_t *notmuch,
>  is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);
>  
>  for (i = 0; i < num_fs_entries; i++) {
> + size_t j;
> +
>   if (interrupted)
>   break;
>  
> @@ -323,8 +327,6 @@ add_files_recursive (notmuch_database_t *notmuch,
>* Also ignore the .notmuch directory and any "tmp" directory
>* that appears within a maildir.
>*/
> - /* XXX: Eventually we'll want more sophistication to let the
> -  * user specify files to be ignored. */
>   if (strcmp (entry->d_name, ".") == 0 ||
>   strcmp (entry->d_name, "..") == 0 ||
>   (is_maildir && strcmp (entry->d_name, "tmp") == 0) ||
> @@ -332,6 +334,12 @@ add_files_recursive (notmuch_database_t *notmuch,
>   {
>   continue;
>   }
> + /* Ignore user-specified directories */
> + for (j = 0; j < state->database_exclude_length; j++)
> + if (strcmp(entry->d_name, state->database_exclude[j]) == 0)
> + break;
> + if (j < state->database_exclude_length)
> + continue;

How about wrapping that in a function you can use here and below?

if (user_wants_this_excluded (...))
continue;

Please also have a look at id:"87pqecylon@nikula.org" and the
patches Austin posted. "Auto ignore"?

BR,
Jani.

>  
>   next = talloc_asprintf (notm

Re: Bug?: notmuch-search-show-thread shows several threads; only one containing matching messages

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 13:44:50 +0100, Gregor Zattler  wrote:
> Hi Jamie, Austin,
> * Jameson Graef Rollins  [25. Jan. 2012]:
> > On Wed, 25 Jan 2012 20:19:03 -0500, Austin Clements  
> > wrote:
> >> One very common cause of this is someone using "reply" to get an
> >> initial set of recipients, but then replacing the entire message and
> >> subject (presumably without realizing that the mail is still tracking
> >> what it was a reply to).  This can also happen if someone
> >> intentionally replies to multiple messages (though few mail clients
> >> support this), or if there was a message ID collision.
> > 
> > This is a very common occurrence for me as well.  I would put money down
> > that this is what you're seeing.
> 
> I thought about this too and this is why I checked for any
> occurrence of Message-IDs in the other emails: 
> 
>|> I isolated the thread I was interested in,
>|> extracted the message ids of its messages and greped the rest of
>|> the messages for this message ids: no matches.[2] Therefore no of
>|> the rests messages are part of the thread I was interested in
> 
> perhaps there was a logic error in how I did this:
> 
>|> [2] grep -I "^Message-Id:" /tmp/thread-I-m-interested-in.mbox |sed -e 
> "s/Message-Id: $//" >really.mid
>|> grep -I -F really.mid rest.mbox
>|> --> no match
> 
> /tmp/thread-I-m-interested-in.mbox  is a mbox with messages
> I'minterested in, the "real" ones.  really.mid is a list of
> Message-IDs of these "real" emails.  rest.mbox is a mbox with the
> other emails, Emacs showed in his notmuch show buffer but are
> other threads.
> 
> Since there is no match I concluded, the threads are not linked.
> Perhaps I made a mistake.  I'l retest it and report again.  But
> right now I don't have the time to do this.

Do you have an mbox file in the maildir indexed by notmuch? That seems
like the issue.

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


Re: [PATCH 1/3] emacs: bind "s" to `notmuch-search' in notmuch-hello buffer

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 14:48:44 +0100, Pieter Praet  wrote:
> On Tue, 17 Jan 2012 23:22:30 +0200, Jani Nikula  wrote:
> > [...]
> > 
> > After this, what would the user have to do to bind some key to put the
> > point in the search box? If someone wants to restore old behaviour for
> > themselves.
> > 
> 
> This should work:
> 
>   #+begin_src emacs-lisp
> (add-hook 'notmuch-hello-mode-hook
>   (lambda ()
>  (local-set-key (kbd "s")
>   (lambda() (interactive)
>(re-search-forward "Search: ")
>   #+end_src

Thanks for the basic idea, iterated into:

(define-key notmuch-hello-mode-map "S"
  (lambda() (interactive)
(goto-char (point-min))
(re-search-forward "Search: ")))


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


Re: [PATCH 0/2] re-enable line wrapping and add some header bling

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 08:17:49 +, David Edmondson  wrote:
> By default, re-enable `visual-line-mode' in `notmuch-show-mode'. Do it
> via a hook so that purists (ahem) can turn it off.
> 
> Add some more processing of headers to make them look nice. Do it via
> hooks so that unbelievers can turn it off.

Tried them all, I like them all. I think it's good to have them enabled
by default.

Had to play with the options a bit to realize what the difference
between notmuch-show-fill-headers and
notmuch-show-turn-on-visual-line-mode is, especially when it comes to
headers and the "title line" for each message, and why I'd want to have
them both enabled (I do). So perhaps you could improve the documentation
as Dmitry suggested.

Thanks for these patches.

BR,
Jani.

> 
> David Edmondson (2):
>   emacs: Re-enable line wrapping in `notmuch-show-mode'.
>   emacs: Add more processing of displayed headers.
> 
>  emacs/notmuch-show.el |   50 +---
>  1 files changed, 42 insertions(+), 8 deletions(-)
> 
> -- 
> 1.7.8.3
> 
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] emacs: add default value to notmuch-search-line-faces

2012-01-26 Thread Jani Nikula
Add default value to notmuch-search-line-faces to show "unread"
messages in bold, and "flagged" messages in red, to have some visual
indication of important messages in search results. This should be
helpful for new users.

"unread" tag is quite obvious, and handled specially both in the lib
and emacs ui. "flagged" is synced to maildir F flag in the lib. If one
syncs the maildir to IMAP, this also translates to corresponding IMAP
flag. (This is "starred" in GMail and Android.)

Signed-off-by: Jani Nikula 
---
 emacs/notmuch.el |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 6b2c252..551ea9d 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -662,7 +662,8 @@ This function advances the next thread when finished."
  (goto-char (point-min))
  (forward-line (1- notmuch-search-target-line
 
-(defcustom notmuch-search-line-faces nil
+(defcustom notmuch-search-line-faces '(("unread" :weight bold)
+  ("flagged" :foreground "red"))
   "Tag/face mapping for line highlighting in notmuch-search.
 
 Here is an example of how to color search results based on tags.
-- 
1.7.5.4

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


Re: [PATCH] emacs: add default value to notmuch-search-line-faces

2012-01-26 Thread Jani Nikula
On Thu, 26 Jan 2012 14:41:46 -0500, Austin Clements  wrote:
> Quoth Jani Nikula on Jan 26 at  9:21 pm:
> > Add default value to notmuch-search-line-faces to show "unread"
> > messages in bold, and "flagged" messages in red, to have some visual
> > indication of important messages in search results. This should be
> > helpful for new users.
> > 
> > "unread" tag is quite obvious, and handled specially both in the lib
> > and emacs ui. "flagged" is synced to maildir F flag in the lib. If one
> > syncs the maildir to IMAP, this also translates to corresponding IMAP
> > flag. (This is "starred" in GMail and Android.)
> > 
> > Signed-off-by: Jani Nikula 
> 
> While I'm sure this can be bikeshod to death, I do have one legitimate
> concern (and one illegitimate).
> 
> I completely agree with what you said on IRC, though, that setting
> this to non-nil is more about making this capability more discoverable
> to new users than trying to come up with the perfect faces.

Thanks for repeating that here too before full blown bikeshedding. I'm
just trying to help other people find this option quicker than I and
some others did...

> > ---
> >  emacs/notmuch.el |3 ++-
> >  1 files changed, 2 insertions(+), 1 deletions(-)
> > 
> > diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> > index 6b2c252..551ea9d 100644
> > --- a/emacs/notmuch.el
> > +++ b/emacs/notmuch.el
> > @@ -662,7 +662,8 @@ This function advances the next thread when finished."
> >   (goto-char (point-min))
> >   (forward-line (1- notmuch-search-target-line
> >  
> > -(defcustom notmuch-search-line-faces nil
> > +(defcustom notmuch-search-line-faces '(("unread" :weight bold)
> 
> As much as I would like this, many terminals don't visually
> distinguish between the default face and the default face in bold.

Would it really matter, though? People on such terminals are probably
aware they are missing out on a bunch of visual stuff. But please do
suggest an alternative that could be "composited" with the :foreground
setting below for "unread" and "flagged" threads.

> > +  ("flagged" :foreground "red"))
> 
> Red is pretty universally used to indicate danger or a serious
> condition, while "flagged" is simply supposed to draw attention.  I
> would say blue as a neutral and distinct indicator, but it also has
> poor visibility (I used to use blue, but found that when scanning my
> mail, I would habitually skip over flagged messages because they were
> dark, which was the opposite of what I wanted).  Personally I've
> settled on yellow; it's visually distinct enough to be easily
> noticeable and bright enough that I don't skip over it, though it
> obviously wouldn't work on a light background.

Can be yellow, I don't really care that much. But isn't a light
background the default for emacs in most distros? If that matters,
*shrug*.


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


Re: [PATCH 0/2] re-enable line wrapping and add some header bling

2012-01-27 Thread Jani Nikula
On Fri, 27 Jan 2012 06:52:46 +, David Edmondson  wrote:
> On Thu, 26 Jan 2012 20:17:49 +0400, Dmitry Kurochkin 
>  wrote:
> > I did not review the code, but here is a general comment for both
> > patches (but especially for the first one).  It would be nice to have a
> > more detailed documentation for hooks.  Docstring like "Enable Visual
> > Line mode." for a function named `notmuch-show-turn-on-visual-line-mode'
> > is near useless.  It is quite obvious that the function enables
> > visual-line-mode from it's name.  And it does not give any information
> > on why would someone actually want to use it.  I do not remember what
> > visual-line-mode is exactly, so to understand whether this hook is
> > actually useful for me, I have to read visual-line-mode docs, think
> > about how it helps in notmuch-show, read some code, perhaps, etc.  I
> > would argue that since the hook itself is trivial, the main point in
> > having it is to provide a clearly documented solution for a common
> > problem for those who do not know how to solve this problem right away.
> > Currently, those who know what visual-line-mode is do not need this
> > hook, because they can easily write their own, and those who do not know
> > what visual-line-mode is can not use this hook, because it says nothing
> > about why it is actually useful.
> > 
> > Also, in addition to better docs, I would rename
> > `notmuch-show-turn-on-visual-line-mode' to something that reflects what
> > it does from user POV (like the other two hooks).
> > 
> > Though, the fact that the hook is enabled by default makes the above
> > arguments less important, I guess.
> 
> I have a bunch of somewhat conflicting thoughts about this:
>   - Being able to configure the behaviour without having to change the
> core code is good, so implementing behaviour using hook functions is
> useful.
>   - Things should behave well in the default configuration, so most of
> the hook functions are enabled by default.
>   - Everything can't be hook functions, so there's a balance to be made
> between implementing things as in-line code and via hook functions.
>   - Most users shouldn't need to modify any of the hooks.
>   - Documentation that explains what a hook function is about is
> obviously good.
>   - Documenting something that is external to notmuch can be both
> wasteful and risky.
> 
> Wasteful because such documentation typically already exists and
> risky because the precise behaviour of external components is not
> under our control.
> 
> For example, the documentation for `visual-line-mode' is both
> concise and good, so there's little point in repeating it and, of
> course, the exact details of what `visual-line-mode' does can be
> changed by the Emacs developers. One would expect that they would
> update the documentation for `visual-line-mode' in such situations,
> which would leave any cloned documentation in an incorrect state.
> 
> Hence, I would probably take issue with your statement:
> 
> > I would argue that since the hook itself is trivial, the main point in
> > having it is to provide a clearly documented solution for a common
> > problem for those who do not know how to solve this problem right
> > away.
> 
> That's not the intention of the hook functions under discussion
> here. They are hook functions so that a curious and interested user can
> make a change based on some aesthetic preference. The are not about
> solving problems with the default configuration.
> 
> I think that `turn-on-visual-line-mode' (or the package local derivative
> of it that was chosen) is precisely the right name for a function that
> enables `visual-line-mode'. It describes perfectly and succinctly what
> the function does and provides a pointer to follow to find out more (the
> documentation for `visual-line-mode') without a user even having to
> examine the documentation of the function itself.

Agree completely.

Concrete suggestion:

+(defun notmuch-show-turn-on-visual-line-mode ()
+  "Enable `visual-line-mode'."
+  (visual-line-mode t))

To provide a link to the visual-line-mode documentation.

> All of that said, I'd agree that the documentation of
> `notmuch-show-indent-continuations' could have been better. How about:
>   "Indent any continuation lines in the current headers."
> ?

Sounds good.


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


[PATCH] emacs: support limiting the number of results shown in search results

2012-01-27 Thread Jani Nikula
Add support for limiting the maximum number of results initially displayed
in search results. When enabled, the search results will contain push
buttons to double the number of results displayed or to show unlimited
results.

The approach is inspired by vc-print-log in Emacs vc.el.

Signed-off-by: Jani Nikula 

---

Rebased since id:"1321560458-32010-1-git-send-email-j...@nikula.org",
and added option to limit results to window height. Limiting does not
work through the 's' key binding in search view, and some of the
issues reported by Austin in id:"2004205415.gj22...@mit.edu" and
Aneesh in id:"87hb1gu643@linux.vnet.ibm.com" are unfortunately
still there.

If anyone wants to pick this up from here, I'd be delighted. I use
this, but don't have the time to polish. This is just to share the
rebased patch as Aneesh was asking for it on IRC.
---
 emacs/notmuch-hello.el |   21 +--
 emacs/notmuch.el   |   64 +++
 2 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index d17a30f..9ed68e2 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -26,7 +26,7 @@
 (require 'notmuch-lib)
 (require 'notmuch-mua)
 
-(declare-function notmuch-search "notmuch" (query &optional oldest-first 
target-thread target-line continuation))
+(declare-function notmuch-search "notmuch" (query &optional oldest-first limit 
target-thread target-line continuation))
 (declare-function notmuch-poll "notmuch" ())
 
 (defcustom notmuch-hello-recent-searches-max 10
@@ -34,6 +34,21 @@
   :type 'integer
   :group 'notmuch-hello)
 
+(defcustom notmuch-search-limit nil
+  "The maximum number of results to show in search results.
+
+This variables controls the maximum number of results to
+initially show in search results. Set to 0 to limit to window
+height. The search results will contain push buttons to double
+the number (can be repeated) or show unlimited number of results.
+
+If set to nil, the number of results is not limited."
+  :type '(choice (const :tag "Unlimited" nil)
+(const :tag "Window height" 0)
+(integer :tag "Limit"))
+  :group 'notmuch-search
+  :group 'notmuch)
+
 (defcustom notmuch-show-empty-saved-searches nil
   "Should saved searches with no messages be listed?"
   :type 'boolean
@@ -178,7 +193,7 @@ International Bureau of Weights and Measures."
 (setq search (notmuch-hello-trim search))
 (let ((history-delete-duplicates t))
   (add-to-history 'notmuch-search-history search)))
-  (notmuch-search search notmuch-search-oldest-first nil nil
+  (notmuch-search search notmuch-search-oldest-first notmuch-search-limit nil 
nil
  #'notmuch-hello-search-continuation))
 
 (defun notmuch-hello-add-saved-search (widget)
@@ -228,7 +243,7 @@ diagonal."
 (defun notmuch-hello-widget-search (widget &rest ignore)
   (notmuch-search (widget-get widget
  :notmuch-search-terms)
- notmuch-search-oldest-first
+ notmuch-search-oldest-first notmuch-search-limit
  nil nil #'notmuch-hello-search-continuation))
 
 (defun notmuch-saved-search-count (search)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 72f78ed..b3fef88 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -231,6 +231,7 @@ For a mouse binding, return nil."
 
 (defvar notmuch-search-mode-map
   (let ((map (make-sparse-keymap)))
+(set-keymap-parent map widget-keymap)
 (define-key map "?" 'notmuch-help)
 (define-key map "q" 'notmuch-search-quit)
 (define-key map "x" 'notmuch-search-quit)
@@ -277,6 +278,7 @@ For a mouse binding, return nil."
 (defvar notmuch-search-target-thread)
 (defvar notmuch-search-target-line)
 (defvar notmuch-search-continuation)
+(defvar notmuch-search-limit)
 
 (defvar notmuch-search-disjunctive-regexp  "\\<[oO][rR]\\>")
 
@@ -418,6 +420,7 @@ Complete list of currently available key bindings:
   (make-local-variable 'notmuch-search-oldest-first)
   (make-local-variable 'notmuch-search-target-thread)
   (make-local-variable 'notmuch-search-target-line)
+  (make-local-variable 'notmuch-search-limit)
   (set (make-local-variable 'notmuch-search-continuation) nil)
   (set (make-local-variable 'scroll-preserve-screen-position) t)
   (add-to-invisibility-spec (cons 'ellipsis t))
@@ -680,6 +683,11 @@ This function advances the next thread when finished."
(insert "End of search results.")
(unless (= exit-status 0)
  (insert (format " (process r

Re: [PATCH 7/6] emacs: relax tag syntax check in `notmuch-tag' function

2012-01-28 Thread Jani Nikula
On Jan 28, 2012 7:06 AM, "Dmitry Kurochkin" 
wrote:
>
> The tag syntax check in `notmuch-tag' function was too strict and did
> not allow nmbug tags with "::".  Since the check is done for all
> tagging operations in Emacs UI, this basically means that no nmbug
> tags can be changed.  The patch relaxes the tag syntax check to allow
> any tag names that do not include whitespace characters.

Imho the syntax check should be in cli, or lib even. I posted a patch to
cli some time ago when I realized it's possible to add tag "-" but you
can't remove it with the current cli. (On the road, can't find the message
id now.)

> ---
>  emacs/notmuch.el |2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index 9813e0a..0de6123 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -555,7 +555,7 @@ notmuch-after-tag-hook will be run."
>   ;; Perform some validation
>   (when (null tags) (error "No tags given"))
>   (mapc (lambda (tag)
> - (unless (string-match-p "^[-+][-+_.[:word:]]+$" tag)
> + (unless (string-match-p "^[-+]\\S-+$" tag)
>(error "Tag must be of the form `+this_tag' or `-that_tag'")))
>tags)
>   (run-hooks 'notmuch-before-tag-hook)
> --
> 1.7.8.3
>
> ___
> 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: [PATCH 8/6] emacs: use message ids instead of thread id in `notmuch-show-operate-all'

2012-01-28 Thread Jani Nikula
I guess this now includes the optimization of doing the tagging in a single
call to notmuch tag. (As opposed to calling it once per msg like it used to
be a while back.) There was some discussion about the cmdline length for
large threads potentially growing too big when I sent such an optimization
patch, shall we just ignore that and hope for the best? I guess an idea was
to limit to, say, a few hundred msg ids per command. (Again, sorry I can't
look up the earlier thread now.)

On Jan 28, 2012 8:00 AM, "Dmitry Kurochkin" 
wrote:
>
> Before the change, `notmuch-show-operate-all' used thread id for
> "notmuch tag" search.  This could result in tagging unexpected
> messages that were added to the thread after the notmuch-show buffer
> was created.  The patch changes `notmuch-show-operate-all' to use ids
> of shown messages to fix this.
> ---
>  emacs/notmuch-show.el |   23 ++-
>  1 files changed, 22 insertions(+), 1 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 2ca4d92..e606224 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1170,6 +1170,15 @@ All currently available key bindings:
> (notmuch-show-move-to-message-top)
> t))
>
> +(defun notmuch-show-mapc (function)
> +  "Iterate through all messages with
> +`notmuch-show-goto-message-next' and call `function' for side
> +effects."
> +  (save-excursion
> +(goto-char (point-min))
> +(loop do (funcall function)
> + while (notmuch-show-goto-message-next
> +
>  ;; Functions relating to the visibility of messages and their
>  ;; components.
>
> @@ -1222,6 +1231,18 @@ Some useful entries are:
>   "Return the message id of the current message."
>   (concat "id:\"" (notmuch-show-get-prop :id) "\""))
>
> +(defun notmuch-show-get-messages-ids ()
> +  "Return all message ids of currently shown messages."
> +  (let ((message-ids))
> +(notmuch-show-mapc
> + (lambda () (push (notmuch-show-get-message-id) message-ids)))
> +message-ids))
> +
> +(defun notmuch-show-get-messages-ids-search ()
> +  "Return a search string for all message ids of currently shown
> +messages."
> +  (mapconcat 'identity (notmuch-show-get-messages-ids) " or "))
> +
>  ;; dme: Would it make sense to use a macro for many of these?
>
>  (defun notmuch-show-get-filename ()
> @@ -1496,7 +1517,7 @@ i.e. a list of tags to change with '+' and '-'
prefixes."
>  `Changed-tags' is a list of tag operations for \"notmuch tag\",
>  i.e. a list of tags to change with '+' and '-' prefixes."
>   (interactive (notmuch-select-tags-with-completion nil
notmuch-show-thread-id))
> -  (apply 'notmuch-tag notmuch-show-thread-id changed-tags)
> +  (apply 'notmuch-tag (notmuch-show-get-messages-ids-search)
changed-tags)
>   (save-excursion
> (goto-char (point-min))
> (loop do (let* ((current-tags (notmuch-show-get-tags))
> --
> 1.7.8.3
>
> ___
> 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: [PATCH] emacs: globally replace non-branching "(if COND (progn ..." with "(when ..."

2012-01-28 Thread Jani Nikula
On Jan 28, 2012 2:41 PM, "David Bremner"  wrote:
>
> On Sat, 14 Jan 2012 10:17:18 +0100, Pieter Praet  wrote:
> > Less code, same results, without sacrificing readability.
> >
>
> This looks OK, although the re-indenting makes these kind of changes
> painful to review (not that I'm suggesting we should re-indent, just
> some random complaining).

Sometimes someone (Dmitry?) sent patches that separated a small functional
change, and the big non-functional indentation change it caused,
separately. Would you prefer (or tolerate ;) that style?

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


Re: [PATCH] lib: notmuch_tags_get example was not updated to reflect api change

2012-01-28 Thread Jani Nikula
The subject should be about what this patch does, like "lib: update
notmuch_tags_get example to reflect api change"

On Jan 29, 2012 12:46 AM, "Allan Wind"  wrote:
>

And preferably you would describe here what the api change was.

> ---
>  lib/notmuch.h |   21 +++--
>  1 files changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index 7929fe7..5e6e449 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -941,21 +941,22 @@ notmuch_message_get_header (notmuch_message_t
*message, const char *header);
>  * Typical usage might be:
>  *
>  * notmuch_message_t *message;
> + * notmuch_status_t status;
>  * notmuch_tags_t *tags;
>  * const char *tag;
>  *
> - * message = notmuch_database_find_message (database, message_id);
> - *
> - * for (tags = notmuch_message_get_tags (message);
> - *  notmuch_tags_valid (tags);
> - *  notmuch_result_move_to_next (tags))
> - * {
> - * tag = notmuch_tags_get (tags);
> - * 
> + * status = notmuch_database_find_message (database, message_id,
&message);
> + * if(!status && message) {
> + *  for (tags = notmuch_message_get_tags (message);
> + *   notmuch_tags_valid (tags);
> + *   notmuch_result_move_to_next (tags))
> + *  {
> + *   tag = notmuch_tags_get (tags);
> + *   
> + *  }
> + *  notmuch_message_destroy (message);
>  * }
>  *
> - * notmuch_message_destroy (message);
> - *
>  * Note that there's no explicit destructor needed for the
>  * notmuch_tags_t object. (For consistency, we do provide a
>  * notmuch_tags_destroy function, but there's no good reason to call
> --
> 1.7.2.5
>
> ___
> 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: [PATCH] STYLE: Initial draft of coding style document

2012-01-30 Thread Jani Nikula
On Jan 30, 2012 4:38 PM, "Tomi Ollila"  wrote:
>
> On Fri, 27 Jan 2012 19:46:58 -0400, David Bremner 
wrote:
> > From: David Bremner 
>
> [ ... ]
>
> > +
> > +* Indent is 4 spaces with mixed tabs/spaces and a tab width of 8.
> > +  Tabs should be only at the beginning of the line.
>
> So, after initial indentation (with tabs) there should not be further
> tabs? We'll be using the former instead of the latter in these 2 below?

I'd prefer tabs for aligning comments at the end of lines.

>
> /* excerpt from command-line-arguments.h -- indentation without tabs */
>
> enum notmuch_opt_type {
>NOTMUCH_OPT_END = 0,
>NOTMUCH_OPT_BOOLEAN,/* --verbose  */
>NOTMUCH_OPT_INT,/* --frob=8   */
>NOTMUCH_OPT_KEYWORD,/* --format=raw|json|text */
>NOTMUCH_OPT_STRING, /* --file=/tmp/gnarf.txt  */
>NOTMUCH_OPT_POSITION/* notmuch dump pos_arg   */
> };
>
> /* excerpt from command-line-arguments.h -- indentation with tabs */
>
> enum notmuch_opt_type {
>NOTMUCH_OPT_END = 0,
>NOTMUCH_OPT_BOOLEAN,/* --verbose  */
>NOTMUCH_OPT_INT,/* --frob=8   */
>NOTMUCH_OPT_KEYWORD,/* --format=raw|json|text */
>NOTMUCH_OPT_STRING, /* --file=/tmp/gnarf.txt  */
>NOTMUCH_OPT_POSITION/* notmuch dump pos_arg   */
> };
>
>
> [ ... ]
>
>
> Tomi
> ___
> 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: [PATCH 4/5] emacs: Add a binding (>) to toggle the truncation of long lines.

2012-01-30 Thread Jani Nikula
On Jan 30, 2012 6:31 PM, "David Edmondson"  wrote:
>
> ---
>  emacs/notmuch-show.el |1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index a2c4daf..8b07adf 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1114,6 +1114,7 @@ Refreshes the current view, observing changes in
cryptographic preferences."
>(define-key map "!" 'notmuch-show-toggle-elide-non-matching)
>(define-key map "$" 'notmuch-show-toggle-process-crypto)
>(define-key map "<" 'notmuch-show-toggle-thread-indentation)
> +   (define-key map ">" 'toggle-truncate-lines)

Okay, this is bikeshedding, but we have ¦ to pipe a message - wouldn't it
be appropriate to reserve > for saving a message to file?

>map)
>   "Keymap for \"notmuch show\" buffers.")
>  (fset 'notmuch-show-mode-map notmuch-show-mode-map)
> --
> 1.7.8.3
>
> ___
> 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: [PATCH] emacs: add default value to notmuch-search-line-faces

2012-01-31 Thread Jani Nikula
On Thu, 26 Jan 2012 23:58:51 +0200, Jani Nikula  wrote:
> On Thu, 26 Jan 2012 14:41:46 -0500, Austin Clements  wrote:
> > Quoth Jani Nikula on Jan 26 at  9:21 pm:
> > > +("flagged" :foreground "red"))
> > 
> > Red is pretty universally used to indicate danger or a serious
> > condition, while "flagged" is simply supposed to draw attention.  I
> > would say blue as a neutral and distinct indicator, but it also has
> > poor visibility (I used to use blue, but found that when scanning my
> > mail, I would habitually skip over flagged messages because they were
> > dark, which was the opposite of what I wanted).  Personally I've
> > settled on yellow; it's visually distinct enough to be easily
> > noticeable and bright enough that I don't skip over it, though it
> > obviously wouldn't work on a light background.
> 
> Can be yellow, I don't really care that much. But isn't a light
> background the default for emacs in most distros? If that matters,
> *shrug*.

Ugh, yellow is absolutely horrible on a white background... that would
certainly draw people to figure out how to change the settings. Now
shall I send v2 with bold for unread and yellow for flagged, or can this
go in as it is?

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


[RFC PATCH] emacs: make show view a/A/x/X key bindings more consistent

2012-01-31 Thread Jani Nikula
Proposal for show view a/A/x/X key bindings, according to
http://titanpad.com/SA39EbNezU and IRC discussion:

'a' = Archive current message, then move to next message, or show next
thread from search if at the last message in thread.

'A' = Archive each message in thread, then show next thread from
search.

'x' = Archive current message, then move to next message, or exit back
to search results if at the last message in thread.

'X' = Archive each message in thread, then exit back to search
results.

IMHO these changes would make the current implementation more
consistent in two ways: 1) 'a'/'A' would advance to next thread like
'a' used to do, 2) 'x' would operate on messages and 'X' on threads
like 'a'/'A' do now.

The implementation here is hacky at best, and I agree with dme that
notmuch-show.el could use some code cleanup and provide
non-interactive primitives. However I won't have the time and energy
for that right now.
---
 emacs/notmuch-show.el |   26 --
 1 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index de9421e..62f3664 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1075,9 +1075,10 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "h" 'notmuch-show-toggle-headers)
(define-key map "-" 'notmuch-show-remove-tag)
(define-key map "+" 'notmuch-show-add-tag)
-   (define-key map "x" 'notmuch-show-archive-thread-then-exit)
-   (define-key map "a" 'notmuch-show-archive-message-then-next)
+   (define-key map "X" 'notmuch-show-archive-thread-then-exit)
+   (define-key map "x" 'notmuch-show-archive-message-then-next-then-exit)
(define-key map "A" 'notmuch-show-archive-thread-then-next)
+   (define-key map "a" 'notmuch-show-archive-message-then-next-then-next)
(define-key map "N" 'notmuch-show-next-message)
(define-key map "P" 'notmuch-show-previous-message)
(define-key map "n" 'notmuch-show-next-open-message)
@@ -1425,10 +1426,12 @@ buffer."
 (if r
(progn
  (notmuch-show-mark-read)
- (notmuch-show-message-adjust))
+ (notmuch-show-message-adjust)
+ t)
   (if pop-at-end
  (notmuch-show-next-thread)
-   (goto-char (point-max))
+   (goto-char (point-max))
+   nil
 
 (defun notmuch-show-previous-open-message ()
   "Show the previous open message."
@@ -1645,12 +1648,23 @@ removed)."
   (notmuch-show-add-tag "inbox")
 (notmuch-show-remove-tag "inbox")))
 
-(defun notmuch-show-archive-message-then-next ()
-  "Archive the current message, then show the next open message in the current 
thread."
+(defun notmuch-show-archive-message-then-next-then-exit ()
+  "Archive the current message, then show the next open message in the current 
thread.
+
+If at the last message in thread, then exit back to search results."
   (interactive)
   (notmuch-show-archive-message)
   (notmuch-show-next-open-message t))
 
+(defun notmuch-show-archive-message-then-next-then-next ()
+  "Archive the current message, then show the next open message in the current 
thread.
+
+If at the last message in thread, then show next thread from search."
+  (interactive)
+  (notmuch-show-archive-message)
+  (unless (notmuch-show-next-open-message)
+(notmuch-show-next-thread t)))
+
 (defun notmuch-show-stash-cc ()
   "Copy CC field of current message to kill-ring."
   (interactive)
-- 
1.7.5.4

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


[RFC PATCH v2] emacs: make show view a/A/x/X key bindings more consistent

2012-01-31 Thread Jani Nikula
Modify the show view key bindings as follows to make them more
consistent:

'a' = Archive current message, then move to next message, or show next
thread from search if at the last message in thread.

'A' = Archive each message in thread, then show next thread from
search.

'x' = Archive current message, then move to next message, or exit back
to search results if at the last message in thread.

'X' = Archive each message in thread, then exit back to search
results.

The changes make the key bindings more consistent in two ways:
1) 'a'/'A' both advance to the next thread like 'a' used to.
2) 'x' operates on messages and 'X' on threads like 'a'/'A'.

---

The original proposal with some discussion is at
http://titanpad.com/SA39EbNezU.

This v2 is merely a slightly polished version of the original. There
will be no further contributions on the subject from me.
---
 emacs/notmuch-show.el |   28 ++--
 1 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index de9421e..57830b6 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1075,9 +1075,10 @@ thread id.  If a prefix is given, crypto processing is 
toggled."
(define-key map "h" 'notmuch-show-toggle-headers)
(define-key map "-" 'notmuch-show-remove-tag)
(define-key map "+" 'notmuch-show-add-tag)
-   (define-key map "x" 'notmuch-show-archive-thread-then-exit)
-   (define-key map "a" 'notmuch-show-archive-message-then-next)
+   (define-key map "X" 'notmuch-show-archive-thread-then-exit)
+   (define-key map "x" 'notmuch-show-archive-message-then-next-or-exit)
(define-key map "A" 'notmuch-show-archive-thread-then-next)
+   (define-key map "a" 
'notmuch-show-archive-message-then-next-or-next-thread)
(define-key map "N" 'notmuch-show-next-message)
(define-key map "P" 'notmuch-show-previous-message)
(define-key map "n" 'notmuch-show-next-open-message)
@@ -1417,7 +1418,8 @@ thread, navigate to the next thread in the parent search 
buffer."
 
 If a prefix argument is given and this is the last open message
 in the thread, navigate to the next thread in the parent search
-buffer."
+buffer. Return t if there was a next open message in the thread
+to show, nil otherwise."
   (interactive "P")
   (let (r)
 (while (and (setq r (notmuch-show-goto-message-next))
@@ -1428,7 +1430,8 @@ buffer."
  (notmuch-show-message-adjust))
   (if pop-at-end
  (notmuch-show-next-thread)
-   (goto-char (point-max))
+   (goto-char (point-max
+r))
 
 (defun notmuch-show-previous-open-message ()
   "Show the previous open message."
@@ -1645,12 +1648,25 @@ removed)."
   (notmuch-show-add-tag "inbox")
 (notmuch-show-remove-tag "inbox")))
 
-(defun notmuch-show-archive-message-then-next ()
-  "Archive the current message, then show the next open message in the current 
thread."
+(defun notmuch-show-archive-message-then-next-or-exit ()
+  "Archive the current message, then show the next open message in the current 
thread.
+
+If at the last open message in the current thread, then exit back
+to search results."
   (interactive)
   (notmuch-show-archive-message)
   (notmuch-show-next-open-message t))
 
+(defun notmuch-show-archive-message-then-next-or-next-thread ()
+  "Archive the current message, then show the next open message in the current 
thread.
+
+If at the last open message in the current thread, then show next
+thread from search."
+  (interactive)
+  (notmuch-show-archive-message)
+  (unless (notmuch-show-next-open-message)
+(notmuch-show-next-thread t)))
+
 (defun notmuch-show-stash-cc ()
   "Copy CC field of current message to kill-ring."
   (interactive)
-- 
1.7.5.4

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


Re: [PATCH] added support for user-specified files & directories to ignore

2012-02-02 Thread Jani Nikula
On Tue, 31 Jan 2012 18:28:04 +0200, Tomi Ollila  wrote:
> A new configuration key 'new.ignore' is used to determine which
> files and directories user wants not to be scanned as new mails.

Hi, please find a few drive-by "while my code is compiling" nitpick
review comments inline. ;) Mostly looks good.

BR,
Jani.


> 
> This work merges my previous attempts and Andreas Amann's work
> in id:"ylp7hi23mw8@tyndall.ie"
> 
> See notes in id:"20120131-new-ignore-1-git-send-email-...@iki.fi"
> ---
> Notes
> 
> 1) Currently there is comment for new.ignore in newly created configuration
> file but as the list is initially empty there will be not tag in place.
> 
> 2) Whenever some already existing directory is added to the exclude list
> and the parent directory timestamp has not changed, notmuch new will not
> notice the directory has gone (as it still is there), user needs to 'touch'
> the parent directory before next 'notmuch new' no make notmuch notice.
> 
> 2012-01-26: could notmuch track mtime of the configuration file and if
> that changes, ignore mail directory timestamps ?
> 
> 
> 3) in id:"1327572718-13411-2-git-send-email-tomi.oll...@iki.fi" dropped...
> 
>  notmuch-client.h |8 
>  notmuch-config.c |   35 +--
>  notmuch-new.c|   45 +
>  3 files changed, 74 insertions(+), 14 deletions(-)
> 
> diff --git a/notmuch-client.h b/notmuch-client.h
> index e0eb594..c62ce78 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -250,6 +250,14 @@ notmuch_config_set_new_tags (notmuch_config_t *config,
>const char *new_tags[],
>size_t length);
>  
> +const char **
> +notmuch_config_get_new_ignore (notmuch_config_t *config,
> +size_t *length);
> +void
> +notmuch_config_set_new_ignore (notmuch_config_t *config,
> +const char *new_ignore[],
> +size_t length);
> +
>  notmuch_bool_t
>  notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config);
>  
> diff --git a/notmuch-config.c b/notmuch-config.c
> index a124e34..f1cc5c2 100644
> --- a/notmuch-config.c
> +++ b/notmuch-config.c
> @@ -44,7 +44,10 @@ static const char new_config_comment[] =
>  " The following options are supported here:\n"
>  "\n"
>  "\ttags  A list (separated by ';') of the tags that will be\n"
> -"\t  added to all messages incorporated by \"notmuch new\".\n";
> +"\t  added to all messages incorporated by \"notmuch new\".\n"
> +"\n"
> +"\tignoreA list (separated by ';') of files and directories that"
> +"\t  will not be searched for messages by \"notmuch new\".\n";
>  
>  static const char user_config_comment[] =
>  " User configuration\n"
> @@ -105,6 +108,8 @@ struct _notmuch_config {
>  size_t user_other_email_length;
>  const char **new_tags;
>  size_t new_tags_length;
> +const char **new_ignore;
> +size_t new_ignore_length;
>  notmuch_bool_t maildir_synchronize_flags;
>  const char **search_exclude_tags;
>  size_t search_exclude_tags_length;
> @@ -264,6 +269,8 @@ notmuch_config_open (void *ctx,
>  config->user_other_email_length = 0;
>  config->new_tags = NULL;
>  config->new_tags_length = 0;
> +config->new_ignore = NULL;
> +config->new_ignore_length = 0;
>  config->maildir_synchronize_flags = TRUE;
>  config->search_exclude_tags = NULL;
>  config->search_exclude_tags_length = 0;
> @@ -360,7 +367,11 @@ notmuch_config_open (void *ctx,
>  const char *tags[] = { "unread", "inbox" };
>   notmuch_config_set_new_tags (config, tags, 2);
>  }
> -
> +#if 0 /* No point setting empty list -- it's not written */
> +if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
> + notmuch_config_set_new_ignore (config, NULL, 0);
> +}
> +#endif

I'd prefer not having any #if 0 code. How about just having the code
there, even if it ends up being a NOP? You never know when the config
plumbing is going to change (it could use some love), e.g. it might
write the default value in comments in the future.

>  if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
>   if (is_new) {
>   const char *tags[] = { "deleted", "spam" };
> @@ -609,6 +620,15 @@ notmuch_config_get_new_tags (notmuch_config_t *config,   
> size_t *length)
>&(config->new_tags_length), length);
>  }
>  
> +const char **
> +notmuch_config_get_new_ignore (notmuch_config_t *config,   size_t *length)

Is there extra space in there?

> +{
> +return _config_get_list (config, "new", "ignore",
> +  &(config->new_ignore),
> +  &(config->new_ignore_length), length);
> +}
> +
> +
>  void
>  notmuch_config_set_user_other_email (notmuch_config_t *config,
>const char *list[],
> @@ 

[PATCH v2] emacs: add default value to notmuch-search-line-faces

2012-02-02 Thread Jani Nikula
Add default value to notmuch-search-line-faces to show "unread"
messages in bold, and "flagged" messages in blue, to have some visual
indication of important messages in search results. This should be
helpful for new users.

"unread" tag is quite obvious, and handled specially both in the lib
and emacs ui. "flagged" is synced to maildir F flag in the lib. If one
syncs the maildir to IMAP, this also translates to corresponding IMAP
flag. (This is "starred" in GMail and Android.)

Signed-off-by: Jani Nikula 
---
 emacs/notmuch.el |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 5fa239a..bbf0aec 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -688,7 +688,8 @@ This function advances the next thread when finished."
  (goto-char (point-min))
  (forward-line (1- notmuch-search-target-line
 
-(defcustom notmuch-search-line-faces nil
+(defcustom notmuch-search-line-faces '(("unread" :weight bold)
+  ("flagged" :foreground "blue"))
   "Tag/face mapping for line highlighting in notmuch-search.
 
 Here is an example of how to color search results based on tags.
-- 
1.7.5.4

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


Re: [PATCH] add support for user-specified files & directories to ignore

2012-02-02 Thread Jani Nikula

Hi Tomi, please find a few more comments and nitpicks inline. No need to
roll another version for them, though.

BR,
Jani.

On Thu,  2 Feb 2012 17:17:33 +0200, Tomi Ollila  wrote:
> A new configuration key 'new.ignore' is used to determine which
> files and directories user wants not to be scanned as new mails.
> 
> Mark the corresponding test as no longer broken
> (test from id:"1328105573-4626-1-git-send-email-pie...@praet.org" ).
> 
> This work merges my previous attempts and Andreas Amann's work
> in id:"ylp7hi23mw8@tyndall.ie"
> 
> See notes in id:"20120202-new-ignore-1-git-send-email-...@iki.fi"
> ---
> 
> Whenever some already existing directory is added to the exclude list
> and the parent directory timestamp has not changed, notmuch new will not
> notice the directory has gone (as it still is there), user needs to 'touch'
> the parent directory before next 'notmuch new' no make notmuch notice.
> 
> 2012-01-26: could notmuch track mtime of the configuration file and if
> that changes, ignore mail directory timestamps ?
> 
> See previous notes in id:"20120131-new-ignore-1-git-send-email-...@iki.fi"
> 
>  notmuch-client.h |   10 ++
>  notmuch-config.c |   33 +++--
>  notmuch-new.c|   45 +
>  test/new |1 -
>  4 files changed, 74 insertions(+), 15 deletions(-)
> 
> diff --git a/notmuch-client.h b/notmuch-client.h
> index e0eb594..26153df 100644
> --- a/notmuch-client.h
> +++ b/notmuch-client.h
> @@ -245,11 +245,21 @@ notmuch_config_set_user_other_email (notmuch_config_t 
> *config,
>  const char **
>  notmuch_config_get_new_tags (notmuch_config_t *config,
>size_t *length);
> +

Nitpick: unrelated change.

>  void
>  notmuch_config_set_new_tags (notmuch_config_t *config,
>const char *new_tags[],
>size_t length);
>  
> +const char **
> +notmuch_config_get_new_ignore (notmuch_config_t *config,
> +size_t *length);
> +
> +void
> +notmuch_config_set_new_ignore (notmuch_config_t *config,
> +const char *new_ignore[],
> +size_t length);
> +
>  notmuch_bool_t
>  notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config);
>  
> diff --git a/notmuch-config.c b/notmuch-config.c
> index a124e34..1f01004 100644
> --- a/notmuch-config.c
> +++ b/notmuch-config.c
> @@ -44,7 +44,10 @@ static const char new_config_comment[] =
>  " The following options are supported here:\n"
>  "\n"
>  "\ttags  A list (separated by ';') of the tags that will be\n"
> -"\t  added to all messages incorporated by \"notmuch new\".\n";
> +"\t  added to all messages incorporated by \"notmuch new\".\n"
> +"\n"
> +"\tignoreA list (separated by ';') of file and directory names\n"
> +"\t  that will not be searched for messages by \"notmuch new\".\n";

Do I understand the code correctly, the ignore list must contain file
and directory names without (absolute or relative) paths? And that there
is no way to exclude only the subdirectory "foo" within directory "foo",
because they would both get ignored?

I don't see this as a bad thing, not at all. This keeps things nice and
simple, it just needs proper documentation.

>  
>  static const char user_config_comment[] =
>  " User configuration\n"
> @@ -105,6 +108,8 @@ struct _notmuch_config {
>  size_t user_other_email_length;
>  const char **new_tags;
>  size_t new_tags_length;
> +const char **new_ignore;
> +size_t new_ignore_length;
>  notmuch_bool_t maildir_synchronize_flags;
>  const char **search_exclude_tags;
>  size_t search_exclude_tags_length;
> @@ -264,6 +269,8 @@ notmuch_config_open (void *ctx,
>  config->user_other_email_length = 0;
>  config->new_tags = NULL;
>  config->new_tags_length = 0;
> +config->new_ignore = NULL;
> +config->new_ignore_length = 0;
>  config->maildir_synchronize_flags = TRUE;
>  config->search_exclude_tags = NULL;
>  config->search_exclude_tags_length = 0;
> @@ -361,6 +368,10 @@ notmuch_config_open (void *ctx,
>   notmuch_config_set_new_tags (config, tags, 2);
>  }
>  
> +if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
> + notmuch_config_set_new_ignore (config, NULL, 0);
> +}
> +
>  if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
>   if (is_new) {
>   const char *tags[] = { "deleted", "spam" };
> @@ -504,7 +515,8 @@ _config_set_list (notmuch_config_t *config,
> const char *list[],
> size_t length, const char ***config_var )
>  {
> -g_key_file_set_string_list (config->key_file, group, name, list, length);
> +g_key_file_set_string_list (config->key_file,
> + group, name, list, length);

Nitpick: unrelated change.

>  talloc_free (*config_var

Re: Set "From" based on "To" when replying

2012-02-02 Thread Jani Nikula
On Sat, 21 Jan 2012 16:35:10 +0100, Simon Campese  
wrote:
> Dear Community,
> 
> I've got my own domain and when registering or shopping at some website,
> I always use email addresses of the form "websiten...@mydomain.org", so
> for example I use "ama...@mydomain.org" when shopping at amazon. The
> reason for this is categorizing incoming mail on the one hand, and
> immediately being able to spot the source of spam on the other hand. 
> 
> I would like to implement the following behaviour: When replying to a
> mail that has "someth...@mydomain.org" in the "To"-header, I would like
> to have the "From"-header of the reply to be automatically set to this
> address. 
> 
> Is there some kind of reply-hook in notmuch where one could put an
> appropriate function? 

Do you have all those email addresses in the user.other_email
configuration option in your ~/.notmuch-config? It should do the trick,
though I can see that it might get a bit tedious if you use plenty of
email addresses like above.

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


Re: [PATCH v4 07/11] lib: added interface notmuch_thread_get_flag_messages

2012-02-02 Thread Jani Nikula

Hi Mark -

This is my first look at any version of the series; apologies if I'm
clueless about some details... Please find some comments below.

BR,
Jani.


On Thu,  2 Feb 2012 17:43:35 +, Mark Walters  
wrote:
> The function is
> notmuch_thread_get_flag_messages
> (notmuch_thread_t *thread, unsigned int flag_mask, unsigned int flags)
> 
> and returns the number of messages with the specified flags on flag_mask.

Is the purpose of this function to get the count of messages that have
certain flags set, certain flags not set, and certain flags don't-care?

At the very least, I think the documentation of the function should be
greatly improved.

I think the name of the function should be notmuch_thread_count_messages
which is like notmuch_query_count_messages, but for messages in threads
(and with some extra restrictions).

> 
> This generalises the existing function
> notmuch_thread_get_total_messages and
> notmuch_thread_get_matched_messages which are retained to maintain
> compatibility.
> ---
>  lib/message.cc |6 +++---
>  lib/notmuch.h  |   15 +--
>  lib/thread.cc  |   39 ++-
>  3 files changed, 42 insertions(+), 18 deletions(-)
> 
> diff --git a/lib/message.cc b/lib/message.cc
> index 0075425..d60da83 100644
> --- a/lib/message.cc
> +++ b/lib/message.cc
> @@ -746,7 +746,7 @@ notmuch_bool_t
>  notmuch_message_get_flag (notmuch_message_t *message,
> notmuch_message_flag_t flag)
>  {
> -return message->flags & (1 << flag);
> +return message->flags & flag;
>  }
>  
>  void
> @@ -754,9 +754,9 @@ notmuch_message_set_flag (notmuch_message_t *message,
> notmuch_message_flag_t flag, notmuch_bool_t enable)
>  {
>  if (enable)
> - message->flags |= (1 << flag);
> + message->flags |= flag;
>  else
> - message->flags &= ~(1 << flag);
> + message->flags &= ~flag;
>  }
>  
>  time_t
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index f75afae..c02e7f4 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -654,6 +654,16 @@ notmuch_thread_get_thread_id (notmuch_thread_t *thread);
>  int
>  notmuch_thread_get_total_messages (notmuch_thread_t *thread);
>  
> +/* Get the number of messages in 'thread' which have the specified
> + * flags on flag_mask.
> + *
> + * This is a more general interface than
> + * notmuch_thread_get_total_messages or
> + * notmuch_thread_get_matched_messages
> + */
> +int
> +notmuch_thread_get_flag_messages (notmuch_thread_t *thread, unsigned int 
> flag_mask, unsigned int flags);
> +
>  /* Get a notmuch_messages_t iterator for the top-level messages in
>   * 'thread'.
>   *
> @@ -902,8 +912,9 @@ notmuch_message_get_filenames (notmuch_message_t 
> *message);
>  
>  /* Message flags */
>  typedef enum _notmuch_message_flag {
> -NOTMUCH_MESSAGE_FLAG_MATCH,
> -NOTMUCH_MESSAGE_FLAG_EXCLUDED
> +NOTMUCH_MESSAGE_FLAG_MATCH = (1<<0),
> +NOTMUCH_MESSAGE_FLAG_EXCLUDED = (1<<1),
> +NOTMUCH_MESSAGE_FLAG_MAX  = (1<<2)

How are these used by the current lib users at the moment? How will they
break with this change?

Please align the assignments. 

>  } notmuch_message_flag_t;
>  
>  /* Get a value of a flag for the email corresponding to 'message'. */
> diff --git a/lib/thread.cc b/lib/thread.cc
> index e976d64..542f7f4 100644
> --- a/lib/thread.cc
> +++ b/lib/thread.cc
> @@ -37,8 +37,7 @@ struct visible _notmuch_thread {
>  
>  notmuch_message_list_t *message_list;
>  GHashTable *message_hash;
> -int total_messages;
> -int matched_messages;
> +int flag_count_messages[NOTMUCH_MESSAGE_FLAG_MAX];
>  time_t oldest;
>  time_t newest;
>  };
> @@ -226,7 +225,6 @@ _thread_add_message (notmuch_thread_t *thread,
>  
>  _notmuch_message_list_add_message (thread->message_list,
>  talloc_steal (thread, message));
> -thread->total_messages++;
>  
>  g_hash_table_insert (thread->message_hash,
>xstrdup (notmuch_message_get_message_id (message)),
> @@ -319,21 +317,18 @@ _thread_add_matched_message (notmuch_thread_t *thread,
>  
>  date = notmuch_message_get_date (message);
>  
> -if (date < thread->oldest || ! thread->matched_messages) {
> +if (date < thread->oldest || ! notmuch_thread_get_matched_messages 
> (thread)) {
>   thread->oldest = date;
>   if (sort == NOTMUCH_SORT_OLDEST_FIRST)
>   _thread_set_subject_from_message (thread, message);
>  }
>  
> -if (date > thread->newest || ! thread->matched_messages) {
> +if (date > thread->newest || ! notmuch_thread_get_matched_messages 
> (thread)) {
>   thread->newest = date;
>   if (sort != NOTMUCH_SORT_OLDEST_FIRST)
>   _thread_set_subject_from_message (thread, message);
>  }
>  
> -if (!notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED))
> - thread->matched_messages++;
> -
>  if (g_hash_table_lookup_extended (thread->message_hash,
>

Re: [PATCH v4 08/11] cli: Make notmuch-show respect excludes.

2012-02-02 Thread Jani Nikula
On Thu,  2 Feb 2012 17:43:36 +, Mark Walters  
wrote:
> This adds the excludes to notmuch-show.c. We do not exclude when only
> a single message (or part) is requested. notmuch-show will output the
> exclude information when either text or json format is requested. As
> this changes the output from notmuch-show it breaks many tests (in a
> trivial and expected fashion).
> ---
>  notmuch-show.c |   24 
>  1 files changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/notmuch-show.c b/notmuch-show.c
> index dec799c..108f13b 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -193,10 +193,11 @@ _get_one_line_summary (const void *ctx, 
> notmuch_message_t *message)
>  static void
>  format_message_text (unused (const void *ctx), notmuch_message_t *message, 
> int indent)
>  {
> -printf ("id:%s depth:%d match:%d filename:%s\n",
> +printf ("id:%s depth:%d match:%d excluded:%d filename:%s\n",
>   notmuch_message_get_message_id (message),
>   indent,
> - notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH),
> + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 
> : 0,
> + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 
> 1 : 0,
>   notmuch_message_get_filename (message));
>  }
>  
> @@ -212,9 +213,10 @@ format_message_json (const void *ctx, notmuch_message_t 
> *message, unused (int in
>  date = notmuch_message_get_date (message);
>  relative_date = notmuch_time_relative_date (ctx, date);
>  
> -printf ("\"id\": %s, \"match\": %s, \"filename\": %s, \"timestamp\": 
> %ld, \"date_relative\": \"%s\", \"tags\": [",
> +printf ("\"id\": %s, \"match\": %s, \"excluded\": %s, \"filename\": %s, 
> \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [",
>   json_quote_str (ctx_quote, notmuch_message_get_message_id 
> (message)),
>   notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 
> "true" : "false",
> + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 
> "true" : "false",
>   json_quote_str (ctx_quote, notmuch_message_get_filename (message)),
>   date, relative_date);
>  
> @@ -1059,9 +1061,13 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>  char *opt;
>  const notmuch_show_format_t *format = &format_text;
>  notmuch_show_params_t params;
> +const char **search_exclude_tags;
> +size_t search_exclude_tags_length;

Please move these within the if (!no_exclude) block.

>  int mbox = 0;
>  int format_specified = 0;
>  int i;
> +notmuch_bool_t no_exclude = FALSE;
> +unsigned int j;

Same. Or better yet, reuse i.

>  
>  params.entire_thread = 0;
>  params.raw = 0;
> @@ -1098,6 +1104,8 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>   params.part = atoi(argv[i] + sizeof ("--part=") - 1);
>   } else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
>   params.entire_thread = 1;
> + } else if (STRNCMP_LITERAL (argv[i], "--no-exclude") == 0) {
> + no_exclude = TRUE;
>   } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||
>  (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
>   if (params.cryptoctx == NULL) {
> @@ -1167,10 +1175,18 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>  if (params.raw && params.part < 0)
>   params.part = 0;
>  
> +/* If a single message is requested we do not use search_excludes. */
>  if (params.part >= 0)
>   return do_show_single (ctx, query, format, ¶ms);
> -else
> +else {

Nitpick: There's no rule about this, but I do like the style of using
braces for both branches if either branch needs them.

> + if (!no_exclude) {
> + search_exclude_tags = notmuch_config_get_search_exclude_tags
> + (config, &search_exclude_tags_length);
> + for (j = 0; j < search_exclude_tags_length; j++)
> + notmuch_query_add_tag_exclude (query, search_exclude_tags[j]);
> + }
>   return do_show (ctx, query, format, ¶ms);
> +}

Hmm, unreachable code below. Why doesn't the compiler complain?

>  
>  notmuch_query_destroy (query);
>  notmuch_database_close (notmuch);
> -- 
> 1.7.2.3
> 
> ___
> 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: [PATCH v4 07/11] lib: added interface notmuch_thread_get_flag_messages

2012-02-02 Thread Jani Nikula
On Thu, 02 Feb 2012 22:27:36 +, Mark Walters  
wrote:
> On Thu, 02 Feb 2012 23:55:33 +0200, Jani Nikula  wrote:
> > 
> > Hi Mark -
> > 
> > This is my first look at any version of the series; apologies if I'm
> > clueless about some details... Please find some comments below.
> > 
> > BR,
> > Jani.
> > 
> > 
> > On Thu,  2 Feb 2012 17:43:35 +, Mark Walters 
> >  wrote:
> > > The function is
> > > notmuch_thread_get_flag_messages
> > > (notmuch_thread_t *thread, unsigned int flag_mask, unsigned int flags)
> > > 
> > > and returns the number of messages with the specified flags on flag_mask.
> > 
> > Is the purpose of this function to get the count of messages that have
> > certain flags set, certain flags not set, and certain flags don't-care?
> 
> Yes: I was trying to follow Austin's suggestion from
> id:"20120124025331.gz16...@mit.edu" (although stupidly I didn't
> follow his suggestion of a function name).
> 
> > At the very least, I think the documentation of the function should be
> > greatly improved.
> > 
> > I think the name of the function should be notmuch_thread_count_messages
> > which is like notmuch_query_count_messages, but for messages in threads
> > (and with some extra restrictions).
> 
> Yes I like your name; before I change it do you (and others) prefer it
> to Austin's suggestion of notmuch_thread_count_flags. Or we could even
> be more verbose with something like
> notmuch_thread_count_messages_with_flags

I'd like to make it clear that it's about message count. Not about
getting flags, not about flag counts. _with_flags is a matter of taste,
no strong opinions there.

> 
> > >  /* Message flags */
> > >  typedef enum _notmuch_message_flag {
> > > -NOTMUCH_MESSAGE_FLAG_MATCH,
> > > -NOTMUCH_MESSAGE_FLAG_EXCLUDED
> > > +NOTMUCH_MESSAGE_FLAG_MATCH = (1<<0),
> > > +NOTMUCH_MESSAGE_FLAG_EXCLUDED = (1<<1),
> > > +NOTMUCH_MESSAGE_FLAG_MAX  = (1<<2)
> > 
> > How are these used by the current lib users at the moment? How will they
> > break with this change?
> 
> The only existing flag is NOTMUCH_MESSAGE_FLAG_MATCH: that is currently
> zero but in the current code that is the bit offset of the flag; in my
> version it is the actual bit for the flag (otherwise I think flag masks
> end up very ugly). I believe all callers use notmuch_message_set_flag
> and notmuch_message_get_flag so they should not notice the difference.
> 
> > Please align the assignments. 
> 
> Will do.
> 
> > > @@ -457,8 +452,8 @@ _notmuch_thread_create (void *ctx,
> > >  thread->message_hash = g_hash_table_new_full (g_str_hash, 
> > > g_str_equal,
> > > free, NULL);
> > >  
> > > -thread->total_messages = 0;
> > > -thread->matched_messages = 0;
> > > +for (i = 0; i < NOTMUCH_MESSAGE_FLAG_MAX; i++)
> > > + thread->flag_count_messages[i] = 0;
> > 
> > memset (thread->flag_count_messages, 0, 
> > sizeof(thread->flag_count_messages));
> 
> 
> Will do 
> 
> > >  thread->oldest = 0;
> > >  thread->newest = 0;
> > >  
> > > @@ -473,6 +468,7 @@ _notmuch_thread_create (void *ctx,
> > >notmuch_messages_move_to_next (messages))
> > >  {
> > >   unsigned int doc_id;
> > > + unsigned int message_flags;
> > >  
> > >   message = notmuch_messages_get (messages);
> > >   doc_id = _notmuch_message_get_doc_id (message);
> > > @@ -485,6 +481,10 @@ _notmuch_thread_create (void *ctx,
> > >   _notmuch_doc_id_set_remove (match_set, doc_id);
> > >   _thread_add_matched_message (thread, message, sort);
> > >   }
> > > + message_flags =
> > > + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) |
> > > + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED);
> > > + thread->flag_count_messages[message_flags]++;
> > 
> > The first impression of using a set of flags as index is that there's a
> > bug. But this is to keep count of messages with certain flag sets rather
> > than total for each flag, right? I think this needs more comments, more
> > documentation. Already naming the field flag_set_message_counts or
> > similar would help greatly.
> 
> I will try and document it better: on first reading I parsed your name
> as flag set (as verb) message counts whereas I assume 

Re: [PATCH v4 08/11] cli: Make notmuch-show respect excludes.

2012-02-02 Thread Jani Nikula
On Thu, 02 Feb 2012 22:35:10 +, Mark Walters  
wrote:
> 
> On Fri, 03 Feb 2012 00:08:32 +0200, Jani Nikula  wrote:
> > On Thu,  2 Feb 2012 17:43:36 +, Mark Walters 
> >  wrote:
> > > This adds the excludes to notmuch-show.c. We do not exclude when only
> > > a single message (or part) is requested. notmuch-show will output the
> > > exclude information when either text or json format is requested. As
> > > this changes the output from notmuch-show it breaks many tests (in a
> > > trivial and expected fashion).
> > > ---
> > >  notmuch-show.c |   24 
> > >  1 files changed, 20 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/notmuch-show.c b/notmuch-show.c
> > > index dec799c..108f13b 100644
> > > --- a/notmuch-show.c
> > > +++ b/notmuch-show.c
> > > @@ -193,10 +193,11 @@ _get_one_line_summary (const void *ctx, 
> > > notmuch_message_t *message)
> > >  static void
> > >  format_message_text (unused (const void *ctx), notmuch_message_t 
> > > *message, int indent)
> > >  {
> > > -printf ("id:%s depth:%d match:%d filename:%s\n",
> > > +printf ("id:%s depth:%d match:%d excluded:%d filename:%s\n",
> > >   notmuch_message_get_message_id (message),
> > >   indent,
> > > - notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH),
> > > + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 
> > > : 0,
> > > + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 
> > > 1 : 0,
> > >   notmuch_message_get_filename (message));
> > >  }
> > >  
> > > @@ -212,9 +213,10 @@ format_message_json (const void *ctx, 
> > > notmuch_message_t *message, unused (int in
> > >  date = notmuch_message_get_date (message);
> > >  relative_date = notmuch_time_relative_date (ctx, date);
> > >  
> > > -printf ("\"id\": %s, \"match\": %s, \"filename\": %s, \"timestamp\": 
> > > %ld, \"date_relative\": \"%s\", \"tags\": [",
> > > +printf ("\"id\": %s, \"match\": %s, \"excluded\": %s, \"filename\": 
> > > %s, \"timestamp\": %ld, \"date_relative\": \"%s\", \"tags\": [",
> > >   json_quote_str (ctx_quote, notmuch_message_get_message_id 
> > > (message)),
> > >   notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 
> > > "true" : "false",
> > > + notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 
> > > "true" : "false",
> > >   json_quote_str (ctx_quote, notmuch_message_get_filename (message)),
> > >   date, relative_date);
> > >  
> > > @@ -1059,9 +1061,13 @@ notmuch_show_command (void *ctx, unused (int 
> > > argc), unused (char *argv[]))
> > >  char *opt;
> > >  const notmuch_show_format_t *format = &format_text;
> > >  notmuch_show_params_t params;
> > > +const char **search_exclude_tags;
> > > +size_t search_exclude_tags_length;
> > 
> > Please move these within the if (!no_exclude) block.
> 
> Will do. (I forgot to move them in notmuch-show when doing notmuch-count
> and notmuch-search)
> 
> > >  int mbox = 0;
> > >  int format_specified = 0;
> > >  int i;
> > > +notmuch_bool_t no_exclude = FALSE;
> > > +unsigned int j;
> > 
> > Same. Or better yet, reuse i.
> 
> Will do.
> 
> > >  params.entire_thread = 0;
> > >  params.raw = 0;
> > > @@ -1098,6 +1104,8 @@ notmuch_show_command (void *ctx, unused (int argc), 
> > > unused (char *argv[]))
> > >   params.part = atoi(argv[i] + sizeof ("--part=") - 1);
> > >   } else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
> > >   params.entire_thread = 1;
> > > + } else if (STRNCMP_LITERAL (argv[i], "--no-exclude") == 0) {
> > > + no_exclude = TRUE;
> > >   } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||
> > >  (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
> > >   if (params.cryptoctx == NULL) {
> > > @@ -1167,10 +1175,18 @@ notmuch_show_command (void *ctx, unused (int 
> > > argc), unused (char *argv[]))
> > >  if 

Re: [PATCH v4 07/11] lib: added interface notmuch_thread_get_flag_messages

2012-02-03 Thread Jani Nikula
On Thu, 02 Feb 2012 23:24:56 +, Mark Walters  
wrote:
> On Fri, 03 Feb 2012 01:07:59 +0200, Jani Nikula  wrote:
> > On Thu, 02 Feb 2012 22:27:36 +, Mark Walters 
> >  wrote:
> > > On Thu, 02 Feb 2012 23:55:33 +0200, Jani Nikula  wrote:
> > > > 
> > > > Hi Mark -
> > > > 
> > > > This is my first look at any version of the series; apologies if I'm
> > > > clueless about some details... Please find some comments below.
> > > > 
> > > > BR,
> > > > Jani.
> > > > 
> > > > 
> > > > On Thu,  2 Feb 2012 17:43:35 +, Mark Walters 
> > > >  wrote:
> > > > > The function is
> > > > > notmuch_thread_get_flag_messages
> > > > > (notmuch_thread_t *thread, unsigned int flag_mask, unsigned int flags)
> > > > > 
> > > > > and returns the number of messages with the specified flags on 
> > > > > flag_mask.
> > > > 
> > > > Is the purpose of this function to get the count of messages that have
> > > > certain flags set, certain flags not set, and certain flags don't-care?
> > > 
> > > Yes: I was trying to follow Austin's suggestion from
> > > id:"20120124025331.gz16...@mit.edu" (although stupidly I didn't
> > > follow his suggestion of a function name).
> > > 
> > > > At the very least, I think the documentation of the function should be
> > > > greatly improved.
> > > > 
> > > > I think the name of the function should be notmuch_thread_count_messages
> > > > which is like notmuch_query_count_messages, but for messages in threads
> > > > (and with some extra restrictions).
> > > 
> > > Yes I like your name; before I change it do you (and others) prefer it
> > > to Austin's suggestion of notmuch_thread_count_flags. Or we could even
> > > be more verbose with something like
> > > notmuch_thread_count_messages_with_flags
> > 
> > I'd like to make it clear that it's about message count. Not about
> > getting flags, not about flag counts. _with_flags is a matter of taste,
> > no strong opinions there.
> 
> I think I will go with notmuch_thread_count_messages as you suggest.
> 
> > > > >  /* Message flags */
> > > > >  typedef enum _notmuch_message_flag {
> > > > > -NOTMUCH_MESSAGE_FLAG_MATCH,
> > > > > -NOTMUCH_MESSAGE_FLAG_EXCLUDED
> > > > > +NOTMUCH_MESSAGE_FLAG_MATCH = (1<<0),
> > > > > +NOTMUCH_MESSAGE_FLAG_EXCLUDED = (1<<1),
> > > > > +NOTMUCH_MESSAGE_FLAG_MAX  = (1<<2)
> > > > 
> > > > How are these used by the current lib users at the moment? How will they
> > > > break with this change?
> 
> I will just comment on this: the *only* reason I put in
> NOTMUCH_MESSAGE_FLAG_MAX was as a way of keeping track of the size of
> the bitfield. If there is a better way do say!

At least one improvement would be to make it NOTMUCH_MESSAGE_FLAG_ALL
(or similar) which would be the OR of all the other flags. Above, it
should be equal to (1 << 2) - 1. Not only is this something usable to
the library users, but also more accurate - if I'm not mistaken, the
flagset array currently has one element too many.

If documented properly, the users should not be surprised that in the
future more flags might be added to NOTMUCH_MESSAGE_FLAG_ALL, and
depending on the case they may or may not want to use that.

Some purists might say that #defines are better suited for defining bit
flags than enums, but I'm fine with either.

> 
> > > The only existing flag is NOTMUCH_MESSAGE_FLAG_MATCH: that is currently
> > > zero but in the current code that is the bit offset of the flag; in my
> > > version it is the actual bit for the flag (otherwise I think flag masks
> > > end up very ugly). I believe all callers use notmuch_message_set_flag
> > > and notmuch_message_get_flag so they should not notice the difference.
> > > 
> > > > Please align the assignments. 
> > > 
> > > Will do.
> > > 
> > > > > @@ -457,8 +452,8 @@ _notmuch_thread_create (void *ctx,
> > > > >  thread->message_hash = g_hash_table_new_full (g_str_hash, 
> > > > > g_str_equal,
> > > > > free, NULL);
> > > > >  
> > > > > -thread->total_messages = 0;
> > > > > -   

Re: [PATCH v4 07/11] lib: added interface notmuch_thread_get_flag_messages

2012-02-03 Thread Jani Nikula
On Fri, 03 Feb 2012 09:36:29 +, Mark Walters  
wrote:
> On Fri, 03 Feb 2012 08:48:27 +0000, Jani Nikula  wrote:
> > On Thu, 02 Feb 2012 23:24:56 +, Mark Walters 
> >  wrote:
> > > On Fri, 03 Feb 2012 01:07:59 +0200, Jani Nikula  wrote:
> > > > On Thu, 02 Feb 2012 22:27:36 +, Mark Walters 
> > > >  wrote:
> > > > > On Thu, 02 Feb 2012 23:55:33 +0200, Jani Nikula  
> > > > > wrote:
> > > > > > 
> > > > > > Hi Mark -
> > > > > > 
> > > > > > This is my first look at any version of the series; apologies if I'm
> > > > > > clueless about some details... Please find some comments below.
> > > > > > 
> > > > > > BR,
> > > > > > Jani.
> > > > > > 
> > > > > > 
> > > > > > On Thu,  2 Feb 2012 17:43:35 +, Mark Walters 
> > > > > >  wrote:
> > > > > > > The function is
> > > > > > > notmuch_thread_get_flag_messages
> > > > > > > (notmuch_thread_t *thread, unsigned int flag_mask, unsigned int 
> > > > > > > flags)
> > > > > > > 
> > > > > > > and returns the number of messages with the specified flags on 
> > > > > > > flag_mask.
> > > > > > 
> > > > > > Is the purpose of this function to get the count of messages that 
> > > > > > have
> > > > > > certain flags set, certain flags not set, and certain flags 
> > > > > > don't-care?
> > > > > 
> > > > > Yes: I was trying to follow Austin's suggestion from
> > > > > id:"20120124025331.gz16...@mit.edu" (although stupidly I didn't
> > > > > follow his suggestion of a function name).
> > > > > 
> > > > > > At the very least, I think the documentation of the function should 
> > > > > > be
> > > > > > greatly improved.
> > > > > > 
> > > > > > I think the name of the function should be 
> > > > > > notmuch_thread_count_messages
> > > > > > which is like notmuch_query_count_messages, but for messages in 
> > > > > > threads
> > > > > > (and with some extra restrictions).
> > > > > 
> > > > > Yes I like your name; before I change it do you (and others) prefer it
> > > > > to Austin's suggestion of notmuch_thread_count_flags. Or we could even
> > > > > be more verbose with something like
> > > > > notmuch_thread_count_messages_with_flags
> > > > 
> > > > I'd like to make it clear that it's about message count. Not about
> > > > getting flags, not about flag counts. _with_flags is a matter of taste,
> > > > no strong opinions there.
> > > 
> > > I think I will go with notmuch_thread_count_messages as you suggest.
> > > 
> > > > > > >  /* Message flags */
> > > > > > >  typedef enum _notmuch_message_flag {
> > > > > > > -NOTMUCH_MESSAGE_FLAG_MATCH,
> > > > > > > -NOTMUCH_MESSAGE_FLAG_EXCLUDED
> > > > > > > +NOTMUCH_MESSAGE_FLAG_MATCH = (1<<0),
> > > > > > > +NOTMUCH_MESSAGE_FLAG_EXCLUDED = (1<<1),
> > > > > > > +NOTMUCH_MESSAGE_FLAG_MAX  = (1<<2)
> > > > > > 
> > > > > > How are these used by the current lib users at the moment? How will 
> > > > > > they
> > > > > > break with this change?
> > > 
> > > I will just comment on this: the *only* reason I put in
> > > NOTMUCH_MESSAGE_FLAG_MAX was as a way of keeping track of the size of
> > > the bitfield. If there is a better way do say!
> > 
> > At least one improvement would be to make it NOTMUCH_MESSAGE_FLAG_ALL
> > (or similar) which would be the OR of all the other flags. Above, it
> > should be equal to (1 << 2) - 1. Not only is this something usable to
> > the library users, but also more accurate - if I'm not mistaken, the
> > flagset array currently has one element too many.
> > 
> > If documented properly, the users should not be surprised that in the
> > future more flags might be added to NOTMUCH_MESSAGE_FLAG_ALL, and
> > depending on the case they may or may not want to use that.
> 
> I thin

[PATCH 1/2] cli: convert "notmuch show" to use the new argument parser

2012-02-03 Thread Jani Nikula
Use the new notmuch argument parser to handle arguments in "notmuch
show". There are two corner case functional changes:

1) Also set params.raw = 1 when defaulting to raw format when part is
   requested but format is not specified.

2) Do not set params.decrypt if crypto context creation fails.

Signed-off-by: Jani Nikula 
---
 notmuch-show.c |  153 +---
 1 files changed, 79 insertions(+), 74 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index dec799c..f93e121 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1049,6 +1049,14 @@ do_show (void *ctx,
 return 0;
 }
 
+enum {
+NOTMUCH_FORMAT_NOT_SPECIFIED,
+NOTMUCH_FORMAT_JSON,
+NOTMUCH_FORMAT_TEXT,
+NOTMUCH_FORMAT_MBOX,
+NOTMUCH_FORMAT_RAW
+};
+
 int
 notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
@@ -1056,92 +1064,98 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 notmuch_database_t *notmuch;
 notmuch_query_t *query;
 char *query_string;
-char *opt;
+int opt_index;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params;
-int mbox = 0;
-int format_specified = 0;
-int i;
+notmuch_show_params_t params = { .part = -1 };
+int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
+notmuch_bool_t decrypt = FALSE;
+notmuch_bool_t verify = FALSE;
+notmuch_bool_t entire_thread = FALSE;
+
+notmuch_opt_desc_t options[] = {
+   { NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
+ (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
+ { "text", NOTMUCH_FORMAT_TEXT },
+ { "mbox", NOTMUCH_FORMAT_MBOX },
+ { "raw", NOTMUCH_FORMAT_RAW },
+ { 0, 0 } } },
+   { NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
+   { NOTMUCH_OPT_BOOLEAN, &entire_thread, "entire-thread", 't', 0 },
+   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+   { 0, 0, 0, 0, 0 }
+};
+
+opt_index = parse_arguments (argc, argv, options, 1);
+if (opt_index < 0) {
+   /* diagnostics already printed */
+   return 1;
+}
 
-params.entire_thread = 0;
-params.raw = 0;
-params.part = -1;
-params.cryptoctx = NULL;
-params.decrypt = 0;
+params.entire_thread = entire_thread;
 
-argc--; argv++; /* skip subcommand argument */
+if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
+   /* if part was requested and format was not specified, use format=raw */
+   if (params.part >= 0)
+   format_sel = NOTMUCH_FORMAT_RAW;
+   else
+   format_sel = NOTMUCH_FORMAT_TEXT;
+}
 
-for (i = 0; i < argc && argv[i][0] == '-'; i++) {
-   if (strcmp (argv[i], "--") == 0) {
-   i++;
-   break;
+switch (format_sel) {
+case NOTMUCH_FORMAT_JSON:
+   format = &format_json;
+   params.entire_thread = 1;
+   break;
+case NOTMUCH_FORMAT_TEXT:
+   format = &format_text;
+   break;
+case NOTMUCH_FORMAT_MBOX:
+   if (params.part > 0) {
+   fprintf (stderr, "Error: specifying parts is incompatible with mbox 
output format.\n");
+   return 1;
}
-   if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
-   opt = argv[i] + sizeof ("--format=") - 1;
-   if (strcmp (opt, "text") == 0) {
-   format = &format_text;
-   } else if (strcmp (opt, "json") == 0) {
-   format = &format_json;
-   params.entire_thread = 1;
-   } else if (strcmp (opt, "mbox") == 0) {
-   format = &format_mbox;
-   mbox = 1;
-   } else if (strcmp (opt, "raw") == 0) {
-   format = &format_raw;
-   params.raw = 1;
-   } else {
-   fprintf (stderr, "Invalid value for --format: %s\n", opt);
-   return 1;
-   }
-   format_specified = 1;
-   } else if (STRNCMP_LITERAL (argv[i], "--part=") == 0) {
-   params.part = atoi(argv[i] + sizeof ("--part=") - 1);
-   } else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
-   params.entire_thread = 1;
-   } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||
-  (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
-   if (params.cryptoctx == NULL) {
+   format = &format_mbox;
+   break;
+case NOTMUCH_FORMAT_RA

[PATCH 2/2] cli: reach previously unreachable cleanup code in "notmuch show"

2012-02-03 Thread Jani Nikula
The last lines of notmuch_show_command() function were
unreachable. Fix it by using a variable for return value.

Signed-off-by: Jani Nikula 
---
 notmuch-show.c |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index f93e121..b18e279 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1064,7 +1064,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 notmuch_database_t *notmuch;
 notmuch_query_t *query;
 char *query_string;
-int opt_index;
+int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
 notmuch_show_params_t params = { .part = -1 };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
@@ -1173,9 +1173,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 }
 
 if (params.part >= 0)
-   return do_show_single (ctx, query, format, ¶ms);
+   ret = do_show_single (ctx, query, format, ¶ms);
 else
-   return do_show (ctx, query, format, ¶ms);
+   ret = do_show (ctx, query, format, ¶ms);
 
 notmuch_query_destroy (query);
 notmuch_database_close (notmuch);
@@ -1183,5 +1183,5 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 if (params.cryptoctx)
g_object_unref(params.cryptoctx);
 
-return 0;
+return ret;
 }
-- 
1.7.5.4

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


Re: [PATCH 1/2] cli: convert "notmuch show" to use the new argument parser

2012-02-04 Thread Jani Nikula
On Sat, 04 Feb 2012 00:00:00 +, Mark Walters  
wrote:
> 
> On Sat,  4 Feb 2012 00:41:08 +0200, Jani Nikula  wrote:
> > Use the new notmuch argument parser to handle arguments in "notmuch
> > show". There are two corner case functional changes:
> > 
> > 1) Also set params.raw = 1 when defaulting to raw format when part is
> >requested but format is not specified.
> > 
> > 2) Do not set params.decrypt if crypto context creation fails.
> 
> This looks great. As far as I can see it is fine (I haven't run or even
> compiled it yet). I only have two query/nits below.
> 
> Best wishes
> 
> Mark
> 
> > Signed-off-by: Jani Nikula 
> > ---
> >  notmuch-show.c |  153 
> > +---
> >  1 files changed, 79 insertions(+), 74 deletions(-)
> > 
> > diff --git a/notmuch-show.c b/notmuch-show.c
> > index dec799c..f93e121 100644
> > --- a/notmuch-show.c
> > +++ b/notmuch-show.c
> > @@ -1049,6 +1049,14 @@ do_show (void *ctx,
> >  return 0;
> >  }
> >  
> > +enum {
> > +NOTMUCH_FORMAT_NOT_SPECIFIED,
> > +NOTMUCH_FORMAT_JSON,
> > +NOTMUCH_FORMAT_TEXT,
> > +NOTMUCH_FORMAT_MBOX,
> > +NOTMUCH_FORMAT_RAW
> > +};
> > +
> >  int
> >  notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
> >  {
> > @@ -1056,92 +1064,98 @@ notmuch_show_command (void *ctx, unused (int argc), 
> > unused (char *argv[]))
> >  notmuch_database_t *notmuch;
> >  notmuch_query_t *query;
> >  char *query_string;
> > -char *opt;
> > +int opt_index;
> >  const notmuch_show_format_t *format = &format_text;
> 
> I think you don't need the default value here. If you think it is
> clearer with the default then that is fine. I think I slightly prefer
> without since in some cases the default is raw but entirely up to you.

I actually dropped this at first, but the compiler has no way of knowing
that all the cases are covered in the switch, and thinks format may be
uninitialized. I was wondering whether to have a default case in the
switch (which would be just to make the compiler happy), but settled on
this instead.

> 
> > -notmuch_show_params_t params;
> > -int mbox = 0;
> > -int format_specified = 0;
> > -int i;
> > +notmuch_show_params_t params = { .part = -1 };
> 
> Does this initialize all the other params bits to zero/NULL?  

Yes. It's called a "designated initializer for aggregate type" if you
want to look it up.

Thanks for the review.


BR,
Jani.

> 
> 
> 
> 
> > +int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
> > +notmuch_bool_t decrypt = FALSE;
> > +notmuch_bool_t verify = FALSE;
> > +notmuch_bool_t entire_thread = FALSE;
> > +
> > +notmuch_opt_desc_t options[] = {
> > +   { NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
> > + (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
> > + { "text", NOTMUCH_FORMAT_TEXT },
> > + { "mbox", NOTMUCH_FORMAT_MBOX },
> > + { "raw", NOTMUCH_FORMAT_RAW },
> > + { 0, 0 } } },
> > +   { NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &entire_thread, "entire-thread", 't', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
> > +   { 0, 0, 0, 0, 0 }
> > +};
> > +
> > +opt_index = parse_arguments (argc, argv, options, 1);
> > +if (opt_index < 0) {
> > +   /* diagnostics already printed */
> > +   return 1;
> > +}
> >  
> > -params.entire_thread = 0;
> > -params.raw = 0;
> > -params.part = -1;
> > -params.cryptoctx = NULL;
> > -params.decrypt = 0;
> > +params.entire_thread = entire_thread;
> >  
> > -argc--; argv++; /* skip subcommand argument */
> > +if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
> > +   /* if part was requested and format was not specified, use format=raw */
> > +   if (params.part >= 0)
> > +   format_sel = NOTMUCH_FORMAT_RAW;
> > +   else
> > +   format_sel = NOTMUCH_FORMAT_TEXT;
> > +}
> >  
> > -for (i = 0; i < argc && argv[i][0] == '-&#x

Re: For gmail how do you setup notmuch mail ?...

2012-02-04 Thread Jani Nikula
On Sat, 04 Feb 2012 09:15:16 +, David Edmondson  wrote:
> On Sat, 4 Feb 2012 03:39:23 -0500, don warner saklad  
> wrote:
> > a) For gmail how do you setup notmuch mail ?...
> > 
> > b) Any workarounds?
> > 
> > c) Any kludges?

I'll describe my own setup for using notmuch with gmail. I don't pretend
it will work for everyone, but you might find some bits of it useful.

I don't even try to sync notmuch tags and gmail labels (because I rarely
use the labels or the web interface anyway), but I do get sync for
"unread" and "flagged" (gmail and Android "starred"). You'll need
maildir.synchronize_flags = true in your ~/.notmuch-config for this.

> Many people around here do that using offlineimap, which will
> synchronise an IMAP server (Gmail in this instance) with various local
> directories in Maildir format.

I use offlineimap. I run it from the notmuch pre-new hook. This means I
have to run "notmuch new" to receive new mail.

$ cat ~/.maildir/.notmuch/hooks/pre-new
#!/bin/sh
exec /usr/bin/offlineimap

I only sync "All Mail" from gmail. Perhaps there would be some
optimizations that could be done, but I haven't bothered yet.

$ cat ~/.offlineimaprc
[general]
accounts = Gmail
ui = Noninteractive.Basic

[Account Gmail]
localrepository = Local
remoterepository = Remote

[Repository Local]
type = Maildir
localfolders = ~/.maildir

[Repository Remote]
type = IMAP
ssl = yes
remotehost = imap.gmail.com
remoteuser = u...@gmail.com
expunge = no
realdelete = no

folderfilter = lambda foldername: foldername in ['[Gmail]/All Mail']
nametrans = lambda foldername: re.sub('^\[Gmail\]/All Mail', 'gmail', 
foldername)

> Sending mail via Gmail can be done in various ways. You can set up your
> local MTA (Postfix, Exim, ...) to deliver mail via Gmail, or have Emacs
> do the same directly using the smtpmail.el package.

Personally I use msmtp (msmtp and msmtp-mta packages in Debian based
distros). The msmtp-mta sets up a sendmail-like binary that works out of
the box in Emacs. Beware that it doesn't have a local queue, it works
synchronously.

$ cat ~/.msmtprc
defaults
logfile ~/.msmtp.log
tls_trust_file /etc/ssl/certs/ca-certificates.crt

account default
host smtp.gmail.com
from u...@gmail.com
tls on
tls_starttls off
auth on
user u...@gmail.com

Finally, I use goobook to use the gmail contacts as addressbook in
Emacs. See http://mid.gmane.org/87zkfuh3i0@nikula.org for that.


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


Re: [PATCH 1/2] cli: add --from option to reply to restrict guessing of the From: header.

2012-02-04 Thread Jani Nikula
On Sat,  4 Feb 2012 17:09:09 +, Mark Walters  
wrote:
> Add an option --from= to notmuch-reply.c to restrict guessing of the
> From: header. The existing logic looks as the main headers, then at
> the delivery headers, and finally defaults to the config file address.
> 
> This patch allows the user to restrict which of these guesses are
> made.  Currently the supported values are:
>default|fallback-allcurrent behaviour
>fallback-received   fallback to delivery headers but not config 
> file
>fallback-none only look at from/reply-to/to/cc/ headers
>none  From: header is always left empty

As discussed on IRC, --from=primary is a natural extension to always use
the primary address from config, but that can be a later patch.

> 
> If the code does not find an allowed address it outputs an empty From:
> line and the caller can decide how to respond.
> ---
>  notmuch-reply.c |   39 ++-
>  1 files changed, 30 insertions(+), 9 deletions(-)
> 
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index f55b1d2..f660749 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -24,6 +24,13 @@
>  #include "gmime-filter-reply.h"
>  #include "gmime-filter-headers.h"
>  

I think it would be good to have a comment here reminding later
developers that the order matters in this enum.

> +enum {
> +FROM_FALLBACK_ALL,
> +FROM_FALLBACK_RECEIVED,
> +FROM_FALLBACK_NONE,
> +FROM_NONE
> +};
> +
>  static void
>  reply_headers_message_part (GMimeMessage *message);
>  
> @@ -510,7 +517,8 @@ notmuch_reply_format_default(void *ctx,
>notmuch_config_t *config,
>notmuch_query_t *query,
>notmuch_show_params_t *params,
> -  notmuch_bool_t reply_all)
> +  notmuch_bool_t reply_all,
> +  int from_guess)

Hrmh, I'd like this to sound more deterministic than
"guessing". from_select? from_use? from?

>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -542,15 +550,19 @@ notmuch_reply_format_default(void *ctx,
>   from_addr = add_recipients_from_message (reply, config, message,
>reply_all);
>  
> - if (from_addr == NULL)
> + if ((from_addr == NULL) && (from_guess <= FROM_FALLBACK_RECEIVED))

Please drop the extra braces here and below.

>   from_addr = guess_from_received_header (config, message);
>  
> - if (from_addr == NULL)
> + if ((from_addr == NULL) && (from_guess <= FROM_FALLBACK_ALL ))
>   from_addr = notmuch_config_get_user_primary_email (config);
>  
> - from_addr = talloc_asprintf (ctx, "%s <%s>",
> -  notmuch_config_get_user_name (config),
> -  from_addr);
> + if ((from_addr != NULL) || (from_guess = FROM_NONE)) {

Should that be (from_addr != NULL && from_guess != FROM_NONE)?
Definitely the assignment is an error!

> + from_addr = talloc_asprintf (ctx, "%s <%s>",
> +  notmuch_config_get_user_name (config),
> +  from_addr);
> + } else {
> + from_addr = talloc_strdup (ctx, "");
> + }
>   g_mime_object_set_header (GMIME_OBJECT (reply),
> "From", from_addr);
>  
> @@ -590,7 +602,8 @@ notmuch_reply_format_headers_only(void *ctx,
> notmuch_config_t *config,
> notmuch_query_t *query,
> unused (notmuch_show_params_t *params),
> -   notmuch_bool_t reply_all)
> +   notmuch_bool_t reply_all,
> +   unused (int from_guess))
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -657,10 +670,11 @@ notmuch_reply_command (void *ctx, int argc, char 
> *argv[])
>  notmuch_query_t *query;
>  char *query_string;
>  int opt_index, ret = 0;
> -int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all);
> +int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all, int from_guess);
>  notmuch_show_params_t params = { .part = -1 };
>  int format = FORMAT_DEFAULT;
>  int reply_all = TRUE;
> +int from_guess = FROM_FALLBACK_ALL;
>  notmuch_bool_t decrypt = FALSE;
>  
>  notmuch_opt_desc_t options[] = {
> @@ -672,6 +686,13 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
> (notmuch_keyword_t []){ { "all", TRUE },
> { "sender", FALSE },
> { 0, 0 } } },
> + { NOTMUCH_OPT_KEYWORD, &fro

Re: [PATCH 2/2] emacs: Improve prompting for user address when replying.

2012-02-04 Thread Jani Nikula
On Sat,  4 Feb 2012 17:09:10 +, Mark Walters  
wrote:
> This patch uses the new --from option to notmuch reply to allow it to
> prompt the user for the From: address in cases when the cli does not
> know the "correct" from address. If the cli does not it either uses
> the users default address or, if notmuch-always-prompt-for-sender
> is set, prompts the user.
> ---
>  emacs/notmuch-mua.el |   47 ---
>  1 files changed, 28 insertions(+), 19 deletions(-)
> 
> diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
> index 41f82c2..36e62f9 100644
> --- a/emacs/notmuch-mua.el
> +++ b/emacs/notmuch-mua.el
> @@ -51,6 +51,24 @@ list."
>  
>  ;;
>  
> +(defcustom notmuch-identities nil
> +  "Identities that can be used as the From: address when composing a new 
> message.
> +
> +If this variable is left unset, then a list will be constructed from the
> +name and addresses configured in the notmuch configuration file."
> +  :type '(repeat string)
> +  :group 'notmuch-send)
> +
> +(defcustom notmuch-always-prompt-for-sender nil
> +  "Always prompt for the From: address when composing or forwarding a 
> message.
> +
> +This is not taken into account when replying to a message, because in that 
> case
> +the From: header is already filled in by notmuch."
> +  :type 'boolean
> +  :group 'notmuch-send)
> +
> +(defvar notmuch-mua-sender-history nil)
> +
>  (defun notmuch-mua-user-agent-full ()
>"Generate a `User-Agent:' string suitable for notmuch."
>(concat (notmuch-mua-user-agent-notmuch)
> @@ -75,7 +93,7 @@ list."
>  (defun notmuch-mua-reply (query-string &optional sender reply-all)
>(let (headers
>   body
> - (args '("reply")))
> + (args '("reply" "--from=fallback-received")))

There are better reviewers for the rest of the emacs bits, but wouldn't
it be better to just use the "notmuch reply" default when the user wants
the current behaviour?

BR,
Jani.


>  (if notmuch-show-process-crypto
>   (setq args (append args '("--decrypt"
>  (if reply-all
> @@ -99,6 +117,15 @@ list."
>  ;; If sender is non-nil, set the From: header to its value.
>  (when sender
>(mail-header-set 'from sender headers))
> +;; If we do not have a From: header yet it means that
> +;; notmuch-reply.c was not able to make a useful guess so we fill
> +;; it in ourselves.
> +(when (string= "" (mail-header 'from headers))
> +  (if notmuch-always-prompt-for-sender
> +   (setq sender (notmuch-mua-prompt-for-sender))
> + (setq sender (concat
> +   (notmuch-user-name) " <" (notmuch-user-primary-email) 
> ">")))
> +  (mail-header-set 'from sender headers))
>  (let
>   ;; Overlay the composition window on that being used to read
>   ;; the original message.
> @@ -153,24 +180,6 @@ OTHER-ARGS are passed through to `message-mail'."
>  
>(message-goto-to))
>  
> -(defcustom notmuch-identities nil
> -  "Identities that can be used as the From: address when composing a new 
> message.
> -
> -If this variable is left unset, then a list will be constructed from the
> -name and addresses configured in the notmuch configuration file."
> -  :type '(repeat string)
> -  :group 'notmuch-send)
> -
> -(defcustom notmuch-always-prompt-for-sender nil
> -  "Always prompt for the From: address when composing or forwarding a 
> message.
> -
> -This is not taken into account when replying to a message, because in that 
> case
> -the From: header is already filled in by notmuch."
> -  :type 'boolean
> -  :group 'notmuch-send)
> -
> -(defvar notmuch-mua-sender-history nil)
> -
>  (defun notmuch-mua-prompt-for-sender ()
>(interactive)
>(let (name addresses one-name-only)
> -- 
> 1.7.2.3
> 
> ___
> 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: [PATCH v2 1/4] cli: add --from option to reply to restrict guessing of the From: header.

2012-02-04 Thread Jani Nikula
On Sat,  4 Feb 2012 20:45:14 +, Mark Walters  
wrote:
> Add an option --from= to notmuch-reply.c to restrict guessing of the
> From: header. The existing logic looks as the main headers, then at
> the delivery headers, and finally defaults to the config file address.
> 
> This patch allows the user to restrict which of these guesses are
> made.  Currently the supported values are:
>default|fallback-allcurrent behaviour
>fallback-received   fallback to delivery headers but not config 
> file
>fallback-none only look at from/reply-to/to/cc/ headers
>none  From: header is always left empty

The patch looks good. The "primary" option added in v2 is missing from
the commit message, but no need to send a new version because of that.

I didn't check the other patches in the series.

BR,
Jani.


> 
> If the code does not find an allowed address it outputs an empty From:
> line and the caller can decide how to respond.
> ---
>  notmuch-reply.c |   45 -
>  1 files changed, 36 insertions(+), 9 deletions(-)
> 
> diff --git a/notmuch-reply.c b/notmuch-reply.c
> index f55b1d2..8c73cb7 100644
> --- a/notmuch-reply.c
> +++ b/notmuch-reply.c
> @@ -24,6 +24,15 @@
>  #include "gmime-filter-reply.h"
>  #include "gmime-filter-headers.h"
>  
> +/* The order here matters as we use '<' when deciding how to behave. */
> +enum {
> +FROM_FALLBACK_ALL,
> +FROM_FALLBACK_RECEIVED,
> +FROM_FALLBACK_NONE,
> +FROM_NONE,
> +FROM_PRIMARY
> +};
> +
>  static void
>  reply_headers_message_part (GMimeMessage *message);
>  
> @@ -510,7 +519,8 @@ notmuch_reply_format_default(void *ctx,
>notmuch_config_t *config,
>notmuch_query_t *query,
>notmuch_show_params_t *params,
> -  notmuch_bool_t reply_all)
> +  notmuch_bool_t reply_all,
> +  int from_select)
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -542,15 +552,22 @@ notmuch_reply_format_default(void *ctx,
>   from_addr = add_recipients_from_message (reply, config, message,
>reply_all);
>  
> - if (from_addr == NULL)
> + if (from_addr == NULL && from_select <= FROM_FALLBACK_RECEIVED)
>   from_addr = guess_from_received_header (config, message);
>  
> - if (from_addr == NULL)
> + if ((from_addr == NULL && from_select <= FROM_FALLBACK_ALL) ||
> + from_select == FROM_PRIMARY)
>   from_addr = notmuch_config_get_user_primary_email (config);
>  
> - from_addr = talloc_asprintf (ctx, "%s <%s>",
> -  notmuch_config_get_user_name (config),
> -  from_addr);
> + /* If we have an address and we want an address print
> +  * it. Otherwise set an empty From: header. */
> + if (from_addr != NULL && from_select != FROM_NONE) {
> + from_addr = talloc_asprintf (ctx, "%s <%s>",
> +  notmuch_config_get_user_name (config),
> +  from_addr);
> + } else {
> + from_addr = talloc_strdup (ctx, "");
> + }
>   g_mime_object_set_header (GMIME_OBJECT (reply),
> "From", from_addr);
>  
> @@ -590,7 +607,8 @@ notmuch_reply_format_headers_only(void *ctx,
> notmuch_config_t *config,
> notmuch_query_t *query,
> unused (notmuch_show_params_t *params),
> -   notmuch_bool_t reply_all)
> +   notmuch_bool_t reply_all,
> +   unused (int from_select))
>  {
>  GMimeMessage *reply;
>  notmuch_messages_t *messages;
> @@ -657,10 +675,11 @@ notmuch_reply_command (void *ctx, int argc, char 
> *argv[])
>  notmuch_query_t *query;
>  char *query_string;
>  int opt_index, ret = 0;
> -int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all);
> +int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
> notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
> reply_all, int from_select);
>  notmuch_show_params_t params = { .part = -1 };
>  int format = FORMAT_DEFAULT;
>  int reply_all = TRUE;
> +int from_select = FROM_FALLBACK_ALL;
>  notmuch_bool_t decrypt = FALSE;
>  
>  notmuch_opt_desc_t options[] = {
> @@ -672,6 +691,14 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
> (notmuch_keyword_t []){ { "all", TRUE },
> { "sender", FALSE },
> { 0, 0 } } },
> + { NOTMUCH_OPT_KEYWORD, &from_select, "from", 'F',
> +   (no

Re: [Patch v2 0/4] Control selection of From: header when replying

2012-02-05 Thread Jani Nikula
On Sun, 05 Feb 2012 10:58:04 +0400, Dmitry Kurochkin 
 wrote:
> Hi Mark.
> 
> I am not sure I like this solution.  My concerns are:
> 
> * New option looks too complex, too specific.

*shrug* The --from parameter is simple to implement, simple to test, and
simple to use.

> * There are more aspects of notmuch reply behavior which users would
>   like to change (e.g. which part to quote).  If we add an option for
>   each, we complicate both nomtuch show UI and code.

This I agree is more of an issue.

> The problem is that notmuch show output format is too limiting.  Instead
> of providing myriad of options for tweaking notmuch show text format
> behavior, we should add JSON format for notmuch reply similar to nomtuch
> show.  That would allow notmuch reply to produce structured output with
> required additional information, which should be enough for users to
> construct whatever reply they want.

Heh, when I told Mark on IRC to just send the patches and not discuss
and worry about it too much, I added "...and then someone will come up
with an approach we failed to think of, and scrap the whole
thing". Thanks Dmitry! ;)

> In this particular case, notmuch reply JSON format could have
> "from-source" attribute that would indicate how it was guessed.

My first thought is that it's offloading things that are trivial in the
cli to the users of the cli where it might be slightly more complicated,
but...

> Now the best part.  Not so long ago, Adam (in Cc) provided a patch for
> improving nomtuch reply for HTML-only emails.  At first he added an
> option for notmuch reply, like you did for from-guessing.  I suggested
> him to implement it based on the JSON format instead and he did.  AFAIK
> the latest version of his patches is [1].  I did not look at the code
> though.  It seems that it is waiting for more review.
> 
> So, instead of adding more nomtuch show options, I think a better
> solution is to work with Adam to get the notmuch reply JSON format to
> master and then fix the from-guessing issue by adding an attribute to
> notmuch reply JSON format.

...no matter what the solution will be in the end, I agree it's best to
get Adam's work merged first, and see how easily this can be handled
using JSON vs. the parameter.

Thanks for your insights.


BR,
Jani.


> Regards,
>   Dmitry
> 
> [1] id:"1326995217-27423-1-git-send-email-awg+notm...@xvx.ca"
> ___
> 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: [PATCH 1/2] cli: convert "notmuch show" to use the new argument parser

2012-02-05 Thread Jani Nikula
On Sun, 5 Feb 2012 23:12:05 -0500, Austin Clements  wrote:
> Yikes.  I don't envy you this patch.  Two minor nits, otherwise this
> and the next patch LGTM.

Thanks for the review. I'll roll another version, I think it will be
better with your suggestions incorporated.

> Quoth Jani Nikula on Feb 04 at 12:41 am:
> > Use the new notmuch argument parser to handle arguments in "notmuch
> > show". There are two corner case functional changes:
> > 
> > 1) Also set params.raw = 1 when defaulting to raw format when part is
> >requested but format is not specified.
> 
> Huh.  So "notmuch show --part=0 " was broken before.

Hmm, yes, it seems so. Do you think I should make this a separate fix?

BTW an alternative would be to require setting --format if --part is
specified, and not adapt the default format depending on --part.

> > 2) Do not set params.decrypt if crypto context creation fails.
> 
> Technically this also behaves differently if given multiple --format
> arguments, but I'll let that slide.

Ugh, right, the old parsing was broken also that way. Luckily that falls
in the corner case department too.

> > 
> > Signed-off-by: Jani Nikula 
> > ---
> >  notmuch-show.c |  153 
> > +---
> >  1 files changed, 79 insertions(+), 74 deletions(-)
> > 
> > diff --git a/notmuch-show.c b/notmuch-show.c
> > index dec799c..f93e121 100644
> > --- a/notmuch-show.c
> > +++ b/notmuch-show.c
> > @@ -1049,6 +1049,14 @@ do_show (void *ctx,
> >  return 0;
> >  }
> >  
> > +enum {
> > +NOTMUCH_FORMAT_NOT_SPECIFIED,
> > +NOTMUCH_FORMAT_JSON,
> > +NOTMUCH_FORMAT_TEXT,
> > +NOTMUCH_FORMAT_MBOX,
> > +NOTMUCH_FORMAT_RAW
> > +};
> > +
> >  int
> >  notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
> >  {
> > @@ -1056,92 +1064,98 @@ notmuch_show_command (void *ctx, unused (int argc), 
> > unused (char *argv[]))
> >  notmuch_database_t *notmuch;
> >  notmuch_query_t *query;
> >  char *query_string;
> > -char *opt;
> > +int opt_index;
> >  const notmuch_show_format_t *format = &format_text;
> > -notmuch_show_params_t params;
> > -int mbox = 0;
> > -int format_specified = 0;
> > -int i;
> > +notmuch_show_params_t params = { .part = -1 };
> > +int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
> > +notmuch_bool_t decrypt = FALSE;
> > +notmuch_bool_t verify = FALSE;
> > +notmuch_bool_t entire_thread = FALSE;
> > +
> > +notmuch_opt_desc_t options[] = {
> > +   { NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
> > + (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
> > + { "text", NOTMUCH_FORMAT_TEXT },
> > + { "mbox", NOTMUCH_FORMAT_MBOX },
> > + { "raw", NOTMUCH_FORMAT_RAW },
> > + { 0, 0 } } },
> > +   { NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &entire_thread, "entire-thread", 't', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
> > +   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
> > +   { 0, 0, 0, 0, 0 }
> > +};
> > +
> > +opt_index = parse_arguments (argc, argv, options, 1);
> > +if (opt_index < 0) {
> > +   /* diagnostics already printed */
> > +   return 1;
> > +}
> >  
> > -params.entire_thread = 0;
> > -params.raw = 0;
> > -params.part = -1;
> > -params.cryptoctx = NULL;
> > -params.decrypt = 0;
> > +params.entire_thread = entire_thread;
> 
> If you make params.entire_thread a notmuch_bool_t (instead of an int),
> you could pass ¶ms.entire_thread in the notmuch_opt_desc_t and get
> rid of the local variable.

You're right; I was a bit lazy and didn't consider changing
notmuch_show_params_t. I'll change both this and params.decrypt to
notmuch_bool_t.

> 
> >  
> > -argc--; argv++; /* skip subcommand argument */
> > +if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
> > +   /* if part was requested and format was not specified, use format=raw */
> > +   if (params.part >= 0)
> > +   format_sel = NOTMUCH_FORMAT_RAW;
> > +   else
> > +   format_sel = NOTMUCH_FORMAT_TEXT;
> > +}
>

[PATCH 0/3] notmuch show argument parsing

2012-02-06 Thread Jani Nikula
Hi all, 

v2 addressing Austin's comments in id:"20120206041205.gp10...@mit.edu".
Separate the bool cleanup into a new patch, cleaning up notmuch reply
while at it. No functional changes since v1.

For reviewing convenience, the diff between v1 and v2 is at the end of
this cover letter.

BR,
Jani.

Jani Nikula (3):
  cli: use notmuch_bool_t for boolean fields in notmuch_show_params_t
  cli: convert "notmuch show" to use the new argument parser
  cli: reach previously unreachable cleanup code in "notmuch show"

 notmuch-client.h |6 +-
 notmuch-reply.c  |7 +--
 notmuch-show.c   |  155 +++---
 3 files changed, 84 insertions(+), 84 deletions(-)

-- 
1.7.5.4

diff --git a/notmuch-client.h b/notmuch-client.h
index e0eb594..60828aa 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -98,15 +98,15 @@ typedef struct notmuch_show_format {
 } notmuch_show_format_t;
 
 typedef struct notmuch_show_params {
-int entire_thread;
-int raw;
+notmuch_bool_t entire_thread;
+notmuch_bool_t raw;
 int part;
 #ifdef GMIME_ATLEAST_26
 GMimeCryptoContext* cryptoctx;
 #else
 GMimeCipherContext* cryptoctx;
 #endif
-int decrypt;
+notmuch_bool_t decrypt;
 } notmuch_show_params_t;
 
 /* There's no point in continuing when we've detected that we've done
diff --git a/notmuch-reply.c b/notmuch-reply.c
index f55b1d2..6b244e6 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -661,7 +661,6 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_show_params_t params = { .part = -1 };
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;
-notmuch_bool_t decrypt = FALSE;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format, "format", 'f',
@@ -672,7 +671,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "all", TRUE },
  { "sender", FALSE },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -687,7 +686,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;
 
-if (decrypt) {
+if (params.decrypt) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg");
@@ -697,8 +696,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 #endif
if (params.cryptoctx) {
g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.cryptoctx, FALSE);
-   params.decrypt = TRUE;
} else {
+   params.decrypt = FALSE;
fprintf (stderr, "Failed to construct gpg context.\n");
}
 #ifndef GMIME_ATLEAST_26
diff --git a/notmuch-show.c b/notmuch-show.c
index b18e279..c8fbd79 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1068,9 +1068,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 const notmuch_show_format_t *format = &format_text;
 notmuch_show_params_t params = { .part = -1 };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
-notmuch_bool_t decrypt = FALSE;
 notmuch_bool_t verify = FALSE;
-notmuch_bool_t entire_thread = FALSE;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1080,8 +1078,8 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
  { "raw", NOTMUCH_FORMAT_RAW },
  { 0, 0 } } },
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &entire_thread, "entire-thread", 't', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
{ 0, 0, 0, 0, 0 }
 };
@@ -1092,8 +1090,6 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
return 1;
 }
 
-params.entire_thread = entire_thread;
-
 if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
/* if part was requested and format was not specified, use format=raw */
if (params.part >= 0)
@@ -1105,7 +1101,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 switch (format_sel) {
 case NOTMUCH_FORMAT_JSON:
format = &form

[PATCH v2 1/3] cli: use notmuch_bool_t for boolean fields in notmuch_show_params_t

2012-02-06 Thread Jani Nikula
Use notmuch_bool_t instead of int for entire_thread, raw, and decrypt
boolean fields in notmuch_show_params_t. No functional changes.

Signed-off-by: Jani Nikula 
---
 notmuch-client.h |6 +++---
 notmuch-reply.c  |7 +++
 notmuch-show.c   |   14 +++---
 3 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index e0eb594..60828aa 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -98,15 +98,15 @@ typedef struct notmuch_show_format {
 } notmuch_show_format_t;
 
 typedef struct notmuch_show_params {
-int entire_thread;
-int raw;
+notmuch_bool_t entire_thread;
+notmuch_bool_t raw;
 int part;
 #ifdef GMIME_ATLEAST_26
 GMimeCryptoContext* cryptoctx;
 #else
 GMimeCipherContext* cryptoctx;
 #endif
-int decrypt;
+notmuch_bool_t decrypt;
 } notmuch_show_params_t;
 
 /* There's no point in continuing when we've detected that we've done
diff --git a/notmuch-reply.c b/notmuch-reply.c
index f55b1d2..6b244e6 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -661,7 +661,6 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_show_params_t params = { .part = -1 };
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;
-notmuch_bool_t decrypt = FALSE;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format, "format", 'f',
@@ -672,7 +671,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "all", TRUE },
  { "sender", FALSE },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, &decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -687,7 +686,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;
 
-if (decrypt) {
+if (params.decrypt) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg");
@@ -697,8 +696,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 #endif
if (params.cryptoctx) {
g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.cryptoctx, FALSE);
-   params.decrypt = TRUE;
} else {
+   params.decrypt = FALSE;
fprintf (stderr, "Failed to construct gpg context.\n");
}
 #ifndef GMIME_ATLEAST_26
diff --git a/notmuch-show.c b/notmuch-show.c
index dec799c..e04b3cc 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1063,11 +1063,11 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 int format_specified = 0;
 int i;
 
-params.entire_thread = 0;
-params.raw = 0;
+params.entire_thread = FALSE;
+params.raw = FALSE;
 params.part = -1;
 params.cryptoctx = NULL;
-params.decrypt = 0;
+params.decrypt = FALSE;
 
 argc--; argv++; /* skip subcommand argument */
 
@@ -1082,13 +1082,13 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
format = &format_text;
} else if (strcmp (opt, "json") == 0) {
format = &format_json;
-   params.entire_thread = 1;
+   params.entire_thread = TRUE;
} else if (strcmp (opt, "mbox") == 0) {
format = &format_mbox;
mbox = 1;
} else if (strcmp (opt, "raw") == 0) {
format = &format_raw;
-   params.raw = 1;
+   params.raw = TRUE;
} else {
fprintf (stderr, "Invalid value for --format: %s\n", opt);
return 1;
@@ -1097,7 +1097,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
} else if (STRNCMP_LITERAL (argv[i], "--part=") == 0) {
params.part = atoi(argv[i] + sizeof ("--part=") - 1);
} else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
-   params.entire_thread = 1;
+   params.entire_thread = TRUE;
} else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||
   (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
if (params.cryptoctx == NULL) {
@@ -1117,7 +1117,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 #endif
}
if (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)
-   params.decrypt = 1;
+   params.decrypt = TRUE;
} else {
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
return 1;
-- 
1.7.5.4

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


[PATCH v2 2/3] cli: convert "notmuch show" to use the new argument parser

2012-02-06 Thread Jani Nikula
Use the new notmuch argument parser to handle arguments in "notmuch
show". There are three minor functional changes:

1) Also set params.raw = TRUE when defaulting to raw format when part
   is requested but format is not specified. This was a bug, and
   --part=0 without --format=raw did not work previously.

2) Set params.decrypt = FALSE if crypto context creation fails.

3) Only use the parameters for the last --format if specified multiple
   times. Previously this could have resulted in a non-working mixture
   of parameters.

Signed-off-by: Jani Nikula 
---
 notmuch-show.c |  149 
 1 files changed, 75 insertions(+), 74 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index e04b3cc..b358278 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1049,6 +1049,14 @@ do_show (void *ctx,
 return 0;
 }
 
+enum {
+NOTMUCH_FORMAT_NOT_SPECIFIED,
+NOTMUCH_FORMAT_JSON,
+NOTMUCH_FORMAT_TEXT,
+NOTMUCH_FORMAT_MBOX,
+NOTMUCH_FORMAT_RAW
+};
+
 int
 notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
@@ -1056,92 +1064,94 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 notmuch_database_t *notmuch;
 notmuch_query_t *query;
 char *query_string;
-char *opt;
+int opt_index;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params;
-int mbox = 0;
-int format_specified = 0;
-int i;
+notmuch_show_params_t params = { .part = -1 };
+int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
+notmuch_bool_t verify = FALSE;
+
+notmuch_opt_desc_t options[] = {
+   { NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
+ (notmuch_keyword_t []){ { "json", NOTMUCH_FORMAT_JSON },
+ { "text", NOTMUCH_FORMAT_TEXT },
+ { "mbox", NOTMUCH_FORMAT_MBOX },
+ { "raw", NOTMUCH_FORMAT_RAW },
+ { 0, 0 } } },
+   { NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+   { 0, 0, 0, 0, 0 }
+};
 
-params.entire_thread = FALSE;
-params.raw = FALSE;
-params.part = -1;
-params.cryptoctx = NULL;
-params.decrypt = FALSE;
+opt_index = parse_arguments (argc, argv, options, 1);
+if (opt_index < 0) {
+   /* diagnostics already printed */
+   return 1;
+}
 
-argc--; argv++; /* skip subcommand argument */
+if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
+   /* if part was requested and format was not specified, use format=raw */
+   if (params.part >= 0)
+   format_sel = NOTMUCH_FORMAT_RAW;
+   else
+   format_sel = NOTMUCH_FORMAT_TEXT;
+}
 
-for (i = 0; i < argc && argv[i][0] == '-'; i++) {
-   if (strcmp (argv[i], "--") == 0) {
-   i++;
-   break;
+switch (format_sel) {
+case NOTMUCH_FORMAT_JSON:
+   format = &format_json;
+   params.entire_thread = TRUE;
+   break;
+case NOTMUCH_FORMAT_TEXT:
+   format = &format_text;
+   break;
+case NOTMUCH_FORMAT_MBOX:
+   if (params.part > 0) {
+   fprintf (stderr, "Error: specifying parts is incompatible with mbox 
output format.\n");
+   return 1;
}
-   if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
-   opt = argv[i] + sizeof ("--format=") - 1;
-   if (strcmp (opt, "text") == 0) {
-   format = &format_text;
-   } else if (strcmp (opt, "json") == 0) {
-   format = &format_json;
-   params.entire_thread = TRUE;
-   } else if (strcmp (opt, "mbox") == 0) {
-   format = &format_mbox;
-   mbox = 1;
-   } else if (strcmp (opt, "raw") == 0) {
-   format = &format_raw;
-   params.raw = TRUE;
-   } else {
-   fprintf (stderr, "Invalid value for --format: %s\n", opt);
-   return 1;
-   }
-   format_specified = 1;
-   } else if (STRNCMP_LITERAL (argv[i], "--part=") == 0) {
-   params.part = atoi(argv[i] + sizeof ("--part=") - 1);
-   } else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
-   params.entire_thread = TRUE;
-   } else if ((STRNCMP_LITERAL (argv[i], "--verify") == 0) ||
-  (STRNCMP_LITERAL (argv[i], "--decrypt") == 0)) {
- 

[PATCH v2 3/3] cli: reach previously unreachable cleanup code in "notmuch show"

2012-02-06 Thread Jani Nikula
The last lines of notmuch_show_command() function were
unreachable. Fix it by using a variable for return value.

Signed-off-by: Jani Nikula 
---
 notmuch-show.c |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index b358278..c8fbd79 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1064,7 +1064,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 notmuch_database_t *notmuch;
 notmuch_query_t *query;
 char *query_string;
-int opt_index;
+int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
 notmuch_show_params_t params = { .part = -1 };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
@@ -1169,9 +1169,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 }
 
 if (params.part >= 0)
-   return do_show_single (ctx, query, format, ¶ms);
+   ret = do_show_single (ctx, query, format, ¶ms);
 else
-   return do_show (ctx, query, format, ¶ms);
+   ret = do_show (ctx, query, format, ¶ms);
 
 notmuch_query_destroy (query);
 notmuch_database_close (notmuch);
@@ -1179,5 +1179,5 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 if (params.cryptoctx)
g_object_unref(params.cryptoctx);
 
-return 0;
+return ret;
 }
-- 
1.7.5.4

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


Re: [PATCH] Free the results of scandir()

2012-02-06 Thread Jani Nikula
On Mon,  6 Feb 2012 17:02:49 -0500, Ethan Glasser-Camp  
wrote:
> From: Ethan Glasser-Camp 
> 
> scandir() returns "strings allocated via malloc(3)" which are then
> "collected in array namelist which is allocated via
> malloc(3)". Currently we just free the array namelist. Instead, free
> all the entries of namelist, and then free namelist.
> 
> entry only points to elements of namelist, so we don't free it
> separately.
> ---
> 
> This should fix a minor memory leak in notmuch-new. Please confirm I'm
> reading the manpage correctly ;)

It looks right, good catch! Please do also fix the other scandir() usage
in count_files().

BR,
Jani.


> 
>  notmuch-new.c |8 +---
>  1 files changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/notmuch-new.c b/notmuch-new.c
> index a569a54..c536873 100644
> --- a/notmuch-new.c
> +++ b/notmuch-new.c
> @@ -559,12 +559,14 @@ add_files_recursive (notmuch_database_t *notmuch,
>DONE:
>  if (next)
>   talloc_free (next);
> -if (entry)
> - free (entry);
>  if (dir)
>   closedir (dir);
> -if (fs_entries)
> +if (fs_entries){
> + for (i = 0; i < num_fs_entries; i++){
> + free (fs_entries[i]);
> + }
>   free (fs_entries);
> +}
>  if (db_subdirs)
>   notmuch_filenames_destroy (db_subdirs);
>  if (db_files)
> -- 
> 1.7.5.4
> 
> ___
> 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: [PATCH v2] Free the results of scandir()

2012-02-07 Thread Jani Nikula
On Tue,  7 Feb 2012 01:50:05 -0500, Ethan Glasser-Camp  
wrote:
> From: Ethan Glasser-Camp 
> 
> scandir() returns "strings allocated via malloc(3)" which are then
> "collected in array namelist which is allocated via
> malloc(3)". Currently we just free the array namelist. Instead, free
> all the entries of namelist, and then free namelist.
> 
> entry only points to elements of namelist, so we don't free it
> separately.

Looks good. Thanks, Ethan.

David, I'm not sure if this is worth a bugfix release on its own, but
definitely worth including if something else comes up.

id:"2flfwhht87d@diskless.uio.no" is a report about potential memory
leak in notmuch new from a few months back. CC Petter, the reporter.

> ---
> 
> Fixes the other use of scandir in count_files. Thanks, Jani.
> 
>  notmuch-new.c |   16 ++--
>  1 files changed, 10 insertions(+), 6 deletions(-)
> 
> diff --git a/notmuch-new.c b/notmuch-new.c
> index a569a54..e62560b 100644
> --- a/notmuch-new.c
> +++ b/notmuch-new.c
> @@ -559,12 +559,14 @@ add_files_recursive (notmuch_database_t *notmuch,
>DONE:
>  if (next)
>   talloc_free (next);
> -if (entry)
> - free (entry);
>  if (dir)
>   closedir (dir);
> -if (fs_entries)
> +if (fs_entries){
> + for (i = 0; i < num_fs_entries; i++){
> + free (fs_entries[i]);
> + }
>   free (fs_entries);
> +}
>  if (db_subdirs)
>   notmuch_filenames_destroy (db_subdirs);
>  if (db_files)
> @@ -704,10 +706,12 @@ count_files (const char *path, int *count)
>  }
>  
>DONE:
> -if (entry)
> - free (entry);
> -if (fs_entries)
> +if (fs_entries){
> + for (i = 0; i < num_fs_entries; i++){
> + free (fs_entries[i]);
> + }
>  free (fs_entries);
> +}
>  }
>  
>  static void
> -- 
> 1.7.5.4
> 
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2] emacs: call "notmuch tag" only once when archiving a thread

2012-02-07 Thread Jani Nikula
Optimize thread archiving by combining all the -inbox tagging
operations to a single "notmuch tag" call. Also skip redisplay of tag
changes in current buffer, as it is immediately killed by the
archiving functions.

For threads in the order of tens or a hundred inbox tagged messages,
this gives a noticeable speedup. On two different machines, archiving
a thread of about 50 inbox tagged messages goes down from 10+ seconds
to about 0.5 seconds.

The bottleneck is not within emacs; the same behaviour can be observed
in the cli. This patch is a quick fix to thread archiving, but it
seems clear that generally the thread tagging functions should be
refactored to do tagging in one go. This approach would have the added
benefit of being more reliable: any of the individual tagging
operations might face a locked database, leading to partial results.

This introduces a limitation to the number of messages that can be
archived at the same time (through ARG_MAX limiting the command
line). While at least on Linux this seems more like a theoretical
limitation than a real one, it could be avoided by archiving at most a
few hundred messages at a time.

Signed-off-by: Jani Nikula 

---

v1 is at id:"1325615346-8302-1-git-send-email-j...@nikula.org".

Although this saves me several minutes a day, I don't have the time
for further improvements. I'm just too slow writing elisp...
---
 emacs/notmuch-show.el |   19 +--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 7469e2e..a0b8eb3 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1614,6 +1614,21 @@ added."
   (if show-next
  (notmuch-search-show-thread)
 
+(defun notmuch-show-archive-thread-quick ()
+  "Remove \"inbox\" tag from the current set of messages.
+
+Note: This function does not call `notmuch-show-set-tags' on the
+messages to redisplay the changed tags. This is meant to be
+called by functions that archive the messages and kill the buffer
+afterwards."
+  (goto-char (point-min))
+  (let (message-ids)
+(loop do
+ (add-to-list 'message-ids (notmuch-show-get-message-id))
+ until (not (notmuch-show-goto-message-next)))
+(when message-ids
+  (notmuch-tag (mapconcat 'identity message-ids " OR ") "-inbox"
+
 (defun notmuch-show-archive-thread (&optional unarchive)
   "Archive each message in thread.
 
@@ -1637,13 +1652,13 @@ buffer."
 (defun notmuch-show-archive-thread-then-next ()
   "Archive each message in thread, then show next thread from search."
   (interactive)
-  (notmuch-show-archive-thread)
+  (notmuch-show-archive-thread-quick)
   (notmuch-show-next-thread t))
 
 (defun notmuch-show-archive-thread-then-exit ()
   "Archive each message in thread, then exit back to search results."
   (interactive)
-  (notmuch-show-archive-thread)
+  (notmuch-show-archive-thread-quick)
   (notmuch-show-next-thread))
 
 (defun notmuch-show-archive-message (&optional unarchive)
-- 
1.7.5.4

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


Re: For gmail how do you setup notmuch mail ?...

2012-02-08 Thread Jani Nikula
On Wed, 08 Feb 2012 09:15:59 -, Patrick Totzke 
 wrote:
> Quoting Alex Botero-Lowry (2012-02-08 08:24:51)
> >I'm using a similar setup.  An inconvenience with the setup is that I 
> > have
> >various filters in gmail that filter, e.g., mailing list mails by 
> > skipping
> >the gmail inbox and applying specific tags. ... 
> >Ideally, I'd like a view in notmuch that shows the same messages as the
> >gmail inbox.  Is there a way to accomplish this?
> >- b
> 
> You could sync every subfolder *but* "All Mail" instead of just this
> folder: Gmail tags are available as imap folders. You can then tune
> your tagging filters to sort by folder: queries.

That's a good alternative only if you have relatively few messages that
have many gmail labels assigned to them. Otherwise you end up syncing
the same messages many times through many IMAP folders (each
corresponding to one label).

My approach is basically to reproduce the gmail filters as saved
searches in emacs. The messages need not have tags. YMMV.

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


[PATCH 0/2] multipart/alternative display and text/calendar

2012-02-08 Thread Jani Nikula
I like to have notmuch-show-all-multipart/alternative-parts nil. I'd also
like to see the text/calendar alternatives that I keep getting that have
the information that the text/plain alternative is missing (like date and
time *sigh*).

Patch 1 allows me to specify the alternative parts I want to always see
(nil and t work as before):

(setq notmuch-show-all-multipart/alternative-parts '("text/calendar"))

Patch 2 parses text/calendar as text/x-vcalendar for me so I don't have to.

BR,
Jani.

Jani Nikula (2):
  emacs: support defining a list of alternative parts to show
  emacs: regard text/calendar as text/x-vcalendar

 emacs/notmuch-show.el |   11 +--
 1 files changed, 9 insertions(+), 2 deletions(-)

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


[PATCH 1/2] emacs: support defining a list of alternative parts to show

2012-02-08 Thread Jani Nikula
Make notmuch-show-all-multipart/alternative-parts accept a list of
multipart/alternative types to show in addition to the preferred
types. This allows the user to force display some alternative part
types while normally showing just the preferred ones.

Signed-off-by: Jani Nikula 
---
 emacs/notmuch-show.el |8 ++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index faa9f9b..1340380 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -97,7 +97,9 @@ any given message."
 ;; Mostly useful for debugging.
 (defcustom notmuch-show-all-multipart/alternative-parts t
   "Should all parts of multipart/alternative parts be shown?"
-  :type 'boolean
+  :type '(choice (const :tag "Show all" t)
+(const :tag "Show preferred" nil)
+(repeat :tag "Show preferred and custom" string))
   :group 'notmuch-show)
 
 (defcustom notmuch-show-indent-messages-width 1
@@ -513,7 +515,9 @@ current buffer, if possible."
 ;; should be chosen if there are more than one that match?
 (mapc (lambda (inner-part)
(let ((inner-type (plist-get inner-part :content-type)))
- (if (or notmuch-show-all-multipart/alternative-parts
+ (if (or (equal notmuch-show-all-multipart/alternative-parts t)
+ (member inner-type
+ notmuch-show-all-multipart/alternative-parts)
  (string= chosen-type inner-type))
  (notmuch-show-insert-bodypart msg inner-part depth)
(notmuch-show-insert-part-header (plist-get inner-part :id) 
inner-type inner-type nil " (not shown)"
-- 
1.7.1

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


[PATCH 2/2] emacs: regard text/calendar as text/x-vcalendar

2012-02-08 Thread Jani Nikula
Treat text/calendar as text/x-vcalendar. At least the following
produce text/calendar that parse as text/x-vcalendar:

PRODID:-//Google Inc//Google Calendar 70.9054//EN
PRODID:Microsoft Exchange Server 2010

Code by David Edmondson 

---

I wish I had some references here, other than my own maildirs. Almost
all of the calendar invites I have are text/calendar, and all of them
parse just fine as text/x-vcalendar.
---
 emacs/notmuch-show.el |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 1340380..f6588b3 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -720,6 +720,9 @@ current buffer, if possible."
  result)))
   t)
 
+(defun notmuch-show-insert-part-text/calendar (msg part content-type nth depth 
declared-type)
+  (notmuch-show-insert-part-text/x-vcalendar msg part content-type nth depth 
declared-type))
+
 (defun notmuch-show-insert-part-application/octet-stream (msg part 
content-type nth depth declared-type)
   ;; If we can deduce a MIME type from the filename of the attachment,
   ;; do so and pass it on to the handler for that type.
-- 
1.7.1

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


Re: A big thank you for the major tagging speedup

2012-02-09 Thread Jani Nikula
On Thu, 09 Feb 2012 09:57:30 +0200, Tomi Ollila  wrote:
> On Wed, 8 Feb 2012 22:20:54 -0600, Michael Roth  wrote:
> > Anyone know what commit fixed this? Curious whether I'm using or not
> > already
> 
> No, you're not. 
> id:"1328719731-13402-1-git-send-email-dmitry.kuroch...@gmail.com"
> 
> Will do this.

I think he might be referring to commit id
da67bf12ce122759f72d1d510fb8996df3c9f946 "tag: Automatically limit to
messages whose tags will actually change." This was released in 0.11.

At some point we also had some database changes, and there is a
performance benefit in re-creating the db. This was released in
0.10. See NEWS and http://notmuchmail.org/howto/.


Jani.

> 
> Tomi
> 
> PS: Top-post, yack ;)
> 
> > On Feb 8, 2012 3:13 PM, "Xavier Maillard"  wrote:
> > 
> > >
> > > On Tue, 07 Feb 2012 17:36:24 +0100, Florian Friesdorf 
> > > wrote:
> > > >
> > > > I just wanted to express my gratitude, that for a while now notmuch is
> > > > tagging by a factor 200 faster than it used to be!
> > >
> > > +1 It is really comfortable to notmuch tag now !
> > >
> > > /Xavier
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 1/2] emacs: support defining a list of alternative parts to show

2012-02-09 Thread Jani Nikula
Make notmuch-show-all-multipart/alternative-parts accept a list of
regexps to match the part types to determine which parts to show in
addition to the preferred types. This allows the user to force display
some alternative part types while normally showing just the preferred
ones.

Signed-off-by: Jani Nikula 
---
 emacs/notmuch-show.el |   23 ++-
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 24fde05..5f643f1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -94,10 +94,20 @@ any given message."
   :group 'notmuch-show
   :group 'notmuch-hooks)
 
-;; Mostly useful for debugging.
 (defcustom notmuch-show-all-multipart/alternative-parts t
-  "Should all parts of multipart/alternative parts be shown?"
-  :type 'boolean
+  "Which parts of multipart/alternative should be shown?
+
+This variable determines which parts of multipart/alternative
+should be displayed. Set to t (the default) to show all
+parts. Set to nil to only show the preferred parts. Set to a list
+of regexps to display the preferred parts, and parts matching any
+of the regexps, for example:
+
+ (setq notmuch-show-all-multipart/alternative-parts
+  '(\"text/.*calendar\" \"text/html\"))"
+  :type '(choice (const :tag "Show all parts" t)
+(const :tag "Show preferred parts" nil)
+(repeat :tag "Show preferred and parts matching regexps" 
string))
   :group 'notmuch-show)
 
 (defcustom notmuch-show-indent-messages-width 1
@@ -513,8 +523,11 @@ current buffer, if possible."
 ;; should be chosen if there are more than one that match?
 (mapc (lambda (inner-part)
(let ((inner-type (plist-get inner-part :content-type)))
- (if (or notmuch-show-all-multipart/alternative-parts
- (string= chosen-type inner-type))
+ (if (or (equal notmuch-show-all-multipart/alternative-parts t)
+ (string= chosen-type inner-type)
+ (and
+  notmuch-show-all-multipart/alternative-parts
+  (equal (string-match-p (mapconcat (lambda (s) (format 
"^%s$" s)) notmuch-show-all-multipart/alternative-parts "\\|") inner-type) 0)))
  (notmuch-show-insert-bodypart msg inner-part depth)
(notmuch-show-insert-part-header (plist-get inner-part :id) 
inner-type inner-type nil " (not shown)"
  inner-parts)
-- 
1.7.1

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


[PATCH v2 2/2] emacs: support text/calendar mime type

2012-02-09 Thread Jani Nikula
Replace text/x-vcalendar with text/calendar, while maintaining support
and backwards compatibility for text/x-vcalendar.

Code by David Edmondson 
---
 emacs/notmuch-show.el |6 +-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 5f643f1..33a4f18 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -711,7 +711,7 @@ current buffer, if possible."
(run-hook-with-args 'notmuch-show-insert-text/plain-hook msg depth
   t)
 
-(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth 
depth declared-type)
+(defun notmuch-show-insert-part-text/calendar (msg part content-type nth depth 
declared-type)
   (notmuch-show-insert-part-header nth declared-type content-type (plist-get 
part :filename))
   (insert (with-temp-buffer
(insert (notmuch-show-get-bodypart-content msg part nth))
@@ -729,6 +729,10 @@ current buffer, if possible."
  result)))
   t)
 
+;; For backwards compatibility.
+(defun notmuch-show-insert-part-text/x-vcalendar (msg part content-type nth 
depth declared-type)
+  (notmuch-show-insert-part-text/calendar msg part content-type nth depth 
declared-type))
+
 (defun notmuch-show-insert-part-application/octet-stream (msg part 
content-type nth depth declared-type)
   ;; If we can deduce a MIME type from the filename of the attachment,
   ;; do so and pass it on to the handler for that type.
-- 
1.7.1

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


Re: [PATCH v2 1/2] emacs: support defining a list of alternative parts to show

2012-02-10 Thread Jani Nikula
On Fri, 10 Feb 2012 10:05:46 +, David Edmondson  wrote:
> On Thu,  9 Feb 2012 14:46:02 +0000, Jani Nikula  wrote:
> > Make notmuch-show-all-multipart/alternative-parts accept a list of
> > regexps to match the part types to determine which parts to show in
> > addition to the preferred types. This allows the user to force display
> > some alternative part types while normally showing just the preferred
> > ones.
> > 
> > Signed-off-by: Jani Nikula 
> > ---
> >  emacs/notmuch-show.el |   23 ++-
> >  1 files changed, 18 insertions(+), 5 deletions(-)
> > 
> > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> > index 24fde05..5f643f1 100644
> > --- a/emacs/notmuch-show.el
> > +++ b/emacs/notmuch-show.el
> > @@ -94,10 +94,20 @@ any given message."
> >:group 'notmuch-show
> >:group 'notmuch-hooks)
> >  
> > -;; Mostly useful for debugging.
> >  (defcustom notmuch-show-all-multipart/alternative-parts t
> > -  "Should all parts of multipart/alternative parts be shown?"
> > -  :type 'boolean
> > +  "Which parts of multipart/alternative should be shown?
> > +
> > +This variable determines which parts of multipart/alternative
> > +should be displayed. Set to t (the default) to show all
> > +parts. Set to nil to only show the preferred parts. Set to a list
> > +of regexps to display the preferred parts, and parts matching any
> > +of the regexps, for example:
> 
> "If set to `t' (the default), all sub-parts of a
> \"multipart/alternative\" part are shown. If set to `nil', only the
> preferred part is shown. If set to a list of regexps, the preferred part
> and all parts whose type matches one of the regexps will be shown."

Thank you; this is the best kind of comment on improving documentation.

> 
> > +
> > + (setq notmuch-show-all-multipart/alternative-parts
> > +  '(\"text/.*calendar\" \"text/html\"))"
> > +  :type '(choice (const :tag "Show all parts" t)
> > +(const :tag "Show preferred parts" nil)
> > +(repeat :tag "Show preferred and parts matching regexps" 
> > string))
> >:group 'notmuch-show)
> >  
> >  (defcustom notmuch-show-indent-messages-width 1
> > @@ -513,8 +523,11 @@ current buffer, if possible."
> >  ;; should be chosen if there are more than one that match?
> >  (mapc (lambda (inner-part)
> > (let ((inner-type (plist-get inner-part :content-type)))
> > - (if (or notmuch-show-all-multipart/alternative-parts
> > - (string= chosen-type inner-type))
> > + (if (or (equal notmuch-show-all-multipart/alternative-parts t)
> > + (string= chosen-type inner-type)
> > + (and
> > +  notmuch-show-all-multipart/alternative-parts
> > +  (equal (string-match-p (mapconcat (lambda (s) (format 
> > "^%s$" s)) notmuch-show-all-multipart/alternative-parts "\\|") inner-type) 
> > 0)))
> 
> This is quite messy. How about we add a general helper to "notmuch-lib.el":
> 
> (defun notmuch-string-match-list-p (regexps string)
>   (loop for regexp in regexps
>   if (string-match-p regexp string)
>   return t))
> 
> and then write:
> 
> (if (or (string= chosen-type inner-type)
> (equal notmuch-show-all-multipart/alternative-parts t)
> (notmuch-string-match-list-p 
> notmuch-show-all-multipart/alternative-parts inner-type))
>...
> 
> ?

*sigh* I was so happy to make that mapconcat work. And I guess soon I'll
have to add "code by dme" in this patch too. ;)

But you're right, it will be more readable that way. v3 in a few days.


BR,
Jani.


> 
> >   (notmuch-show-insert-bodypart msg inner-part depth)
> > (notmuch-show-insert-part-header (plist-get inner-part :id) 
> > inner-type inner-type nil " (not shown)"
> >   inner-parts)
> > -- 
> > 1.7.1
> > 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v2 1/2] emacs: support defining a list of alternative parts to show

2012-02-12 Thread Jani Nikula
On Fri, 10 Feb 2012 10:05:46 +, David Edmondson  wrote:
> On Thu,  9 Feb 2012 14:46:02 +0000, Jani Nikula  wrote:
> > Make notmuch-show-all-multipart/alternative-parts accept a list of
> > regexps to match the part types to determine which parts to show in
> > addition to the preferred types. This allows the user to force display
> > some alternative part types while normally showing just the preferred
> > ones.
> > 
> > Signed-off-by: Jani Nikula 
> > ---
> >  emacs/notmuch-show.el |   23 ++-
> >  1 files changed, 18 insertions(+), 5 deletions(-)
> > 
> > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> > index 24fde05..5f643f1 100644
> > --- a/emacs/notmuch-show.el
> > +++ b/emacs/notmuch-show.el
> > @@ -94,10 +94,20 @@ any given message."
> >:group 'notmuch-show
> >:group 'notmuch-hooks)
> >  
> > -;; Mostly useful for debugging.
> >  (defcustom notmuch-show-all-multipart/alternative-parts t
> > -  "Should all parts of multipart/alternative parts be shown?"
> > -  :type 'boolean
> > +  "Which parts of multipart/alternative should be shown?
> > +
> > +This variable determines which parts of multipart/alternative
> > +should be displayed. Set to t (the default) to show all
> > +parts. Set to nil to only show the preferred parts. Set to a list
> > +of regexps to display the preferred parts, and parts matching any
> > +of the regexps, for example:
> 
> "If set to `t' (the default), all sub-parts of a
> \"multipart/alternative\" part are shown. If set to `nil', only the
> preferred part is shown. If set to a list of regexps, the preferred part
> and all parts whose type matches one of the regexps will be shown."
> 
> > +
> > + (setq notmuch-show-all-multipart/alternative-parts
> > +  '(\"text/.*calendar\" \"text/html\"))"
> > +  :type '(choice (const :tag "Show all parts" t)
> > +(const :tag "Show preferred parts" nil)
> > +(repeat :tag "Show preferred and parts matching regexps" 
> > string))
> >:group 'notmuch-show)
> >  
> >  (defcustom notmuch-show-indent-messages-width 1
> > @@ -513,8 +523,11 @@ current buffer, if possible."
> >  ;; should be chosen if there are more than one that match?
> >  (mapc (lambda (inner-part)
> > (let ((inner-type (plist-get inner-part :content-type)))
> > - (if (or notmuch-show-all-multipart/alternative-parts
> > - (string= chosen-type inner-type))
> > + (if (or (equal notmuch-show-all-multipart/alternative-parts t)
> > + (string= chosen-type inner-type)
> > + (and
> > +  notmuch-show-all-multipart/alternative-parts
> > +  (equal (string-match-p (mapconcat (lambda (s) (format 
> > "^%s$" s)) notmuch-show-all-multipart/alternative-parts "\\|") inner-type) 
> > 0)))
> 
> This is quite messy. How about we add a general helper to "notmuch-lib.el":
> 
> (defun notmuch-string-match-list-p (regexps string)
>   (loop for regexp in regexps
>   if (string-match-p regexp string)
>   return t))
> 
> and then write:
> 
> (if (or (string= chosen-type inner-type)
> (equal notmuch-show-all-multipart/alternative-parts t)
> (notmuch-string-match-list-p 
> notmuch-show-all-multipart/alternative-parts inner-type))
>...

Hmm. I wrapped the regexps between ^ and $ to not match substrings. I
think that's less surprising and better than having the user add them,
and the user can still use e.g. ".*foo.*" to explicitly match a
substring.

If this is fixed in notmuch-string-match-list-p then it's not general
anymore. But does adding a mapcar to wrap the regexps here make this
messy again...? What if notmuch-string-match-list-p were just a local
specific helper for clarity?

> 
> ?
> 
> >   (notmuch-show-insert-bodypart msg inner-part depth)
> > (notmuch-show-insert-part-header (plist-get inner-part :id) 
> > inner-type inner-type nil " (not shown)"
> >   inner-parts)
> > -- 
> > 1.7.1
> > 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] emacs: Fix display of highlighted line in notmuch-show

2012-02-14 Thread Jani Nikula
On Tue, 14 Feb 2012 11:24:16 +0100, Michal Sojka  
wrote:
> When notmuch-search-line-faces is used to set background color in search
> results, the highlight of the current line is not always displayed
> correctly. This patch fixes that by increasing the priority property of
> the highlight overlay.

One nitpick: The subject line refers to notmuch-show.

BR,
Jani.

> ---
>  emacs/notmuch.el |   15 +++
>  1 files changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index 5b4f1c5..f851c6f 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -249,10 +249,17 @@ For a mouse binding, return nil."
>(set-buffer-modified-p nil)
>(view-buffer (current-buffer) 'kill-buffer-if-not-modified
>  
> -(defcustom notmuch-search-hook '(hl-line-mode)
> +(require 'hl-line)
> +
> +(defun notmuch-hl-line-mode ()
> +  (prog1 (hl-line-mode)
> +(when hl-line-overlay
> +  (overlay-put hl-line-overlay 'priority 1
> +
> +(defcustom notmuch-search-hook '(notmuch-hl-line-mode)
>"List of functions to call when notmuch displays the search results."
>:type 'hook
> -  :options '(hl-line-mode)
> +  :options '(notmuch-hl-line-mode)
>:group 'notmuch-search
>:group 'notmuch-hooks)
>  
> @@ -567,7 +574,7 @@ a list of strings of the form \"+TAG\" or \"-TAG\".
>  the messages that are about to be tagged"
>  
>:type 'hook
> -  :options '(hl-line-mode)
> +  :options '(notmuch-hl-line-mode)
>:group 'notmuch-hooks)
>  
>  (defcustom notmuch-after-tag-hook nil
> @@ -578,7 +585,7 @@ a list of strings of the form \"+TAG\" or \"-TAG\".
>  'query' will be a string containing the search query that determines
>  the messages that were tagged"
>:type 'hook
> -  :options '(hl-line-mode)
> +  :options '(notmuch-hl-line-mode)
>:group 'notmuch-hooks)
>  
>  (defun notmuch-search-set-tags (tags)
> -- 
> 1.7.7.3
> 
> ___
> 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: [PATCH] emacs: Add the option of counting threads in notmuch-hello

2012-02-15 Thread Jani Nikula
On Wed, 15 Feb 2012 19:14:19 +0200, Tomi Ollila  wrote:
> On Wed, 15 Feb 2012 09:23:31 -0700, Adam Wolfe Gordon  
> wrote:
> > On Wed, Feb 15, 2012 at 08:52, Dmitry Kurochkin
> >  wrote:
> > > Can we delay this patch until user-defined sections are pushed?  I know
> > > I promised to review it long ago.  But I still did not manage to finish
> > > it yet.  I hope I can do it in the beginning of the next week.
> > 
> > Absolutely. I was just building new notmuch packages for myself this
> > morning and realized I had this commit sitting in my tree collecting
> > dust.
> 
> notmuch count is fast
> notmuch count --output=threads  is slower

Yup, it's because you can't query Xapian about threads. Compare
notmuch_query_count_{messages,threads} in lib/query.cc for details.

> I was thinking why not show both? but as threads
> count is slow there could be customization variable
> for showing *optionally* thread count in addition 
> to message count like
> 
> "You have nn,nnn messages in n,nnn threads"
> 
> Tomi
> ___
> 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: search by date range

2012-02-16 Thread Jani Nikula
On Thu, 16 Feb 2012 12:58:00 -0500, Philippe LeCavalier 
 wrote:
> I really like searching my inde by date and I came across a post that I
> can't seems to find for the life of me regarding the functionality of
> doing such a thing. I'll I'm left with is this[1] and I can't figure out
> what the heck it is. I do know that what it does do is limit mail from
> two weeks back to present. I suppose the omition at .. implies present
> but what the number represent and how to I play with that?

Hi Philippe -

Out of the box you have the date search syntax described in 'man
notmuch-search-terms', i.e. specifying a date range in terms of
timestamps. Not very user friendly, but can be helped a little by using
date(1) to produce the timestamps. See the man page.

Quite some time ago I posted patches to add gnulib date search, but the
gnulib semantics, while compatible with other GNU programs, are a bit
awkward for the needs of notmuch. Plus it's plenty of code. See
id:"cover.1312964528.git.j...@nikula.org" for the patches (they may not
apply anymore though).

Finally, I've been working on adding support for a decent date range
search. It still needs some polish and tests, but seeing the demand,
perhaps I should just post the patches and see what happens.


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


Re: [PATCH] emacs: Mention race condition safety in user visible documentation

2012-02-18 Thread Jani Nikula
On Feb 19, 2012 12:44 AM, "Michal Sojka"  wrote:
>
> After recent rework of a/A/x/X key bindings, the important paragraph in
> documentation of `notmuch-show-archive-thread' stayed hidden from users,
> because no key is bound to this function.
>
> This patch copies the important paragraph to the documentation of
> functions currently bound to keys.

Hi Michal, this was discussed earlier, and Dmitry convinced me that the
code does exactly what the user expects it to do (archives only the
messages in the buffer) so it would be unnecessary and confusing to have
this documentation. It could be added as a comment for developers I guess.

BR,
Jani.

> ---
>  emacs/notmuch-show.el |   14 --
>  1 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index aa9ccee..1916146 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1721,13 +1721,23 @@ buffer."
> (notmuch-show-tag-all (concat op "inbox"
>
>  (defun notmuch-show-archive-thread-then-next ()
> -  "Archive each message in thread, then show next thread from search."
> +  "Archive each message in thread, then show next thread from search.
> +
> +Note: This command is safe from any race condition of new messages
> +being delivered to the same thread. It does not archive the
> +entire thread, but only the messages shown in the current
> +buffer."
>   (interactive)
>   (notmuch-show-archive-thread)
>   (notmuch-show-next-thread t))
>
>  (defun notmuch-show-archive-thread-then-exit ()
> -  "Archive each message in thread, then exit back to search results."
> +  "Archive each message in thread, then exit back to search results.
> +
> +Note: This command is safe from any race condition of new messages
> +being delivered to the same thread. It does not archive the
> +entire thread, but only the messages shown in the current
> +buffer."
>   (interactive)
>   (notmuch-show-archive-thread)
>   (notmuch-show-next-thread))
> --
> 1.7.7.3
>
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[RFC PATCH 0/2] natural language date range search

2012-02-19 Thread Jani Nikula
Hi all, these patches add support for natural language date range search
of the form date:since..until, where since and until can be fairly free
form date/time expressions in English.

Examples:

date:two-days..yesterday (all mail in the two days before today)
date:12h.. (all mail since 12 hrs ago)
date:november..november (all mail in previous november)
date:2011.. (all mail since the beginning of 2011)
date:last-week..this-week (all mail over last and current week)
date:5/10/2011-12:34:55..10pm_2012-01-14

Plus plenty more and combinations of the above.

The repository for the date/time parser with a command line tool is at
[1], and there's a README [2] with a bunch of details too.


BR,
Jani.


[1] https://gitorious.org/parse-time-string/parse-time-string
[2] 
https://gitorious.org/parse-time-string/parse-time-string/blobs/master/README


Jani Nikula (2):
  lib: add date/time parser
  lib: add date range search

 lib/Makefile.local  |2 +
 lib/database-private.h  |1 +
 lib/database.cc |4 +
 lib/getdate-proc.cc |   34 ++
 lib/getdate-proc.h  |   21 +
 lib/parse-time-string.c | 1304 +++
 lib/parse-time-string.h |   95 
 7 files changed, 1461 insertions(+), 0 deletions(-)
 create mode 100644 lib/getdate-proc.cc
 create mode 100644 lib/getdate-proc.h
 create mode 100644 lib/parse-time-string.c
 create mode 100644 lib/parse-time-string.h

-- 
1.7.5.4

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


[RFC PATCH 1/2] lib: add date/time parser

2012-02-19 Thread Jani Nikula
Signed-off-by: Jani Nikula 
---
 lib/Makefile.local  |1 +
 lib/parse-time-string.c | 1304 +++
 lib/parse-time-string.h |   95 
 3 files changed, 1400 insertions(+), 0 deletions(-)
 create mode 100644 lib/parse-time-string.c
 create mode 100644 lib/parse-time-string.h

diff --git a/lib/Makefile.local b/lib/Makefile.local
index 54c4dea..803a284 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -53,6 +53,7 @@ libnotmuch_c_srcs =   \
$(dir)/libsha1.c\
$(dir)/message-file.c   \
$(dir)/messages.c   \
+   $(dir)/parse-time-string.c  \
$(dir)/sha1.c   \
$(dir)/tags.c
 
diff --git a/lib/parse-time-string.c b/lib/parse-time-string.c
new file mode 100644
index 000..59713dc
--- /dev/null
+++ b/lib/parse-time-string.c
@@ -0,0 +1,1304 @@
+/*
+ * parse time string - user friendly date and time parser
+ * Copyright © 2012 Jani Nikula
+ *
+ * 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 2 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: Jani Nikula 
+ */
+
+#ifndef PARSE_TIME_DEBUG
+#define NDEBUG /* for assert() */
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "parse-time-string.h"
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0]))
+
+/* field indices in struct state tm, and set fields */
+enum field {
+/* keep SEC...YEAR in this order */
+TM_ABS_SEC,/* seconds */
+TM_ABS_MIN,/* minutes */
+TM_ABS_HOUR,   /* hours */
+TM_ABS_MDAY,   /* day of the month */
+TM_ABS_MON,/* month */
+TM_ABS_YEAR,   /* year */
+
+TM_ABS_WDAY,   /* day of the week. special: may be relative */
+TM_ABS_ISDST,  /* daylight saving time */
+
+TM_AMPM,   /* am vs. pm */
+TM_TZ, /* timezone in minutes */
+
+/* keep SEC...YEAR in this order */
+TM_REL_SEC,/* seconds relative to now */
+TM_REL_MIN,/* minutes ... */
+TM_REL_HOUR,   /* hours ... */
+TM_REL_DAY,/* days ... */
+TM_REL_MON,/* months ... */
+TM_REL_YEAR,   /* years ... */
+TM_REL_WEEK,   /* weeks ... */
+
+TM_NONE,   /* not a field */
+
+TM_SIZE = TM_NONE,
+};
+
+enum field_set {
+FIELD_UNSET,
+FIELD_SET,
+FIELD_NOW,
+};
+
+static enum field
+next_field (enum field field)
+{
+/* note: depends on the enum ordering */
+return field < TM_ABS_YEAR ? field + 1 : TM_NONE;
+}
+
+static enum field
+abs_to_rel_field (enum field field)
+{
+assert (field <= TM_ABS_YEAR);
+
+/* note: depends on the enum ordering */
+return field + (TM_REL_SEC - TM_ABS_SEC);
+}
+
+/* get zero value for field */
+static int
+field_zero (enum field field)
+{
+if (field == TM_ABS_MDAY || field == TM_ABS_MON)
+   return 1;
+else if (field == TM_ABS_YEAR)
+   return 1970;
+else
+   return 0;
+}
+
+struct state {
+int tm[TM_SIZE];   /* parsed date and time */
+enum field_set set[TM_SIZE];   /* set status of tm */
+
+enum field last_field;
+char delim;
+
+int postponed_length;  /* number of digits in postponed value */
+int postponed_value;
+};
+
+/*
+ * Helpers for postponed numbers.
+ *
+ * postponed_length is the number of digits in postponed value. 0
+ * means there is no postponed number. -1 means there is a postponed
+ * number, but it comes from a keyword, and it doesn't have digits.
+ */
+static int
+get_postponed_length (struct state *state)
+{
+return state->postponed_length;
+}
+
+static bool
+get_postponed_number (struct state *state, int *v, int *n)
+{
+if (!state->postponed_length)
+   return false;
+
+if (n)
+   *n = state->postponed_length;
+
+if (v)
+   *v = state->postponed_value;
+
+state->postponed_length = 0;
+state->postponed_value = 0;
+
+return true;
+}
+
+/* parse postponed number if one exists */
+static int parse_postponed_number (struct state *state, int v, int n);
+static int
+handle_postponed_number (struct state *state)
+{
+int v = state->postponed_value;
+int n = state->postponed_length;
+
+if (!n)
+   retu

[RFC PATCH 2/2] lib: add date range search

2012-02-19 Thread Jani Nikula
Add a custom value range processor to enable date and time searches of
the form date:since..until, where "since" and "until" are expressions
understood by parse_time_string().

If "since" or "until" describes date/time at an accuracy of days or
less, the values are rounded according to the accuracy, towards past
for "since" and towards future for "until". For example,
date:november..yesterday would match from the beginning of November
until the end of yesterday. Expressions such as date:today..today
means since the beginning of today until the end of today.

Open-ended ranges are supported (since Xapian 1.2.1), i.e. you can
specify date:..until or date:since.. to not limit the start or end
date, respectively.

CAVEATS:

Xapian does not support spaces in range expressions. You can replace
the spaces with '_' or (in most cases) '-' or (in some cases) leave
the spaces out altogether.

Entering date:expr without ".." (for example date:yesterday) won't
work. You can achieve the expected result by duplicating the expr both
sides of ".." (for example date:yesterday..yesterday).

Signed-off-by: Jani Nikula 
---
 lib/Makefile.local |1 +
 lib/database-private.h |1 +
 lib/database.cc|4 
 lib/getdate-proc.cc|   34 ++
 lib/getdate-proc.h |   21 +
 5 files changed, 61 insertions(+), 0 deletions(-)
 create mode 100644 lib/getdate-proc.cc
 create mode 100644 lib/getdate-proc.h

diff --git a/lib/Makefile.local b/lib/Makefile.local
index 803a284..7dd1f7d 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -59,6 +59,7 @@ libnotmuch_c_srcs =   \
 
 libnotmuch_cxx_srcs =  \
$(dir)/database.cc  \
+   $(dir)/getdate-proc.cc  \
$(dir)/directory.cc \
$(dir)/index.cc \
$(dir)/message.cc   \
diff --git a/lib/database-private.h b/lib/database-private.h
index 88532d5..ba13dc7 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -52,6 +52,7 @@ struct _notmuch_database {
 Xapian::QueryParser *query_parser;
 Xapian::TermGenerator *term_gen;
 Xapian::ValueRangeProcessor *value_range_processor;
+Xapian::ValueRangeProcessor *getdate_proc;
 };
 
 /* Return the list of terms from the given iterator matching a prefix.
diff --git a/lib/database.cc b/lib/database.cc
index c928d02..a3f8adb 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -19,6 +19,7 @@
  */
 
 #include "database-private.h"
+#include "getdate-proc.h"
 
 #include 
 
@@ -682,12 +683,14 @@ notmuch_database_open (const char *path,
notmuch->term_gen = new Xapian::TermGenerator;
notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor 
(NOTMUCH_VALUE_TIMESTAMP);
+   notmuch->getdate_proc = new GetDateValueRangeProcessor 
(NOTMUCH_VALUE_TIMESTAMP, "date:", true);
 
notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
notmuch->query_parser->set_database (*notmuch->xapian_db);
notmuch->query_parser->set_stemmer (Xapian::Stem ("english"));
notmuch->query_parser->set_stemming_strategy 
(Xapian::QueryParser::STEM_SOME);
notmuch->query_parser->add_valuerangeprocessor 
(notmuch->value_range_processor);
+   notmuch->query_parser->add_valuerangeprocessor (notmuch->getdate_proc);
 
for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) {
prefix_t *prefix = &BOOLEAN_PREFIX_EXTERNAL[i];
@@ -729,6 +732,7 @@ notmuch_database_close (notmuch_database_t *notmuch)
 delete notmuch->query_parser;
 delete notmuch->xapian_db;
 delete notmuch->value_range_processor;
+delete notmuch->getdate_proc;
 talloc_free (notmuch);
 }
 
diff --git a/lib/getdate-proc.cc b/lib/getdate-proc.cc
new file mode 100644
index 000..31f8f03
--- /dev/null
+++ b/lib/getdate-proc.cc
@@ -0,0 +1,34 @@
+
+#include "database-private.h"
+#include "getdate-proc.h"
+#include "parse-time-string.h"
+
+/* see *ValueRangeProcessor in xapian-core/api/valuerangeproc.cc */
+Xapian::valueno
+GetDateValueRangeProcessor::operator() (std::string &begin, std::string &end)
+{
+time_t t, now;
+
+if (Xapian::StringValueRangeProcessor::operator() (begin, end) == 
Xapian::BAD_VALUENO)
+   return Xapian::BAD_VALUENO;
+
+/* use the same 'now' for begin and end */
+if (time (&now) == (time_t) -1)
+   return Xapian::BAD_VALUENO;
+
+if (!begin.empty ()) {
+   if (parse_time_string (begin.c_str (), &t, &now, PARSE_TIME_ROUND_DOWN))
+   return Xapian::BAD_VALUENO;
+
+   begin.assign (Xapian::sortable_serialise ((double) t));
+}
+

Re: [PATCH v2 1/2] emacs: support defining a list of alternative parts to show

2012-02-20 Thread Jani Nikula
On Thu,  9 Feb 2012 14:46:02 +, Jani Nikula  wrote:
> Make notmuch-show-all-multipart/alternative-parts accept a list of
> regexps to match the part types to determine which parts to show in
> addition to the preferred types. This allows the user to force display
> some alternative part types while normally showing just the preferred
> ones.

Wah, this patch (1/2) is crap, as it also seems to affect the
reply. I'll probably return to this later, after the json reply stuff is
merged or so.

BR,
Jani.


> 
> Signed-off-by: Jani Nikula 
> ---
>  emacs/notmuch-show.el |   23 ++-
>  1 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 24fde05..5f643f1 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -94,10 +94,20 @@ any given message."
>:group 'notmuch-show
>:group 'notmuch-hooks)
>  
> -;; Mostly useful for debugging.
>  (defcustom notmuch-show-all-multipart/alternative-parts t
> -  "Should all parts of multipart/alternative parts be shown?"
> -  :type 'boolean
> +  "Which parts of multipart/alternative should be shown?
> +
> +This variable determines which parts of multipart/alternative
> +should be displayed. Set to t (the default) to show all
> +parts. Set to nil to only show the preferred parts. Set to a list
> +of regexps to display the preferred parts, and parts matching any
> +of the regexps, for example:
> +
> + (setq notmuch-show-all-multipart/alternative-parts
> +  '(\"text/.*calendar\" \"text/html\"))"
> +  :type '(choice (const :tag "Show all parts" t)
> +  (const :tag "Show preferred parts" nil)
> +  (repeat :tag "Show preferred and parts matching regexps" 
> string))
>:group 'notmuch-show)
>  
>  (defcustom notmuch-show-indent-messages-width 1
> @@ -513,8 +523,11 @@ current buffer, if possible."
>  ;; should be chosen if there are more than one that match?
>  (mapc (lambda (inner-part)
>   (let ((inner-type (plist-get inner-part :content-type)))
> -   (if (or notmuch-show-all-multipart/alternative-parts
> -   (string= chosen-type inner-type))
> +   (if (or (equal notmuch-show-all-multipart/alternative-parts t)
> +   (string= chosen-type inner-type)
> +   (and
> +notmuch-show-all-multipart/alternative-parts
> +(equal (string-match-p (mapconcat (lambda (s) (format 
> "^%s$" s)) notmuch-show-all-multipart/alternative-parts "\\|") inner-type) 
> 0)))
> (notmuch-show-insert-bodypart msg inner-part depth)
>   (notmuch-show-insert-part-header (plist-get inner-part :id) 
> inner-type inner-type nil " (not shown)"
> inner-parts)
> -- 
> 1.7.1
> 
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


  1   2   3   4   5   6   7   8   9   10   >