"snoozing" with notmuch?
[notmuch-archives.git] / 50 / f3f36b3482898b3525b52b7042528f933e22e3
1 Return-Path: <amdragon@mit.edu>\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 C68EE431FAF\r
6         for <notmuch@notmuchmail.org>; Sun,  6 Jan 2013 12:23:13 -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.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] 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 ktdQvEuy5Zas for <notmuch@notmuchmail.org>;\r
16         Sun,  6 Jan 2013 12:23:12 -0800 (PST)\r
17 Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU\r
18         [18.7.68.35])\r
19         by olra.theworths.org (Postfix) with ESMTP id E6FAE431FAE\r
20         for <notmuch@notmuchmail.org>; Sun,  6 Jan 2013 12:23:11 -0800 (PST)\r
21 X-AuditID: 12074423-b7ef96d000000725-20-50e9dd2ed548\r
22 Received: from mailhub-auth-4.mit.edu ( [18.7.62.39])\r
23         by dmz-mailsec-scanner-6.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id A6.D1.01829.E2DD9E05; Sun,  6 Jan 2013 15:23:10 -0500 (EST)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-4.mit.edu (8.13.8/8.9.2) with ESMTP id r06KN9tj012714; \r
27         Sun, 6 Jan 2013 15:23:09 -0500\r
28 Received: from drake.dyndns.org (a069.catapulsion.net [70.36.81.69])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id r06KMqP7020340\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Sun, 6 Jan 2013 15:23:02 -0500 (EST)\r
34 Received: from amthrax by drake.dyndns.org with local (Exim 4.77)\r
35         (envelope-from <amdragon@mit.edu>)\r
36         id 1Trwk5-0007Y6-EE; Sun, 06 Jan 2013 15:22:49 -0500\r
37 From: Austin Clements <amdragon@MIT.EDU>\r
38 To: notmuch@notmuchmail.org\r
39 Subject: [PATCH v5 0/6] Use Xapian query syntax for batch-tag dump/restore\r
40 Date: Sun,  6 Jan 2013 15:22:36 -0500\r
41 Message-Id: <1357503762-28759-1-git-send-email-amdragon@mit.edu>\r
42 X-Mailer: git-send-email 1.7.10.4\r
43 X-Brightmail-Tracker:\r
44  H4sIAAAAAAAAA+NgFjrEIsWRmVeSWpSXmKPExsUixG6nrqt392WAwdmnghY3WrsZLZqmO1us\r
45         nstjcf3mTGaLNyvnsTqweuycdZfd4/DXhSwet+6/Zvd4tuoWs8eWQ++ZA1ijuGxSUnMyy1KL\r
46         9O0SuDKmLHnFWLA5oGLC4nlMDYz7bLsYOTkkBEwkFt2/wAZhi0lcuLceyObiEBLYxyixceMr\r
47         VghnPaPEq1/PoDL7mSQmTFjOAuHMZZR48mozC0g/m4CGxLb9yxlBbBEBaYmdd2ezgtjMAnES\r
48         Ky8tZgexhQW8JKb0TAXbxyKgKtHyfDIziM0r4CBx/EMX1B2KEt3PJrBNYORdwMiwilE2JbdK\r
49         NzcxM6c4NVm3ODkxLy+1SNdMLzezRC81pXQTIzioXJR3MP45qHSIUYCDUYmH98LOFwFCrIll\r
50         xZW5hxglOZiURHl3X3wZIMSXlJ9SmZFYnBFfVJqTWnyIUYKDWUmEd98xoBxvSmJlVWpRPkxK\r
51         moNFSZz3WspNfyGB9MSS1OzU1ILUIpisDAeHkgSv5B2gRsGi1PTUirTMnBKENBMHJ8hwHqDh\r
52         L2+DDC8uSMwtzkyHyJ9iVJQS55UBaRYASWSU5sH1wqL+FaM40CvCvAYgVTzAhAHX/QpoMBPQ\r
53         4NTHz0EGlyQipKQaGB07rOXapmw7f/pHUNaS4utrqnfPtFn4oFNO5vzLa0bFleueiTHszt0a\r
54         v3/jxpi1X6/wXLHj2nCPQz3zzDoD811cnj8WnOIySkwvyDLleMwYuEgn0feNuJXIOr0LyQVB\r
55         ZvvdZ2du8Py8f7Vuy44UL/livkb3EK+jzcyRUdeWiRY7ZOWHRC3mUGIpzkg01GIuKk4EAGpD\r
56         +tDVAgAA\r
57 Cc: tomi.ollila@iki.fi\r
58 X-BeenThere: notmuch@notmuchmail.org\r
59 X-Mailman-Version: 2.1.13\r
60 Precedence: list\r
61 List-Id: "Use and development of the notmuch mail system."\r
62         <notmuch.notmuchmail.org>\r
63 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
64         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
65 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
66 List-Post: <mailto:notmuch@notmuchmail.org>\r
67 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
68 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
69         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
70 X-List-Received-Date: Sun, 06 Jan 2013 20:23:13 -0000\r
71 \r
72 This obsoletes\r
73 \r
74   id:1356936162-2589-1-git-send-email-amdragon@mit.edu\r
75 \r
76 v5 should address all of the comments on v4 except those I\r
77 specifically replied to (via the ML or IRC).  It also adds a new patch\r
78 at the beginning that makes missing message IDs non-fatal in restore,\r
79 like they were in 0.14.  This patch can be pushed separately; it's in\r
80 this series because later tests rely on it.\r
81 \r
82 The diff from v4 follows.\r
83 \r
84 diff --git a/notmuch-dump.c b/notmuch-dump.c\r
85 index bf01a39..a3244e0 100644\r
86 --- a/notmuch-dump.c\r
87 +++ b/notmuch-dump.c\r
88 @@ -103,6 +103,18 @@ notmuch_dump_command (unused (void *ctx), int argc, char *argv[])\r
89         message = notmuch_messages_get (messages);\r
90         message_id = notmuch_message_get_message_id (message);\r
91  \r
92 +       if (output_format == DUMP_FORMAT_BATCH_TAG &&\r
93 +           strchr (message_id, '\n')) {\r
94 +           /* This will produce a line break in the output, which\r
95 +            * would be difficult to handle in tools.  However, it's\r
96 +            * also impossible to produce an email containing a line\r
97 +            * break in a message ID because of unfolding, so we can\r
98 +            * safely disallow it. */\r
99 +           fprintf (stderr, "Warning: skipping message id containing line break: \"%s\"\n", message_id);\r
100 +           notmuch_message_destroy (message);\r
101 +           continue;\r
102 +       }\r
103 +\r
104         if (output_format == DUMP_FORMAT_SUP) {\r
105             fprintf (output, "%s (", message_id);\r
106         }\r
107 @@ -133,19 +145,10 @@ notmuch_dump_command (unused (void *ctx), int argc, char *argv[])\r
108         if (output_format == DUMP_FORMAT_SUP) {\r
109             fputs (")\n", output);\r
110         } else {\r
111 -           if (strchr (message_id, '\n')) {\r
112 -               /* This will produce a line break in the output, which\r
113 -                * would be difficult to handle in tools.  However,\r
114 -                * it's also impossible to produce an email containing\r
115 -                * a line break in a message ID because of unfolding,\r
116 -                * so we can safely disallow it. */\r
117 -               fprintf (stderr, "Error: cannot dump message id containing line break: %s\n", message_id);\r
118 -               return 1;\r
119 -           }\r
120             if (make_boolean_term (notmuch, "id", message_id,\r
121                                    &buffer, &buffer_size)) {\r
122 -                   fprintf (stderr, "Error: failed to quote message id %s\n",\r
123 -                            message_id);\r
124 +                   fprintf (stderr, "Error quoting message id %s: %s\n",\r
125 +                            message_id, strerror (errno));\r
126                     return 1;\r
127             }\r
128             fprintf (output, " -- %s\n", buffer);\r
129 diff --git a/notmuch-restore.c b/notmuch-restore.c\r
130 index 77a4c27..81d4d98 100644\r
131 --- a/notmuch-restore.c\r
132 +++ b/notmuch-restore.c\r
133 @@ -26,7 +26,8 @@\r
134  static regex_t regex;\r
135  \r
136  /* Non-zero return indicates an error in retrieving the message,\r
137 - * or in applying the tags.\r
138 + * or in applying the tags.  Missing messages are reported, but not\r
139 + * considered errors.\r
140   */\r
141  static int\r
142  tag_message (unused (void *ctx),\r
143 @@ -40,13 +41,17 @@ tag_message (unused (void *ctx),\r
144      int ret = 0;\r
145  \r
146      status = notmuch_database_find_message (notmuch, message_id, &message);\r
147 -    if (status || message == NULL) {\r
148 -       fprintf (stderr, "Warning: cannot apply tags to %smessage: %s\n",\r
149 -                message ? "" : "missing ", message_id);\r
150 -       if (status)\r
151 -           fprintf (stderr, "%s\n", notmuch_status_to_string (status));\r
152 +    if (status) {\r
153 +       fprintf (stderr, "Error applying tags to message %s: %s\n",\r
154 +                message_id, notmuch_status_to_string (status));\r
155         return 1;\r
156      }\r
157 +    if (message == NULL) {\r
158 +       fprintf (stderr, "Warning: cannot apply tags to missing message: %s\n",\r
159 +                message_id);\r
160 +       /* We consider this a non-fatal error. */\r
161 +       return 0;\r
162 +    }\r
163  \r
164      /* In order to detect missing messages, this check/optimization is\r
165       * intentionally done *after* first finding the message. */\r
166 @@ -222,12 +227,17 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
167             if (ret == 0) {\r
168                 ret = parse_boolean_term (line_ctx, query_string,\r
169                                           &prefix, &term);\r
170 -               if (ret) {\r
171 -                   fprintf (stderr, "Warning: cannot parse query: %s\n",\r
172 -                            query_string);\r
173 +               if (ret && errno == EINVAL) {\r
174 +                   fprintf (stderr, "Warning: cannot parse query: %s (skipping)\n", query_string);\r
175                     continue;\r
176 +               } else if (ret) {\r
177 +                   /* This is more fatal (e.g., out of memory) */\r
178 +                   fprintf (stderr, "Error parsing query: %s\n",\r
179 +                            strerror (errno));\r
180 +                   ret = 1;\r
181 +                   break;\r
182                 } else if (strcmp ("id", prefix) != 0) {\r
183 -                   fprintf (stderr, "Warning: not an id query: %s\n", query_string);\r
184 +                   fprintf (stderr, "Warning: not an id query: %s (skipping)\n", query_string);\r
185                     continue;\r
186                 }\r
187                 query_string = term;\r
188 diff --git a/test/dump-restore b/test/dump-restore\r
189 index f9ae5b3..f076c12 100755\r
190 --- a/test/dump-restore\r
191 +++ b/test/dump-restore\r
192 @@ -202,18 +202,32 @@ a\r
193  + +e -- id:20091117232137.GA7669@griffis1.net\r
194  # valid id, but warning about missing message\r
195  +e id:missing_message_id\r
196 +# exercise parser\r
197 ++e -- id:some)stuff\r
198 ++e -- id:some stuff\r
199 ++e -- id:some"stuff\r
200 ++e -- id:"a_message_id_with""_a_quote"\r
201 ++e -- id:"a message id with spaces"\r
202 ++e --  id:an_id_with_leading_and_trailing_ws \\r
203 +\r
204  EOF\r
205  \r
206  cat <<EOF > EXPECTED\r
207 -Warning: cannot parse query: a\r
208 +Warning: cannot parse query: a (skipping)\r
209  Warning: no query string [+0]\r
210  Warning: no query string [+a +b]\r
211  Warning: missing query string [+a +b ]\r
212  Warning: no query string after -- [+c +d --]\r
213  Warning: hex decoding of tag %zz failed [+%zz -- id:whatever]\r
214 -Warning: cannot parse query: id:"\r
215 -Warning: not an id query: tag:abc\r
216 +Warning: cannot parse query: id:" (skipping)\r
217 +Warning: not an id query: tag:abc (skipping)\r
218  Warning: cannot apply tags to missing message: missing_message_id\r
219 +Warning: cannot parse query: id:some)stuff (skipping)\r
220 +Warning: cannot parse query: id:some stuff (skipping)\r
221 +Warning: cannot apply tags to missing message: some"stuff\r
222 +Warning: cannot apply tags to missing message: a_message_id_with"_a_quote\r
223 +Warning: cannot apply tags to missing message: a message id with spaces\r
224 +Warning: cannot apply tags to missing message: an_id_with_leading_and_trailing_ws\r
225  EOF\r
226  \r
227  test_expect_equal_file EXPECTED OUTPUT\r
228 diff --git a/util/string-util.c b/util/string-util.c\r
229 index 52c7781..aba9aa8 100644\r
230 --- a/util/string-util.c\r
231 +++ b/util/string-util.c\r
232 @@ -23,6 +23,7 @@\r
233  #include "talloc.h"\r
234  \r
235  #include <ctype.h>\r
236 +#include <errno.h>\r
237  \r
238  char *\r
239  strtok_len (char *s, const char *delim, size_t *len)\r
240 @@ -36,6 +37,12 @@ strtok_len (char *s, const char *delim, size_t *len)\r
241      return *len ? s : NULL;\r
242  }\r
243  \r
244 +static int\r
245 +is_unquoted_terminator (unsigned char c)\r
246 +{\r
247 +    return c == 0 || c <= ' ' || c == ')';\r
248 +}\r
249 +\r
250  int\r
251  make_boolean_term (void *ctx, const char *prefix, const char *term,\r
252                    char **buf, size_t *len)\r
253 @@ -49,7 +56,8 @@ make_boolean_term (void *ctx, const char *prefix, const char *term,\r
254       * containing a quote, even though it only matters at the\r
255       * beginning, and anything containing non-ASCII text. */\r
256      for (in = term; *in && !need_quoting; in++)\r
257 -       if (*in <= ' ' || *in == ')' || *in == '"' || (unsigned char)*in > 127)\r
258 +       if (is_unquoted_terminator (*in) || *in == '"'\r
259 +           || (unsigned char)*in > 127)\r
260             need_quoting = 1;\r
261  \r
262      if (need_quoting)\r
263 @@ -67,8 +75,10 @@ make_boolean_term (void *ctx, const char *prefix, const char *term,\r
264         *buf = talloc_realloc (ctx, *buf, char, *len);\r
265      }\r
266  \r
267 -    if (! *buf)\r
268 -       return 1;\r
269 +    if (! *buf) {\r
270 +       errno = ENOMEM;\r
271 +       return -1;\r
272 +    }\r
273  \r
274      out = *buf;\r
275  \r
276 @@ -102,7 +112,7 @@ make_boolean_term (void *ctx, const char *prefix, const char *term,\r
277  static const char*\r
278  skip_space (const char *str)\r
279  {\r
280 -    while (*str && isspace (*str))\r
281 +    while (*str && isspace ((unsigned char) *str))\r
282         ++str;\r
283      return str;\r
284  }\r
285 @@ -111,6 +121,7 @@ int\r
286  parse_boolean_term (void *ctx, const char *str,\r
287                     char **prefix_out, char **term_out)\r
288  {\r
289 +    int err = EINVAL;\r
290      *prefix_out = *term_out = NULL;\r
291  \r
292      /* Parse prefix */\r
293 @@ -119,12 +130,20 @@ parse_boolean_term (void *ctx, const char *str,\r
294      if (! pos)\r
295         goto FAIL;\r
296      *prefix_out = talloc_strndup (ctx, str, pos - str);\r
297 +    if (! *prefix_out) {\r
298 +       err = ENOMEM;\r
299 +       goto FAIL;\r
300 +    }\r
301      ++pos;\r
302  \r
303      /* Implement de-quoting compatible with make_boolean_term. */\r
304      if (*pos == '"') {\r
305         char *out = talloc_array (ctx, char, strlen (pos));\r
306         int closed = 0;\r
307 +       if (! out) {\r
308 +           err = ENOMEM;\r
309 +           goto FAIL;\r
310 +       }\r
311         *term_out = out;\r
312         /* Skip the opening quote, find the closing quote, and\r
313          * un-double doubled internal quotes. */\r
314 @@ -148,18 +167,25 @@ parse_boolean_term (void *ctx, const char *str,\r
315      } else {\r
316         const char *start = pos;\r
317         /* Check for text after the boolean term. */\r
318 -       while (*pos > ' ' && *pos != ')')\r
319 +       while (! is_unquoted_terminator (*pos))\r
320             ++pos;\r
321 -       if (*skip_space (pos))\r
322 +       if (*skip_space (pos)) {\r
323 +           err = EINVAL;\r
324             goto FAIL;\r
325 +       }\r
326         /* No trailing text; dup the string so the caller can free\r
327          * it. */\r
328         *term_out = talloc_strndup (ctx, start, pos - start);\r
329 +       if (! *term_out) {\r
330 +           err = ENOMEM;\r
331 +           goto FAIL;\r
332 +       }\r
333      }\r
334      return 0;\r
335  \r
336   FAIL:\r
337      talloc_free (*prefix_out);\r
338      talloc_free (*term_out);\r
339 -    return 1;\r
340 +    errno = err;\r
341 +    return -1;\r
342  }\r
343 diff --git a/util/string-util.h b/util/string-util.h\r
344 index 8b9fe50..0194607 100644\r
345 --- a/util/string-util.h\r
346 +++ b/util/string-util.h\r
347 @@ -28,7 +28,8 @@ char *strtok_len (char *s, const char *delim, size_t *len);\r
348   * can be parsed by parse_boolean_term.\r
349   *\r
350   * Output is into buf; it may be talloc_realloced.\r
351 - * Return: 0 on success, non-zero on memory allocation failure.\r
352 + * Return: 0 on success, -1 on error.  errno will be set to ENOMEM if\r
353 + * there is an allocation failure.\r
354   */\r
355  int make_boolean_term (void *talloc_ctx, const char *prefix, const char *term,\r
356                        char **buf, size_t *len);\r
357 @@ -42,7 +43,8 @@ int make_boolean_term (void *talloc_ctx, const char *prefix, const char *term,\r
358   * of the quoting styles supported by Xapian (and hence notmuch).\r
359   * *prefix_out and *term_out will be talloc'd with context ctx.\r
360   *\r
361 - * Return: 0 on success, non-zero on parse error.\r
362 + * Return: 0 on success, -1 on error.  errno will be set to EINVAL if\r
363 + * there is a parse error or ENOMEM if there is an allocation failure.\r
364   */\r
365  int\r
366  parse_boolean_term (void *ctx, const char *str,\r
367 \r
368 \r