unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH 0/4] Quoting HTML-only emails in replies redux
@ 2012-01-08  7:52 Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 1/4] test: Add broken test for the new JSON reply format Adam Wolfe Gordon
                   ` (5 more replies)
  0 siblings, 6 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-08  7:52 UTC (permalink / raw)
  To: notmuch, awg

From: Adam Wolfe Gordon <awg@xvx.ca>

Hi everyone,

This is a rework of my previous patch series adding support for replying to HTML
email in the emacs interface
(id:1322671241-23438-1-git-send-email-awg+notmuch@xvx.ca).

It was suggested on IRC that a more general solution would be to add a JSON
format to notmuch reply, and then have the emacs client parse the JSON to create
an appropriate reply. This patchset implements that.

The previous patches had an issue with emails that contained both HTML and
plaintext parts, where all the parts would end up quoted. This version avoids
that problem, since the emacs interface can easily check whether there are
plaintext parts and avoid quoting HTML parts if there are.

There should probably be some customize variables for this in emacs, to control
(for example) whether to quote HTML parts and whether to prefer HTML or
plaintext parts for quoting. Any suggestions for what should be customizable
would be appreciated.

I know Jani is currently working on some reply-related patches (the reply-all
vs. reply-one set). These changes probably won't merge cleanly with those
changes, so some care might be required. If his changes are pushed first, I'll
happily rebase and send a new set.

Thanks in advance for any reviews.

Adam Wolfe Gordon (4):
  test: Add broken test for the new JSON reply format.
  reply: Add a JSON reply format.
  man: Update notmuch-reply man page for JSON format.
  emacs: Use the new JSON reply format.

 emacs/notmuch-mua.el     |   62 +++++++++---
 man/man1/notmuch-reply.1 |    5 +
 notmuch-reply.c          |  269 +++++++++++++++++++++++++++++++++++++++-------
 test/emacs               |    1 +
 test/multipart           |    7 ++
 5 files changed, 292 insertions(+), 52 deletions(-)

-- 
1.7.5.4

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

* [PATCH 1/4] test: Add broken test for the new JSON reply format.
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
@ 2012-01-08  7:52 ` Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 2/4] reply: Add a " Adam Wolfe Gordon
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-08  7:52 UTC (permalink / raw)
  To: notmuch, awg

From: Adam Wolfe Gordon <awg@xvx.ca>

---
 test/multipart |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/test/multipart b/test/multipart
index f83526b..f5ebf04 100755
--- a/test/multipart
+++ b/test/multipart
@@ -589,6 +589,13 @@ Non-text part: text/html
 EOF
 test_expect_equal_file OUTPUT EXPECTED
 
+test_begin_subtest "'notmuch reply' to a multipart message with json format"
+notmuch reply --format=json 'id:87liy5ap00.fsf@yoom.home.cworth.org' >OUTPUT
+cat <<EOF >EXPECTED
+[{ "reply": { "headers": { "from": "Notmuch Test Suite <test_suite@notmuchmail.org>", "to": "Carl Worth <cworth@cworth.org>, cworth@cworth.org", "subject": "Re: Multipart message", "in-reply-to": "<87liy5ap00.fsf@yoom.home.cworth.org>", "references": " <87liy5ap00.fsf@yoom.home.cworth.org>"} }, "original": { "headers": { "from": "Carl Worth <cworth@cworth.org>", "to": "cworth@cworth.org", "cc": "", "subject": "Multipart message", "date": "Fri, 05 Jan 2001 15:43:57 +0000", "in-reply-to": "", "references": "" }, "body": [ { "content-type": "text/html", "content": "<p>This is an embedded message, with a multipart/alternative part.</p>\n"}, { "content-type": "text/plain", "content": "This is an embedded message, with a multipart/alternative part.\n"}, { "content-type": "text/plain", "content": "And this message is signed.\n\n-Carl\n"}, {} ] } }, {} ]
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
 test_begin_subtest "'notmuch show --part' does not corrupt a part with CRLF pair"
 notmuch show --format=raw --part=3 id:base64-part-with-crlf > crlf.out
 echo -n -e "\xEF\x0D\x0A" > crlf.expected
-- 
1.7.5.4

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

* [PATCH 2/4] reply: Add a JSON reply format.
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 1/4] test: Add broken test for the new JSON reply format Adam Wolfe Gordon
@ 2012-01-08  7:52 ` Adam Wolfe Gordon
  2012-01-14 20:58   ` Jani Nikula
  2012-01-08  7:52 ` [PATCH 3/4] man: Update notmuch-reply man page for JSON format Adam Wolfe Gordon
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-08  7:52 UTC (permalink / raw)
  To: notmuch, awg

From: Adam Wolfe Gordon <awg@xvx.ca>

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.
---
 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);
+
 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 ("}, ");
+}
+
+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))
+    {
+	GMimeStream *stream_memory = NULL, *stream_filter = NULL;
+	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)));
+
+	charset = g_mime_object_get_content_type_parameter (part, "charset");
+	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_charset_new(charset, "UTF-8"));
+	    }
+	}
+	wrapper = g_mime_part_get_content_object (GMIME_PART (part));
+	if (wrapper && stream_filter)
+	    g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
+	part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));
+
+	printf("%s", json_quote_chararray(ctx, (char *) part_content->data, part_content->len));
+
+	if (stream_filter)
+	    g_object_unref(stream_filter);
+	if (stream_memory)
+	    g_object_unref(stream_memory);
+    }
+
+    talloc_free (ctx);
+}
+
 /* Is the given address configured as one of the user's "personal" or
  * "other" addresses. */
 static int
@@ -476,6 +573,59 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
     return NULL;
 }
 
+static GMimeMessage *
+create_reply_message(void *ctx,
+		     notmuch_config_t *config,
+		     notmuch_message_t *message)
+{
+    const char *subject, *from_addr = NULL;
+    const char *in_reply_to, *orig_references, *references;
+
+    /* The 1 means we want headers in a "pretty" order. */
+    GMimeMessage *reply = g_mime_message_new (1);
+    if (reply == NULL) {
+	fprintf (stderr, "Out of memory\n");
+	return NULL;
+    }
+
+    subject = notmuch_message_get_header (message, "subject");
+    if (subject) {
+	if (strncasecmp (subject, "Re:", 3))
+	    subject = talloc_asprintf (ctx, "Re: %s", subject);
+	g_mime_message_set_subject (reply, subject);
+    }
+
+    from_addr = add_recipients_from_message (reply, config, message);
+
+    if (from_addr == NULL)
+	from_addr = guess_from_received_header (config, message);
+
+    if (from_addr == NULL)
+	from_addr = notmuch_config_get_user_primary_email (config);
+
+    from_addr = talloc_asprintf (ctx, "%s <%s>",
+				 notmuch_config_get_user_name (config),
+				 from_addr);
+    g_mime_object_set_header (GMIME_OBJECT (reply),
+			      "From", from_addr);
+
+    in_reply_to = talloc_asprintf (ctx, "<%s>",
+				   notmuch_message_get_message_id (message));
+
+    g_mime_object_set_header (GMIME_OBJECT (reply),
+			      "In-Reply-To", in_reply_to);
+
+    orig_references = notmuch_message_get_header (message, "references");
+    references = talloc_asprintf (ctx, "%s%s%s",
+				  orig_references ? orig_references : "",
+				  orig_references ? " " : "",
+				  in_reply_to);
+    g_mime_object_set_header (GMIME_OBJECT (reply),
+			      "References", references);
+
+    return reply;
+}
+
 static int
 notmuch_reply_format_default(void *ctx,
 			     notmuch_config_t *config,
@@ -485,8 +635,6 @@ notmuch_reply_format_default(void *ctx,
     GMimeMessage *reply;
     notmuch_messages_t *messages;
     notmuch_message_t *message;
-    const char *subject, *from_addr = NULL;
-    const char *in_reply_to, *orig_references, *references;
     const notmuch_show_format_t *format = &format_reply;
 
     for (messages = notmuch_query_search_messages (query);
@@ -495,61 +643,102 @@ notmuch_reply_format_default(void *ctx,
     {
 	message = notmuch_messages_get (messages);
 
-	/* The 1 means we want headers in a "pretty" order. */
-	reply = g_mime_message_new (1);
-	if (reply == NULL) {
-	    fprintf (stderr, "Out of memory\n");
-	    return 1;
-	}
+	reply = create_reply_message(ctx, config, message);
 
-	subject = notmuch_message_get_header (message, "subject");
-	if (subject) {
-	    if (strncasecmp (subject, "Re:", 3))
-		subject = talloc_asprintf (ctx, "Re: %s", subject);
-	    g_mime_message_set_subject (reply, subject);
-	}
+	show_reply_headers (reply);
 
-	from_addr = add_recipients_from_message (reply, config, message);
+	g_object_unref (G_OBJECT (reply));
+	reply = NULL;
 
-	if (from_addr == NULL)
-	    from_addr = guess_from_received_header (config, message);
+	printf ("On %s, %s wrote:\n",
+		notmuch_message_get_header (message, "date"),
+		notmuch_message_get_header (message, "from"));
 
-	if (from_addr == NULL)
-	    from_addr = notmuch_config_get_user_primary_email (config);
+	show_message_body (message, format, params);
 
-	from_addr = talloc_asprintf (ctx, "%s <%s>",
-				     notmuch_config_get_user_name (config),
-				     from_addr);
-	g_mime_object_set_header (GMIME_OBJECT (reply),
-				  "From", from_addr);
+	notmuch_message_destroy (message);
+    }
+    return 0;
+}
 
-	in_reply_to = talloc_asprintf (ctx, "<%s>",
-			     notmuch_message_get_message_id (message));
+static int
+notmuch_reply_format_json(void *ctx,
+			  notmuch_config_t *config,
+			  notmuch_query_t *query,
+			  unused (notmuch_show_params_t *params))
+{
+    GMimeMessage *reply;
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    const notmuch_show_format_t *format = &format_json;
 
-	g_mime_object_set_header (GMIME_OBJECT (reply),
-				  "In-Reply-To", in_reply_to);
+    const char *reply_headers[] = {"from", "to", "subject", "in-reply-to", "references"};
+    const int n_reply_headers = 5;
+    const char *orig_headers[] = {"from", "to", "cc", "subject", "date", "in-reply-to", "references"};
+    const int n_orig_headers = 7;
+    int hidx;
 
-	orig_references = notmuch_message_get_header (message, "references");
-	references = talloc_asprintf (ctx, "%s%s%s",
-				      orig_references ? orig_references : "",
-				      orig_references ? " " : "",
-				      in_reply_to);
-	g_mime_object_set_header (GMIME_OBJECT (reply),
-				  "References", references);
+    /* Start array of reply objects */
+    printf ("[");
 
-	show_reply_headers (reply);
+    for (messages = notmuch_query_search_messages (query);
+	 notmuch_messages_valid (messages);
+	 notmuch_messages_move_to_next (messages))
+    {
+	/* Start a reply object */
+	printf ("{ \"reply\": { \"headers\": { ");
+
+	message = notmuch_messages_get (messages);
+
+	reply = create_reply_message(ctx, config, message);
+
+	for (hidx = 0; hidx < n_reply_headers; hidx += 1)
+	{
+	    if (hidx > 0) {
+		printf (", ");
+	    }
+
+	    printf ("%s: %s", json_quote_str(ctx, reply_headers[hidx]),
+		    json_quote_str (ctx, g_mime_object_get_header (GMIME_OBJECT (reply), reply_headers[hidx])));
+	}
 
 	g_object_unref (G_OBJECT (reply));
 	reply = NULL;
 
-	printf ("On %s, %s wrote:\n",
-		notmuch_message_get_header (message, "date"),
-		notmuch_message_get_header (message, "from"));
+	/* Done the headers for the reply, which has no body parts */
+	printf ("} }");
+
+	/* Start the original */
+	printf (", \"original\": { \"headers\": { ");
+
+	for (hidx = 0; hidx < n_orig_headers; hidx += 1)
+	{
+	    if (hidx > 0) {
+		printf (", ");
+	    }
+
+	    printf ("%s: %s", json_quote_str(ctx, orig_headers[hidx]),
+		    json_quote_str (ctx, notmuch_message_get_header (message, orig_headers[hidx])));
+	}
+
+	/* End headers */
+	printf (" }, \"body\": [ ");
 
+	/* Show body parts */
 	show_message_body (message, format, params);
 
 	notmuch_message_destroy (message);
+
+	/* Done the original */
+	printf ("{} ] }");
+
+	/* End the reply object. */
+	printf (" }, ");
     }
+
+    /* End array of reply objects */
+    printf ("{} ]\n");
+
     return 0;
 }
 
@@ -640,6 +829,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 		reply_format_func = notmuch_reply_format_default;
 	    } else if (strcmp (opt, "headers-only") == 0) {
 		reply_format_func = notmuch_reply_format_headers_only;
+	    } else if (strcmp (opt, "json") == 0) {
+		reply_format_func = notmuch_reply_format_json;
 	    } else {
 		fprintf (stderr, "Invalid value for --format: %s\n", opt);
 		return 1;
-- 
1.7.5.4

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

* [PATCH 3/4] man: Update notmuch-reply man page for JSON format.
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 1/4] test: Add broken test for the new JSON reply format Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 2/4] reply: Add a " Adam Wolfe Gordon
@ 2012-01-08  7:52 ` Adam Wolfe Gordon
  2012-01-08  7:52 ` [PATCH 4/4] emacs: Use the new JSON reply format Adam Wolfe Gordon
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-08  7:52 UTC (permalink / raw)
  To: notmuch, awg

From: Adam Wolfe Gordon <awg@xvx.ca>

---
 man/man1/notmuch-reply.1 |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index 099d808..240dfed 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -41,6 +41,11 @@ include
 .BR default
 Includes subject and quoted message body.
 .TP
+.BR json
+Produces JSON output containing headers for a reply message and the
+headers and text parts of the original message. This output can be used
+by a client to create a reply message intelligently.
+.TP
 .BR headers\-only
 Only produces In\-Reply\-To, References, To, Cc, and Bcc headers.
 .RE
-- 
1.7.5.4

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

* [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
                   ` (2 preceding siblings ...)
  2012-01-08  7:52 ` [PATCH 3/4] man: Update notmuch-reply man page for JSON format Adam Wolfe Gordon
@ 2012-01-08  7:52 ` Adam Wolfe Gordon
  2012-01-09  1:27   ` Aaron Ecay
  2012-01-09  8:50   ` David Edmondson
  2012-01-09  1:36 ` [PATCH 0/4] Quoting HTML-only emails in replies redux Aaron Ecay
  2012-01-15  9:26 ` David Edmondson
  5 siblings, 2 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-08  7:52 UTC (permalink / raw)
  To: notmuch, awg

From: Adam Wolfe Gordon <awg@xvx.ca>

Using the new JSON reply format allows emacs to quote HTML parts
nicely by first parsing them with w3m, then quoting them. This is
very useful for users who regularly receive HTML-only email.

The behavior for messages that contain plain text parts should be
unchanged, except that an additional quoted line is added to the end
of the reply message.  The test has been updated to reflect this.
---
 emacs/notmuch-mua.el |   62 +++++++++++++++++++++++++++++++++++++++----------
 test/emacs           |    1 +
 2 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index 7114e48..7f894cb 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -19,6 +19,7 @@
 ;;
 ;; Authors: David Edmondson <dme@dme.org>
 
+(require 'json)
 (require 'message)
 
 (require 'notmuch-lib)
@@ -71,27 +72,62 @@ list."
 	    (push header message-hidden-headers)))
 	notmuch-mua-hidden-headers))
 
+(defun w3m-region (start end)) ;; From `w3m.el'.
+(defun notmuch-mua-quote-part (part)
+  (with-temp-buffer
+    (insert part)
+    (message-mode)
+    (fill-region (point-min) (point-max))
+    (goto-char (point-min))
+    (perform-replace "^" "> " nil t nil)
+    (set-buffer-modified-p nil)
+    (buffer-substring (point-min) (point-max))))
+(defun notmuch-mua-parse-html-part (part)
+  (with-temp-buffer
+    (insert part)
+    (w3m-region (point-min) (point-max))
+    (set-buffer-modified-p nil)
+    (buffer-substring (point-min) (point-max))))
 (defun notmuch-mua-reply (query-string &optional sender)
-  (let (headers
+  (let (reply
+	original
+	headers
 	body
-	(args '("reply")))
+	(args '("reply" "--format=json")))
     (if notmuch-show-process-crypto
 	(setq args (append args '("--decrypt"))))
     (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
-    ;; line and then the body.
+    ;; Get the reply object as JSON, and parse it into an elisp object.
     (with-temp-buffer
       (apply 'call-process (append (list notmuch-command nil (list t t) nil) args))
       (goto-char (point-min))
-      (if (re-search-forward "^$" nil t)
-	  (save-excursion
-	    (save-restriction
-	      (narrow-to-region (point-min) (point))
-	      (goto-char (point-min))
-	      (setq headers (mail-header-extract)))))
-      (forward-line 1)
-      (setq body (buffer-substring (point) (point-max))))
+      (setq reply (aref (json-read) 0)))
+
+    ;; Get the list of headers
+    (setq headers (cdr (assq 'headers (assq 'reply reply))))
+    ;; Construct the body of the reply.
+    (setq original (cdr (assq 'original reply)))
+
+    ;; Start with the prelude, based on the headers of the original message.
+    (let ((original-headers (cdr (assq 'headers original))))
+      (setq body (format "On %s, %s wrote:\n"
+			 (cdr (assq 'date original-headers))
+			 (cdr (assq 'from original-headers)))))
+
+    ;; Extract the body parts and construct a reasonable quoted body.
+    (let* ((body-parts (cdr (assq 'body original)))
+	   (find-parts (lambda (type) (delq nil (mapcar (lambda (part)
+							  (if (string= (cdr (assq 'content-type part)) type)
+							      (cdr (assq 'content part))))
+							body-parts))))
+	   (plain-parts (apply find-parts '("text/plain")))
+	   (html-parts (apply find-parts '("text/html"))))
+      
+      (if (not (null plain-parts))
+	  (mapc (lambda (part) (setq body (concat body (notmuch-mua-quote-part part)))) plain-parts)
+	(mapc (lambda (part) (setq body (concat body (notmuch-mua-quote-part (notmuch-mua-parse-html-part part))))) html-parts)))
+    (setq body (concat body "\n"))
+	
     ;; If sender is non-nil, set the From: header to its value.
     (when sender
       (mail-header-set 'from sender headers))
diff --git a/test/emacs b/test/emacs
index a06c223..fe501da 100755
--- a/test/emacs
+++ b/test/emacs
@@ -270,6 +270,7 @@ Fcc: $(pwd)/mail/sent
 --text follows this line--
 On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:
 > This is a test that messages are sent via SMTP
+> 
 EOF
 test_expect_equal_file OUTPUT EXPECTED
 
-- 
1.7.5.4

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-08  7:52 ` [PATCH 4/4] emacs: Use the new JSON reply format Adam Wolfe Gordon
@ 2012-01-09  1:27   ` Aaron Ecay
  2012-01-10  1:59     ` Adam Wolfe Gordon
  2012-01-09  8:50   ` David Edmondson
  1 sibling, 1 reply; 24+ messages in thread
From: Aaron Ecay @ 2012-01-09  1:27 UTC (permalink / raw)
  To: Adam Wolfe Gordon, notmuch

Adam,

One comment below.

On Sun,  8 Jan 2012 00:52:42 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:
> From: Adam Wolfe Gordon <awg@xvx.ca>
> 
> Using the new JSON reply format allows emacs to quote HTML parts
> nicely by first parsing them with w3m, then quoting them. This is
> very useful for users who regularly receive HTML-only email.
> 
> The behavior for messages that contain plain text parts should be
> unchanged, except that an additional quoted line is added to the end
> of the reply message.  The test has been updated to reflect this.
> ---
>  emacs/notmuch-mua.el |   62 +++++++++++++++++++++++++++++++++++++++----------
>  test/emacs           |    1 +
>  2 files changed, 50 insertions(+), 13 deletions(-)
> 
> diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
> index 7114e48..7f894cb 100644
> --- a/emacs/notmuch-mua.el
> +++ b/emacs/notmuch-mua.el
> @@ -19,6 +19,7 @@
>  ;;
>  ;; Authors: David Edmondson <dme@dme.org>
>  
> +(require 'json)
>  (require 'message)
>  
>  (require 'notmuch-lib)
> @@ -71,27 +72,62 @@ list."
>  	    (push header message-hidden-headers)))
>  	notmuch-mua-hidden-headers))
>  
> +(defun w3m-region (start end)) ;; From `w3m.el'.

What is the purpose of the above line?  If it is to make the compiler
aware of the function, you should use ‘declare-function’ instead.  Defun
will erase the original definition of the w3m-region function.

-- 
Aaron Ecay

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
                   ` (3 preceding siblings ...)
  2012-01-08  7:52 ` [PATCH 4/4] emacs: Use the new JSON reply format Adam Wolfe Gordon
@ 2012-01-09  1:36 ` Aaron Ecay
  2012-01-10  1:53   ` Adam Wolfe Gordon
  2012-01-15  9:26 ` David Edmondson
  5 siblings, 1 reply; 24+ messages in thread
From: Aaron Ecay @ 2012-01-09  1:36 UTC (permalink / raw)
  To: Adam Wolfe Gordon, notmuch, awg

On Sun,  8 Jan 2012 00:52:38 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:

[...]

> 
> There should probably be some customize variables for this in emacs, to control
> (for example) whether to quote HTML parts and whether to prefer HTML or
> plaintext parts for quoting. Any suggestions for what should be customizable
> would be appreciated.

I think two variables should suffice: one (boolean) to control whether
to quote standalone text/html parts, and one to control which parts of a
multipart/alternative part to quote.  The latter should take possible
values 'text, 'html, and 'both.  This requires the emacs reply
functionality to distinguish between html parts that are part of a
multipart/alternative and those which are not, which (AFAICT) the
current code doesn’t do.

I haven’t tested the patch yet, but it looks very promising.  Thanks!

-- 
Aaron Ecay

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-08  7:52 ` [PATCH 4/4] emacs: Use the new JSON reply format Adam Wolfe Gordon
  2012-01-09  1:27   ` Aaron Ecay
@ 2012-01-09  8:50   ` David Edmondson
  2012-01-10  2:10     ` Adam Wolfe Gordon
  1 sibling, 1 reply; 24+ messages in thread
From: David Edmondson @ 2012-01-09  8:50 UTC (permalink / raw)
  To: Adam Wolfe Gordon, notmuch, awg

[-- Attachment #1: Type: text/plain, Size: 3952 bytes --]

On Sun,  8 Jan 2012 00:52:42 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:
> +(defun w3m-region (start end)) ;; From `w3m.el'.
> +(defun notmuch-mua-quote-part (part)
> +  (with-temp-buffer
> +    (insert part)
> +    (message-mode)
> +    (fill-region (point-min) (point-max))
> +    (goto-char (point-min))
> +    (perform-replace "^" "> " nil t nil)
> +    (set-buffer-modified-p nil)
> +    (buffer-substring (point-min) (point-max))))

Couldn't all of this be done directly in the reply buffer?

> +(defun notmuch-mua-parse-html-part (part)
> +  (with-temp-buffer
> +    (insert part)
> +    (w3m-region (point-min) (point-max))
> +    (set-buffer-modified-p nil)
> +    (buffer-substring (point-min) (point-max))))

Blank lines between functions are the house style (as much as there is
such a thing).

Using w3m means that you should `require' it. What happens when a user
doesn't have it? (Either the elisp or the command.)

>  (defun notmuch-mua-reply (query-string &optional sender)
> -  (let (headers
> +  (let (reply
> +	original
> +	headers
>  	body
> -	(args '("reply")))
> +	(args '("reply" "--format=json")))

Initialised variables are generally shown before uninitialised. I know
that you didn't do this 'wrong' and that it's an unrelated change, but
it should be fixed. (To the people who say that should be a separate
patch I say 'meh' - life is too short.)

>      (if notmuch-show-process-crypto
>  	(setq args (append args '("--decrypt"))))
>      (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
> -    ;; line and then the body.
> +    ;; Get the reply object as JSON, and parse it into an elisp object.
>      (with-temp-buffer
>        (apply 'call-process (append (list notmuch-command nil (list t t) nil) args))
>        (goto-char (point-min))
> -      (if (re-search-forward "^$" nil t)
> -	  (save-excursion
> -	    (save-restriction
> -	      (narrow-to-region (point-min) (point))
> -	      (goto-char (point-min))
> -	      (setq headers (mail-header-extract)))))
> -      (forward-line 1)
> -      (setq body (buffer-substring (point) (point-max))))
> +      (setq reply (aref (json-read) 0)))
> +
> +    ;; Get the list of headers
> +    (setq headers (cdr (assq 'headers (assq 'reply reply))))
> +    ;; Construct the body of the reply.
> +    (setq original (cdr (assq 'original reply)))

The scope of (at least) `headers' and `original' could be tightened by
moving them down to the following `let' (and converting it to `let*').

> +
> +    ;; Start with the prelude, based on the headers of the original message.
> +    (let ((original-headers (cdr (assq 'headers original))))
> +      (setq body (format "On %s, %s wrote:\n"
> +			 (cdr (assq 'date original-headers))
> +			 (cdr (assq 'from original-headers)))))
> +
> +    ;; Extract the body parts and construct a reasonable quoted body.
> +    (let* ((body-parts (cdr (assq 'body original)))
> +	   (find-parts (lambda (type) (delq nil (mapcar (lambda (part)
> +							  (if (string= (cdr (assq 'content-type part)) type)
> +							      (cdr (assq 'content part))))
> +							body-parts))))

`find-parts' might be useful in other places. Maybe add it to notmuch-lib.el?

> +	   (plain-parts (apply find-parts '("text/plain")))
> +	   (html-parts (apply find-parts '("text/html"))))
> +      
> +      (if (not (null plain-parts))
> +	  (mapc (lambda (part) (setq body (concat body (notmuch-mua-quote-part part)))) plain-parts)
> +	(mapc (lambda (part) (setq body (concat body (notmuch-mua-quote-part (notmuch-mua-parse-html-part part))))) html-parts)))

If you have an 'else' clause, why test '(if (not ..' ?

> +    (setq body (concat body "\n"))
> +	

If it already ends with a carriage return, why do this?

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-09  1:36 ` [PATCH 0/4] Quoting HTML-only emails in replies redux Aaron Ecay
@ 2012-01-10  1:53   ` Adam Wolfe Gordon
  0 siblings, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-10  1:53 UTC (permalink / raw)
  To: Aaron Ecay; +Cc: notmuch

Thanks for the suggestions.  Specific comments inline:

On Sun, Jan 8, 2012 at 18:36, Aaron Ecay <aaronecay@gmail.com> wrote:
>> There should probably be some customize variables for this in emacs, to control
>> (for example) whether to quote HTML parts and whether to prefer HTML or
>> plaintext parts for quoting. Any suggestions for what should be customizable
>> would be appreciated.
>
> I think two variables should suffice: one (boolean) to control whether
> to quote standalone text/html parts, and one to control which parts of a
> multipart/alternative part to quote.  The latter should take possible
> values 'text, 'html, and 'both.  This requires the emacs reply
> functionality to distinguish between html parts that are part of a
> multipart/alternative and those which are not, which (AFAICT) the
> current code doesn’t do.

The first one I think is obvious, and easy to add.  My previous
version actually had such an option, but I didn't bother with it this
time in the interest of getting the patch out.  I'll add this in and
send a new version.

Regarding the second suggestion, you're right that the current code
doesn't differentiate between text parts that are part of a
multipart/alternative and ones that aren't.  However, it does only
include parts with inline disposition, so it shouldn't end up quoting
stuff intended as attachments.  My thinking in the current operation
was to keep most of the complexity (i.e. going through the MIME parts
to pick out the relevant ones) in the C code, so that it doesn't have
to be implemented in each client - and also so I didn't have to
implement it in emacs lisp ;-).  Do you have some ideas for a JSON
format that's more complex than the current one (to include the
information necessary for making decisions about what to quote), but
less complex than something like notmuch show --format=json (which
would require the client to descend the MIME tree completely to create
a reply)?

A third customization option I was thinking about is a way to control
the format of the first line of the body (On $date, $person wrote).  I
think it would be fairly simple to let people specify an arbitrary
format using any of the headers of the original message, so you would
set it to something like "On %date%, %from% wrote", or "Quoth %from%
(%date%)".  This might be particularly useful to users who correspond
normally in a language other than English.  Anyone have thoughts on
whether this is worth implementing?

> I haven’t tested the patch yet, but it looks very promising.  Thanks!

Thanks for the suggestions - let me know if you have a chance to try it out.

-- 
Adam Wolfe Gordon

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-09  1:27   ` Aaron Ecay
@ 2012-01-10  1:59     ` Adam Wolfe Gordon
  0 siblings, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-10  1:59 UTC (permalink / raw)
  To: Aaron Ecay; +Cc: notmuch

On Sun, Jan 8, 2012 at 18:27, Aaron Ecay <aaronecay@gmail.com> wrote:
>> +(defun w3m-region (start end)) ;; From `w3m.el'.
>
> What is the purpose of the above line?  If it is to make the compiler
> aware of the function, you should use ‘declare-function’ instead.  Defun
> will erase the original definition of the w3m-region function.

Indeed, it's to make the compiler aware of the function.  I followed
the example of notmuch-show.el (defvar w3m-current-buffer, line 391),
but it sounds like declare-function is a better way to accomplish
this.  I haven't written a whole lot of emacs lisp, so thanks for the
tip.

Given David's comments about requiring w3m instead it might be moot,
but if not I'll make this change for the next version.

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-09  8:50   ` David Edmondson
@ 2012-01-10  2:10     ` Adam Wolfe Gordon
  2012-01-10  7:25       ` David Edmondson
  2012-01-12  8:33       ` Dmitry Kurochkin
  0 siblings, 2 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-10  2:10 UTC (permalink / raw)
  To: David Edmondson; +Cc: notmuch

Hi David,

Thanks for the review.  Most of the things you've suggested are easy
changes, and I think obvious improvements, so I'll change them for the
next version.  A bit of discussion on the more involved things below:

On Mon, Jan 9, 2012 at 01:50, David Edmondson <dme@dme.org> wrote:
> On Sun,  8 Jan 2012 00:52:42 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:
>> +(defun w3m-region (start end)) ;; From `w3m.el'.
>> +(defun notmuch-mua-quote-part (part)
>> +  (with-temp-buffer
>> +    (insert part)
>> +    (message-mode)
>> +    (fill-region (point-min) (point-max))
>> +    (goto-char (point-min))
>> +    (perform-replace "^" "> " nil t nil)
>> +    (set-buffer-modified-p nil)
>> +    (buffer-substring (point-min) (point-max))))
>
> Couldn't all of this be done directly in the reply buffer?

Indeed, it could, I just hadn't thought of it.  I'll do this for the
next version.

> Using w3m means that you should `require' it. What happens when a user
> doesn't have it? (Either the elisp or the command.)

This was my initial thought, but when I looked at notmuch-show.el,
which uses w3m features, I noticed that it doesn't have a require.  To
be clear, this patch requires w3m.el (not just the w3m binary), which
I don't think anything else in notmuch does.

In the previous version I had a customize variable specifying whether
to quote HTML parts, which meant that if the user could set the
customize variable to false and everything would work without w3m.el.
I'd like not to introduce a new prerequisite, so if there's a way to
make w3m.el optional that would be my preference.  Can you provide
some guidance on this?

-- 
Adam Wolfe Gordon

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-10  2:10     ` Adam Wolfe Gordon
@ 2012-01-10  7:25       ` David Edmondson
  2012-01-12  8:33       ` Dmitry Kurochkin
  1 sibling, 0 replies; 24+ messages in thread
From: David Edmondson @ 2012-01-10  7:25 UTC (permalink / raw)
  To: Adam Wolfe Gordon; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 1502 bytes --]

On Mon, 9 Jan 2012 19:10:48 -0700, Adam Wolfe Gordon <awg@xvx.ca> wrote:
> > Using w3m means that you should `require' it. What happens when a user
> > doesn't have it? (Either the elisp or the command.)
> 
> This was my initial thought, but when I looked at notmuch-show.el,
> which uses w3m features, I noticed that it doesn't have a require.  To
> be clear, this patch requires w3m.el (not just the w3m binary), which
> I don't think anything else in notmuch does.
> 
> In the previous version I had a customize variable specifying whether
> to quote HTML parts, which meant that if the user could set the
> customize variable to false and everything would work without w3m.el.
> I'd like not to introduce a new prerequisite, so if there's a way to
> make w3m.el optional that would be my preference.  Can you provide
> some guidance on this?

My suggestion would be to move the `html to text' functionality to a new
.el, as we might have more than one way to achieve it (emacs 24 has
`shr', for example).

Have `notmuch-mua.el' use a generically named function to perform the
transformation from html to text and that function should determine the
best way to achieve it.

Testing for `w3m.el' is relatively easy (`require' it and check for
error). Testing for `w3m' itself can be done using some code similar to
`notmuch-address-locate-command' (search the list - it's not yet
integrated), which is itself just copied from w3m (and should end up in
`notmuch-lib.el').

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-10  2:10     ` Adam Wolfe Gordon
  2012-01-10  7:25       ` David Edmondson
@ 2012-01-12  8:33       ` Dmitry Kurochkin
  2012-01-12 12:07         ` David Edmondson
  2012-01-15 21:19         ` Adam Wolfe Gordon
  1 sibling, 2 replies; 24+ messages in thread
From: Dmitry Kurochkin @ 2012-01-12  8:33 UTC (permalink / raw)
  To: Adam Wolfe Gordon, David Edmondson; +Cc: notmuch

Hi Adam.

On Mon, 9 Jan 2012 19:10:48 -0700, Adam Wolfe Gordon <awg@xvx.ca> wrote:
> Hi David,
> 
> Thanks for the review.  Most of the things you've suggested are easy
> changes, and I think obvious improvements, so I'll change them for the
> next version.  A bit of discussion on the more involved things below:
> 
> On Mon, Jan 9, 2012 at 01:50, David Edmondson <dme@dme.org> wrote:
> > On Sun,  8 Jan 2012 00:52:42 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:
> >> +(defun w3m-region (start end)) ;; From `w3m.el'.
> >> +(defun notmuch-mua-quote-part (part)
> >> +  (with-temp-buffer
> >> +    (insert part)
> >> +    (message-mode)
> >> +    (fill-region (point-min) (point-max))
> >> +    (goto-char (point-min))
> >> +    (perform-replace "^" "> " nil t nil)
> >> +    (set-buffer-modified-p nil)
> >> +    (buffer-substring (point-min) (point-max))))
> >
> > Couldn't all of this be done directly in the reply buffer?
> 
> Indeed, it could, I just hadn't thought of it.  I'll do this for the
> next version.
> 
> > Using w3m means that you should `require' it. What happens when a user
> > doesn't have it? (Either the elisp or the command.)
> 
> This was my initial thought, but when I looked at notmuch-show.el,
> which uses w3m features, I noticed that it doesn't have a require.  To
> be clear, this patch requires w3m.el (not just the w3m binary), which
> I don't think anything else in notmuch does.
> 
> In the previous version I had a customize variable specifying whether
> to quote HTML parts, which meant that if the user could set the
> customize variable to false and everything would work without w3m.el.
> I'd like not to introduce a new prerequisite, so if there's a way to
> make w3m.el optional that would be my preference.  Can you provide
> some guidance on this?
> 

I did not follow the rest of the discussion, so sorry if I missed
something obvious.  But why can't we render HTML parts in replies the
same way we do in notmuch-show (using `mm-display-part')?  That should
not introduce a w3m.el requirement, would use the same renderer as
configured for show and hence would produce consistent output in show
and reply.

Regards,
  Dmitry

> -- 
> Adam Wolfe Gordon
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-12  8:33       ` Dmitry Kurochkin
@ 2012-01-12 12:07         ` David Edmondson
  2012-01-12 13:36           ` Tomi Ollila
  2012-01-15 21:19         ` Adam Wolfe Gordon
  1 sibling, 1 reply; 24+ messages in thread
From: David Edmondson @ 2012-01-12 12:07 UTC (permalink / raw)
  To: Dmitry Kurochkin, Adam Wolfe Gordon; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 529 bytes --]

On Thu, 12 Jan 2012 12:33:58 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> I did not follow the rest of the discussion, so sorry if I missed
> something obvious.  But why can't we render HTML parts in replies the
> same way we do in notmuch-show (using `mm-display-part')?  That should
> not introduce a w3m.el requirement, would use the same renderer as
> configured for show and hence would produce consistent output in show
> and reply.

Agreed, that would be good. It could be done as a second stage, though.

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-12 12:07         ` David Edmondson
@ 2012-01-12 13:36           ` Tomi Ollila
  2012-01-12 13:43             ` David Edmondson
  0 siblings, 1 reply; 24+ messages in thread
From: Tomi Ollila @ 2012-01-12 13:36 UTC (permalink / raw)
  To: David Edmondson, Dmitry Kurochkin, Adam Wolfe Gordon; +Cc: notmuch

On Thu, 12 Jan 2012 12:07:40 +0000, David Edmondson <dme@dme.org> wrote:
> On Thu, 12 Jan 2012 12:33:58 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > I did not follow the rest of the discussion, so sorry if I missed
> > something obvious.  But why can't we render HTML parts in replies the
> > same way we do in notmuch-show (using `mm-display-part')?  That should
> > not introduce a w3m.el requirement, would use the same renderer as
> > configured for show and hence would produce consistent output in show
> > and reply.
> 
> Agreed, that would be good. It could be done as a second stage, though.

For the record. I built emacs 23.3 from source and after installation
by default there is no w3m module available.

Related thing: by default the value of (emacs variable)
mm-text-html-renderer is resolved as follows (IIRC):

   if w3m module can be loaded value will be 'w3m
   if no w3m is available but w3m binary exists, value will be 'w3m-standalone
   else it gets some other value (if any).

Tomi

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-12 13:36           ` Tomi Ollila
@ 2012-01-12 13:43             ` David Edmondson
  0 siblings, 0 replies; 24+ messages in thread
From: David Edmondson @ 2012-01-12 13:43 UTC (permalink / raw)
  To: Tomi Ollila, Dmitry Kurochkin, Adam Wolfe Gordon; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 1004 bytes --]

On Thu, 12 Jan 2012 15:36:07 +0200, Tomi Ollila <tomi.ollila@iki.fi> wrote:
> On Thu, 12 Jan 2012 12:07:40 +0000, David Edmondson <dme@dme.org> wrote:
> > On Thu, 12 Jan 2012 12:33:58 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmail.com> wrote:
> > > I did not follow the rest of the discussion, so sorry if I missed
> > > something obvious.  But why can't we render HTML parts in replies the
> > > same way we do in notmuch-show (using `mm-display-part')?  That should
> > > not introduce a w3m.el requirement, would use the same renderer as
> > > configured for show and hence would produce consistent output in show
> > > and reply.
> > 
> > Agreed, that would be good. It could be done as a second stage, though.
> 
> For the record. I built emacs 23.3 from source and after installation
> by default there is no w3m module available.

Currently it's broken for everyone. With the proposed changes it will be
fixed for some people. Further improvements will, of course, be
possible.

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 2/4] reply: Add a JSON reply format.
  2012-01-08  7:52 ` [PATCH 2/4] reply: Add a " Adam Wolfe Gordon
@ 2012-01-14 20:58   ` Jani Nikula
  0 siblings, 0 replies; 24+ messages in thread
From: Jani Nikula @ 2012-01-14 20:58 UTC (permalink / raw)
  To: Adam Wolfe Gordon, notmuch, awg

On Sun,  8 Jan 2012 00:52:40 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:
> From: Adam Wolfe Gordon <awg@xvx.ca>
> 
> 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_charset_new(charset, "UTF-8"));
> +	    }
> +	}
> +	wrapper = g_mime_part_get_content_object (GMIME_PART (part));
> +	if (wrapper && stream_filter)
> +	    g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);
> +	part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));

You only need charset, stream_memory and stream_filter if wrapper is
true. You could perhaps include all that stuff within "if (wrapper)".

> +
> +	printf("%s", json_quote_chararray(ctx, (char *) part_content->data, part_content->len));
> +
> +	if (stream_filter)
> +	    g_object_unref(stream_filter);
> +	if (stream_memory)
> +	    g_object_unref(stream_memory);
> +    }
> +
> +    talloc_free (ctx);
> +}
> +
>  /* Is the given address configured as one of the user's "personal" or
>   * "other" addresses. */
>  static int
> @@ -476,6 +573,59 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
>      return NULL;
>  }
>  
> +static GMimeMessage *
> +create_reply_message(void *ctx,
> +		     notmuch_config_t *config,
> +		     notmuch_message_t *message)
> +{
> +    const char *subject, *from_addr = NULL;
> +    const char *in_reply_to, *orig_references, *references;
> +
> +    /* The 1 means we want headers in a "pretty" order. */
> +    GMimeMessage *reply = g_mime_message_new (1);
> +    if (reply == NULL) {
> +	fprintf (stderr, "Out of memory\n");
> +	return NULL;
> +    }
> +
> +    subject = notmuch_message_get_header (message, "subject");
> +    if (subject) {
> +	if (strncasecmp (subject, "Re:", 3))
> +	    subject = talloc_asprintf (ctx, "Re: %s", subject);
> +	g_mime_message_set_subject (reply, subject);
> +    }
> +
> +    from_addr = add_recipients_from_message (reply, config, message);
> +
> +    if (from_addr == NULL)
> +	from_addr = guess_from_received_header (config, message);
> +
> +    if (from_addr == NULL)
> +	from_addr = notmuch_config_get_user_primary_email (config);
> +
> +    from_addr = talloc_asprintf (ctx, "%s <%s>",
> +				 notmuch_config_get_user_name (config),
> +				 from_addr);
> +    g_mime_object_set_header (GMIME_OBJECT (reply),
> +			      "From", from_addr);
> +
> +    in_reply_to = talloc_asprintf (ctx, "<%s>",
> +				   notmuch_message_get_message_id (message));
> +
> +    g_mime_object_set_header (GMIME_OBJECT (reply),
> +			      "In-Reply-To", in_reply_to);
> +
> +    orig_references = notmuch_message_get_header (message, "references");
> +    references = talloc_asprintf (ctx, "%s%s%s",
> +				  orig_references ? orig_references : "",
> +				  orig_references ? " " : "",
> +				  in_reply_to);
> +    g_mime_object_set_header (GMIME_OBJECT (reply),
> +			      "References", references);
> +
> +    return reply;
> +}

If you want to, you could make review easier by first having a patch
that abstracts the above in the original code, with no other
modifications. Then you could introduce new functionality that utilizes
it later. But this is no big deal in such a small abstraction.

> +
>  static int
>  notmuch_reply_format_default(void *ctx,
>  			     notmuch_config_t *config,
> @@ -485,8 +635,6 @@ notmuch_reply_format_default(void *ctx,
>      GMimeMessage *reply;
>      notmuch_messages_t *messages;
>      notmuch_message_t *message;
> -    const char *subject, *from_addr = NULL;
> -    const char *in_reply_to, *orig_references, *references;
>      const notmuch_show_format_t *format = &format_reply;
>  
>      for (messages = notmuch_query_search_messages (query);
> @@ -495,61 +643,102 @@ notmuch_reply_format_default(void *ctx,
>      {
>  	message = notmuch_messages_get (messages);
>  
> -	/* The 1 means we want headers in a "pretty" order. */
> -	reply = g_mime_message_new (1);
> -	if (reply == NULL) {
> -	    fprintf (stderr, "Out of memory\n");
> -	    return 1;
> -	}
> +	reply = create_reply_message(ctx, config, message);

You should check the return value.

>  
> -	subject = notmuch_message_get_header (message, "subject");
> -	if (subject) {
> -	    if (strncasecmp (subject, "Re:", 3))
> -		subject = talloc_asprintf (ctx, "Re: %s", subject);
> -	    g_mime_message_set_subject (reply, subject);
> -	}
> +	show_reply_headers (reply);
>  
> -	from_addr = add_recipients_from_message (reply, config, message);
> +	g_object_unref (G_OBJECT (reply));
> +	reply = NULL;
>  
> -	if (from_addr == NULL)
> -	    from_addr = guess_from_received_header (config, message);
> +	printf ("On %s, %s wrote:\n",
> +		notmuch_message_get_header (message, "date"),
> +		notmuch_message_get_header (message, "from"));
>  
> -	if (from_addr == NULL)
> -	    from_addr = notmuch_config_get_user_primary_email (config);
> +	show_message_body (message, format, params);
>  
> -	from_addr = talloc_asprintf (ctx, "%s <%s>",
> -				     notmuch_config_get_user_name (config),
> -				     from_addr);
> -	g_mime_object_set_header (GMIME_OBJECT (reply),
> -				  "From", from_addr);
> +	notmuch_message_destroy (message);
> +    }
> +    return 0;
> +}
>  
> -	in_reply_to = talloc_asprintf (ctx, "<%s>",
> -			     notmuch_message_get_message_id (message));
> +static int
> +notmuch_reply_format_json(void *ctx,
> +			  notmuch_config_t *config,
> +			  notmuch_query_t *query,
> +			  unused (notmuch_show_params_t *params))
> +{
> +    GMimeMessage *reply;
> +    notmuch_messages_t *messages;
> +    notmuch_message_t *message;
> +    const notmuch_show_format_t *format = &format_json;
>  
> -	g_mime_object_set_header (GMIME_OBJECT (reply),
> -				  "In-Reply-To", in_reply_to);
> +    const char *reply_headers[] = {"from", "to", "subject", "in-reply-to", "references"};
> +    const int n_reply_headers = 5;

Drop this, and use ARRAY_SIZE (reply_headers) instead.

> +    const char *orig_headers[] = {"from", "to", "cc", "subject", "date", "in-reply-to", "references"};
> +    const int n_orig_headers = 7;

Ditto.

> +    int hidx;
>  
> -	orig_references = notmuch_message_get_header (message, "references");
> -	references = talloc_asprintf (ctx, "%s%s%s",
> -				      orig_references ? orig_references : "",
> -				      orig_references ? " " : "",
> -				      in_reply_to);
> -	g_mime_object_set_header (GMIME_OBJECT (reply),
> -				  "References", references);
> +    /* Start array of reply objects */
> +    printf ("[");
>  
> -	show_reply_headers (reply);
> +    for (messages = notmuch_query_search_messages (query);
> +	 notmuch_messages_valid (messages);
> +	 notmuch_messages_move_to_next (messages))
> +    {
> +	/* Start a reply object */
> +	printf ("{ \"reply\": { \"headers\": { ");
> +
> +	message = notmuch_messages_get (messages);
> +
> +	reply = create_reply_message(ctx, config, message);

Check return value.

> +
> +	for (hidx = 0; hidx < n_reply_headers; hidx += 1)

hidx++ is the pattern in such for loops.

> +	{
> +	    if (hidx > 0) {
> +		printf (", ");
> +	    }

You could just compare "if (hidx)", and also drop the curly braces.

> +
> +	    printf ("%s: %s", json_quote_str(ctx, reply_headers[hidx]),
> +		    json_quote_str (ctx, g_mime_object_get_header (GMIME_OBJECT (reply), reply_headers[hidx])));
> +	}
>  
>  	g_object_unref (G_OBJECT (reply));
>  	reply = NULL;
>  
> -	printf ("On %s, %s wrote:\n",
> -		notmuch_message_get_header (message, "date"),
> -		notmuch_message_get_header (message, "from"));
> +	/* Done the headers for the reply, which has no body parts */
> +	printf ("} }");
> +
> +	/* Start the original */
> +	printf (", \"original\": { \"headers\": { ");
> +
> +	for (hidx = 0; hidx < n_orig_headers; hidx += 1)

hidx++

> +	{
> +	    if (hidx > 0) {
> +		printf (", ");
> +	    }

Same as above.

> +
> +	    printf ("%s: %s", json_quote_str(ctx, orig_headers[hidx]),
> +		    json_quote_str (ctx, notmuch_message_get_header (message, orig_headers[hidx])));
> +	}
> +
> +	/* End headers */
> +	printf (" }, \"body\": [ ");
>  
> +	/* Show body parts */
>  	show_message_body (message, format, params);
>  
>  	notmuch_message_destroy (message);
> +
> +	/* Done the original */
> +	printf ("{} ] }");
> +
> +	/* End the reply object. */
> +	printf (" }, ");
>      }
> +
> +    /* End array of reply objects */
> +    printf ("{} ]\n");
> +
>      return 0;
>  }
>  
> @@ -640,6 +829,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
>  		reply_format_func = notmuch_reply_format_default;
>  	    } else if (strcmp (opt, "headers-only") == 0) {
>  		reply_format_func = notmuch_reply_format_headers_only;
> +	    } else if (strcmp (opt, "json") == 0) {
> +		reply_format_func = notmuch_reply_format_json;
>  	    } else {
>  		fprintf (stderr, "Invalid value for --format: %s\n", opt);
>  		return 1;
> -- 
> 1.7.5.4
> 
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
                   ` (4 preceding siblings ...)
  2012-01-09  1:36 ` [PATCH 0/4] Quoting HTML-only emails in replies redux Aaron Ecay
@ 2012-01-15  9:26 ` David Edmondson
  2012-01-16  7:38   ` Aaron Ecay
  5 siblings, 1 reply; 24+ messages in thread
From: David Edmondson @ 2012-01-15  9:26 UTC (permalink / raw)
  To: Adam Wolfe Gordon, notmuch, awg

[-- Attachment #1: Type: text/plain, Size: 359 bytes --]

Given that we're now doing a bunch of work in emacs as part of the reply
setup, why not just grab the content of the original message from the
show buffer and quote that?

The last time that approach was discussed Carl was against it because it
moved the emacs UI away from the behaviour of the CLI, but it seems that
we're already heading in that direction.

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 4/4] emacs: Use the new JSON reply format.
  2012-01-12  8:33       ` Dmitry Kurochkin
  2012-01-12 12:07         ` David Edmondson
@ 2012-01-15 21:19         ` Adam Wolfe Gordon
  1 sibling, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-15 21:19 UTC (permalink / raw)
  To: Dmitry Kurochkin; +Cc: notmuch

Hi Dmitry,

On Thu, Jan 12, 2012 at 01:33, Dmitry Kurochkin
<dmitry.kurochkin@gmail.com> wrote:
> I did not follow the rest of the discussion, so sorry if I missed
> something obvious.  But why can't we render HTML parts in replies the
> same way we do in notmuch-show (using `mm-display-part')?  That should
> not introduce a w3m.el requirement, would use the same renderer as
> configured for show and hence would produce consistent output in show
> and reply.

Thanks for the suggestion - I've implemented this now and I think it's
definitely the best way to go.  New patches coming soon with all the
suggested changes.

-- 
Adam Wolfe Gordon

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-15  9:26 ` David Edmondson
@ 2012-01-16  7:38   ` Aaron Ecay
  2012-01-16  8:39     ` David Edmondson
  0 siblings, 1 reply; 24+ messages in thread
From: Aaron Ecay @ 2012-01-16  7:38 UTC (permalink / raw)
  To: David Edmondson, Adam Wolfe Gordon, notmuch, awg

On Sun, 15 Jan 2012 09:26:59 +0000, David Edmondson <dme@dme.org> wrote:
> Given that we're now doing a bunch of work in emacs as part of the reply
> setup, why not just grab the content of the original message from the
> show buffer and quote that?
> 
> The last time that approach was discussed Carl was against it because it
> moved the emacs UI away from the behaviour of the CLI, but it seems that
> we're already heading in that direction.

I have been watching this patch series with interest, because it seemed
that when it landed it would be a good time for me to begin work on a
patch to allow notmuch to function like other emacs MUAs in constructing
the reply buffer internally to emacs, rather than through notmuch.  This
allows (at least) three things:
- Greater flexibility in the construction of address lists.  For example,
  there are some email lists where I want replies to list mail to go only
  to the list, not also to the original sender.  Additionally, I like to
  reply from my university address if colleagues write to my Gmail one.
  If a lisp function is generating the replies, it can be made to run a
  hook allowing users to insert these or other custom behaviors.
- The same reasoning as above, applied to signatures.  (different ones
  for different recipients)
- There exists at least one emacs package (supercite) which allows
  customization of the quoting of email replies.  This automates the
  “Firstname>” style quotes one sometimes sees, as well as many other
  possiblities.  It defines a way for emacs MUAs to construct reply
  buffers to cooperate with it, which many of the big emacs MUAs obey
  (Gnus and Wanderlust certainly do).  This is explained in the “hints
  to MUA authors” section of the supercite manual (distributed with
  Emacs).

So, a +1 from me on this idea, from a different perspective.

-- 
Aaron Ecay

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-16  7:38   ` Aaron Ecay
@ 2012-01-16  8:39     ` David Edmondson
  2012-01-16 19:29       ` Jameson Graef Rollins
  2012-01-16 22:31       ` Aaron Ecay
  0 siblings, 2 replies; 24+ messages in thread
From: David Edmondson @ 2012-01-16  8:39 UTC (permalink / raw)
  To: Aaron Ecay, Adam Wolfe Gordon, notmuch, awg

[-- Attachment #1: Type: text/plain, Size: 2329 bytes --]

On Mon, 16 Jan 2012 02:38:38 -0500, Aaron Ecay <aaronecay@gmail.com> wrote:
> On Sun, 15 Jan 2012 09:26:59 +0000, David Edmondson <dme@dme.org> wrote:
> > Given that we're now doing a bunch of work in emacs as part of the reply
> > setup, why not just grab the content of the original message from the
> > show buffer and quote that?
> > 
> > The last time that approach was discussed Carl was against it because it
> > moved the emacs UI away from the behaviour of the CLI, but it seems that
> > we're already heading in that direction.
> 
> I have been watching this patch series with interest, because it seemed
> that when it landed it would be a good time for me to begin work on a
> patch to allow notmuch to function like other emacs MUAs in constructing
> the reply buffer internally to emacs, rather than through notmuch.  This
> allows (at least) three things:
> - Greater flexibility in the construction of address lists.  For example,
>   there are some email lists where I want replies to list mail to go only
>   to the list, not also to the original sender.

Is there a mechanistic way to determine the correct behaviour in this
respect? I suspect that it's exactly the kind of thing that Carl wanted
to be included in 'notmuch' itself, so that other UIs can benefit.

>   Additionally, I like to
>   reply from my university address if colleagues write to my Gmail one.
>   If a lisp function is generating the replies, it can be made to run a
>   hook allowing users to insert these or other custom behaviors.
> - The same reasoning as above, applied to signatures.  (different ones
>   for different recipients)

You can do both of these things today using `message-send-hook' (I do).

> - There exists at least one emacs package (supercite) which allows
>   customization of the quoting of email replies.  This automates the
>   “Firstname>” style quotes one sometimes sees, as well as many other
>   possiblities.  It defines a way for emacs MUAs to construct reply
>   buffers to cooperate with it, which many of the big emacs MUAs obey
>   (Gnus and Wanderlust certainly do).  This is explained in the “hints
>   to MUA authors” section of the supercite manual (distributed with
>   Emacs).

I dislike supercite, so no support from me in that direction :-)

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-16  8:39     ` David Edmondson
@ 2012-01-16 19:29       ` Jameson Graef Rollins
  2012-01-16 22:31       ` Aaron Ecay
  1 sibling, 0 replies; 24+ messages in thread
From: Jameson Graef Rollins @ 2012-01-16 19:29 UTC (permalink / raw)
  To: David Edmondson, Aaron Ecay, Adam Wolfe Gordon, notmuch, awg

[-- Attachment #1: Type: text/plain, Size: 619 bytes --]

On Mon, 16 Jan 2012 08:39:30 +0000, David Edmondson <dme@dme.org> wrote:
> Is there a mechanistic way to determine the correct behaviour in this
> respect? I suspect that it's exactly the kind of thing that Carl wanted
> to be included in 'notmuch' itself, so that other UIs can benefit.

Agreed.  I think it's generally better to get the functionality we want
in the CLI if we can, so that all UIs benefit.  Emacs is still certainly
the most actively developed UI, and it's gotten quite complicated with
quite a few special features, but to the extent that we can put
new functionality into the CLI we should.

jamie.

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-16  8:39     ` David Edmondson
  2012-01-16 19:29       ` Jameson Graef Rollins
@ 2012-01-16 22:31       ` Aaron Ecay
  2012-01-16 22:42         ` Adam Wolfe Gordon
  1 sibling, 1 reply; 24+ messages in thread
From: Aaron Ecay @ 2012-01-16 22:31 UTC (permalink / raw)
  To: David Edmondson, Adam Wolfe Gordon, notmuch, awg

On Mon, 16 Jan 2012 08:39:30 +0000, David Edmondson <dme@dme.org> wrote:
> On Mon, 16 Jan 2012 02:38:38 -0500, Aaron Ecay <aaronecay@gmail.com> wrote:
> > - Greater flexibility in the construction of address lists.  For example,
> >   there are some email lists where I want replies to list mail to go only
> >   to the list, not also to the original sender.
> 
> Is there a mechanistic way to determine the correct behaviour in this
> respect? I suspect that it's exactly the kind of thing that Carl wanted
> to be included in 'notmuch' itself, so that other UIs can benefit.

I think it requires some amount of configuration, but it can be done
sensibly.  I am much more proficient with Elisp than with C, and
Emacs has prejudiced me towards solutions that allow me to have a
Turing-complete configuration language.  :)

I think a good starting point for thinking about mailing lists is what
Mutt does:
http://www.mutt.org/doc/manual/manual-4.html#using_lists

Notmuch at the CLI/C code level could aim for a comparable level of
expressiveness, and I think it would suffice for most people (including
me).

[...]
> 
> You can do both of these things today using `message-send-hook' (I
> do).

I avoided that, as it seemed to me that just before the message is sent
is too late to be doing these things (I’d like to see confirmation when
writing the message that the address/signature changes were applied
correctly).  But “M-x apropos RET message hook RET” shows that there are
some earlier points to hook into as well.  Thanks.

> I dislike supercite, so no support from me in that direction :-)

One advantage of supercite is that it allows non-English speakers to set
up the “On X, X wrote” line as they prefer.  Notmuch’s current approach
(a hard-coded C string) is the opposite of internationalized.  So it
would be nice to support some customization of that as well, even if we
don’t go the supercite route.

-- 
Aaron Ecay

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

* Re: [PATCH 0/4] Quoting HTML-only emails in replies redux
  2012-01-16 22:31       ` Aaron Ecay
@ 2012-01-16 22:42         ` Adam Wolfe Gordon
  0 siblings, 0 replies; 24+ messages in thread
From: Adam Wolfe Gordon @ 2012-01-16 22:42 UTC (permalink / raw)
  To: Aaron Ecay; +Cc: notmuch

On Mon, Jan 16, 2012 at 15:31, Aaron Ecay <aaronecay@gmail.com> wrote:
> One advantage of supercite is that it allows non-English speakers to set
> up the “On X, X wrote” line as they prefer.  Notmuch’s current approach
> (a hard-coded C string) is the opposite of internationalized.  So it
> would be nice to support some customization of that as well, even if we
> don’t go the supercite route.

Note that with my patch, the "On X, X wrote" string is no longer
hardcoded in the CLI (at least when using the JSON reply format).  I
intend to make it configurable in emacs, though right now it is
hardcoded in notmuch-mua.el.

-- 
Adam Wolfe Gordon

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

end of thread, other threads:[~2012-01-16 22:42 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-08  7:52 [PATCH 0/4] Quoting HTML-only emails in replies redux Adam Wolfe Gordon
2012-01-08  7:52 ` [PATCH 1/4] test: Add broken test for the new JSON reply format Adam Wolfe Gordon
2012-01-08  7:52 ` [PATCH 2/4] reply: Add a " Adam Wolfe Gordon
2012-01-14 20:58   ` Jani Nikula
2012-01-08  7:52 ` [PATCH 3/4] man: Update notmuch-reply man page for JSON format Adam Wolfe Gordon
2012-01-08  7:52 ` [PATCH 4/4] emacs: Use the new JSON reply format Adam Wolfe Gordon
2012-01-09  1:27   ` Aaron Ecay
2012-01-10  1:59     ` Adam Wolfe Gordon
2012-01-09  8:50   ` David Edmondson
2012-01-10  2:10     ` Adam Wolfe Gordon
2012-01-10  7:25       ` David Edmondson
2012-01-12  8:33       ` Dmitry Kurochkin
2012-01-12 12:07         ` David Edmondson
2012-01-12 13:36           ` Tomi Ollila
2012-01-12 13:43             ` David Edmondson
2012-01-15 21:19         ` Adam Wolfe Gordon
2012-01-09  1:36 ` [PATCH 0/4] Quoting HTML-only emails in replies redux Aaron Ecay
2012-01-10  1:53   ` Adam Wolfe Gordon
2012-01-15  9:26 ` David Edmondson
2012-01-16  7:38   ` Aaron Ecay
2012-01-16  8:39     ` David Edmondson
2012-01-16 19:29       ` Jameson Graef Rollins
2012-01-16 22:31       ` Aaron Ecay
2012-01-16 22:42         ` Adam Wolfe Gordon

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).