Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / 0e / 78e5c1deacc9382f3530a1f8b3e3b0b16c83d5
1 Return-Path: <m.walters@qmul.ac.uk>\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 9CB5B431FAF\r
6         for <notmuch@notmuchmail.org>; Sat,  8 Dec 2012 02:50:49 -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: -1.098\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-1.098 tagged_above=-999 required=5\r
12         tests=[DKIM_ADSP_CUSTOM_MED=0.001, FREEMAIL_FROM=0.001,\r
13         NML_ADSP_CUSTOM_MED=1.2, RCVD_IN_DNSWL_MED=-2.3] autolearn=disabled\r
14 Received: from olra.theworths.org ([127.0.0.1])\r
15         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
16         with ESMTP id jsmlwgyD-j0x for <notmuch@notmuchmail.org>;\r
17         Sat,  8 Dec 2012 02:50:48 -0800 (PST)\r
18 Received: from mail2.qmul.ac.uk (mail2.qmul.ac.uk [138.37.6.6])\r
19         (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 41DB2431FAE\r
22         for <notmuch@notmuchmail.org>; Sat,  8 Dec 2012 02:50:48 -0800 (PST)\r
23 Received: from smtp.qmul.ac.uk ([138.37.6.40])\r
24         by mail2.qmul.ac.uk with esmtp (Exim 4.71)\r
25         (envelope-from <m.walters@qmul.ac.uk>)\r
26         id 1ThHza-0002ED-8W; Sat, 08 Dec 2012 10:50:46 +0000\r
27 Received: from 93-97-24-31.zone5.bethere.co.uk ([93.97.24.31] helo=localhost)\r
28         by smtp.qmul.ac.uk with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.69)\r
29         (envelope-from <m.walters@qmul.ac.uk>)\r
30         id 1ThHzZ-0006F9-Fm; Sat, 08 Dec 2012 10:50:46 +0000\r
31 From: Mark Walters <markwalters1009@gmail.com>\r
32 To: david@tethera.net, notmuch@notmuchmail.org\r
33 Subject: Re: [Patch v3b 4/9] tag-util.[ch]: New files for common tagging\r
34         routines\r
35 In-Reply-To: <1354843607-17980-5-git-send-email-david@tethera.net>\r
36 References: <1354843607-17980-1-git-send-email-david@tethera.net>\r
37         <1354843607-17980-5-git-send-email-david@tethera.net>\r
38 User-Agent: Notmuch/0.14+81~g9730584 (http://notmuchmail.org) Emacs/23.4.1\r
39         (x86_64-pc-linux-gnu)\r
40 Date: Sat, 08 Dec 2012 10:50:50 +0000\r
41 Message-ID: <8738zghl6d.fsf@qmul.ac.uk>\r
42 MIME-Version: 1.0\r
43 Content-Type: text/plain; charset=us-ascii\r
44 X-Sender-Host-Address: 93.97.24.31\r
45 X-QM-SPAM-Info: Sender has good ham record.  :)\r
46 X-QM-Body-MD5: 5fdb1b91811a276700a0ddc397160292 (of first 20000 bytes)\r
47 X-SpamAssassin-Score: -1.8\r
48 X-SpamAssassin-SpamBar: -\r
49 X-SpamAssassin-Report: The QM spam filters have analysed this message to\r
50         determine if it is\r
51         spam. We require at least 5.0 points to mark a message as spam.\r
52         This message scored -1.8 points.\r
53         Summary of the scoring: \r
54         * -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/,\r
55         *      medium trust\r
56         *      [138.37.6.40 listed in list.dnswl.org]\r
57         * 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail\r
58         provider *      (markwalters1009[at]gmail.com)\r
59         *  0.5 AWL AWL: From: address is in the auto white-list\r
60 X-QM-Scan-Virus: ClamAV says the message is clean\r
61 Cc: David Bremner <bremner@debian.org>\r
62 X-BeenThere: notmuch@notmuchmail.org\r
63 X-Mailman-Version: 2.1.13\r
64 Precedence: list\r
65 List-Id: "Use and development of the notmuch mail system."\r
66         <notmuch.notmuchmail.org>\r
67 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
68         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
69 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
70 List-Post: <mailto:notmuch@notmuchmail.org>\r
71 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
72 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
73         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
74 X-List-Received-Date: Sat, 08 Dec 2012 10:50:49 -0000\r
75 \r
76 On Fri, 07 Dec 2012, david@tethera.net wrote:\r
77 > From: David Bremner <bremner@debian.org>\r
78 >\r
79 > These are meant to be shared between notmuch-tag and notmuch-restore.\r
80 >\r
81 > The bulk of the routines implement a "tag operation list" abstract\r
82 > data type act as a structured representation of a set of tag\r
83 > operations (typically coming from a single tag command or line of\r
84 > input).\r
85 > ---\r
86 >  Makefile.local |    1 +\r
87 >  tag-util.c     |  278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
88 >  tag-util.h     |  119 ++++++++++++++++++++++++\r
89 >  3 files changed, 398 insertions(+)\r
90 >  create mode 100644 tag-util.c\r
91 >  create mode 100644 tag-util.h\r
92 >\r
93 > diff --git a/Makefile.local b/Makefile.local\r
94 > index 2b91946..854867d 100644\r
95 > --- a/Makefile.local\r
96 > +++ b/Makefile.local\r
97 > @@ -274,6 +274,7 @@ notmuch_client_srcs =             \\r
98 >       query-string.c          \\r
99 >       mime-node.c             \\r
100 >       crypto.c                \\r
101 > +     tag-util.c\r
102 >  \r
103 >  notmuch_client_modules = $(notmuch_client_srcs:.c=.o)\r
104 >  \r
105 > diff --git a/tag-util.c b/tag-util.c\r
106 > new file mode 100644\r
107 > index 0000000..932ee7f\r
108 > --- /dev/null\r
109 > +++ b/tag-util.c\r
110 > @@ -0,0 +1,278 @@\r
111 > +#include <assert.h>\r
112 > +#include "string-util.h"\r
113 > +#include "tag-util.h"\r
114 > +#include "hex-escape.h"\r
115 > +\r
116 > +#define TAG_OP_LIST_INITIAL_SIZE 10\r
117 > +\r
118 > +struct _tag_operation_t {\r
119 > +    const char *tag;\r
120 > +    notmuch_bool_t remove;\r
121 > +};\r
122 > +\r
123 > +struct _tag_op_list_t {\r
124 > +    tag_operation_t *ops;\r
125 > +    size_t count;\r
126 > +    size_t size;\r
127 > +};\r
128 > +\r
129 > +int\r
130 > +parse_tag_line (void *ctx, char *line,\r
131 > +             tag_op_flag_t flags,\r
132 > +             char **query_string,\r
133 > +             tag_op_list_t *tag_ops)\r
134 > +{\r
135 > +    char *tok = line;\r
136 > +    size_t tok_len = 0;\r
137 > +    char *line_for_error = talloc_strdup (ctx, line);\r
138 > +    int ret = 0;\r
139 > +\r
140 > +    chomp_newline (line);\r
141 > +\r
142 > +    /* remove leading space */\r
143 > +    while (*tok == ' ' || *tok == '\t')\r
144 > +     tok++;\r
145 > +\r
146 > +    /* Skip empty and comment lines. */\r
147 > +    if (*tok == '\0' || *tok == '#') {\r
148 > +     ret = 1;\r
149 > +     goto DONE;\r
150 > +    }\r
151 > +\r
152 > +    tag_op_list_reset (tag_ops);\r
153 > +\r
154 > +    /* Parse tags. */\r
155 > +    while ((tok = strtok_len (tok + tok_len, " ", &tok_len)) != NULL) {\r
156 > +     notmuch_bool_t remove;\r
157 > +     char *tag;\r
158 > +\r
159 > +     /* Optional explicit end of tags marker. */\r
160 > +     if (tok_len == 2 && strncmp (tok, "--", tok_len) == 0) {\r
161 > +         tok = strtok_len (tok + tok_len, " ", &tok_len);\r
162 > +         break;\r
163 > +     }\r
164 > +\r
165 > +     /* Implicit end of tags. */\r
166 > +     if (*tok != '-' && *tok != '+')\r
167 > +         break;\r
168 > +\r
169 > +     /* If tag is terminated by NUL, there's no query string. */\r
170 > +     if (*(tok + tok_len) == '\0') {\r
171 > +         fprintf (stderr, "no query string: %s\n", line_for_error);\r
172 > +         ret = 1;\r
173 > +         goto DONE;\r
174 > +     }\r
175 > +\r
176 > +     /* Terminate, and start next token after terminator. */\r
177 > +     *(tok + tok_len++) = '\0';\r
178 > +\r
179 > +     remove = (*tok == '-');\r
180 > +     tag = tok + 1;\r
181 > +\r
182 > +     /* Maybe refuse empty tags. */\r
183 > +     if (! (flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {\r
184 > +         fprintf (stderr, "Error: empty tag: %s\n", line_for_error);\r
185 > +         goto DONE;\r
186 > +     }\r
187 > +\r
188 > +     /* Decode tag. */\r
189 > +     if (hex_decode_inplace (tag) != HEX_SUCCESS) {\r
190 > +         fprintf (stderr, "Hex decoding of tag %s failed\n",\r
191 > +                  tag);\r
192 > +         ret = 1;\r
193 > +         goto DONE;\r
194 > +     }\r
195 > +\r
196 > +     if (tag_op_list_append (ctx, tag_ops, tag, remove)) {\r
197 > +         ret = -1;\r
198 > +         goto DONE;\r
199 > +     }\r
200 > +    }\r
201 > +\r
202 > +    if (tok == NULL) {\r
203 > +     fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",\r
204 > +              line_for_error);\r
205 > +     ret = 1;\r
206 > +     goto DONE;\r
207 > +    }\r
208 > +\r
209 > +    /* tok now points to the query string */\r
210 > +    if (hex_decode_inplace (tok) != HEX_SUCCESS) {\r
211 > +     fprintf (stderr, "Hex decoding of query %s failed\n",\r
212 > +              tok);\r
213 \r
214 \r
215 For these hex_decode errors would it be worth printing the full line as\r
216 well as the bit that fails hex_decode? Perhaps put something under DONE:\r
217 to print the whole line if ret is not success?\r
218 \r
219 Otherwise LGTM\r
220 \r
221 Mark\r
222 \r
223 \r
224 > +     ret = 1;\r
225 > +     goto DONE;\r
226 > +    }\r
227 > +\r
228 > +    *query_string = tok;\r
229 > +  DONE:\r
230 > +    talloc_free (line_for_error);\r
231 > +    return ret;\r
232 > +}\r
233 > +\r
234 > +static inline void\r
235 > +message_error (notmuch_message_t *message,\r
236 > +            notmuch_status_t status,\r
237 > +            const char *format, ...)\r
238 > +{\r
239 > +    va_list va_args;\r
240 > +\r
241 > +    va_start (va_args, format);\r
242 > +\r
243 > +    vfprintf (stderr, format, va_args);\r
244 > +    fprintf (stderr, "Message-ID: %s\n", notmuch_message_get_message_id (message));\r
245 > +    fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));\r
246 > +}\r
247 > +\r
248 > +notmuch_status_t\r
249 > +tag_op_list_apply (notmuch_message_t *message,\r
250 > +                tag_op_list_t *list,\r
251 > +                tag_op_flag_t flags)\r
252 > +{\r
253 > +    size_t i;\r
254 > +    notmuch_status_t status = 0;\r
255 > +    tag_operation_t *tag_ops = list->ops;\r
256 > +\r
257 > +    status = notmuch_message_freeze (message);\r
258 > +    if (status) {\r
259 > +     message_error (message, status, "freezing message");\r
260 > +     return status;\r
261 > +    }\r
262 > +\r
263 > +    if (flags & TAG_FLAG_REMOVE_ALL) {\r
264 > +     status = notmuch_message_remove_all_tags (message);\r
265 > +     if (status) {\r
266 > +         message_error (message, status, "removing all tags");\r
267 > +         return status;\r
268 > +     }\r
269 > +    }\r
270 > +\r
271 > +    for (i = 0; i < list->count; i++) {\r
272 > +     if (tag_ops[i].remove) {\r
273 > +         status = notmuch_message_remove_tag (message, tag_ops[i].tag);\r
274 > +         if (status) {\r
275 > +             message_error (message, status, "removing tag %s", tag_ops[i].tag);\r
276 > +             return status;\r
277 > +         }\r
278 > +     } else {\r
279 > +         status = notmuch_message_add_tag (message, tag_ops[i].tag);\r
280 > +         if (status) {\r
281 > +             message_error (message, status, "adding tag %s", tag_ops[i].tag);\r
282 > +             return status;\r
283 > +         }\r
284 > +\r
285 > +     }\r
286 > +    }\r
287 > +\r
288 > +    status = notmuch_message_thaw (message);\r
289 > +    if (status) {\r
290 > +     message_error (message, status, "thawing message");\r
291 > +     return status;\r
292 > +    }\r
293 > +\r
294 > +\r
295 > +    if (flags & TAG_FLAG_MAILDIR_SYNC) {\r
296 > +     status = notmuch_message_tags_to_maildir_flags (message);\r
297 > +     if (status) {\r
298 > +         message_error (message, status, "synching tags to maildir");\r
299 > +         return status;\r
300 > +     }\r
301 > +    }\r
302 > +\r
303 > +    return NOTMUCH_STATUS_SUCCESS;\r
304 > +\r
305 > +}\r
306 > +\r
307 > +\r
308 > +/* Array of tagging operations (add or remove.  Size will be increased\r
309 > + * as necessary. */\r
310 > +\r
311 > +tag_op_list_t *\r
312 > +tag_op_list_create (void *ctx)\r
313 > +{\r
314 > +    tag_op_list_t *list;\r
315 > +\r
316 > +    list = talloc (ctx, tag_op_list_t);\r
317 > +    if (list == NULL)\r
318 > +     return NULL;\r
319 > +\r
320 > +    list->size = TAG_OP_LIST_INITIAL_SIZE;\r
321 > +    list->count = 0;\r
322 > +\r
323 > +    list->ops = talloc_array (ctx, tag_operation_t, list->size);\r
324 > +    if (list->ops == NULL)\r
325 > +     return NULL;\r
326 > +\r
327 > +    return list;\r
328 > +}\r
329 > +\r
330 > +\r
331 > +int\r
332 > +tag_op_list_append (void *ctx,\r
333 > +                 tag_op_list_t *list,\r
334 > +                 const char *tag,\r
335 > +                 notmuch_bool_t remove)\r
336 > +{\r
337 > +    /* Make room if current array is full.  This should be a fairly\r
338 > +     * rare case, considering the initial array size.\r
339 > +     */\r
340 > +\r
341 > +    if (list->count == list->size) {\r
342 > +     list->size *= 2;\r
343 > +     list->ops = talloc_realloc (ctx, list->ops, tag_operation_t,\r
344 > +                                 list->size);\r
345 > +     if (list->ops == NULL) {\r
346 > +         fprintf (stderr, "Out of memory.\n");\r
347 > +         return 1;\r
348 > +     }\r
349 > +    }\r
350 > +\r
351 > +    /* add the new operation */\r
352 > +\r
353 > +    list->ops[list->count].tag = tag;\r
354 > +    list->ops[list->count].remove = remove;\r
355 > +    list->count++;\r
356 > +    return 0;\r
357 > +}\r
358 > +\r
359 > +/*\r
360 > + *   Is the i'th tag operation a remove?\r
361 > + */\r
362 > +\r
363 > +notmuch_bool_t\r
364 > +tag_op_list_isremove (const tag_op_list_t *list, size_t i)\r
365 > +{\r
366 > +    assert (i < list->count);\r
367 > +    return list->ops[i].remove;\r
368 > +}\r
369 > +\r
370 > +/*\r
371 > + * Reset a list to contain no operations\r
372 > + */\r
373 > +\r
374 > +void\r
375 > +tag_op_list_reset (tag_op_list_t *list)\r
376 > +{\r
377 > +    list->count = 0;\r
378 > +}\r
379 > +\r
380 > +/*\r
381 > + * Return the number of operations in a list\r
382 > + */\r
383 > +\r
384 > +size_t\r
385 > +tag_op_list_size (const tag_op_list_t *list)\r
386 > +{\r
387 > +    return list->count;\r
388 > +}\r
389 > +\r
390 > +/*\r
391 > + *   return the i'th tag in the list\r
392 > + */\r
393 > +\r
394 > +const char *\r
395 > +tag_op_list_tag (const tag_op_list_t *list, size_t i)\r
396 > +{\r
397 > +    assert (i < list->count);\r
398 > +    return list->ops[i].tag;\r
399 > +}\r
400 > diff --git a/tag-util.h b/tag-util.h\r
401 > new file mode 100644\r
402 > index 0000000..df05d72\r
403 > --- /dev/null\r
404 > +++ b/tag-util.h\r
405 > @@ -0,0 +1,119 @@\r
406 > +#ifndef _TAG_UTIL_H\r
407 > +#define _TAG_UTIL_H\r
408 > +\r
409 > +#include "notmuch-client.h"\r
410 > +\r
411 > +typedef struct _tag_operation_t tag_operation_t;\r
412 > +typedef struct _tag_op_list_t tag_op_list_t;\r
413 > +\r
414 > +/* Use powers of 2 */\r
415 > +typedef enum {\r
416 > +    TAG_FLAG_NONE = 0,\r
417 > +\r
418 > +    /* Operations are synced to maildir, if possible.\r
419 > +     */\r
420 > +    TAG_FLAG_MAILDIR_SYNC = (1 << 0),\r
421 > +\r
422 > +    /* Remove all tags from message before applying list.\r
423 > +     */\r
424 > +    TAG_FLAG_REMOVE_ALL = (1 << 1),\r
425 > +\r
426 > +    /* Don't try to avoid database operations. Useful when we\r
427 > +     * know that message passed needs these operations.\r
428 > +      */\r
429 > +    TAG_FLAG_PRE_OPTIMIZED = (1 << 2),\r
430 > +\r
431 > +    /* Accept strange tags that might be user error;\r
432 > +     * intended for use by notmuch-restore.\r
433 > +     */\r
434 > +    TAG_FLAG_BE_GENEROUS = (1 << 3)\r
435 > +\r
436 > +} tag_op_flag_t;\r
437 > +\r
438 > +/* Parse a string of the following format:\r
439 > + *\r
440 > + * +<tag>|-<tag> [...] [--] <search-terms>\r
441 > + *\r
442 > + * Each line is interpreted similarly to "notmuch tag" command line\r
443 > + * arguments. The delimiter is one or more spaces ' '. Any characters\r
444 > + * in <tag> and <search-terms> MAY be hex encoded with %NN where NN is\r
445 > + * the hexadecimal value of the character. Any ' ' and '%' characters\r
446 > + * in <tag> and <search-terms> MUST be hex encoded (using %20 and %25,\r
447 > + * respectively). Any characters that are not part of <tag> or\r
448 > + * <search-terms> MUST NOT be hex encoded.\r
449 > + *\r
450 > + * Leading and trailing space ' ' is ignored. Empty lines and lines\r
451 > + * beginning with '#' are ignored.\r
452 > + *\r
453 > + * Returns: 0 for OK, 1 for skipped line, -1 for fatal(ish) error.\r
454 > + *\r
455 > + * Output Parameters:\r
456 > + *   ops     contains a list of tag operations\r
457 > + *   query_str the search terms.\r
458 > + */\r
459 > +int\r
460 > +parse_tag_line (void *ctx, char *line,\r
461 > +             tag_op_flag_t flags,\r
462 > +             char **query_str, tag_op_list_t *ops);\r
463 > +\r
464 > +/*\r
465 > + * Create an empty list of tag operations\r
466 > + *\r
467 > + * ctx is passed to talloc\r
468 > + */\r
469 > +\r
470 > +tag_op_list_t\r
471 > +*tag_op_list_create (void *ctx);\r
472 > +\r
473 > +/*\r
474 > + * Add a tag operation (delete iff remove == TRUE) to a list.\r
475 > + * The list is expanded as necessary.\r
476 > + */\r
477 > +\r
478 > +int\r
479 > +tag_op_list_append (void *ctx,\r
480 > +                 tag_op_list_t *list,\r
481 > +                 const char *tag,\r
482 > +                 notmuch_bool_t remove);\r
483 > +\r
484 > +/*\r
485 > + * Apply a list of tag operations, in order, to a given message.\r
486 > + *\r
487 > + * Flags can be bitwise ORed; see enum above for possibilies.\r
488 > + */\r
489 > +\r
490 > +notmuch_status_t\r
491 > +tag_op_list_apply (notmuch_message_t *message,\r
492 > +                tag_op_list_t *tag_ops,\r
493 > +                tag_op_flag_t flags);\r
494 > +\r
495 > +/*\r
496 > + * Return the number of operations in a list\r
497 > + */\r
498 > +\r
499 > +size_t\r
500 > +tag_op_list_size (const tag_op_list_t *list);\r
501 > +\r
502 > +/*\r
503 > + * Reset a list to contain no operations\r
504 > + */\r
505 > +\r
506 > +void\r
507 > +tag_op_list_reset (tag_op_list_t *list);\r
508 > +\r
509 > +\r
510 > + /*\r
511 > +  *   return the i'th tag in the list\r
512 > +  */\r
513 > +\r
514 > +const char *\r
515 > +tag_op_list_tag (const tag_op_list_t *list, size_t i);\r
516 > +\r
517 > +/*\r
518 > + *   Is the i'th tag operation a remove?\r
519 > + */\r
520 > +\r
521 > +notmuch_bool_t\r
522 > +tag_op_list_isremove (const tag_op_list_t *list, size_t i);\r
523 > +\r
524 > +#endif\r
525 > -- \r
526 > 1.7.10.4\r
527 >\r
528 > _______________________________________________\r
529 > notmuch mailing list\r
530 > notmuch@notmuchmail.org\r
531 > http://notmuchmail.org/mailman/listinfo/notmuch\r