[PATCH 1/9] lib: read "property" terms from messages.
[notmuch-archives.git] / 6b / 3faf3d17ecaae8594cd335afe4d4d899729f38
1 Return-Path: <jani@nikula.org>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id B19CA431FAF\r
6         for <notmuch@notmuchmail.org>; Wed, 18 Jan 2012 15:07:09 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id LNvcW-t9nPoF for <notmuch@notmuchmail.org>;\r
16         Wed, 18 Jan 2012 15:07:08 -0800 (PST)\r
17 Received: from mail-ey0-f181.google.com (mail-ey0-f181.google.com\r
18         [209.85.215.181]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id B5EC5431FAE\r
21         for <notmuch@notmuchmail.org>; Wed, 18 Jan 2012 15:07:07 -0800 (PST)\r
22 Received: by eaal1 with SMTP id l1so499610eaa.26\r
23         for <notmuch@notmuchmail.org>; Wed, 18 Jan 2012 15:07:06 -0800 (PST)\r
24 Received: by 10.213.16.132 with SMTP id o4mr1519710eba.88.1326928026594;\r
25         Wed, 18 Jan 2012 15:07:06 -0800 (PST)\r
26 Received: from localhost (dsl-hkibrasgw4-fe50f800-253.dhcp.inet.fi.\r
27         [84.248.80.253])\r
28         by mx.google.com with ESMTPS id x4sm10718473eeb.4.2012.01.18.15.07.04\r
29         (version=SSLv3 cipher=OTHER); Wed, 18 Jan 2012 15:07:05 -0800 (PST)\r
30 From: Jani Nikula <jani@nikula.org>\r
31 To: Adam Wolfe Gordon <awg+notmuch@xvx.ca>, notmuch@notmuchmail.org\r
32 Subject: Re: [PATCH v2 2/4] reply: Add a JSON reply format.\r
33 In-Reply-To: <1326737603-21166-3-git-send-email-awg+notmuch@xvx.ca>\r
34 References: <1326737603-21166-1-git-send-email-awg+notmuch@xvx.ca>\r
35         <1326737603-21166-3-git-send-email-awg+notmuch@xvx.ca>\r
36 User-Agent: Notmuch/0.11+76~g1de742d (http://notmuchmail.org) Emacs/23.3.1\r
37         (i686-pc-linux-gnu)\r
38 Date: Thu, 19 Jan 2012 01:07:02 +0200\r
39 Message-ID: <87sjjcbofd.fsf@nikula.org>\r
40 MIME-Version: 1.0\r
41 Content-Type: text/plain; charset=us-ascii\r
42 X-BeenThere: notmuch@notmuchmail.org\r
43 X-Mailman-Version: 2.1.13\r
44 Precedence: list\r
45 List-Id: "Use and development of the notmuch mail system."\r
46         <notmuch.notmuchmail.org>\r
47 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
48         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
49 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
50 List-Post: <mailto:notmuch@notmuchmail.org>\r
51 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
52 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
53         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
54 X-List-Received-Date: Wed, 18 Jan 2012 23:07:09 -0000\r
55 \r
56 On Mon, 16 Jan 2012 11:13:21 -0700, Adam Wolfe Gordon <awg+notmuch@xvx.ca> wrote:\r
57 > This new JSON format for replies includes headers generated for a reply\r
58 > message as well as the headers and all text parts of the original message.\r
59 > Using this data, a client can intelligently create a reply. For example,\r
60 > the emacs client will be able to create replies with quoted HTML parts by\r
61 > parsing the HTML parts using w3m.\r
62 \r
63 Hi, admittedly not a very thorough review, but please find a couple of\r
64 comments below.\r
65 \r
66 BR,\r
67 Jani.\r
68 \r
69 \r
70 > ---\r
71 >  notmuch-reply.c |  313 ++++++++++++++++++++++++++++++++++++++++++++-----------\r
72 >  1 files changed, 253 insertions(+), 60 deletions(-)\r
73\r
74 > diff --git a/notmuch-reply.c b/notmuch-reply.c\r
75 > index da3acce..f5a5dcf 100644\r
76 > --- a/notmuch-reply.c\r
77 > +++ b/notmuch-reply.c\r
78 > @@ -30,6 +30,15 @@ reply_headers_message_part (GMimeMessage *message);\r
79 >  static void\r
80 >  reply_part_content (GMimeObject *part);\r
81 >  \r
82 > +static void\r
83 > +reply_part_start_json (GMimeObject *part, int *part_count);\r
84 > +\r
85 > +static void\r
86 > +reply_part_content_json (GMimeObject *part);\r
87 > +\r
88 > +static void\r
89 > +reply_part_end_json (GMimeObject *part);\r
90 > +\r
91 >  static const notmuch_show_format_t format_reply = {\r
92 >      "",\r
93 >       "", NULL,\r
94 > @@ -46,6 +55,22 @@ static const notmuch_show_format_t format_reply = {\r
95 >      ""\r
96 >  };\r
97 >  \r
98 > +static const notmuch_show_format_t format_json = {\r
99 > +    "",\r
100 > +     "", NULL,\r
101 > +         "", NULL, NULL, "",\r
102 > +         "",\r
103 > +             reply_part_start_json,\r
104 > +             NULL,\r
105 > +             NULL,\r
106 > +             reply_part_content_json,\r
107 > +             reply_part_end_json,\r
108 > +             "",\r
109 > +         "",\r
110 > +     "", "",\r
111 > +    ""\r
112 > +};\r
113 > +\r
114 >  static void\r
115 >  show_reply_headers (GMimeMessage *message)\r
116 >  {\r
117 > @@ -54,14 +79,14 @@ show_reply_headers (GMimeMessage *message)\r
118 >      stream_stdout = g_mime_stream_file_new (stdout);\r
119 >      if (stream_stdout) {\r
120 >       g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);\r
121 > -     stream_filter = g_mime_stream_filter_new(stream_stdout);\r
122 > +     stream_filter = g_mime_stream_filter_new (stream_stdout);\r
123 >       if (stream_filter) {\r
124 > -             g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),\r
125 > -                                      g_mime_filter_headers_new());\r
126 > -             g_mime_object_write_to_stream(GMIME_OBJECT(message), stream_filter);\r
127 > -             g_object_unref(stream_filter);\r
128 > +             g_mime_stream_filter_add (GMIME_STREAM_FILTER(stream_filter),\r
129 > +                                       g_mime_filter_headers_new());\r
130 > +             g_mime_object_write_to_stream (GMIME_OBJECT(message), stream_filter);\r
131 > +             g_object_unref (stream_filter);\r
132 >       }\r
133 > -     g_object_unref(stream_stdout);\r
134 > +     g_object_unref (stream_stdout);\r
135 \r
136 I know I asked you to adhere to notmuch coding style like above, but I\r
137 meant in the context of your patch, not elsewhere. Cleanups like this\r
138 should really be separate patches. Sorry if I was ambiguous.\r
139 \r
140 >      }\r
141 >  }\r
142 >  \r
143 > @@ -86,6 +111,17 @@ reply_headers_message_part (GMimeMessage *message)\r
144 >      printf ("> Date: %s\n", g_mime_message_get_date_as_string (message));\r
145 >  }\r
146 >  \r
147 > +static notmuch_bool_t\r
148 > +reply_check_part_type (GMimeObject *part, const char *type, const char *subtype,\r
149 > +                    const char *disposition)\r
150 > +{\r
151 > +    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));\r
152 > +    GMimeContentDisposition *part_disposition = g_mime_object_get_content_disposition (part);\r
153 > +\r
154 > +    return (g_mime_content_type_is_type (content_type, type, subtype) &&\r
155 > +         (!part_disposition ||\r
156 > +          strcmp (part_disposition->disposition, disposition) == 0));\r
157 > +}\r
158 >  \r
159 >  static void\r
160 >  reply_part_content (GMimeObject *part)\r
161 > @@ -108,32 +144,29 @@ reply_part_content (GMimeObject *part)\r
162 >      {\r
163 >       GMimeStream *stream_stdout = NULL, *stream_filter = NULL;\r
164 >       GMimeDataWrapper *wrapper;\r
165 > -     const char *charset;\r
166 > -\r
167 > -     charset = g_mime_object_get_content_type_parameter (part, "charset");\r
168 >       stream_stdout = g_mime_stream_file_new (stdout);\r
169 >       if (stream_stdout) {\r
170 >           g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);\r
171 > -         stream_filter = g_mime_stream_filter_new(stream_stdout);\r
172 > -         if (charset) {\r
173 > -             g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),\r
174 > -                                      g_mime_filter_charset_new(charset, "UTF-8"));\r
175 > -         }\r
176 > +         stream_filter = g_mime_stream_filter_new (stream_stdout);\r
177 > +\r
178 > +         const char *charset = g_mime_object_get_content_type_parameter (part, "charset");\r
179 > +         if (charset)\r
180 > +             g_mime_stream_filter_add(GMIME_STREAM_FILTER (stream_filter),\r
181 > +                                      g_mime_filter_charset_new (charset, "UTF-8"));\r
182 >       }\r
183 > -     g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),\r
184 > -                              g_mime_filter_reply_new(TRUE));\r
185 > +     g_mime_stream_filter_add (GMIME_STREAM_FILTER (stream_filter),\r
186 > +                               g_mime_filter_reply_new (TRUE));\r
187 >       wrapper = g_mime_part_get_content_object (GMIME_PART (part));\r
188 >       if (wrapper && stream_filter)\r
189 >           g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);\r
190 >       if (stream_filter)\r
191 > -         g_object_unref(stream_filter);\r
192 > +         g_object_unref (stream_filter);\r
193 >       if (stream_stdout)\r
194 > -         g_object_unref(stream_stdout);\r
195 > +         g_object_unref (stream_stdout);\r
196 >      }\r
197 >      else\r
198 >      {\r
199 > -     if (disposition &&\r
200 > -         strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)\r
201 > +     if (disposition && strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)\r
202 \r
203 This is also a change not related to your patch.\r
204 \r
205 >       {\r
206 >           const char *filename = g_mime_part_get_filename (GMIME_PART (part));\r
207 >           printf ("Attachment: %s (%s)\n", filename,\r
208 > @@ -147,6 +180,67 @@ reply_part_content (GMimeObject *part)\r
209 >      }\r
210 >  }\r
211 >  \r
212 > +static void\r
213 > +reply_part_start_json (GMimeObject *part, unused (int *part_count))\r
214 > +{\r
215 > +    if (reply_check_part_type (part, "text", "*", GMIME_DISPOSITION_INLINE))\r
216 > +     printf ("{ ");\r
217 > +}\r
218 > +\r
219 > +static void\r
220 > +reply_part_end_json (GMimeObject *part)\r
221 > +{\r
222 > +    if (reply_check_part_type (part, "text", "*", GMIME_DISPOSITION_INLINE))\r
223 > +     printf ("}, ");\r
224 > +}\r
225 > +\r
226 > +static void\r
227 > +reply_part_content_json (GMimeObject *part)\r
228 > +{\r
229 > +    GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));\r
230 > +    void *ctx = talloc_new (NULL);\r
231 > +\r
232 > +    /* We only care about inline text parts for reply purposes */\r
233 > +    if (reply_check_part_type (part, "text", "*", GMIME_DISPOSITION_INLINE))\r
234 > +    {\r
235 \r
236 The style in notmuch is to put the opening brace in the end of the if\r
237 line. Same applies below.\r
238 \r
239 > +     GMimeDataWrapper *wrapper;\r
240 > +     GByteArray *part_content;\r
241 > +\r
242 > +     printf ("\"content-type\": %s, \"content\": ",\r
243 > +            json_quote_str (ctx, g_mime_content_type_to_string (content_type)));\r
244 > +\r
245 > +     wrapper = g_mime_part_get_content_object (GMIME_PART (part));\r
246 > +     if (wrapper)\r
247 > +     {\r
248 > +         const char *charset = g_mime_object_get_content_type_parameter (part, "charset");\r
249 > +         GMimeStream *stream_memory = g_mime_stream_mem_new ();\r
250 > +         if (stream_memory) {\r
251 > +             GMimeStream *stream_filter = NULL;\r
252 > +             stream_filter = g_mime_stream_filter_new (stream_memory);\r
253 > +             if (charset) {\r
254 > +                 g_mime_stream_filter_add (GMIME_STREAM_FILTER (stream_filter),\r
255 > +                                           g_mime_filter_charset_new (charset, "UTF-8"));\r
256 > +             }\r
257 > +\r
258 > +             if (stream_filter)\r
259 > +             {\r
260 > +                 g_mime_data_wrapper_write_to_stream (wrapper, stream_filter);\r
261 > +                 part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory));\r
262 > +\r
263 > +                 printf ("%s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len));\r
264 > +             }\r
265 > +             if (stream_filter)\r
266 > +                 g_object_unref (stream_filter);\r
267 > +         }\r
268 > +\r
269 > +         if (stream_memory)\r
270 > +             g_object_unref (stream_memory);\r
271 > +     }\r
272 > +    }\r
273 > +\r
274 > +    talloc_free (ctx);\r
275 > +}\r
276 > +\r
277 >  /* Is the given address configured as one of the user's "personal" or\r
278 >   * "other" addresses. */\r
279 >  static int\r
280 > @@ -505,6 +599,61 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message\r
281 >      return NULL;\r
282 >  }\r
283 >  \r
284 > +static GMimeMessage *\r
285 > +create_reply_message(void *ctx,\r
286 > +                  notmuch_config_t *config,\r
287 > +                  notmuch_message_t *message,\r
288 > +                  notmuch_bool_t reply_all)\r
289 > +{\r
290 > +    const char *subject, *from_addr = NULL;\r
291 > +    const char *in_reply_to, *orig_references, *references;\r
292 > +\r
293 > +    /* The 1 means we want headers in a "pretty" order. */\r
294 > +    GMimeMessage *reply = g_mime_message_new (1);\r
295 > +    if (reply == NULL) {\r
296 > +     fprintf (stderr, "Out of memory\n");\r
297 > +     return NULL;\r
298 > +    }\r
299 > +\r
300 > +    subject = notmuch_message_get_header (message, "subject");\r
301 > +    if (subject) {\r
302 > +     if (strncasecmp (subject, "Re:", 3))\r
303 > +         subject = talloc_asprintf (ctx, "Re: %s", subject);\r
304 > +     g_mime_message_set_subject (reply, subject);\r
305 > +    }\r
306 > +\r
307 > +    from_addr = add_recipients_from_message (reply, config,\r
308 > +                                          message, reply_all);\r
309 > +\r
310 > +    if (from_addr == NULL)\r
311 > +     from_addr = guess_from_received_header (config, message);\r
312 > +\r
313 > +    if (from_addr == NULL)\r
314 > +     from_addr = notmuch_config_get_user_primary_email (config);\r
315 > +\r
316 > +    from_addr = talloc_asprintf (ctx, "%s <%s>",\r
317 > +                              notmuch_config_get_user_name (config),\r
318 > +                              from_addr);\r
319 > +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
320 > +                           "From", from_addr);\r
321 > +\r
322 > +    in_reply_to = talloc_asprintf (ctx, "<%s>",\r
323 > +                                notmuch_message_get_message_id (message));\r
324 > +\r
325 > +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
326 > +                           "In-Reply-To", in_reply_to);\r
327 > +\r
328 > +    orig_references = notmuch_message_get_header (message, "references");\r
329 > +    references = talloc_asprintf (ctx, "%s%s%s",\r
330 > +                               orig_references ? orig_references : "",\r
331 > +                               orig_references ? " " : "",\r
332 > +                               in_reply_to);\r
333 > +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
334 > +                           "References", references);\r
335 > +\r
336 > +    return reply;\r
337 > +}\r
338 > +\r
339 >  static int\r
340 >  notmuch_reply_format_default(void *ctx,\r
341 >                            notmuch_config_t *config,\r
342 > @@ -515,8 +664,6 @@ notmuch_reply_format_default(void *ctx,\r
343 >      GMimeMessage *reply;\r
344 >      notmuch_messages_t *messages;\r
345 >      notmuch_message_t *message;\r
346 > -    const char *subject, *from_addr = NULL;\r
347 > -    const char *in_reply_to, *orig_references, *references;\r
348 >      const notmuch_show_format_t *format = &format_reply;\r
349 >  \r
350 >      for (messages = notmuch_query_search_messages (query);\r
351 > @@ -525,62 +672,104 @@ notmuch_reply_format_default(void *ctx,\r
352 >      {\r
353 >       message = notmuch_messages_get (messages);\r
354 >  \r
355 > -     /* The 1 means we want headers in a "pretty" order. */\r
356 > -     reply = g_mime_message_new (1);\r
357 > -     if (reply == NULL) {\r
358 > -         fprintf (stderr, "Out of memory\n");\r
359 > -         return 1;\r
360 > -     }\r
361 > +     reply = create_reply_message (ctx, config, message, reply_all);\r
362 >  \r
363 > -     subject = notmuch_message_get_header (message, "subject");\r
364 > -     if (subject) {\r
365 > -         if (strncasecmp (subject, "Re:", 3))\r
366 > -             subject = talloc_asprintf (ctx, "Re: %s", subject);\r
367 > -         g_mime_message_set_subject (reply, subject);\r
368 > -     }\r
369 > +     if (!reply)\r
370 > +         continue;\r
371 >  \r
372 > -     from_addr = add_recipients_from_message (reply, config, message,\r
373 > -                                              reply_all);\r
374 > +     show_reply_headers (reply);\r
375 >  \r
376 > -     if (from_addr == NULL)\r
377 > -         from_addr = guess_from_received_header (config, message);\r
378 > +     g_object_unref (G_OBJECT (reply));\r
379 > +     reply = NULL;\r
380 >  \r
381 > -     if (from_addr == NULL)\r
382 > -         from_addr = notmuch_config_get_user_primary_email (config);\r
383 > +     printf ("On %s, %s wrote:\n",\r
384 > +             notmuch_message_get_header (message, "date"),\r
385 > +             notmuch_message_get_header (message, "from"));\r
386 >  \r
387 > -     from_addr = talloc_asprintf (ctx, "%s <%s>",\r
388 > -                                  notmuch_config_get_user_name (config),\r
389 > -                                  from_addr);\r
390 > -     g_mime_object_set_header (GMIME_OBJECT (reply),\r
391 > -                               "From", from_addr);\r
392 > +     show_message_body (message, format, params);\r
393 >  \r
394 > -     in_reply_to = talloc_asprintf (ctx, "<%s>",\r
395 > -                          notmuch_message_get_message_id (message));\r
396 > +     notmuch_message_destroy (message);\r
397 > +    }\r
398 > +    return 0;\r
399 > +}\r
400 >  \r
401 > -     g_mime_object_set_header (GMIME_OBJECT (reply),\r
402 > -                               "In-Reply-To", in_reply_to);\r
403 > +static int\r
404 > +notmuch_reply_format_json(void *ctx,\r
405 > +                       notmuch_config_t *config,\r
406 > +                       notmuch_query_t *query,\r
407 > +                       unused (notmuch_show_params_t *params),\r
408 > +                       notmuch_bool_t reply_all)\r
409 > +{\r
410 > +    GMimeMessage *reply;\r
411 > +    notmuch_messages_t *messages;\r
412 > +    notmuch_message_t *message;\r
413 > +    const notmuch_show_format_t *format = &format_json;\r
414 >  \r
415 > -     orig_references = notmuch_message_get_header (message, "references");\r
416 > -     references = talloc_asprintf (ctx, "%s%s%s",\r
417 > -                                   orig_references ? orig_references : "",\r
418 > -                                   orig_references ? " " : "",\r
419 > -                                   in_reply_to);\r
420 > -     g_mime_object_set_header (GMIME_OBJECT (reply),\r
421 > -                               "References", references);\r
422 > +    const char *reply_headers[] = {"from", "to", "subject", "in-reply-to", "references"};\r
423 > +    const char *orig_headers[] = {"from", "to", "cc", "subject", "date", "in-reply-to", "references"};\r
424 > +    unsigned int hidx;\r
425 >  \r
426 > -     show_reply_headers (reply);\r
427 > +    /* Start array of reply objects */\r
428 > +    printf ("[");\r
429 > +\r
430 > +    for (messages = notmuch_query_search_messages (query);\r
431 > +      notmuch_messages_valid (messages);\r
432 > +      notmuch_messages_move_to_next (messages))\r
433 > +    {\r
434 > +     /* Start a reply object */\r
435 > +     printf ("{ \"reply\": { \"headers\": { ");\r
436 > +\r
437 > +     message = notmuch_messages_get (messages);\r
438 > +\r
439 > +     reply = create_reply_message (ctx, config, message, reply_all);\r
440 > +     if (!reply)\r
441 > +         continue;\r
442 \r
443 If this occurs, it will create broken JSON.\r
444 \r
445 > +\r
446 > +     for (hidx = 0; hidx < ARRAY_SIZE (reply_headers); hidx++)\r
447 > +     {\r
448 > +         if (hidx)\r
449 > +             printf (", ");\r
450 > +\r
451 > +         printf ("%s: %s", json_quote_str (ctx, reply_headers[hidx]),\r
452 > +                 json_quote_str (ctx, g_mime_object_get_header (GMIME_OBJECT (reply), reply_headers[hidx])));\r
453 > +     }\r
454 >  \r
455 >       g_object_unref (G_OBJECT (reply));\r
456 >       reply = NULL;\r
457 >  \r
458 > -     printf ("On %s, %s wrote:\n",\r
459 > -             notmuch_message_get_header (message, "date"),\r
460 > -             notmuch_message_get_header (message, "from"));\r
461 > +     /* Done the headers for the reply, which has no body parts */\r
462 > +     printf ("} }");\r
463 > +\r
464 > +     /* Start the original */\r
465 > +     printf (", \"original\": { \"headers\": { ");\r
466 > +\r
467 > +     for (hidx = 0; hidx < ARRAY_SIZE (orig_headers); hidx++)\r
468 > +     {\r
469 > +         if (hidx)\r
470 > +             printf (", ");\r
471 > +\r
472 > +         printf ("%s: %s", json_quote_str (ctx, orig_headers[hidx]),\r
473 > +                 json_quote_str (ctx, notmuch_message_get_header (message, orig_headers[hidx])));\r
474 > +     }\r
475 > +\r
476 > +     /* End headers */\r
477 > +     printf (" }, \"body\": [ ");\r
478 >  \r
479 > +     /* Show body parts */\r
480 >       show_message_body (message, format, params);\r
481 >  \r
482 >       notmuch_message_destroy (message);\r
483 > +\r
484 > +     /* Done the original */\r
485 > +     printf ("{} ] }");\r
486 > +\r
487 > +     /* End the reply object. */\r
488 > +     printf (" }, ");\r
489 >      }\r
490 > +\r
491 > +    /* End array of reply objects */\r
492 > +    printf ("{} ]\n");\r
493 > +\r
494 >      return 0;\r
495 >  }\r
496 >  \r
497 > @@ -646,6 +835,7 @@ notmuch_reply_format_headers_only(void *ctx,\r
498 >  \r
499 >  enum {\r
500 >      FORMAT_DEFAULT,\r
501 > +    FORMAT_JSON,\r
502 >      FORMAT_HEADERS_ONLY,\r
503 >  };\r
504 >  \r
505 > @@ -666,6 +856,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
506 >      notmuch_opt_desc_t options[] = {\r
507 >       { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',\r
508 >         (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },\r
509 > +                               { "json", FORMAT_JSON },\r
510 >                                 { "headers-only", FORMAT_HEADERS_ONLY },\r
511 >                                 { 0, 0 } } },\r
512 >       { NOTMUCH_OPT_KEYWORD, &reply_all, "reply-to", 'r',\r
513 > @@ -684,6 +875,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
514 >  \r
515 >      if (format == FORMAT_HEADERS_ONLY)\r
516 >       reply_format_func = notmuch_reply_format_headers_only;\r
517 > +    else if (format == FORMAT_JSON)\r
518 > +     reply_format_func = notmuch_reply_format_json;\r
519 >      else\r
520 >       reply_format_func = notmuch_reply_format_default;\r
521 >  \r
522 > -- \r
523 > 1.7.5.4\r
524\r
525 > _______________________________________________\r
526 > notmuch mailing list\r
527 > notmuch@notmuchmail.org\r
528 > http://notmuchmail.org/mailman/listinfo/notmuch\r