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
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
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
57 Cc: tomi.ollila@iki.fi
\r
58 X-BeenThere: notmuch@notmuchmail.org
\r
59 X-Mailman-Version: 2.1.13
\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
74 id:1356936162-2589-1-git-send-email-amdragon@mit.edu
\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
82 The diff from v4 follows.
\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
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
104 if (output_format == DUMP_FORMAT_SUP) {
\r
105 fprintf (output, "%s (", message_id);
\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
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
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
124 + fprintf (stderr, "Error quoting message id %s: %s\n",
\r
125 + message_id, strerror (errno));
\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
134 static regex_t regex;
\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
142 tag_message (unused (void *ctx),
\r
143 @@ -40,13 +41,17 @@ tag_message (unused (void *ctx),
\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
151 - fprintf (stderr, "%s\n", notmuch_status_to_string (status));
\r
153 + fprintf (stderr, "Error applying tags to message %s: %s\n",
\r
154 + message_id, notmuch_status_to_string (status));
\r
157 + if (message == NULL) {
\r
158 + fprintf (stderr, "Warning: cannot apply tags to missing message: %s\n",
\r
160 + /* We consider this a non-fatal error. */
\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
168 ret = parse_boolean_term (line_ctx, query_string,
\r
171 - fprintf (stderr, "Warning: cannot parse query: %s\n",
\r
173 + if (ret && errno == EINVAL) {
\r
174 + fprintf (stderr, "Warning: cannot parse query: %s (skipping)\n", query_string);
\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
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
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
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
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
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
233 #include "talloc.h"
\r
236 +#include <errno.h>
\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
245 +is_unquoted_terminator (unsigned char c)
\r
247 + return c == 0 || c <= ' ' || c == ')';
\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
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
276 @@ -102,7 +112,7 @@ make_boolean_term (void *ctx, const char *prefix, const char *term,
\r
278 skip_space (const char *str)
\r
280 - while (*str && isspace (*str))
\r
281 + while (*str && isspace ((unsigned char) *str))
\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
289 + int err = EINVAL;
\r
290 *prefix_out = *term_out = NULL;
\r
293 @@ -119,12 +130,20 @@ parse_boolean_term (void *ctx, const char *str,
\r
296 *prefix_out = talloc_strndup (ctx, str, pos - str);
\r
297 + if (! *prefix_out) {
\r
303 /* Implement de-quoting compatible with make_boolean_term. */
\r
305 char *out = talloc_array (ctx, char, strlen (pos));
\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
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
321 - if (*skip_space (pos))
\r
322 + if (*skip_space (pos)) {
\r
326 /* No trailing text; dup the string so the caller can free
\r
328 *term_out = talloc_strndup (ctx, start, pos - start);
\r
329 + if (! *term_out) {
\r
337 talloc_free (*prefix_out);
\r
338 talloc_free (*term_out);
\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
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
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
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
366 parse_boolean_term (void *ctx, const char *str,
\r