Re: Hi all
[notmuch-archives.git] / 29 / 4d926729207b794a0ff58149e34d5103e137fc
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 02406421195\r
6         for <notmuch@notmuchmail.org>; Wed, 15 Feb 2012 19:12:53 -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 kWV6SMnJZa4Y for <notmuch@notmuchmail.org>;\r
16         Wed, 15 Feb 2012 19:12:51 -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 54CC4429E43\r
19         for <notmuch@notmuchmail.org>; Wed, 15 Feb 2012 19:12:47 -0800 (PST)\r
20 Received: from pd4ml1so-ssvc.prod.shaw.ca ([10.0.141.141])\r
21         by pd3mo1so-svcs.prod.shaw.ca with ESMTP; 15 Feb 2012 20:12:46 -0700\r
22 X-Cloudmark-SP-Filtered: true\r
23 X-Cloudmark-SP-Result: v=1.1 cv=zu4PKjlF+9DoPrG/TPTQ4CC8dREy1gI1uGhqrRhVwqE=\r
24         c=1 sm=1\r
25         a=9U844qFRHGkA:10 a=BLceEmwcHowA:10 a=yQp6g8lIsgqumF79BAsFDg==:17\r
26         a=zj4l01KfgLfMms7IjnsA:9 a=Dx_uIxvhEoZ4WgtTZTMA:7 a=cQ6rN1uShYHculXO:21\r
27         a=epQYAQWoZu4M9vRf:21 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117\r
28 Received: from unknown (HELO lagos.xvx.ca) ([96.52.216.56])\r
29         by pd4ml1so-dmz.prod.shaw.ca with ESMTP; 15 Feb 2012 20:12:46 -0700\r
30 Received: by lagos.xvx.ca (Postfix, from userid 1000)\r
31         id D147B8004C3A; Wed, 15 Feb 2012 20:12:45 -0700 (MST)\r
32 From: Adam Wolfe Gordon <awg+notmuch@xvx.ca>\r
33 To: notmuch@notmuchmail.org\r
34 Subject: [PATCH v5.2 3/7] reply: Add a JSON reply format.\r
35 Date: Wed, 15 Feb 2012 20:12:33 -0700\r
36 Message-Id: <1329361957-28493-4-git-send-email-awg+notmuch@xvx.ca>\r
37 X-Mailer: git-send-email 1.7.5.4\r
38 In-Reply-To: <1329361957-28493-1-git-send-email-awg+notmuch@xvx.ca>\r
39 References: <1329361957-28493-1-git-send-email-awg+notmuch@xvx.ca>\r
40 X-BeenThere: notmuch@notmuchmail.org\r
41 X-Mailman-Version: 2.1.13\r
42 Precedence: list\r
43 List-Id: "Use and development of the notmuch mail system."\r
44         <notmuch.notmuchmail.org>\r
45 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
46         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
47 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
48 List-Post: <mailto:notmuch@notmuchmail.org>\r
49 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
50 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
51         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
52 X-List-Received-Date: Thu, 16 Feb 2012 03:12:53 -0000\r
53 \r
54 This new JSON format for replies includes headers generated for a\r
55 reply message as well as the headers of the original message.  Using\r
56 this data, a client can intelligently create a reply. For example, the\r
57 emacs client will be able to create replies with quoted HTML parts by\r
58 parsing the HTML parts.\r
59 \r
60 Reply now enforces that only one message is returned, as the semantics\r
61 of replying to multiple messages are not well-defined.\r
62 ---\r
63  notmuch-client.h |    3 +\r
64  notmuch-reply.c  |  121 ++++++++++++++++++++++++++++++++++++++++++++++-------\r
65  notmuch-show.c   |    2 +-\r
66  3 files changed, 109 insertions(+), 17 deletions(-)\r
67 \r
68 diff --git a/notmuch-client.h b/notmuch-client.h\r
69 index 60828aa..d28ea07 100644\r
70 --- a/notmuch-client.h\r
71 +++ b/notmuch-client.h\r
72 @@ -344,6 +344,9 @@ typedef struct mime_node {\r
73      int next_part_num;\r
74  } mime_node_t;\r
75  \r
76 +void\r
77 +format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first);\r
78 +\r
79  /* Construct a new MIME node pointing to the root message part of\r
80   * message.  If cryptoctx is non-NULL, it will be used to verify\r
81   * signatures on any child parts.  If decrypt is true, then cryptoctx\r
82 diff --git a/notmuch-reply.c b/notmuch-reply.c\r
83 index 8e56245..6670288 100644\r
84 --- a/notmuch-reply.c\r
85 +++ b/notmuch-reply.c\r
86 @@ -572,30 +572,115 @@ notmuch_reply_format_default(void *ctx,\r
87      notmuch_message_t *message;\r
88      const notmuch_show_format_t *format = &format_reply;\r
89  \r
90 -    for (messages = notmuch_query_search_messages (query);\r
91 -        notmuch_messages_valid (messages);\r
92 -        notmuch_messages_move_to_next (messages))\r
93 -    {\r
94 -       message = notmuch_messages_get (messages);\r
95 +    if (notmuch_query_count_messages (query) != 1) {\r
96 +       fprintf (stderr, "Error: search term did not match precisely one message.\n");\r
97 +       return 1;\r
98 +    }\r
99  \r
100 -       reply = create_reply_message (ctx, config, message, reply_all);\r
101 +    messages = notmuch_query_search_messages (query);\r
102 +    message = notmuch_messages_get (messages);\r
103  \r
104 -       if (!reply)\r
105 -           continue;\r
106 +    reply = create_reply_message (ctx, config, message, reply_all);\r
107  \r
108 -       show_reply_headers (reply);\r
109 +    if (!reply)\r
110 +       return 1;\r
111  \r
112 -       g_object_unref (G_OBJECT (reply));\r
113 -       reply = NULL;\r
114 +    show_reply_headers (reply);\r
115  \r
116 -       printf ("On %s, %s wrote:\n",\r
117 -               notmuch_message_get_header (message, "date"),\r
118 -               notmuch_message_get_header (message, "from"));\r
119 +    g_object_unref (G_OBJECT (reply));\r
120 +    reply = NULL;\r
121  \r
122 -       show_message_body (message, format, params);\r
123 +    printf ("On %s, %s wrote:\n",\r
124 +           notmuch_message_get_header (message, "date"),\r
125 +           notmuch_message_get_header (message, "from"));\r
126  \r
127 -       notmuch_message_destroy (message);\r
128 +    show_message_body (message, format, params);\r
129 +\r
130 +    notmuch_message_destroy (message);\r
131 +\r
132 +    return 0;\r
133 +}\r
134 +\r
135 +static void\r
136 +format_reply_headers_json (const void *ctx, GMimeMessage *message)\r
137 +{\r
138 +    void *local = talloc_new (ctx);\r
139 +    InternetAddressList *recipients;\r
140 +    const char *recipients_string;\r
141 +\r
142 +    printf ("{%s: %s",\r
143 +           json_quote_str (local, "Subject"),\r
144 +           json_quote_str (local, g_mime_message_get_subject (message)));\r
145 +    printf (", %s: %s",\r
146 +           json_quote_str (local, "From"),\r
147 +           json_quote_str (local, g_mime_message_get_sender (message)));\r
148 +    recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO);\r
149 +    recipients_string = internet_address_list_to_string (recipients, 0);\r
150 +    if (recipients_string)\r
151 +       printf (", %s: %s",\r
152 +               json_quote_str (local, "To"),\r
153 +               json_quote_str (local, recipients_string));\r
154 +    recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC);\r
155 +    recipients_string = internet_address_list_to_string (recipients, 0);\r
156 +    if (recipients_string)\r
157 +       printf (", %s: %s",\r
158 +               json_quote_str (local, "Cc"),\r
159 +               json_quote_str (local, recipients_string));\r
160 +\r
161 +    printf (", %s: %s",\r
162 +           json_quote_str (local, "In-reply-to"),\r
163 +           json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "In-reply-to")));\r
164 +\r
165 +    printf (", %s: %s",\r
166 +           json_quote_str (local, "References"),\r
167 +           json_quote_str (local, g_mime_object_get_header (GMIME_OBJECT (message), "References")));\r
168 +\r
169 +    talloc_free (local);\r
170 +}\r
171 +\r
172 +static int\r
173 +notmuch_reply_format_json(void *ctx,\r
174 +                         notmuch_config_t *config,\r
175 +                         notmuch_query_t *query,\r
176 +                         notmuch_show_params_t *params,\r
177 +                         notmuch_bool_t reply_all)\r
178 +{\r
179 +    GMimeMessage *reply;\r
180 +    notmuch_messages_t *messages;\r
181 +    notmuch_message_t *message;\r
182 +    mime_node_t *node;\r
183 +\r
184 +    if (notmuch_query_count_messages (query) != 1) {\r
185 +       fprintf (stderr, "Error: search term did not match precisely one message.\n");\r
186 +       return 1;\r
187      }\r
188 +\r
189 +    messages = notmuch_query_search_messages (query);\r
190 +    message = notmuch_messages_get (messages);\r
191 +    if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,\r
192 +                       &node) != NOTMUCH_STATUS_SUCCESS)\r
193 +       return 1;\r
194 +\r
195 +    reply = create_reply_message (ctx, config, message, reply_all);\r
196 +    if (!reply)\r
197 +       return 1;\r
198 +\r
199 +    /* The headers of the reply message we've created */\r
200 +    printf ("{\"reply-headers\": ");\r
201 +    format_reply_headers_json (ctx, reply);\r
202 +    printf ("}");\r
203 +    g_object_unref (G_OBJECT (reply));\r
204 +    reply = NULL;\r
205 +\r
206 +    /* Start the original */\r
207 +    printf (", \"original\": ");\r
208 +\r
209 +    format_part_json (ctx, node, TRUE);\r
210 +\r
211 +    /* End */\r
212 +    printf ("}\n");\r
213 +    notmuch_message_destroy (message);\r
214 +\r
215      return 0;\r
216  }\r
217  \r
218 @@ -661,6 +746,7 @@ notmuch_reply_format_headers_only(void *ctx,\r
219  \r
220  enum {\r
221      FORMAT_DEFAULT,\r
222 +    FORMAT_JSON,\r
223      FORMAT_HEADERS_ONLY,\r
224  };\r
225  \r
226 @@ -680,6 +766,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
227      notmuch_opt_desc_t options[] = {\r
228         { NOTMUCH_OPT_KEYWORD, &format, "format", 'f',\r
229           (notmuch_keyword_t []){ { "default", FORMAT_DEFAULT },\r
230 +                                 { "json", FORMAT_JSON },\r
231                                   { "headers-only", FORMAT_HEADERS_ONLY },\r
232                                   { 0, 0 } } },\r
233         { NOTMUCH_OPT_KEYWORD, &reply_all, "reply-to", 'r',\r
234 @@ -698,6 +785,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
235  \r
236      if (format == FORMAT_HEADERS_ONLY)\r
237         reply_format_func = notmuch_reply_format_headers_only;\r
238 +    else if (format == FORMAT_JSON)\r
239 +       reply_format_func = notmuch_reply_format_json;\r
240      else\r
241         reply_format_func = notmuch_reply_format_default;\r
242  \r
243 diff --git a/notmuch-show.c b/notmuch-show.c\r
244 index 6a171a4..c570a16 100644\r
245 --- a/notmuch-show.c\r
246 +++ b/notmuch-show.c\r
247 @@ -652,7 +652,7 @@ format_part_text (const void *ctx, mime_node_t *node,\r
248      printf ("\f%s}\n", part_type);\r
249  }\r
250  \r
251 -static void\r
252 +void\r
253  format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first)\r
254  {\r
255      /* Any changes to the JSON format should be reflected in the file\r
256 -- \r
257 1.7.5.4\r
258 \r