Re: [PATCH v4 01/16] add util/search-path.{c, h} to test for executables in $PATH
[notmuch-archives.git] / c1 / b1f9702b4e4282d3d33ab9571c41faf39d8f3f
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
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0\r
10 X-Spam-Level: \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
24         c=1 sm=1\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
43 Precedence: list\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
54 \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
60 \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
63 \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
67 ---\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
73 \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
81  "\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
86          (json-false 'nil))\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
97 -.B \-\-format=json\r
98 -implies\r
99 -.B \-\-entire\-thread\r
100 +reflected in nested JSON output.\r
101  \r
102  .RE\r
103  .RS 4\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
109      return NULL;\r
110  }\r
111  \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
117 +{\r
118 +    const char *subject, *from_addr = NULL;\r
119 +    const char *in_reply_to, *orig_references, *references;\r
120 +\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
125 +       return NULL;\r
126 +    }\r
127 +\r
128 +    subject = notmuch_message_get_header (message, "subject");\r
129 +    if (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
133 +    }\r
134 +\r
135 +    from_addr = add_recipients_from_message (reply, config,\r
136 +                                            message, reply_all);\r
137 +\r
138 +    if (from_addr == NULL)\r
139 +       from_addr = guess_from_received_header (config, message);\r
140 +\r
141 +    if (from_addr == NULL)\r
142 +       from_addr = notmuch_config_get_user_primary_email (config);\r
143 +\r
144 +    from_addr = talloc_asprintf (ctx, "%s <%s>",\r
145 +                                notmuch_config_get_user_name (config),\r
146 +                                from_addr);\r
147 +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
148 +                             "From", from_addr);\r
149 +\r
150 +    in_reply_to = talloc_asprintf (ctx, "<%s>",\r
151 +                                  notmuch_message_get_message_id (message));\r
152 +\r
153 +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
154 +                             "In-Reply-To", in_reply_to);\r
155 +\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
160 +                                 in_reply_to);\r
161 +    g_mime_object_set_header (GMIME_OBJECT (reply),\r
162 +                             "References", references);\r
163 +\r
164 +    return reply;\r
165 +}\r
166 +\r
167  static int\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
177  \r
178      for (messages = notmuch_query_search_messages (query);\r
179 @@ -525,48 +578,10 @@ notmuch_reply_format_default(void *ctx,\r
180      {\r
181         message = notmuch_messages_get (messages);\r
182  \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
187 -           return 1;\r
188 -       }\r
189 -\r
190 -       subject = notmuch_message_get_header (message, "subject");\r
191 -       if (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
195 -       }\r
196 -\r
197 -       from_addr = add_recipients_from_message (reply, config, message,\r
198 -                                                reply_all);\r
199 -\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
203  \r
204 -       if (from_addr == NULL)\r
205 -           from_addr = notmuch_config_get_user_primary_email (config);\r
206 -\r
207 -       from_addr = talloc_asprintf (ctx, "%s <%s>",\r
208 -                                    notmuch_config_get_user_name (config),\r
209 -                                    from_addr);\r
210 -       g_mime_object_set_header (GMIME_OBJECT (reply),\r
211 -                                 "From", from_addr);\r
212 -\r
213 -       in_reply_to = talloc_asprintf (ctx, "<%s>",\r
214 -                            notmuch_message_get_message_id (message));\r
215 -\r
216 -       g_mime_object_set_header (GMIME_OBJECT (reply),\r
217 -                                 "In-Reply-To", in_reply_to);\r
218 -\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
223 -                                     in_reply_to);\r
224 -       g_mime_object_set_header (GMIME_OBJECT (reply),\r
225 -                                 "References", references);\r
226 +       if (!reply)\r
227 +           continue;\r
228  \r
229         show_reply_headers (reply);\r
230  \r
231 @@ -584,6 +599,68 @@ notmuch_reply_format_default(void *ctx,\r
232      return 0;\r
233  }\r
234  \r
235 +static int\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
241 +{\r
242 +    GMimeMessage *reply;\r
243 +    notmuch_messages_t *messages;\r
244 +    notmuch_message_t *message;\r
245 +\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
249 +\r
250 +    if (notmuch_query_count_messages (query) != 1) {\r
251 +       fprintf (stderr, "Error: search term did not match precisely one message.\n");\r
252 +       return 1;\r
253 +    }\r
254 +\r
255 +    messages = notmuch_query_search_messages (query);\r
256 +    message = notmuch_messages_get (messages);\r
257 +\r
258 +    reply = create_reply_message (ctx, config, message, reply_all);\r
259 +    if (!reply)\r
260 +       return 1;\r
261 +\r
262 +    /* Start a reply object */\r
263 +    printf ("{ \"reply\": { ");\r
264 +\r
265 +    for (hidx = 0; hidx < ARRAY_SIZE (reply_headers); hidx++) {\r
266 +       if (hidx)\r
267 +           printf (", ");\r
268 +\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
271 +    }\r
272 +\r
273 +    g_object_unref (G_OBJECT (reply));\r
274 +    reply = NULL;\r
275 +\r
276 +    /* Done the headers for the reply, which has no body */\r
277 +    printf (" }");\r
278 +\r
279 +    /* Start the original */\r
280 +    printf (", \"original\": { ");\r
281 +\r
282 +    for (hidx = 0; hidx < ARRAY_SIZE (orig_headers); hidx++) {\r
283 +       if (hidx)\r
284 +           printf (", ");\r
285 +\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
288 +    }\r
289 +\r
290 +    /* End */\r
291 +    printf (" } }\n");\r
292 +    notmuch_message_destroy (message);\r
293 +\r
294 +    return 0;\r
295 +}\r
296 +\r
297  /* This format is currently tuned for a git send-email --notmuch hook */\r
298  static int\r
299  notmuch_reply_format_headers_only(void *ctx,\r
300 @@ -646,6 +723,7 @@ notmuch_reply_format_headers_only(void *ctx,\r
301  \r
302  enum {\r
303      FORMAT_DEFAULT,\r
304 +    FORMAT_JSON,\r
305      FORMAT_HEADERS_ONLY,\r
306  };\r
307  \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
314                                   { 0, 0 } } },\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
317  \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
322      else\r
323         reply_format_func = notmuch_reply_format_default;\r
324  \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
336                 mbox = 1;\r
337 -- \r
338 1.7.5.4\r
339 \r