[PATCH] configure: add --without-api-docs option
[notmuch-archives.git] / 56 / ffbae58633faaec6132fb3d06577273e0039f3
1 Return-Path: <bremner@tethera.net>\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 66FDC431FBF\r
6         for <notmuch@notmuchmail.org>; Sun, 18 Nov 2012 11:05:34 -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 tests=[none]\r
12         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 zqhzYSnasydp for <notmuch@notmuchmail.org>;\r
16         Sun, 18 Nov 2012 11:05:31 -0800 (PST)\r
17 Received: from tesseract.cs.unb.ca (tesseract.cs.unb.ca [131.202.240.238])\r
18         (using TLSv1 with cipher AES256-SHA (256/256 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id 3515F431FAF\r
21         for <notmuch@notmuchmail.org>; Sun, 18 Nov 2012 11:05:19 -0800 (PST)\r
22 Received: from fctnnbsc30w-156034089108.dhcp-dynamic.fibreop.nb.bellaliant.net\r
23         ([156.34.89.108] helo=zancas.localnet)\r
24         by tesseract.cs.unb.ca with esmtpsa\r
25         (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.72)\r
26         (envelope-from <bremner@tethera.net>)\r
27         id 1TaABC-000288-2Z; Sun, 18 Nov 2012 15:05:18 -0400\r
28 Received: from bremner by zancas.localnet with local (Exim 4.80)\r
29         (envelope-from <bremner@tethera.net>)\r
30         id 1TaAB6-0001Ij-Hd; Sun, 18 Nov 2012 15:05:12 -0400\r
31 From: david@tethera.net\r
32 To: notmuch@notmuchmail.org\r
33 Subject: [PATCH 08/16] tag-util.[ch]: New files for common tagging routines\r
34 Date: Sun, 18 Nov 2012 15:04:50 -0400\r
35 Message-Id: <1353265498-3839-9-git-send-email-david@tethera.net>\r
36 X-Mailer: git-send-email 1.7.10.4\r
37 In-Reply-To: <1353265498-3839-1-git-send-email-david@tethera.net>\r
38 References: <1353265498-3839-1-git-send-email-david@tethera.net>\r
39 X-Spam_bar: -\r
40 Cc: David Bremner <bremner@debian.org>\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: Sun, 18 Nov 2012 19:05:34 -0000\r
54 \r
55 From: David Bremner <bremner@debian.org>\r
56 \r
57 These are meant to be shared between notmuch-tag and notmuch-restore.\r
58 \r
59 The bulk of the routines implement a "tag operation list" abstract\r
60 data type act as a structured representation of a set of tag\r
61 operations (typically coming from a single tag command or line of\r
62 input).\r
63 ---\r
64  Makefile.local |    1 +\r
65  tag-util.c     |  273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
66  tag-util.h     |   71 +++++++++++++++\r
67  3 files changed, 345 insertions(+)\r
68  create mode 100644 tag-util.c\r
69  create mode 100644 tag-util.h\r
70 \r
71 diff --git a/Makefile.local b/Makefile.local\r
72 index 2b91946..854867d 100644\r
73 --- a/Makefile.local\r
74 +++ b/Makefile.local\r
75 @@ -274,6 +274,7 @@ notmuch_client_srcs =               \\r
76         query-string.c          \\r
77         mime-node.c             \\r
78         crypto.c                \\r
79 +       tag-util.c\r
80  \r
81  notmuch_client_modules = $(notmuch_client_srcs:.c=.o)\r
82  \r
83 diff --git a/tag-util.c b/tag-util.c\r
84 new file mode 100644\r
85 index 0000000..5329b1f\r
86 --- /dev/null\r
87 +++ b/tag-util.c\r
88 @@ -0,0 +1,273 @@\r
89 +#include "tag-util.h"\r
90 +#include "hex-escape.h"\r
91 +\r
92 +static char *\r
93 +strtok_len (char *s, const char *delim, size_t *len)\r
94 +{\r
95 +    /* skip initial delims */\r
96 +    s += strspn (s, delim);\r
97 +\r
98 +    /* length of token */\r
99 +    *len = strcspn (s, delim);\r
100 +\r
101 +    return *len ? s : NULL;\r
102 +}\r
103 +\r
104 +/* Tag messages according to 'input', which must consist of lines of\r
105 + * the format:\r
106 + *\r
107 + * +<tag>|-<tag> [...] [--] <search-terms>\r
108 + *\r
109 + * Each line is interpreted similarly to "notmuch tag" command line\r
110 + * arguments. The delimiter is one or more spaces ' '. Any characters\r
111 + * in <tag> and <search-terms> MAY be hex encoded with %NN where NN is\r
112 + * the hexadecimal value of the character. Any ' ' and '%' characters\r
113 + * in <tag> and <search-terms> MUST be hex encoded (using %20 and %25,\r
114 + * respectively). Any characters that are not part of <tag> or\r
115 + * <search-terms> MUST NOT be hex encoded.\r
116 + *\r
117 + * Leading and trailing space ' ' is ignored. Empty lines and lines\r
118 + * beginning with '#' are ignored.\r
119 + */\r
120 +int\r
121 +parse_tag_line (void *ctx, char *line,\r
122 +               char **query_string,\r
123 +               tag_op_list_t *tag_ops)\r
124 +{\r
125 +    char *tok = line;\r
126 +    size_t tok_len = 0;\r
127 +\r
128 +    chomp_newline (line);\r
129 +    tag_op_list_reset (tag_ops);\r
130 +\r
131 +    /* Parse tags. */\r
132 +    while ((tok = strtok_len (tok + tok_len, " ", &tok_len)) != NULL) {\r
133 +       notmuch_bool_t remove;\r
134 +       char *tag;\r
135 +\r
136 +       /* Optional explicit end of tags marker. */\r
137 +       if (strncmp (tok, "--", tok_len) == 0) {\r
138 +           tok = strtok_len (tok + tok_len, " ", &tok_len);\r
139 +           break;\r
140 +       }\r
141 +\r
142 +       /* Implicit end of tags. */\r
143 +       if (*tok != '-' && *tok != '+')\r
144 +           break;\r
145 +\r
146 +       /* If tag is terminated by NUL, there's no query string. */\r
147 +       if (*(tok + tok_len) == '\0') {\r
148 +           tok = NULL;\r
149 +           break;\r
150 +       }\r
151 +\r
152 +       /* Terminate, and start next token after terminator. */\r
153 +       *(tok + tok_len++) = '\0';\r
154 +\r
155 +       remove = (*tok == '-');\r
156 +       tag = tok + 1;\r
157 +\r
158 +       /* Refuse empty tags. */\r
159 +       if (*tag == '\0') {\r
160 +           tok = NULL;\r
161 +           break;\r
162 +       }\r
163 +\r
164 +       /* Decode tag. */\r
165 +       if (hex_decode_inplace (tag) != HEX_SUCCESS) {\r
166 +           tok = NULL;\r
167 +           break;\r
168 +       }\r
169 +\r
170 +       if (tag_op_list_append (ctx, tag_ops, tag, remove))\r
171 +           return -1;\r
172 +    }\r
173 +\r
174 +    if (tok == NULL || tag_ops->count == 0) {\r
175 +       /* FIXME: line has been modified! */\r
176 +       fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",\r
177 +                line);\r
178 +       return 1;\r
179 +    }\r
180 +\r
181 +    /* tok now points to the query string */\r
182 +    if (hex_decode_inplace (tok) != HEX_SUCCESS) {\r
183 +       /* FIXME: line has been modified! */\r
184 +       fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",\r
185 +                line);\r
186 +       return 1;\r
187 +    }\r
188 +\r
189 +    *query_string = tok;\r
190 +\r
191 +    return 0;\r
192 +}\r
193 +\r
194 +static inline void\r
195 +message_error (notmuch_message_t *message,\r
196 +              notmuch_status_t status,\r
197 +              const char *format, ...)\r
198 +{\r
199 +    va_list va_args;\r
200 +\r
201 +    va_start (va_args, format);\r
202 +\r
203 +    vfprintf (stderr, format, va_args);\r
204 +    fprintf (stderr, "Message-ID: %s\n", notmuch_message_get_message_id (message));\r
205 +    fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));\r
206 +}\r
207 +\r
208 +notmuch_status_t\r
209 +tag_op_list_apply (notmuch_message_t *message,\r
210 +                  tag_op_list_t *list,\r
211 +                  tag_op_flag_t flags)\r
212 +{\r
213 +    int i;\r
214 +\r
215 +    notmuch_status_t status = 0;\r
216 +    tag_operation_t *tag_ops = list->ops;\r
217 +\r
218 +    status = notmuch_message_freeze (message);\r
219 +    if (status) {\r
220 +       message_error (message, status, "freezing message");\r
221 +       return status;\r
222 +    }\r
223 +\r
224 +    if (flags & TAG_FLAG_REMOVE_ALL) {\r
225 +       status = notmuch_message_remove_all_tags (message);\r
226 +       if (status) {\r
227 +           message_error (message, status, "removing all tags" );\r
228 +           return status;\r
229 +       }\r
230 +    }\r
231 +\r
232 +    for (i = 0; i < list->count; i++) {\r
233 +       if (tag_ops[i].remove) {\r
234 +           status = notmuch_message_remove_tag (message, tag_ops[i].tag);\r
235 +           if (status) {\r
236 +               message_error (message, status, "removing tag %s", tag_ops[i].tag);\r
237 +               return status;\r
238 +           }\r
239 +       } else {\r
240 +           status = notmuch_message_add_tag (message, tag_ops[i].tag);\r
241 +           if (status) {\r
242 +               message_error (message, status, "adding tag %s", tag_ops[i].tag);\r
243 +               return status;\r
244 +           }\r
245 +\r
246 +       }\r
247 +    }\r
248 +\r
249 +    status = notmuch_message_thaw (message);\r
250 +    if (status) {\r
251 +       message_error (message, status, "thawing message");\r
252 +       return status;\r
253 +    }\r
254 +\r
255 +\r
256 +    if (flags & TAG_FLAG_MAILDIR_SYNC) {\r
257 +       status = notmuch_message_tags_to_maildir_flags (message);\r
258 +       if (status) {\r
259 +           message_error (message, status, "synching tags to maildir");\r
260 +           return status;\r
261 +       }\r
262 +    }\r
263 +\r
264 +    return NOTMUCH_STATUS_SUCCESS;\r
265 +\r
266 +}\r
267 +\r
268 +\r
269 +/* Array of tagging operations (add or remove), terminated with an\r
270 + * empty element. Size will be increased as necessary. */\r
271 +\r
272 +tag_op_list_t *\r
273 +tag_op_list_create (void *ctx)\r
274 +{\r
275 +    tag_op_list_t *list;\r
276 +\r
277 +    list = talloc (ctx, tag_op_list_t);\r
278 +    if (list == NULL)\r
279 +       return NULL;\r
280 +\r
281 +    list->size = TAG_OP_LIST_INITIAL_SIZE;\r
282 +    list->count = 0;\r
283 +\r
284 +    list->ops = talloc_array (ctx, tag_operation_t, list->size);\r
285 +    if (list->ops == NULL)\r
286 +       return NULL;\r
287 +\r
288 +    return list;\r
289 +}\r
290 +\r
291 +\r
292 +int\r
293 +tag_op_list_append (void *ctx,\r
294 +                   tag_op_list_t *list,\r
295 +                   const char *tag,\r
296 +                   notmuch_bool_t remove)\r
297 +{\r
298 +    list->ops[list->count].tag = tag;\r
299 +    list->ops[list->count].remove = remove;\r
300 +    list->count++;\r
301 +\r
302 +    /* Make room for terminating empty element and potential\r
303 +     * new tags, if necessary. This should be a fairly rare\r
304 +     * case, considering the initial array size. */\r
305 +    if (list->count == list->size) {\r
306 +       list->size *= 2;\r
307 +       list->ops = talloc_realloc (ctx, list->ops, tag_operation_t,\r
308 +                                   list->size);\r
309 +       if (list->ops == NULL) {\r
310 +           fprintf (stderr, "Out of memory.\n");\r
311 +           return 1;\r
312 +       }\r
313 +    }\r
314 +\r
315 +    list->ops[list->count].tag = NULL;\r
316 +\r
317 +    return 0;\r
318 +}\r
319 +\r
320 +\r
321 +/* WARNING: modifies it's string argument */\r
322 +\r
323 +int\r
324 +tag_op_list_from_string (void *ctx,\r
325 +                        char *tag_string,\r
326 +                        notmuch_bool_t remove,\r
327 +                        tag_op_list_t *tag_ops)\r
328 +{\r
329 +    char *tok = tag_string;\r
330 +    size_t tok_len = 0;\r
331 +\r
332 +    tag_op_list_reset (tag_ops);\r
333 +\r
334 +/* Parse tags. */\r
335 +    while ((tok = strtok_len (tok + tok_len, " ", &tok_len)) != NULL) {\r
336 +\r
337 +       if (*(tok + tok_len) != '\0') {\r
338 +           *(tok + tok_len) = '\0';\r
339 +           tok_len++;\r
340 +       }\r
341 +\r
342 +       if (tag_op_list_append (ctx, tag_ops, tok, remove))\r
343 +           return -1;\r
344 +    }\r
345 +\r
346 +    return 0;\r
347 +\r
348 +}\r
349 +\r
350 +notmuch_bool_t\r
351 +tag_op_list_empty (tag_op_list_t *list)\r
352 +{\r
353 +    return (list->count == 0);\r
354 +}\r
355 +\r
356 +\r
357 +void\r
358 +tag_op_list_reset (tag_op_list_t *list)\r
359 +{\r
360 +    list->count = 0;\r
361 +}\r
362 diff --git a/tag-util.h b/tag-util.h\r
363 new file mode 100644\r
364 index 0000000..b381b8e\r
365 --- /dev/null\r
366 +++ b/tag-util.h\r
367 @@ -0,0 +1,71 @@\r
368 +#ifndef _TAG_UTIL_H\r
369 +#define _TAG_UTIL_H\r
370 +\r
371 +#include "notmuch-client.h"\r
372 +\r
373 +typedef struct {\r
374 +    const char *tag;\r
375 +    notmuch_bool_t remove;\r
376 +} tag_operation_t;\r
377 +\r
378 +#define TAG_OP_LIST_INITIAL_SIZE 10\r
379 +\r
380 +typedef struct {\r
381 +    tag_operation_t *ops;\r
382 +    int count;\r
383 +    int size;\r
384 +} tag_op_list_t;\r
385 +\r
386 +/* Use powers of 2 */\r
387 +typedef enum  { TAG_FLAG_NONE = 0,\r
388 +               TAG_FLAG_MAILDIR_SYNC = 1,\r
389 +               TAG_FLAG_REMOVE_ALL = 2 } tag_op_flag_t;\r
390 +\r
391 +\r
392 +typedef int (*tag_callback_t)(void *ctx,\r
393 +                             notmuch_database_t *notmuch,\r
394 +                             const char *query_string,\r
395 +                             tag_op_list_t *tag_ops,\r
396 +                             tag_op_flag_t flags);\r
397 +\r
398 +int\r
399 +parse_tag_stream (void *ctx,\r
400 +                 notmuch_database_t *notmuch,\r
401 +                 FILE *input,\r
402 +                 tag_callback_t callback,\r
403 +                 tag_op_flag_t flags,\r
404 +                 volatile sig_atomic_t *interrupted);\r
405 +\r
406 +/*\r
407 + * Returns: 0 for OK, 1 for skipped line, -1 for fatal(ish) error.\r
408 + */\r
409 +int\r
410 +parse_tag_line (void *ctx, char *line, char **query_str, tag_op_list_t *ops);\r
411 +\r
412 +tag_op_list_t\r
413 +*tag_op_list_create (void *ctx);\r
414 +\r
415 +int\r
416 +tag_op_list_append (void *ctx,\r
417 +                   tag_op_list_t *list,\r
418 +                   const char *tag,\r
419 +                   notmuch_bool_t remove);\r
420 +\r
421 +notmuch_status_t\r
422 +tag_op_list_apply (notmuch_message_t *message,\r
423 +                  tag_op_list_t *tag_ops,\r
424 +                  tag_op_flag_t flags);\r
425 +\r
426 +int\r
427 +tag_op_list_from_string (void *ctx,\r
428 +                        char *tag_string,\r
429 +                        notmuch_bool_t remove,\r
430 +                        tag_op_list_t *tag_ops);\r
431 +\r
432 +notmuch_bool_t\r
433 +tag_op_list_empty (tag_op_list_t *list);\r
434 +\r
435 +void\r
436 +tag_op_list_reset (tag_op_list_t *list);\r
437 +\r
438 +#endif\r
439 -- \r
440 1.7.10.4\r
441 \r