1 Return-Path: <awg@lagos.xvx.ca>
\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 3B62E429E3B
\r
6 for <notmuch@notmuchmail.org>; Wed, 8 Feb 2012 16:22:12 -0800 (PST)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=0 tagged_above=-999 required=5
\r
12 tests=[RCVD_IN_DNSWL_NONE=-0.0001] 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 Q9blpNBKc6Ka for <notmuch@notmuchmail.org>;
\r
16 Wed, 8 Feb 2012 16:22:09 -0800 (PST)
\r
17 Received: from idcmail-mo1so.shaw.ca (idcmail-mo1so.shaw.ca [24.71.223.10])
\r
18 by olra.theworths.org (Postfix) with ESMTP id E87A5429E25
\r
19 for <notmuch@notmuchmail.org>; Wed, 8 Feb 2012 16:22:08 -0800 (PST)
\r
20 Received: from pd2ml2so-ssvc.prod.shaw.ca ([10.0.141.134])
\r
21 by pd3mo1so-svcs.prod.shaw.ca with ESMTP; 08 Feb 2012 17:22:07 -0700
\r
22 X-Cloudmark-SP-Filtered: true
\r
23 X-Cloudmark-SP-Result: v=1.1 cv=FBhiVrZmCxhz+jlnxOWeJaR14+PwdUeacMZGNnSzbtQ=
\r
25 a=55xAQ_mktAEA:10 a=BLceEmwcHowA:10 a=yQp6g8lIsgqumF79BAsFDg==:17
\r
26 a=3-z4jJ9MB81Z5CkkUWIA:9 a=6eKa8LJ50ZS4bQRKnmUA:7
\r
27 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117
\r
28 Received: from unknown (HELO lagos.xvx.ca) ([96.52.216.56])
\r
29 by pd2ml2so-dmz.prod.shaw.ca with ESMTP; 08 Feb 2012 17:22:07 -0700
\r
30 Received: by lagos.xvx.ca (Postfix, from userid 1000)
\r
31 id 8D344802A3D9; Wed, 8 Feb 2012 17:22:07 -0700 (MST)
\r
32 From: Adam Wolfe Gordon <awg+notmuch@xvx.ca>
\r
33 To: notmuch@notmuchmail.org
\r
34 Subject: [PATCH v4 2/4] reply: Add a JSON reply format.
\r
35 Date: Wed, 8 Feb 2012 17:21:54 -0700
\r
36 Message-Id: <1328746916-25447-3-git-send-email-awg+notmuch@xvx.ca>
\r
37 X-Mailer: git-send-email 1.7.5.4
\r
38 In-Reply-To: <1328746916-25447-1-git-send-email-awg+notmuch@xvx.ca>
\r
39 References: <1326995217-27423-1-git-send-email-awg+notmuch@xvx.ca>
\r
40 <1328746916-25447-1-git-send-email-awg+notmuch@xvx.ca>
\r
41 X-BeenThere: notmuch@notmuchmail.org
\r
42 X-Mailman-Version: 2.1.13
\r
44 List-Id: "Use and development of the notmuch mail system."
\r
45 <notmuch.notmuchmail.org>
\r
46 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
47 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
48 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
49 List-Post: <mailto:notmuch@notmuchmail.org>
\r
50 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
51 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
52 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
53 X-List-Received-Date: Thu, 09 Feb 2012 00:22:12 -0000
\r
55 This new JSON format for replies includes headers generated for a
\r
56 reply message as well as the headers of the original message. Using
\r
57 this data, a client can intelligently create a reply. For example, the
\r
58 emacs client will be able to create replies with quoted HTML parts by
\r
59 parsing the HTML parts using w3m.
\r
61 Reply now enforces that only one message is returned, as the semantics
\r
62 of replying to multiple messages are not wel-defined.
\r
64 Show is modified such that --format=json no longer implies
\r
65 --entire-thread, as MUAs will use --format=json when constructing
\r
66 replies. The man page is updated to reflect this change.
\r
68 emacs/notmuch-query.el | 2 +-
\r
69 man/man1/notmuch-show.1 | 6 +--
\r
70 notmuch-reply.c | 167 +++++++++++++++++++++++++++++++++++------------
\r
71 notmuch-show.c | 1 -
\r
72 4 files changed, 126 insertions(+), 50 deletions(-)
\r
74 diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el
\r
75 index d66baea..cdf2d6b 100644
\r
76 --- a/emacs/notmuch-query.el
\r
77 +++ b/emacs/notmuch-query.el
\r
78 @@ -29,7 +29,7 @@ A thread is a forest or list of trees. A tree is a two element
\r
79 list where the first element is a message, and the second element
\r
80 is a possibly empty forest of replies.
\r
82 - (let ((args '("show" "--format=json"))
\r
83 + (let ((args '("show" "--format=json" "--entire-thread"))
\r
84 (json-object-type 'plist)
\r
85 (json-array-type 'list)
\r
87 diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1
\r
88 index b2301d8..c86b9db 100644
\r
89 --- a/man/man1/notmuch-show.1
\r
90 +++ b/man/man1/notmuch-show.1
\r
91 @@ -55,11 +55,7 @@ be nested.
\r
92 The output is formatted with Javascript Object Notation (JSON). This
\r
93 format is more robust than the text format for automated
\r
94 processing. The nested structure of multipart MIME messages is
\r
95 -reflected in nested JSON output. JSON output always includes all
\r
96 -messages in a matching thread; in effect
\r
99 -.B \-\-entire\-thread
\r
100 +reflected in nested JSON output.
\r
104 diff --git a/notmuch-reply.c b/notmuch-reply.c
\r
105 index f55b1d2..bfbc307 100644
\r
106 --- a/notmuch-reply.c
\r
107 +++ b/notmuch-reply.c
\r
108 @@ -505,6 +505,61 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
\r
112 +static GMimeMessage *
\r
113 +create_reply_message(void *ctx,
\r
114 + notmuch_config_t *config,
\r
115 + notmuch_message_t *message,
\r
116 + notmuch_bool_t reply_all)
\r
118 + const char *subject, *from_addr = NULL;
\r
119 + const char *in_reply_to, *orig_references, *references;
\r
121 + /* The 1 means we want headers in a "pretty" order. */
\r
122 + GMimeMessage *reply = g_mime_message_new (1);
\r
123 + if (reply == NULL) {
\r
124 + fprintf (stderr, "Out of memory\n");
\r
128 + subject = notmuch_message_get_header (message, "subject");
\r
130 + if (strncasecmp (subject, "Re:", 3))
\r
131 + subject = talloc_asprintf (ctx, "Re: %s", subject);
\r
132 + g_mime_message_set_subject (reply, subject);
\r
135 + from_addr = add_recipients_from_message (reply, config,
\r
136 + message, reply_all);
\r
138 + if (from_addr == NULL)
\r
139 + from_addr = guess_from_received_header (config, message);
\r
141 + if (from_addr == NULL)
\r
142 + from_addr = notmuch_config_get_user_primary_email (config);
\r
144 + from_addr = talloc_asprintf (ctx, "%s <%s>",
\r
145 + notmuch_config_get_user_name (config),
\r
147 + g_mime_object_set_header (GMIME_OBJECT (reply),
\r
148 + "From", from_addr);
\r
150 + in_reply_to = talloc_asprintf (ctx, "<%s>",
\r
151 + notmuch_message_get_message_id (message));
\r
153 + g_mime_object_set_header (GMIME_OBJECT (reply),
\r
154 + "In-Reply-To", in_reply_to);
\r
156 + orig_references = notmuch_message_get_header (message, "references");
\r
157 + references = talloc_asprintf (ctx, "%s%s%s",
\r
158 + orig_references ? orig_references : "",
\r
159 + orig_references ? " " : "",
\r
161 + g_mime_object_set_header (GMIME_OBJECT (reply),
\r
162 + "References", references);
\r
168 notmuch_reply_format_default(void *ctx,
\r
169 notmuch_config_t *config,
\r
170 @@ -515,8 +570,6 @@ notmuch_reply_format_default(void *ctx,
\r
171 GMimeMessage *reply;
\r
172 notmuch_messages_t *messages;
\r
173 notmuch_message_t *message;
\r
174 - const char *subject, *from_addr = NULL;
\r
175 - const char *in_reply_to, *orig_references, *references;
\r
176 const notmuch_show_format_t *format = &format_reply;
\r
178 for (messages = notmuch_query_search_messages (query);
\r
179 @@ -525,48 +578,10 @@ notmuch_reply_format_default(void *ctx,
\r
181 message = notmuch_messages_get (messages);
\r
183 - /* The 1 means we want headers in a "pretty" order. */
\r
184 - reply = g_mime_message_new (1);
\r
185 - if (reply == NULL) {
\r
186 - fprintf (stderr, "Out of memory\n");
\r
190 - subject = notmuch_message_get_header (message, "subject");
\r
192 - if (strncasecmp (subject, "Re:", 3))
\r
193 - subject = talloc_asprintf (ctx, "Re: %s", subject);
\r
194 - g_mime_message_set_subject (reply, subject);
\r
197 - from_addr = add_recipients_from_message (reply, config, message,
\r
200 - if (from_addr == NULL)
\r
201 - from_addr = guess_from_received_header (config, message);
\r
202 + reply = create_reply_message (ctx, config, message, reply_all);
\r
204 - if (from_addr == NULL)
\r
205 - from_addr = notmuch_config_get_user_primary_email (config);
\r
207 - from_addr = talloc_asprintf (ctx, "%s <%s>",
\r
208 - notmuch_config_get_user_name (config),
\r
210 - g_mime_object_set_header (GMIME_OBJECT (reply),
\r
211 - "From", from_addr);
\r
213 - in_reply_to = talloc_asprintf (ctx, "<%s>",
\r
214 - notmuch_message_get_message_id (message));
\r
216 - g_mime_object_set_header (GMIME_OBJECT (reply),
\r
217 - "In-Reply-To", in_reply_to);
\r
219 - orig_references = notmuch_message_get_header (message, "references");
\r
220 - references = talloc_asprintf (ctx, "%s%s%s",
\r
221 - orig_references ? orig_references : "",
\r
222 - orig_references ? " " : "",
\r
224 - g_mime_object_set_header (GMIME_OBJECT (reply),
\r
225 - "References", references);
\r
229 show_reply_headers (reply);
\r
231 @@ -584,6 +599,68 @@ notmuch_reply_format_default(void *ctx,
\r
236 +notmuch_reply_format_json(void *ctx,
\r
237 + notmuch_config_t *config,
\r
238 + notmuch_query_t *query,
\r
239 + unused (notmuch_show_params_t *params),
\r
240 + notmuch_bool_t reply_all)
\r
242 + GMimeMessage *reply;
\r
243 + notmuch_messages_t *messages;
\r
244 + notmuch_message_t *message;
\r
246 + const char *reply_headers[] = {"from", "to", "subject", "in-reply-to", "references"};
\r
247 + const char *orig_headers[] = {"from", "to", "cc", "subject", "date", "in-reply-to", "references", "message-id"};
\r
248 + unsigned int hidx;
\r
250 + if (notmuch_query_count_messages (query) != 1) {
\r
251 + fprintf (stderr, "Error: search term did not match precisely one message.\n");
\r
255 + messages = notmuch_query_search_messages (query);
\r
256 + message = notmuch_messages_get (messages);
\r
258 + reply = create_reply_message (ctx, config, message, reply_all);
\r
262 + /* Start a reply object */
\r
263 + printf ("{ \"reply\": { ");
\r
265 + for (hidx = 0; hidx < ARRAY_SIZE (reply_headers); hidx++) {
\r
269 + printf ("%s: %s", json_quote_str (ctx, reply_headers[hidx]),
\r
270 + json_quote_str (ctx, g_mime_object_get_header (GMIME_OBJECT (reply), reply_headers[hidx])));
\r
273 + g_object_unref (G_OBJECT (reply));
\r
276 + /* Done the headers for the reply, which has no body */
\r
279 + /* Start the original */
\r
280 + printf (", \"original\": { ");
\r
282 + for (hidx = 0; hidx < ARRAY_SIZE (orig_headers); hidx++) {
\r
286 + printf ("%s: %s", json_quote_str (ctx, orig_headers[hidx]),
\r
287 + json_quote_str (ctx, notmuch_message_get_header (message, orig_headers[hidx])));
\r
291 + printf (" } }\n");
\r
292 + notmuch_message_destroy (message);
\r
297 /* This format is currently tuned for a git send-email --notmuch hook */
\r
299 notmuch_reply_format_headers_only(void *ctx,
\r
300 @@ -646,6 +723,7 @@ notmuch_reply_format_headers_only(void *ctx,
\r
305 FORMAT_HEADERS_ONLY,
\r
308 @@ -666,6 +744,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
\r
309 notmuch_opt_desc_t options[] = {
\r
310 { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',
\r
311 (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },
\r
312 + { "json", FORMAT_JSON },
\r
313 { "headers-only", FORMAT_HEADERS_ONLY },
\r
315 { NOTMUCH_OPT_KEYWORD, &reply_all, "reply-to", 'r',
\r
316 @@ -684,6 +763,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
\r
318 if (format == FORMAT_HEADERS_ONLY)
\r
319 reply_format_func = notmuch_reply_format_headers_only;
\r
320 + else if (format == FORMAT_JSON)
\r
321 + reply_format_func = notmuch_reply_format_json;
\r
323 reply_format_func = notmuch_reply_format_default;
\r
325 diff --git a/notmuch-show.c b/notmuch-show.c
\r
326 index dec799c..344d08c 100644
\r
327 --- a/notmuch-show.c
\r
328 +++ b/notmuch-show.c
\r
329 @@ -1082,7 +1082,6 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
\r
330 format = &format_text;
\r
331 } else if (strcmp (opt, "json") == 0) {
\r
332 format = &format_json;
\r
333 - params.entire_thread = 1;
\r
334 } else if (strcmp (opt, "mbox") == 0) {
\r
335 format = &format_mbox;
\r