Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / d0 / c587fb05af9e25df40e29dbe1d6372838323df
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 6B29A431FD0\r
6         for <notmuch@notmuchmail.org>; Sun, 18 Mar 2012 09:33:05 -0700 (PDT)\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 29e9aDZZbfj9 for <notmuch@notmuchmail.org>;\r
16         Sun, 18 Mar 2012 09:33:03 -0700 (PDT)\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 1CB59431FD6\r
19         for <notmuch@notmuchmail.org>; Sun, 18 Mar 2012 09:33:01 -0700 (PDT)\r
20 Received: from pd4ml3so-ssvc.prod.shaw.ca ([10.0.141.150])\r
21         by pd4mo1so-svcs.prod.shaw.ca with ESMTP; 18 Mar 2012 10:33:00 -0600\r
22 X-Cloudmark-SP-Filtered: true\r
23 X-Cloudmark-SP-Result: v=1.1 cv=b/gStvK98Bs6YfhBwCpxRApoLO2qoBYaarCtclPE+68=\r
24         c=1 sm=1\r
25         a=PHNqX133DScA:10 a=BLceEmwcHowA:10 a=yQp6g8lIsgqumF79BAsFDg==:17\r
26         a=bz-zy3QpAAAA:8 a=n6QtOu-G53KnuZUlGJ0A:9 a=_PtZexEyJN9in46kyVIA:7\r
27         a=NFWI-YhVVZsA:10 a=VqgfUknEhrnVsQv5:21 a=7kzdyUmDbSbuI7Hz:21\r
28         a=HpAAvcLHHh0Zw7uRqdWCyQ==:117\r
29 Received: from unknown (HELO lagos.xvx.ca) ([96.52.216.56])\r
30         by pd4ml3so-dmz.prod.shaw.ca with ESMTP; 18 Mar 2012 10:33:00 -0600\r
31 Received: by lagos.xvx.ca (Postfix, from userid 1000)\r
32         id 12BB28004838; Sun, 18 Mar 2012 10:33:00 -0600 (MDT)\r
33 From: Adam Wolfe Gordon <awg+notmuch@xvx.ca>\r
34 To: notmuch@notmuchmail.org\r
35 Subject: [PATCH v8 04/11] reply: Add a JSON reply format.\r
36 Date: Sun, 18 Mar 2012 10:32:36 -0600\r
37 Message-Id: <1332088363-22476-5-git-send-email-awg+notmuch@xvx.ca>\r
38 X-Mailer: git-send-email 1.7.5.4\r
39 In-Reply-To: <1332088363-22476-1-git-send-email-awg+notmuch@xvx.ca>\r
40 References: <87fwd6kqtv.fsf@zancas.localnet>\r
41         <1332088363-22476-1-git-send-email-awg+notmuch@xvx.ca>\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: Sun, 18 Mar 2012 16:33:05 -0000\r
55 \r
56 This new JSON format for replies includes headers generated for a\r
57 reply message as well as the headers of the original message.  Using\r
58 this data, a client can intelligently create a reply. For example, the\r
59 emacs client will be able to create replies with quoted HTML parts by\r
60 parsing the HTML parts.\r
61 ---\r
62  notmuch-client.h |   12 +++++++++---\r
63  notmuch-reply.c  |   49 +++++++++++++++++++++++++++++++++++++++++++++++++\r
64  notmuch-show.c   |   29 +++++++++++++++++++++--------\r
65  test/multipart   |    1 -\r
66  4 files changed, 79 insertions(+), 12 deletions(-)\r
67 \r
68 diff --git a/notmuch-client.h b/notmuch-client.h\r
69 index a220fe4..fa04fa2 100644\r
70 --- a/notmuch-client.h\r
71 +++ b/notmuch-client.h\r
72 @@ -62,7 +62,7 @@\r
73  #define STRINGIFY(s) STRINGIFY_(s)\r
74  #define STRINGIFY_(s) #s\r
75  \r
76 -struct mime_node;\r
77 +typedef struct mime_node mime_node_t;\r
78  struct notmuch_show_params;\r
79  \r
80  typedef struct notmuch_show_format {\r
81 @@ -191,6 +191,12 @@ show_message_body (notmuch_message_t *message,\r
82  notmuch_status_t\r
83  show_one_part (const char *filename, int part);\r
84  \r
85 +void\r
86 +format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first);\r
87 +\r
88 +void\r
89 +format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t reply);\r
90 +\r
91  char *\r
92  json_quote_chararray (const void *ctx, const char *str, const size_t len);\r
93  \r
94 @@ -288,7 +294,7 @@ debugger_is_active (void);\r
95   * parts.  Message-type parts have one child, multipart-type parts\r
96   * have multiple children, and leaf parts have zero children.\r
97   */\r
98 -typedef struct mime_node {\r
99 +struct mime_node {\r
100      /* The MIME object of this part.  This will be a GMimeMessage,\r
101       * GMimePart, GMimeMultipart, or a subclass of one of these.\r
102       *\r
103 @@ -351,7 +357,7 @@ typedef struct mime_node {\r
104       * number to assign it (or -1 if unknown). */\r
105      int next_child;\r
106      int next_part_num;\r
107 -} mime_node_t;\r
108 +};\r
109  \r
110  /* Construct a new MIME node pointing to the root message part of\r
111   * message.  If cryptoctx is non-NULL, it will be used to verify\r
112 diff --git a/notmuch-reply.c b/notmuch-reply.c\r
113 index f1478cc..e2b6c25 100644\r
114 --- a/notmuch-reply.c\r
115 +++ b/notmuch-reply.c\r
116 @@ -604,6 +604,51 @@ notmuch_reply_format_default(void *ctx,\r
117      return 0;\r
118  }\r
119  \r
120 +static int\r
121 +notmuch_reply_format_json(void *ctx,\r
122 +                         notmuch_config_t *config,\r
123 +                         notmuch_query_t *query,\r
124 +                         notmuch_show_params_t *params,\r
125 +                         notmuch_bool_t reply_all)\r
126 +{\r
127 +    GMimeMessage *reply;\r
128 +    notmuch_messages_t *messages;\r
129 +    notmuch_message_t *message;\r
130 +    mime_node_t *node;\r
131 +\r
132 +    if (notmuch_query_count_messages (query) != 1) {\r
133 +       fprintf (stderr, "Error: search term did not match precisely one message.\n");\r
134 +       return 1;\r
135 +    }\r
136 +\r
137 +    messages = notmuch_query_search_messages (query);\r
138 +    message = notmuch_messages_get (messages);\r
139 +    if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,\r
140 +                       &node) != NOTMUCH_STATUS_SUCCESS)\r
141 +       return 1;\r
142 +\r
143 +    reply = create_reply_message (ctx, config, message, reply_all);\r
144 +    if (!reply)\r
145 +       return 1;\r
146 +\r
147 +    /* The headers of the reply message we've created */\r
148 +    printf ("{\"reply-headers\": ");\r
149 +    format_headers_json (ctx, reply, TRUE);\r
150 +    g_object_unref (G_OBJECT (reply));\r
151 +    reply = NULL;\r
152 +\r
153 +    /* Start the original */\r
154 +    printf (", \"original\": ");\r
155 +\r
156 +    format_part_json (ctx, node, TRUE);\r
157 +\r
158 +    /* End */\r
159 +    printf ("}\n");\r
160 +    notmuch_message_destroy (message);\r
161 +\r
162 +    return 0;\r
163 +}\r
164 +\r
165  /* This format is currently tuned for a git send-email --notmuch hook */\r
166  static int\r
167  notmuch_reply_format_headers_only(void *ctx,\r
168 @@ -666,6 +711,7 @@ notmuch_reply_format_headers_only(void *ctx,\r
169  \r
170  enum {\r
171      FORMAT_DEFAULT,\r
172 +    FORMAT_JSON,\r
173      FORMAT_HEADERS_ONLY,\r
174  };\r
175  \r
176 @@ -685,6 +731,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
177      notmuch_opt_desc_t options[] = {\r
178         { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',\r
179           (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },\r
180 +                                 { "json", FORMAT_JSON },\r
181                                   { "headers-only", FORMAT_HEADERS_ONLY },\r
182                                   { 0, 0 } } },\r
183         { NOTMUCH_OPT_KEYWORD, &reply_all, "reply-to", 'r',\r
184 @@ -703,6 +750,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
185  \r
186      if (format == FORMAT_HEADERS_ONLY)\r
187         reply_format_func = notmuch_reply_format_headers_only;\r
188 +    else if (format == FORMAT_JSON)\r
189 +       reply_format_func = notmuch_reply_format_json;\r
190      else\r
191         reply_format_func = notmuch_reply_format_default;\r
192  \r
193 diff --git a/notmuch-show.c b/notmuch-show.c\r
194 index a7463dc..ff9d427 100644\r
195 --- a/notmuch-show.c\r
196 +++ b/notmuch-show.c\r
197 @@ -200,8 +200,8 @@ _is_from_line (const char *line)\r
198         return 0;\r
199  }\r
200  \r
201 -static void\r
202 -format_headers_json (const void *ctx, GMimeMessage *message)\r
203 +void\r
204 +format_headers_json (const void *ctx, GMimeMessage *message, notmuch_bool_t reply)\r
205  {\r
206      void *local = talloc_new (ctx);\r
207      InternetAddressList *recipients;\r
208 @@ -225,9 +225,22 @@ format_headers_json (const void *ctx, GMimeMessage *message)\r
209         printf (", %s: %s",\r
210                 json_quote_str (local, "Cc"),\r
211                 json_quote_str (local, recipients_string));\r
212 -    printf (", %s: %s}",\r
213 -           json_quote_str (local, "Date"),\r
214 -           json_quote_str (local, g_mime_message_get_date_as_string (message)));\r
215 +\r
216 +    if (reply) {\r
217 +       printf (", %s: %s",\r
218 +               json_quote_str (local, "In-reply-to"),\r
219 +               json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to")));\r
220 +\r
221 +       printf (", %s: %s",\r
222 +               json_quote_str (local, "References"),\r
223 +               json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "References")));\r
224 +    } else {\r
225 +       printf (", %s: %s",\r
226 +               json_quote_str (local, "Date"),\r
227 +               json_quote_str (local, g_mime_message_get_date_as_string (message)));\r
228 +    }\r
229 +\r
230 +    printf ("}");\r
231  \r
232      talloc_free (local);\r
233  }\r
234 @@ -538,7 +551,7 @@ format_part_text (const void *ctx, mime_node_t *node,\r
235      return NOTMUCH_STATUS_SUCCESS;\r
236  }\r
237  \r
238 -static void\r
239 +void\r
240  format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)\r
241  {\r
242      /* Any changes to the JSON format should be reflected in the file\r
243 @@ -549,7 +562,7 @@ format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)\r
244         format_message_json (ctx, node->envelope_file);\r
245  \r
246         printf ("\"headers\": ");\r
247 -       format_headers_json (ctx, GMIME_MESSAGE (node->part));\r
248 +       format_headers_json (ctx, GMIME_MESSAGE (node->part), FALSE);\r
249  \r
250         printf (", \"body\": [");\r
251         format_part_json (ctx, mime_node_child (node, 0), first);\r
252 @@ -623,7 +636,7 @@ format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)\r
253      } else if (GMIME_IS_MESSAGE (node->part)) {\r
254         printf (", \"content\": [{");\r
255         printf ("\"headers\": ");\r
256 -       format_headers_json (local, GMIME_MESSAGE (node->part));\r
257 +       format_headers_json (local, GMIME_MESSAGE (node->part), FALSE);\r
258  \r
259         printf (", \"body\": [");\r
260         terminator = "]}]";\r
261 diff --git a/test/multipart b/test/multipart\r
262 index e5de5d3..72d3927 100755\r
263 --- a/test/multipart\r
264 +++ b/test/multipart\r
265 @@ -613,7 +613,6 @@ EOF\r
266  test_expect_equal_file OUTPUT EXPECTED\r
267  \r
268  test_begin_subtest "'notmuch reply' to a multipart message with json format"\r
269 -test_subtest_known_broken\r
270  notmuch reply --format=json 'id:87liy5ap00.fsf@yoom.home.cworth.org' | notmuch_json_show_sanitize >OUTPUT\r
271  cat <<EOF >EXPECTED\r
272  {"reply-headers": {"Subject": "Re: Multipart message",\r
273 -- \r
274 1.7.5.4\r
275 \r