unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH v1 0/3] Address completion entirely in elisp.
@ 2014-09-05 12:59 David Edmondson
  2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw)
  To: notmuch


Address completion entirely in elisp.

I grew frustrated with having to use an external command to provide
address completion, as they all had annoyances (up front scanning,
requiring python bindings, etc.). This is an attempt to provide
something similar to jkr's notmuch-addresses.py (which I was
previously using) entirely in elisp, relying only on the `notmuch'
command.


David Edmondson (3):
  emacs: Allow query to exclude the entire thread and body.
  emacs: Add `notmuch-user-all-email'.
  emacs: Add an address completer in elisp.

 emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++-----
 emacs/notmuch-lib.el     |  4 ++++
 emacs/notmuch-query.el   |  7 ++++++-
 3 files changed, 54 insertions(+), 6 deletions(-)

-- 
1.8.5.2 (Apple Git-48)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body.
  2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson
@ 2014-09-05 12:59 ` David Edmondson
  2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 12+ messages in thread
From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw)
  To: notmuch

Callers to `notmuch-query-get-threads' can optionally choose not to
receive either the entire thread and/or the body of messages.

This is intended to reduce the amount of output in cases where one or
both of these items is not useful.
---
 emacs/notmuch-query.el | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el
index d1daffc..f83ca9b 100644
--- a/emacs/notmuch-query.el
+++ b/emacs/notmuch-query.el
@@ -21,7 +21,8 @@
 
 (require 'notmuch-lib)
 
-(defun notmuch-query-get-threads (search-terms)
+(defun notmuch-query-get-threads (search-terms &optional exclude-entire-thread
+					       exclude-body)
   "Return a list of threads of messages matching SEARCH-TERMS.
 
 A thread is a forest or list of trees. A tree is a two element
@@ -31,6 +32,10 @@ is a possibly empty forest of replies.
   (let ((args '("show" "--format=sexp" "--format-version=1")))
     (if notmuch-show-process-crypto
 	(setq args (append args '("--decrypt"))))
+    (if exclude-entire-thread
+	(setq args (append args '("--entire-thread=false"))))
+    (if exclude-body
+	(setq args (append args '("--body=false"))))
     (setq args (append args search-terms))
     (apply #'notmuch-call-notmuch-sexp args)))
 
-- 
1.8.5.2 (Apple Git-48)

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 2/3] emacs: Add `notmuch-user-all-email'.
  2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson
  2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson
@ 2014-09-05 12:59 ` David Edmondson
  2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson
  2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters
  3 siblings, 0 replies; 12+ messages in thread
From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw)
  To: notmuch

`notmuch-user-all-email' returns a list of the user's primary and
secondary email addresses.
---
 emacs/notmuch-lib.el | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 19269e3..685469c 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -228,6 +228,10 @@ on the command line, and then retry your notmuch command")))
   "Return the user.other_email value (as a list) from the notmuch configuration."
   (split-string (notmuch-config-get "user.other_email") "\n" t))
 
+(defun notmuch-user-all-email ()
+  "Return all email addresses for the user from the notmuch configuration."
+  (append (list (notmuch-user-primary-email)) (notmuch-user-other-email)))
+
 (defun notmuch-poll ()
   "Run \"notmuch new\" or an external script to import mail.
 
-- 
1.8.5.2 (Apple Git-48)

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 3/3] emacs: Add an address completer in elisp.
  2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson
  2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson
  2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson
@ 2014-09-05 12:59 ` David Edmondson
  2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters
  3 siblings, 0 replies; 12+ messages in thread
From: David Edmondson @ 2014-09-05 12:59 UTC (permalink / raw)
  To: notmuch

Rather than relying on an external comment to provide address
completion in composition mode, provide a solution purely in elisp.

Update `notmuch-address-command' to allow it to specify an external
command or a function, with the default remaining as an external
command called "notmuch-addresses".
---
 emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 44 insertions(+), 5 deletions(-)

diff --git a/emacs/notmuch-address.el b/emacs/notmuch-address.el
index fa65cd5..449fa54 100644
--- a/emacs/notmuch-address.el
+++ b/emacs/notmuch-address.el
@@ -24,10 +24,17 @@
 ;;
 
 (defcustom notmuch-address-command "notmuch-addresses"
-  "The command which generates possible addresses. It must take a
-single argument and output a list of possible matches, one per
-line."
-  :type 'string
+  "Command or function which generates possible addresses.
+
+A command must take a single argument and output a list of
+possible matches, one per line.
+
+A function must take a single argument and return a list of
+possible matches."
+  :type '(choice (string :tag "External command")
+		 (function :tag "Standard function"
+			   :value notmuch-address-option-generator)
+		 (function :tag "Custom function"))
   :group 'notmuch-send
   :group 'notmuch-external)
 
@@ -42,6 +49,32 @@ to know how address selection is made by default."
   :group 'notmuch-send
   :group 'notmuch-external)
 
+(defun notmuch-address-extractor (message)
+  "Return a list of addresses mentioned in `message'."
+  (let* ((headers (plist-get message :headers))
+	 (from (plist-get headers :From)))
+    from))
+
+(defun notmuch-address-option-generator (initial)
+  "Generate a set of possible address completions for `initial'."
+  (let* ((my-addresses (notmuch-user-all-email))
+	 (query (list (format "(%s) AND from:%s*"
+			      (mapconcat (lambda (a) (concat "to:" a))
+					 my-addresses " OR ")
+			      initial)))
+	 bare-results
+	 results)
+    (dolist (address
+	     (notmuch-query-map-threads 'notmuch-address-extractor
+					(notmuch-query-get-threads query t t)))
+      (when address
+	(let ((bare-address (cadr (std11-extract-address-components address))))
+	  (unless (or (member bare-address my-addresses)
+		      (member bare-address bare-results))
+	    (push bare-address bare-results)
+	    (push address results)))))
+    results))
+
 (defun notmuch-address-selection-function (prompt collection initial-input)
   "Call (`completing-read'
       PROMPT COLLECTION nil nil INITIAL-INPUT 'notmuch-address-history)"
@@ -60,7 +93,13 @@ to know how address selection is made by default."
 	  (push notmuch-address-message-alist-member message-completion-alist))))
 
 (defun notmuch-address-options (original)
-  (process-lines notmuch-address-command original))
+  (cond
+   ((stringp notmuch-address-command)
+    (process-lines notmuch-address-command original))
+   ((functionp notmuch-address-command)
+    (funcall notmuch-address-command original))
+   (t
+    (error "No address completion mechanism defined."))))
 
 (defun notmuch-address-expand-name ()
   (let* ((end (point))
-- 
1.8.5.2 (Apple Git-48)

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v1 0/3] Address completion entirely in elisp.
  2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson
                   ` (2 preceding siblings ...)
  2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson
@ 2014-09-05 15:29 ` Mark Walters
  2014-09-05 16:06   ` David Edmondson
  3 siblings, 1 reply; 12+ messages in thread
From: Mark Walters @ 2014-09-05 15:29 UTC (permalink / raw)
  To: David Edmondson, notmuch


Hi

On Fri, 05 Sep 2014, David Edmondson <dme@dme.org> wrote:
> Address completion entirely in elisp.
>
> I grew frustrated with having to use an external command to provide
> address completion, as they all had annoyances (up front scanning,
> requiring python bindings, etc.). This is an attempt to provide
> something similar to jkr's notmuch-addresses.py (which I was
> previously using) entirely in elisp, relying only on the `notmuch'
> command.

Just a few quick comments: the first is relevant to others trying this
patch.

1) You seem to be missing a (require 'std11) somewhere. I did this via M-:
and then it ran fine.

2) It is not quick on a spinning rust disk. This may not be relevant as
the delay is probably notmuch so would also be the case if I were using
notmuch-addresses.py (i normally just use a trivial script that parses
my .mailrc)

3) Have you tried
id:1407771091-12651-1-git-send-email-sojkam1@fel.cvut.cz and do you have
any comments on the comparison?

4) Finally, I wonder if we would be worth approaching the backend
notmuch use slightly differently: if we added a
notmuch_messages_collect_from function which was very similar to
notmuch_messages_collect_tags, and added a corresponding --output=from
to notmuch search then you would get the information you need very
quickly. I think it might be a lot faster as I think the from header is
stored in the database but some other headers are not, so that the
current method the show --body=false needs to look at the actually
messages

I should emphasise that none of the above means I am opposed to the
patch: having respectable built in address-completion support would be
very nice.

Best wishes

Mark




>
>
> David Edmondson (3):
>   emacs: Allow query to exclude the entire thread and body.
>   emacs: Add `notmuch-user-all-email'.
>   emacs: Add an address completer in elisp.
>
>  emacs/notmuch-address.el | 49 +++++++++++++++++++++++++++++++++++++++++++-----
>  emacs/notmuch-lib.el     |  4 ++++
>  emacs/notmuch-query.el   |  7 ++++++-
>  3 files changed, 54 insertions(+), 6 deletions(-)
>
> -- 
> 1.8.5.2 (Apple Git-48)
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v1 0/3] Address completion entirely in elisp.
  2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters
@ 2014-09-05 16:06   ` David Edmondson
  2014-09-06  8:14     ` [PATCH] cli: add --output=address-{from,to,all} to notmuch search Jani Nikula
  0 siblings, 1 reply; 12+ messages in thread
From: David Edmondson @ 2014-09-05 16:06 UTC (permalink / raw)
  To: Mark Walters, notmuch

On Fri, Sep 05 2014, Mark Walters wrote:
> On Fri, 05 Sep 2014, David Edmondson <dme@dme.org> wrote:
>> Address completion entirely in elisp.
>>
>> I grew frustrated with having to use an external command to provide
>> address completion, as they all had annoyances (up front scanning,
>> requiring python bindings, etc.). This is an attempt to provide
>> something similar to jkr's notmuch-addresses.py (which I was
>> previously using) entirely in elisp, relying only on the `notmuch'
>> command.
>
> Just a few quick comments: the first is relevant to others trying this
> patch.
>
> 1) You seem to be missing a (require 'std11) somewhere. I did this via M-:
> and then it ran fine.

My apologies. Will fix (and a compiler warning at the same time).

> 2) It is not quick on a spinning rust disk. This may not be relevant as
> the delay is probably notmuch so would also be the case if I were using
> notmuch-addresses.py (i normally just use a trivial script that parses
> my .mailrc)

It's not always as fast as I would like on SSD either :-) The mechanism
is very similar to the equivalent Python program, so I think that it's
probably about the same.

> 3) Have you tried
> id:1407771091-12651-1-git-send-email-sojkam1@fel.cvut.cz and do you have
> any comments on the comparison?

No, I will dig it out and look.

> 4) Finally, I wonder if we would be worth approaching the backend
> notmuch use slightly differently: if we added a
> notmuch_messages_collect_from function which was very similar to
> notmuch_messages_collect_tags, and added a corresponding --output=from
> to notmuch search then you would get the information you need very
> quickly. I think it might be a lot faster as I think the from header is
> stored in the database but some other headers are not, so that the
> current method the show --body=false needs to look at the actually
> messages

Extending notmuch to help with this was next on my list of things to
do. At the moment I just needed a solution that worked.

> I should emphasise that none of the above means I am opposed to the
> patch: having respectable built in address-completion support would be
> very nice.

Cool, thanks!

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] cli: add --output=address-{from,to,all} to notmuch search
  2014-09-05 16:06   ` David Edmondson
@ 2014-09-06  8:14     ` Jani Nikula
  0 siblings, 0 replies; 12+ messages in thread
From: Jani Nikula @ 2014-09-06  8:14 UTC (permalink / raw)
  To: notmuch, David Edmondson, Mark Walters

address-from prints reply-to or from, address-to prints to, cc, and
bcc, and address-all prints all of them.

---

Mark, David -

I wrote most of this almost two years ago, but wasn't really happy
with it. There's address deduplication, but for large result sets that
might use lots of memory. Maybe the --duplicate option could be
overloaded for doing or not doing deduplication. I'd like to have some
way of picking the prettiest (that's subjective too) name part to go
with the address, now it's just the first encountered. And so on.

But maybe this will be useful for you, and you can pick some ideas. I
won't have the time to do much on this.

Cheers,
Jani.
---
 notmuch-search.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 113 insertions(+), 1 deletion(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index bc9be4593ecc..33da90eaceec 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -26,6 +26,9 @@ typedef enum {
     OUTPUT_SUMMARY,
     OUTPUT_THREADS,
     OUTPUT_MESSAGES,
+    OUTPUT_ADDRESS_FROM,
+    OUTPUT_ADDRESS_TO,
+    OUTPUT_ADDRESS_ALL,
     OUTPUT_FILES,
     OUTPUT_TAGS
 } output_t;
@@ -214,6 +217,78 @@ do_search_threads (sprinter_t *format,
     return 0;
 }
 
+static void
+print_address_list (sprinter_t *format, GHashTable *addrs,
+		    InternetAddressList *list)
+{
+    InternetAddress *address;
+    int i;
+
+    for (i = 0; i < internet_address_list_length (list); i++) {
+	address = internet_address_list_get_address (list, i);
+	if (INTERNET_ADDRESS_IS_GROUP (address)) {
+	    InternetAddressGroup *group;
+	    InternetAddressList *group_list;
+
+	    group = INTERNET_ADDRESS_GROUP (address);
+	    group_list = internet_address_group_get_members (group);
+	    if (group_list == NULL)
+		continue;
+
+	    print_address_list (format, addrs, group_list);
+	} else {
+	    InternetAddressMailbox *mailbox;
+	    const char *name;
+	    const char *addr;
+	    char *full_address;
+
+	    mailbox = INTERNET_ADDRESS_MAILBOX (address);
+
+	    name = internet_address_get_name (address);
+	    addr = internet_address_mailbox_get_addr (mailbox);
+
+	    if (g_hash_table_lookup_extended (addrs, addr, NULL, NULL))
+		continue;
+
+	    g_hash_table_insert (addrs, talloc_strdup (NULL, addr), NULL);
+
+	    if (name && *name)
+		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
+	    else
+		full_address = talloc_asprintf (NULL, "<%s>", addr);
+
+	    if (!full_address)
+		break;
+
+	    format->string (format, full_address);
+	    format->separator (format);
+
+	    talloc_free (full_address);
+	}
+    }
+}
+
+static void
+print_address_string (sprinter_t *format, GHashTable *addrs, const char *recipients)
+{
+    InternetAddressList *list;
+
+    if (recipients == NULL)
+	return;
+
+    list = internet_address_list_parse_string (recipients);
+    if (list == NULL)
+	return;
+
+    print_address_list (format, addrs, list);
+}
+
+static void
+_my_talloc_free_for_g_hash (void *ptr)
+{
+    talloc_free (ptr);
+}
+
 static int
 do_search_messages (sprinter_t *format,
 		    notmuch_query_t *query,
@@ -225,8 +300,14 @@ do_search_messages (sprinter_t *format,
     notmuch_message_t *message;
     notmuch_messages_t *messages;
     notmuch_filenames_t *filenames;
+    GHashTable *addresses = NULL;
     int i;
 
+    if (output == OUTPUT_ADDRESS_FROM || output == OUTPUT_ADDRESS_TO ||
+	output == OUTPUT_ADDRESS_ALL)
+	addresses = g_hash_table_new_full (g_str_hash, g_str_equal,
+				       _my_talloc_free_for_g_hash, NULL);
+
     if (offset < 0) {
 	offset += notmuch_query_count_messages (query);
 	if (offset < 0)
@@ -264,16 +345,41 @@ do_search_messages (sprinter_t *format,
 	    
 	    notmuch_filenames_destroy( filenames );
 
-	} else { /* output == OUTPUT_MESSAGES */
+	} else if (output == OUTPUT_MESSAGES) {
 	    format->set_prefix (format, "id");
 	    format->string (format,
 			    notmuch_message_get_message_id (message));
 	    format->separator (format);
+	} else {
+	    if (output == OUTPUT_ADDRESS_FROM || output == OUTPUT_ADDRESS_ALL) {
+		const char *addrs;
+
+		addrs = notmuch_message_get_header (message, "reply-to");
+
+		if (addrs == NULL || *addrs == '\0')
+		    addrs = notmuch_message_get_header (message, "from");
+
+		print_address_string (format, addresses, addrs);
+	    }
+
+	    if (output == OUTPUT_ADDRESS_TO || output == OUTPUT_ADDRESS_ALL) {
+		const char *hdrs[] = { "to", "cc", "bcc" };
+		const char *addrs;
+		size_t j;
+
+		for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
+		    addrs = notmuch_message_get_header (message, hdrs[j]);
+		    print_address_string (format, addresses, addrs);
+		}
+	    }
 	}
 
 	notmuch_message_destroy (message);
     }
 
+    if (addresses)
+	g_hash_table_unref (addresses);
+
     notmuch_messages_destroy (messages);
 
     format->end (format);
@@ -368,6 +474,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
 	  (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY },
 				  { "threads", OUTPUT_THREADS },
 				  { "messages", OUTPUT_MESSAGES },
+				  { "address-from", OUTPUT_ADDRESS_FROM },
+				  { "address-to", OUTPUT_ADDRESS_TO },
+				  { "address-all", OUTPUT_ADDRESS_ALL },
 				  { "files", OUTPUT_FILES },
 				  { "tags", OUTPUT_TAGS },
 				  { 0, 0 } } },
@@ -459,6 +568,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
 	ret = do_search_threads (format, query, sort, output, offset, limit);
 	break;
     case OUTPUT_MESSAGES:
+    case OUTPUT_ADDRESS_FROM:
+    case OUTPUT_ADDRESS_TO:
+    case OUTPUT_ADDRESS_ALL:
     case OUTPUT_FILES:
 	ret = do_search_messages (format, query, output, offset, limit, dupe);
 	break;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH] cli: add --output=address-{from,to,all} to notmuch search
  2014-09-06 13:35 [PATCH 2/3] cli: add --output=address-{from, to, all} " Mark Walters
@ 2014-09-06 16:41 ` Jani Nikula
  2014-09-06 16:47   ` [PATCH] cli: add --output=address-{from, to, all} " Jani Nikula
                     ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Jani Nikula @ 2014-09-06 16:41 UTC (permalink / raw)
  To: notmuch

address-from prints reply-to or from, address-to prints to, cc, and
bcc, and address-all prints all of them.
---
 notmuch-search.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 100 insertions(+), 9 deletions(-)

diff --git a/notmuch-search.c b/notmuch-search.c
index bc9be4593ecc..e7cf3d2a0fdf 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -23,11 +23,14 @@
 #include "string-util.h"
 
 typedef enum {
-    OUTPUT_SUMMARY,
-    OUTPUT_THREADS,
-    OUTPUT_MESSAGES,
-    OUTPUT_FILES,
-    OUTPUT_TAGS
+    OUTPUT_SUMMARY	= 1 << 0,
+    OUTPUT_THREADS	= 1 << 1,
+    OUTPUT_MESSAGES	= 1 << 2,
+    OUTPUT_FILES	= 1 << 3,
+    OUTPUT_TAGS		= 1 << 4,
+    OUTPUT_SENDER	= 1 << 5,
+    OUTPUT_RECIPIENTS	= 1 << 6,
+    OUTPUT_ADDRESSES	= OUTPUT_SENDER | OUTPUT_RECIPIENTS,
 } output_t;
 
 /* Return two stable query strings that identify exactly the matched
@@ -214,6 +217,66 @@ do_search_threads (sprinter_t *format,
     return 0;
 }
 
+static void
+print_address_list (sprinter_t *format, InternetAddressList *list)
+{
+    InternetAddress *address;
+    int i;
+
+    for (i = 0; i < internet_address_list_length (list); i++) {
+	address = internet_address_list_get_address (list, i);
+	if (INTERNET_ADDRESS_IS_GROUP (address)) {
+	    InternetAddressGroup *group;
+	    InternetAddressList *group_list;
+
+	    group = INTERNET_ADDRESS_GROUP (address);
+	    group_list = internet_address_group_get_members (group);
+	    if (group_list == NULL)
+		continue;
+
+	    print_address_list (format, group_list);
+	} else {
+	    InternetAddressMailbox *mailbox;
+	    const char *name;
+	    const char *addr;
+	    char *full_address;
+
+	    mailbox = INTERNET_ADDRESS_MAILBOX (address);
+
+	    name = internet_address_get_name (address);
+	    addr = internet_address_mailbox_get_addr (mailbox);
+
+	    if (name && *name)
+		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
+	    else
+		full_address = talloc_asprintf (NULL, "<%s>", addr);
+
+	    if (!full_address)
+		break;
+
+	    format->string (format, full_address);
+	    format->separator (format);
+
+	    talloc_free (full_address);
+	}
+    }
+}
+
+static void
+print_address_string (sprinter_t *format, const char *recipients)
+{
+    InternetAddressList *list;
+
+    if (recipients == NULL)
+	return;
+
+    list = internet_address_list_parse_string (recipients);
+    if (list == NULL)
+	return;
+
+    print_address_list (format, list);
+}
+
 static int
 do_search_messages (sprinter_t *format,
 		    notmuch_query_t *query,
@@ -264,11 +327,29 @@ do_search_messages (sprinter_t *format,
 	    
 	    notmuch_filenames_destroy( filenames );
 
-	} else { /* output == OUTPUT_MESSAGES */
+	} else if (output == OUTPUT_MESSAGES) {
 	    format->set_prefix (format, "id");
 	    format->string (format,
 			    notmuch_message_get_message_id (message));
 	    format->separator (format);
+	} else {
+	    if (output & OUTPUT_SENDER) {
+		const char *addrs;
+
+		addrs = notmuch_message_get_header (message, "from");
+		print_address_string (format, addrs);
+	    }
+
+	    if (output & OUTPUT_RECIPIENTS) {
+		const char *hdrs[] = { "to", "cc", "bcc" };
+		const char *addrs;
+		size_t j;
+
+		for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
+		    addrs = notmuch_message_get_header (message, hdrs[j]);
+		    print_address_string (format, addrs);
+		}
+	    }
 	}
 
 	notmuch_message_destroy (message);
@@ -338,7 +419,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
     notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
     sprinter_t *format = NULL;
     int opt_index, ret;
-    output_t output = OUTPUT_SUMMARY;
+    output_t output = 0;
     int offset = 0;
     int limit = -1; /* unlimited */
     notmuch_exclude_t exclude = NOTMUCH_EXCLUDE_TRUE;
@@ -364,10 +445,12 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
 				  { "text0", NOTMUCH_FORMAT_TEXT0 },
 				  { 0, 0 } } },
 	{ NOTMUCH_OPT_INT, &notmuch_format_version, "format-version", 0, 0 },
-	{ NOTMUCH_OPT_KEYWORD, &output, "output", 'o',
+	{ NOTMUCH_OPT_KEYWORD_FLAGS, &output, "output", 'o',
 	  (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY },
 				  { "threads", OUTPUT_THREADS },
 				  { "messages", OUTPUT_MESSAGES },
+				  { "sender", OUTPUT_SENDER },
+				  { "recipients", OUTPUT_RECIPIENTS },
 				  { "files", OUTPUT_FILES },
 				  { "tags", OUTPUT_TAGS },
 				  { 0, 0 } } },
@@ -387,6 +470,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
     if (opt_index < 0)
 	return EXIT_FAILURE;
 
+    if (! output)
+	output = OUTPUT_SUMMARY;
+
     switch (format_sel) {
     case NOTMUCH_FORMAT_TEXT:
 	format = sprinter_text_create (config, stdout);
@@ -453,18 +539,23 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
     }
 
     switch (output) {
-    default:
     case OUTPUT_SUMMARY:
     case OUTPUT_THREADS:
 	ret = do_search_threads (format, query, sort, output, offset, limit);
 	break;
     case OUTPUT_MESSAGES:
+    case OUTPUT_SENDER:
+    case OUTPUT_RECIPIENTS:
+    case OUTPUT_ADDRESSES:
     case OUTPUT_FILES:
 	ret = do_search_messages (format, query, output, offset, limit, dupe);
 	break;
     case OUTPUT_TAGS:
 	ret = do_search_tags (notmuch, format, query);
 	break;
+    default:
+	fprintf (stderr, "Error: the combination of outputs is not supported.\n");
+	ret = 1;
     }
 
     notmuch_query_destroy (query);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] cli: add --output=address-{from, to, all} to notmuch search
  2014-09-06 16:41 ` [PATCH] cli: add --output=address-{from,to,all} " Jani Nikula
@ 2014-09-06 16:47   ` Jani Nikula
  2014-09-06 17:47   ` Mark Walters
  2014-09-19 19:57   ` [PATCH] cli: add --output=address-{from,to,all} " David Bremner
  2 siblings, 0 replies; 12+ messages in thread
From: Jani Nikula @ 2014-09-06 16:47 UTC (permalink / raw)
  To: notmuch

On Sat, 06 Sep 2014, Jani Nikula <jani@nikula.org> wrote:
> address-from prints reply-to or from, address-to prints to, cc, and
> bcc, and address-all prints all of them.

*sigh* this was supposed to be:

---

cli: add --output=sender and --output=recipients to notmuch search
    
sender prints from, recipients prints to, cc, and bcc.

---

I don't have the time for this, and I'm rushing too much...


BR,
Jani.



> ---
>  notmuch-search.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 100 insertions(+), 9 deletions(-)
>
> diff --git a/notmuch-search.c b/notmuch-search.c
> index bc9be4593ecc..e7cf3d2a0fdf 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -23,11 +23,14 @@
>  #include "string-util.h"
>  
>  typedef enum {
> -    OUTPUT_SUMMARY,
> -    OUTPUT_THREADS,
> -    OUTPUT_MESSAGES,
> -    OUTPUT_FILES,
> -    OUTPUT_TAGS
> +    OUTPUT_SUMMARY	= 1 << 0,
> +    OUTPUT_THREADS	= 1 << 1,
> +    OUTPUT_MESSAGES	= 1 << 2,
> +    OUTPUT_FILES	= 1 << 3,
> +    OUTPUT_TAGS		= 1 << 4,
> +    OUTPUT_SENDER	= 1 << 5,
> +    OUTPUT_RECIPIENTS	= 1 << 6,
> +    OUTPUT_ADDRESSES	= OUTPUT_SENDER | OUTPUT_RECIPIENTS,
>  } output_t;
>  
>  /* Return two stable query strings that identify exactly the matched
> @@ -214,6 +217,66 @@ do_search_threads (sprinter_t *format,
>      return 0;
>  }
>  
> +static void
> +print_address_list (sprinter_t *format, InternetAddressList *list)
> +{
> +    InternetAddress *address;
> +    int i;
> +
> +    for (i = 0; i < internet_address_list_length (list); i++) {
> +	address = internet_address_list_get_address (list, i);
> +	if (INTERNET_ADDRESS_IS_GROUP (address)) {
> +	    InternetAddressGroup *group;
> +	    InternetAddressList *group_list;
> +
> +	    group = INTERNET_ADDRESS_GROUP (address);
> +	    group_list = internet_address_group_get_members (group);
> +	    if (group_list == NULL)
> +		continue;
> +
> +	    print_address_list (format, group_list);
> +	} else {
> +	    InternetAddressMailbox *mailbox;
> +	    const char *name;
> +	    const char *addr;
> +	    char *full_address;
> +
> +	    mailbox = INTERNET_ADDRESS_MAILBOX (address);
> +
> +	    name = internet_address_get_name (address);
> +	    addr = internet_address_mailbox_get_addr (mailbox);
> +
> +	    if (name && *name)
> +		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
> +	    else
> +		full_address = talloc_asprintf (NULL, "<%s>", addr);
> +
> +	    if (!full_address)
> +		break;
> +
> +	    format->string (format, full_address);
> +	    format->separator (format);
> +
> +	    talloc_free (full_address);
> +	}
> +    }
> +}
> +
> +static void
> +print_address_string (sprinter_t *format, const char *recipients)
> +{
> +    InternetAddressList *list;
> +
> +    if (recipients == NULL)
> +	return;
> +
> +    list = internet_address_list_parse_string (recipients);
> +    if (list == NULL)
> +	return;
> +
> +    print_address_list (format, list);
> +}
> +
>  static int
>  do_search_messages (sprinter_t *format,
>  		    notmuch_query_t *query,
> @@ -264,11 +327,29 @@ do_search_messages (sprinter_t *format,
>  	    
>  	    notmuch_filenames_destroy( filenames );
>  
> -	} else { /* output == OUTPUT_MESSAGES */
> +	} else if (output == OUTPUT_MESSAGES) {
>  	    format->set_prefix (format, "id");
>  	    format->string (format,
>  			    notmuch_message_get_message_id (message));
>  	    format->separator (format);
> +	} else {
> +	    if (output & OUTPUT_SENDER) {
> +		const char *addrs;
> +
> +		addrs = notmuch_message_get_header (message, "from");
> +		print_address_string (format, addrs);
> +	    }
> +
> +	    if (output & OUTPUT_RECIPIENTS) {
> +		const char *hdrs[] = { "to", "cc", "bcc" };
> +		const char *addrs;
> +		size_t j;
> +
> +		for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
> +		    addrs = notmuch_message_get_header (message, hdrs[j]);
> +		    print_address_string (format, addrs);
> +		}
> +	    }
>  	}
>  
>  	notmuch_message_destroy (message);
> @@ -338,7 +419,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
>      sprinter_t *format = NULL;
>      int opt_index, ret;
> -    output_t output = OUTPUT_SUMMARY;
> +    output_t output = 0;
>      int offset = 0;
>      int limit = -1; /* unlimited */
>      notmuch_exclude_t exclude = NOTMUCH_EXCLUDE_TRUE;
> @@ -364,10 +445,12 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>  				  { "text0", NOTMUCH_FORMAT_TEXT0 },
>  				  { 0, 0 } } },
>  	{ NOTMUCH_OPT_INT, &notmuch_format_version, "format-version", 0, 0 },
> -	{ NOTMUCH_OPT_KEYWORD, &output, "output", 'o',
> +	{ NOTMUCH_OPT_KEYWORD_FLAGS, &output, "output", 'o',
>  	  (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY },
>  				  { "threads", OUTPUT_THREADS },
>  				  { "messages", OUTPUT_MESSAGES },
> +				  { "sender", OUTPUT_SENDER },
> +				  { "recipients", OUTPUT_RECIPIENTS },
>  				  { "files", OUTPUT_FILES },
>  				  { "tags", OUTPUT_TAGS },
>  				  { 0, 0 } } },
> @@ -387,6 +470,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      if (opt_index < 0)
>  	return EXIT_FAILURE;
>  
> +    if (! output)
> +	output = OUTPUT_SUMMARY;
> +
>      switch (format_sel) {
>      case NOTMUCH_FORMAT_TEXT:
>  	format = sprinter_text_create (config, stdout);
> @@ -453,18 +539,23 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      }
>  
>      switch (output) {
> -    default:
>      case OUTPUT_SUMMARY:
>      case OUTPUT_THREADS:
>  	ret = do_search_threads (format, query, sort, output, offset, limit);
>  	break;
>      case OUTPUT_MESSAGES:
> +    case OUTPUT_SENDER:
> +    case OUTPUT_RECIPIENTS:
> +    case OUTPUT_ADDRESSES:
>      case OUTPUT_FILES:
>  	ret = do_search_messages (format, query, output, offset, limit, dupe);
>  	break;
>      case OUTPUT_TAGS:
>  	ret = do_search_tags (notmuch, format, query);
>  	break;
> +    default:
> +	fprintf (stderr, "Error: the combination of outputs is not supported.\n");
> +	ret = 1;
>      }
>  
>      notmuch_query_destroy (query);
> -- 
> 2.1.0

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] cli: add --output=address-{from, to, all} to notmuch search
  2014-09-06 16:41 ` [PATCH] cli: add --output=address-{from,to,all} " Jani Nikula
  2014-09-06 16:47   ` [PATCH] cli: add --output=address-{from, to, all} " Jani Nikula
@ 2014-09-06 17:47   ` Mark Walters
  2014-09-19 19:57   ` [PATCH] cli: add --output=address-{from,to,all} " David Bremner
  2 siblings, 0 replies; 12+ messages in thread
From: Mark Walters @ 2014-09-06 17:47 UTC (permalink / raw)
  To: Jani Nikula, notmuch


On Sat, 06 Sep 2014, Jani Nikula <jani@nikula.org> wrote:
> address-from prints reply-to or from, address-to prints to, cc, and
> bcc, and address-all prints all of them.

This looks good to me. Obviously needs the new commit
message. 

I think we should think  about the deduplication possibilities but that
can be added later. My timings suggest that there is a 20 times speed up
in using this with --output=sender over calling notmuch show
--body=false --entire-thread=false.

If you want the to,cc then this version is only twice as fast as the
notmuch show version. 

(All the above are with a hot cache: I expect bigger improvements with a
cold cache).

So this could well speed up dme's address completion patch
id:1409921969-65129-1-git-send-email-dme@dme.org by a factor of 20.

(The nevermore variants will not get such a big gain as they look at
to/cc rather than from)

Best wishes

Mark


> ---
>  notmuch-search.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 100 insertions(+), 9 deletions(-)
>
> diff --git a/notmuch-search.c b/notmuch-search.c
> index bc9be4593ecc..e7cf3d2a0fdf 100644
> --- a/notmuch-search.c
> +++ b/notmuch-search.c
> @@ -23,11 +23,14 @@
>  #include "string-util.h"
>  
>  typedef enum {
> -    OUTPUT_SUMMARY,
> -    OUTPUT_THREADS,
> -    OUTPUT_MESSAGES,
> -    OUTPUT_FILES,
> -    OUTPUT_TAGS
> +    OUTPUT_SUMMARY	= 1 << 0,
> +    OUTPUT_THREADS	= 1 << 1,
> +    OUTPUT_MESSAGES	= 1 << 2,
> +    OUTPUT_FILES	= 1 << 3,
> +    OUTPUT_TAGS		= 1 << 4,
> +    OUTPUT_SENDER	= 1 << 5,
> +    OUTPUT_RECIPIENTS	= 1 << 6,
> +    OUTPUT_ADDRESSES	= OUTPUT_SENDER | OUTPUT_RECIPIENTS,
>  } output_t;
>  
>  /* Return two stable query strings that identify exactly the matched
> @@ -214,6 +217,66 @@ do_search_threads (sprinter_t *format,
>      return 0;
>  }
>  
> +static void
> +print_address_list (sprinter_t *format, InternetAddressList *list)
> +{
> +    InternetAddress *address;
> +    int i;
> +
> +    for (i = 0; i < internet_address_list_length (list); i++) {
> +	address = internet_address_list_get_address (list, i);
> +	if (INTERNET_ADDRESS_IS_GROUP (address)) {
> +	    InternetAddressGroup *group;
> +	    InternetAddressList *group_list;
> +
> +	    group = INTERNET_ADDRESS_GROUP (address);
> +	    group_list = internet_address_group_get_members (group);
> +	    if (group_list == NULL)
> +		continue;
> +
> +	    print_address_list (format, group_list);
> +	} else {
> +	    InternetAddressMailbox *mailbox;
> +	    const char *name;
> +	    const char *addr;
> +	    char *full_address;
> +
> +	    mailbox = INTERNET_ADDRESS_MAILBOX (address);
> +
> +	    name = internet_address_get_name (address);
> +	    addr = internet_address_mailbox_get_addr (mailbox);
> +
> +	    if (name && *name)
> +		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
> +	    else
> +		full_address = talloc_asprintf (NULL, "<%s>", addr);
> +
> +	    if (!full_address)
> +		break;
> +
> +	    format->string (format, full_address);
> +	    format->separator (format);
> +
> +	    talloc_free (full_address);
> +	}
> +    }
> +}
> +
> +static void
> +print_address_string (sprinter_t *format, const char *recipients)
> +{
> +    InternetAddressList *list;
> +
> +    if (recipients == NULL)
> +	return;
> +
> +    list = internet_address_list_parse_string (recipients);
> +    if (list == NULL)
> +	return;
> +
> +    print_address_list (format, list);
> +}
> +
>  static int
>  do_search_messages (sprinter_t *format,
>  		    notmuch_query_t *query,
> @@ -264,11 +327,29 @@ do_search_messages (sprinter_t *format,
>  	    
>  	    notmuch_filenames_destroy( filenames );
>  
> -	} else { /* output == OUTPUT_MESSAGES */
> +	} else if (output == OUTPUT_MESSAGES) {
>  	    format->set_prefix (format, "id");
>  	    format->string (format,
>  			    notmuch_message_get_message_id (message));
>  	    format->separator (format);
> +	} else {
> +	    if (output & OUTPUT_SENDER) {
> +		const char *addrs;
> +
> +		addrs = notmuch_message_get_header (message, "from");
> +		print_address_string (format, addrs);
> +	    }
> +
> +	    if (output & OUTPUT_RECIPIENTS) {
> +		const char *hdrs[] = { "to", "cc", "bcc" };
> +		const char *addrs;
> +		size_t j;
> +
> +		for (j = 0; j < ARRAY_SIZE (hdrs); j++) {
> +		    addrs = notmuch_message_get_header (message, hdrs[j]);
> +		    print_address_string (format, addrs);
> +		}
> +	    }
>  	}
>  
>  	notmuch_message_destroy (message);
> @@ -338,7 +419,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
>      sprinter_t *format = NULL;
>      int opt_index, ret;
> -    output_t output = OUTPUT_SUMMARY;
> +    output_t output = 0;
>      int offset = 0;
>      int limit = -1; /* unlimited */
>      notmuch_exclude_t exclude = NOTMUCH_EXCLUDE_TRUE;
> @@ -364,10 +445,12 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>  				  { "text0", NOTMUCH_FORMAT_TEXT0 },
>  				  { 0, 0 } } },
>  	{ NOTMUCH_OPT_INT, &notmuch_format_version, "format-version", 0, 0 },
> -	{ NOTMUCH_OPT_KEYWORD, &output, "output", 'o',
> +	{ NOTMUCH_OPT_KEYWORD_FLAGS, &output, "output", 'o',
>  	  (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY },
>  				  { "threads", OUTPUT_THREADS },
>  				  { "messages", OUTPUT_MESSAGES },
> +				  { "sender", OUTPUT_SENDER },
> +				  { "recipients", OUTPUT_RECIPIENTS },
>  				  { "files", OUTPUT_FILES },
>  				  { "tags", OUTPUT_TAGS },
>  				  { 0, 0 } } },
> @@ -387,6 +470,9 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      if (opt_index < 0)
>  	return EXIT_FAILURE;
>  
> +    if (! output)
> +	output = OUTPUT_SUMMARY;
> +
>      switch (format_sel) {
>      case NOTMUCH_FORMAT_TEXT:
>  	format = sprinter_text_create (config, stdout);
> @@ -453,18 +539,23 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])
>      }
>  
>      switch (output) {
> -    default:
>      case OUTPUT_SUMMARY:
>      case OUTPUT_THREADS:
>  	ret = do_search_threads (format, query, sort, output, offset, limit);
>  	break;
>      case OUTPUT_MESSAGES:
> +    case OUTPUT_SENDER:
> +    case OUTPUT_RECIPIENTS:
> +    case OUTPUT_ADDRESSES:
>      case OUTPUT_FILES:
>  	ret = do_search_messages (format, query, output, offset, limit, dupe);
>  	break;
>      case OUTPUT_TAGS:
>  	ret = do_search_tags (notmuch, format, query);
>  	break;
> +    default:
> +	fprintf (stderr, "Error: the combination of outputs is not supported.\n");
> +	ret = 1;
>      }
>  
>      notmuch_query_destroy (query);
> -- 
> 2.1.0
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] cli: add --output=address-{from,to,all} to notmuch search
  2014-09-06 16:41 ` [PATCH] cli: add --output=address-{from,to,all} " Jani Nikula
  2014-09-06 16:47   ` [PATCH] cli: add --output=address-{from, to, all} " Jani Nikula
  2014-09-06 17:47   ` Mark Walters
@ 2014-09-19 19:57   ` David Bremner
  2014-09-20  8:04     ` [PATCH] cli: add --output=address-{from, to, all} " Michal Sojka
  2 siblings, 1 reply; 12+ messages in thread
From: David Bremner @ 2014-09-19 19:57 UTC (permalink / raw)
  To: Jani Nikula, notmuch

Jani Nikula <jani@nikula.org> writes:

> +	    if (name && *name)
> +		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
> +	    else
> +		full_address = talloc_asprintf (NULL, "<%s>", addr

Is there some reason not to use sprinter as a talloc context here?

> +
> +	    if (!full_address)
> +		break;

Is the error here out of memory? Maybe an error message would be a good
idea.


Obviously the docs need to be updated as well, and ideally the tests.  I
think Jani was hinting that he didn't want to be the person to do
that. Any volunteers?

d

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] cli: add --output=address-{from, to, all} to notmuch search
  2014-09-19 19:57   ` [PATCH] cli: add --output=address-{from,to,all} " David Bremner
@ 2014-09-20  8:04     ` Michal Sojka
  0 siblings, 0 replies; 12+ messages in thread
From: Michal Sojka @ 2014-09-20  8:04 UTC (permalink / raw)
  To: David Bremner, Jani Nikula, notmuch

On Fri, Sep 19 2014, David Bremner wrote:
> Jani Nikula <jani@nikula.org> writes:
>
>> +	    if (name && *name)
>> +		full_address = talloc_asprintf (NULL, "%s <%s>", name, addr);
>> +	    else
>> +		full_address = talloc_asprintf (NULL, "<%s>", addr
>
> Is there some reason not to use sprinter as a talloc context here?
>
>> +
>> +	    if (!full_address)
>> +		break;
>
> Is the error here out of memory? Maybe an error message would be a good
> idea.
>
>
> Obviously the docs need to be updated as well, and ideally the tests.  I
> think Jani was hinting that he didn't want to be the person to do
> that. Any volunteers?

Yes, I'll look at that. It will probably take me a few days.

-Michal

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-09-20  8:04 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-05 12:59 [PATCH v1 0/3] Address completion entirely in elisp David Edmondson
2014-09-05 12:59 ` [PATCH v1 1/3] emacs: Allow query to exclude the entire thread and body David Edmondson
2014-09-05 12:59 ` [PATCH v1 2/3] emacs: Add `notmuch-user-all-email' David Edmondson
2014-09-05 12:59 ` [PATCH v1 3/3] emacs: Add an address completer in elisp David Edmondson
2014-09-05 15:29 ` [PATCH v1 0/3] Address completion entirely " Mark Walters
2014-09-05 16:06   ` David Edmondson
2014-09-06  8:14     ` [PATCH] cli: add --output=address-{from,to,all} to notmuch search Jani Nikula
  -- strict thread matches above, loose matches on Subject: below --
2014-09-06 13:35 [PATCH 2/3] cli: add --output=address-{from, to, all} " Mark Walters
2014-09-06 16:41 ` [PATCH] cli: add --output=address-{from,to,all} " Jani Nikula
2014-09-06 16:47   ` [PATCH] cli: add --output=address-{from, to, all} " Jani Nikula
2014-09-06 17:47   ` Mark Walters
2014-09-19 19:57   ` [PATCH] cli: add --output=address-{from,to,all} " David Bremner
2014-09-20  8:04     ` [PATCH] cli: add --output=address-{from, to, all} " Michal Sojka

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).