This new JSON format for replies includes headers generated for a
reply message as well as the headers 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.
---
 notmuch-client.h |   10 ++++++++--
 notmuch-reply.c  |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 notmuch-show.c   |   30 ++++++++++++++++++++++--------
 test/multipart   |    1 -
 4 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index f4a62cc..ef4eaba 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -62,13 +62,13 @@
 #define STRINGIFY(s) STRINGIFY_(s)
 #define STRINGIFY_(s) #s

-struct mime_node;
+typedef struct mime_node mime_node_t;
 struct notmuch_show_params;

 typedef struct notmuch_show_format {
     const char *message_set_start;
     void (*part) (const void *ctx,
-                 struct mime_node *node, int indent,
+                 mime_node_t *node, int indent,
                  const struct notmuch_show_params *params);
     const char *message_start;
     void (*message) (const void *ctx,
@@ -191,6 +191,12 @@ show_message_body (notmuch_message_t *message,
 notmuch_status_t
 show_one_part (const char *filename, int part);

+void
+format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first);
+
+void
+format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t 
reply);
+
 char *
 json_quote_chararray (const void *ctx, const char *str, const size_t len);

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 177e6ca..017c6ae 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -601,6 +601,51 @@ notmuch_reply_format_default(void *ctx,
     return 0;
 }

+static int
+notmuch_reply_format_json(void *ctx,
+                         notmuch_config_t *config,
+                         notmuch_query_t *query,
+                         notmuch_show_params_t *params,
+                         notmuch_bool_t reply_all)
+{
+    GMimeMessage *reply;
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    mime_node_t *node;
+
+    if (notmuch_query_count_messages (query) != 1) {
+       fprintf (stderr, "Error: search term did not match precisely one 
message.\n");
+       return 1;
+    }
+
+    messages = notmuch_query_search_messages (query);
+    message = notmuch_messages_get (messages);
+    if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,
+                       &node) != NOTMUCH_STATUS_SUCCESS)
+       return 1;
+
+    reply = create_reply_message (ctx, config, message, reply_all);
+    if (!reply)
+       return 1;
+
+    /* The headers of the reply message we've created */
+    printf ("{\"reply-headers\": ");
+    format_headers_json (ctx, reply, TRUE);
+    g_object_unref (G_OBJECT (reply));
+    reply = NULL;
+
+    /* Start the original */
+    printf (", \"original\": ");
+
+    format_part_json (ctx, node, TRUE);
+
+    /* End */
+    printf ("}\n");
+    notmuch_message_destroy (message);
+
+    return 0;
+}
+
 /* This format is currently tuned for a git send-email --notmuch hook */
 static int
 notmuch_reply_format_headers_only(void *ctx,
@@ -663,6 +708,7 @@ notmuch_reply_format_headers_only(void *ctx,

 enum {
     FORMAT_DEFAULT,
+    FORMAT_JSON,
     FORMAT_HEADERS_ONLY,
 };

@@ -682,6 +728,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
     notmuch_opt_desc_t options[] = {
        { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',
          (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },
+                                 { "json", FORMAT_JSON },
                                  { "headers-only", FORMAT_HEADERS_ONLY },
                                  { 0, 0 } } },
        { NOTMUCH_OPT_KEYWORD, &reply_all, "reply-to", 'r',
@@ -700,6 +747,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])

     if (format == FORMAT_HEADERS_ONLY)
        reply_format_func = notmuch_reply_format_headers_only;
+    else if (format == FORMAT_JSON)
+       reply_format_func = notmuch_reply_format_json;
     else
        reply_format_func = notmuch_reply_format_default;

diff --git a/notmuch-show.c b/notmuch-show.c
index 6a171a4..2126d78 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -290,8 +290,8 @@ format_headers_message_part_text (GMimeMessage *message)
     printf ("Date: %s\n", g_mime_message_get_date_as_string (message));
 }

-static void
-format_headers_json (const void *ctx, GMimeMessage *message)
+void
+format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t 
reply)
 {
     void *local = talloc_new (ctx);
     InternetAddressList *recipients;
@@ -315,9 +315,23 @@ format_headers_json (const void *ctx, GMimeMessage 
*message)
        printf (", %s: %s",
                json_quote_str (local, "Cc"),
                json_quote_str (local, recipients_string));
-    printf (", %s: %s}",
-           json_quote_str (local, "Date"),
-           json_quote_str (local, g_mime_message_get_date_as_string 
(message)));
+
+    if (!reply)
+       printf (", %s: %s",
+               json_quote_str (local, "Date"),
+               json_quote_str (local, g_mime_message_get_date_as_string 
(message)));
+
+    if (reply) {
+       printf (", %s: %s",
+               json_quote_str (local, "In-reply-to"),
+               json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT 
(message), "In-reply-to")));
+
+       printf (", %s: %s",
+               json_quote_str (local, "References"),
+               json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT 
(message), "References")));
+    }
+
+    printf ("}");

     talloc_free (local);
 }
@@ -652,7 +666,7 @@ format_part_text (const void *ctx, mime_node_t *node,
     printf ("\f%s}\n", part_type);
 }

-static void
+void
 format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)
 {
     /* Any changes to the JSON format should be reflected in the file
@@ -663,7 +677,7 @@ format_part_json (const void *ctx, mime_node_t *node, 
notmuch_bool_t first)
        format_message_json (ctx, node->envelope_file);

        printf ("\"headers\": ");
-       format_headers_json (ctx, GMIME_MESSAGE (node->part));
+       format_headers_json (ctx, GMIME_MESSAGE (node->part), FALSE);

        printf (", \"body\": [");
        format_part_json (ctx, mime_node_child (node, 0), first);
@@ -737,7 +751,7 @@ format_part_json (const void *ctx, mime_node_t *node, 
notmuch_bool_t first)
     } else if (GMIME_IS_MESSAGE (node->part)) {
        printf (", \"content\": [{");
        printf ("\"headers\": ");
-       format_headers_json (local, GMIME_MESSAGE (node->part));
+       format_headers_json (local, GMIME_MESSAGE (node->part), FALSE);

        printf (", \"body\": [");
        terminator = "]}]";
diff --git a/test/multipart b/test/multipart
index f102294..e7abcc2 100755
--- a/test/multipart
+++ b/test/multipart
@@ -590,7 +590,6 @@ EOF
 test_expect_equal_file OUTPUT EXPECTED

 test_begin_subtest "'notmuch reply' to a multipart message with json format"
-test_subtest_known_broken
 notmuch reply --format=json 'id:87liy5ap00.fsf at yoom.home.cworth.org' | 
notmuch_json_show_sanitize >OUTPUT
 cat <<EOF >EXPECTED
 {"reply-headers": {"Subject": "Re: Multipart message",
-- 
1.7.5.4

Reply via email to