[PATCH v6 05/10] reply: Add a JSON reply format.

Jani Nikula jani at nikula.org
Fri Mar 9 15:08:58 PST 2012


On Tue, 21 Feb 2012 23:46:34 -0700, Adam Wolfe Gordon <awg+notmuch at xvx.ca> wrote:
> 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) {

Isn't that an "else"?

Otherwise looks good.

BR,
Jani.


> +	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
> 
> _______________________________________________
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


More information about the notmuch mailing list