Re: [PATCH 0/4] Allow specifying alternate names for addresses in other_email
[notmuch-archives.git] / ec / 86a49db9efaace2096fe3bd5fbf7a36f42f480
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 AF182429E2E\r
6         for <notmuch@notmuchmail.org>; Sun,  6 Jan 2013 12:23:16 -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.151\r
10 X-Spam-Level: *\r
11 X-Spam-Status: No, score=1.151 tagged_above=-999 required=5\r
12         tests=[FUZZY_AMBIEN=1.851, 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 Ld+YcG5s4F4j for <notmuch@notmuchmail.org>;\r
16         Sun,  6 Jan 2013 12:23:14 -0800 (PST)\r
17 Received: from dmz-mailsec-scanner-7.mit.edu (DMZ-MAILSEC-SCANNER-7.MIT.EDU\r
18         [18.7.68.36])\r
19         by olra.theworths.org (Postfix) with ESMTP id 7437C431FD7\r
20         for <notmuch@notmuchmail.org>; Sun,  6 Jan 2013 12:23:14 -0800 (PST)\r
21 X-AuditID: 12074424-b7f4e6d0000004ca-8e-50e9dd32f175\r
22 Received: from mailhub-auth-4.mit.edu ( [18.7.62.39])\r
23         by dmz-mailsec-scanner-7.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id C0.4E.01226.23DD9E05; Sun,  6 Jan 2013 15:23:14 -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 r06KND4o012721; \r
27         Sun, 6 Jan 2013 15:23:13 -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 r06KMqJI020342\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Sun, 6 Jan 2013 15:23:11 -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 1Trwk7-0007YA-Bc; Sun, 06 Jan 2013 15:22:51 -0500\r
37 From: Austin Clements <amdragon@MIT.EDU>\r
38 To: notmuch@notmuchmail.org\r
39 Subject: [PATCH v5 2/6] util: Factor out boolean term quoting routine\r
40 Date: Sun,  6 Jan 2013 15:22:38 -0500\r
41 Message-Id: <1357503762-28759-3-git-send-email-amdragon@mit.edu>\r
42 X-Mailer: git-send-email 1.7.10.4\r
43 In-Reply-To: <1357503762-28759-1-git-send-email-amdragon@mit.edu>\r
44 References: <1357503762-28759-1-git-send-email-amdragon@mit.edu>\r
45 X-Brightmail-Tracker:\r
46  H4sIAAAAAAAAA+NgFrrJIsWRmVeSWpSXmKPExsUixG6nrmt092WAwZt9/BY3WrsZLZqmO1us\r
47         nstjcf3mTGaLNyvnsTqweuycdZfd4/DXhSwet+6/Zvd4tuoWs8eWQ++ZA1ijuGxSUnMyy1KL\r
48         9O0SuDJ6lr5hL5hkUrH9/jvWBsYW9S5GTg4JAROJb4d+MkLYYhIX7q1n62Lk4hAS2McosbGn\r
49         FcpZzyhxbOo9FghnP5NE/6ZWJpAWIYG5jBLPN8iA2GwCGhLb9i8HGyUiIC2x8+5sVpAGZoEm\r
50         Rolrm+aygSSEBVwlmnZuZAexWQRUJda92cEKYvMKOEi0vLvGCnGHokT3swlA9RwcnAKOEh/n\r
51         yULscpC4s+M++wRG/gWMDKsYZVNyq3RzEzNzilOTdYuTE/PyUot0zfVyM0v0UlNKNzGCQ9BF\r
52         ZQdj8yGlQ4wCHIxKPLwXdr4IEGJNLCuuzD3EKMnBpCTKu/viywAhvqT8lMqMxOKM+KLSnNTi\r
53         Q4wSHMxKIrz7jgHleFMSK6tSi/JhUtIcLErivNdTbvoLCaQnlqRmp6YWpBbBZGU4OJQkeJfc\r
54         BmoULEpNT61Iy8wpQUgzcXCCDOcBGr4epIa3uCAxtzgzHSJ/ilFRSpx3JUhCACSRUZoH1wtL\r
55         Ea8YxYFeEebdClLFA0wvcN2vgAYzAQ1OffwcZHBJIkJKqoExu3ubss2sLWtOT0vJjt6Qrs3e\r
56         xp8W+eHOHY3kFukPuwMynW/mRU8wlvjkzMvLWPx08tIpImFHX8y7UvU/0uJ8+8LUE/K7HbeE\r
57         /uVMrFrlfcHjz7aT75L+HX9j1LHt6Z52D4b6dbz/Oy6sE5pZY7Ca5eXu86K5Fw4sFW88Kc0Y\r
58         KHg04sHrJrdTSizFGYmGWsxFxYkANl867OwCAAA=\r
59 Cc: tomi.ollila@iki.fi\r
60 X-BeenThere: notmuch@notmuchmail.org\r
61 X-Mailman-Version: 2.1.13\r
62 Precedence: list\r
63 List-Id: "Use and development of the notmuch mail system."\r
64         <notmuch.notmuchmail.org>\r
65 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
66         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
67 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
68 List-Post: <mailto:notmuch@notmuchmail.org>\r
69 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
70 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
71         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
72 X-List-Received-Date: Sun, 06 Jan 2013 20:23:17 -0000\r
73 \r
74 From: Austin Clements <amdragon@MIT.EDU>\r
75 \r
76 This is now a generic boolean term quoting function.  It performs\r
77 minimal quoting to produce user-friendly queries.\r
78 \r
79 This could live in tag-util as well, but it is really nothing specific\r
80 to tags (although the conventions are specific to Xapian).\r
81 \r
82 The API is changed from "caller-allocates" to "readline-like".  The\r
83 scan for max tag length is pushed down into the quoting routine.\r
84 Furthermore, this now combines the term prefix with the quoted term;\r
85 arguably this is just as easy to do in the caller, but this will\r
86 nicely parallel the boolean term parsing function to be introduced\r
87 shortly.\r
88 \r
89 This is an amalgamation of code written by David Bremner and myself.\r
90 ---\r
91  notmuch-tag.c      |   48 ++++++++++-----------------------\r
92  util/string-util.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++\r
93  util/string-util.h |   15 +++++++++++\r
94  3 files changed, 104 insertions(+), 34 deletions(-)\r
95 \r
96 diff --git a/notmuch-tag.c b/notmuch-tag.c\r
97 index 88d559b..fc9d43a 100644\r
98 --- a/notmuch-tag.c\r
99 +++ b/notmuch-tag.c\r
100 @@ -19,6 +19,7 @@\r
101   */\r
102  \r
103  #include "notmuch-client.h"\r
104 +#include "string-util.h"\r
105  \r
106  static volatile sig_atomic_t interrupted;\r
107  \r
108 @@ -35,25 +36,6 @@ handle_sigint (unused (int sig))\r
109      interrupted = 1;\r
110  }\r
111  \r
112 -static char *\r
113 -_escape_tag (char *buf, const char *tag)\r
114 -{\r
115 -    const char *in = tag;\r
116 -    char *out = buf;\r
117 -\r
118 -    /* Boolean terms surrounded by double quotes can contain any\r
119 -     * character.  Double quotes are quoted by doubling them. */\r
120 -    *out++ = '"';\r
121 -    while (*in) {\r
122 -       if (*in == '"')\r
123 -           *out++ = '"';\r
124 -       *out++ = *in++;\r
125 -    }\r
126 -    *out++ = '"';\r
127 -    *out = 0;\r
128 -    return buf;\r
129 -}\r
130 -\r
131  typedef struct {\r
132      const char *tag;\r
133      notmuch_bool_t remove;\r
134 @@ -71,25 +53,16 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
135       * parenthesize and the exclusion part of the query must not use\r
136       * the '-' operator (though the NOT operator is fine). */\r
137  \r
138 -    char *escaped, *query_string;\r
139 +    char *escaped = NULL;\r
140 +    size_t escaped_len = 0;\r
141 +    char *query_string;\r
142      const char *join = "";\r
143 -    int i;\r
144 -    unsigned int max_tag_len = 0;\r
145 +    size_t i;\r
146  \r
147      /* Don't optimize if there are no tag changes. */\r
148      if (tag_ops[0].tag == NULL)\r
149         return talloc_strdup (ctx, orig_query_string);\r
150  \r
151 -    /* Allocate a buffer for escaping tags.  This is large enough to\r
152 -     * hold a fully escaped tag with every character doubled plus\r
153 -     * enclosing quotes and a NUL. */\r
154 -    for (i = 0; tag_ops[i].tag; i++)\r
155 -       if (strlen (tag_ops[i].tag) > max_tag_len)\r
156 -           max_tag_len = strlen (tag_ops[i].tag);\r
157 -    escaped = talloc_array (ctx, char, max_tag_len * 2 + 3);\r
158 -    if (! escaped)\r
159 -       return NULL;\r
160 -\r
161      /* Build the new query string */\r
162      if (strcmp (orig_query_string, "*") == 0)\r
163         query_string = talloc_strdup (ctx, "(");\r
164 @@ -97,10 +70,17 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
165         query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);\r
166  \r
167      for (i = 0; tag_ops[i].tag && query_string; i++) {\r
168 +       /* XXX in case of OOM, query_string will be deallocated when\r
169 +        * ctx is, which might be at shutdown */\r
170 +       if (make_boolean_term (ctx,\r
171 +                              "tag", tag_ops[i].tag,\r
172 +                              &escaped, &escaped_len))\r
173 +           return NULL;\r
174 +\r
175         query_string = talloc_asprintf_append_buffer (\r
176 -           query_string, "%s%stag:%s", join,\r
177 +           query_string, "%s%s%s", join,\r
178             tag_ops[i].remove ? "" : "not ",\r
179 -           _escape_tag (escaped, tag_ops[i].tag));\r
180 +           escaped);\r
181         join = " or ";\r
182      }\r
183  \r
184 diff --git a/util/string-util.c b/util/string-util.c\r
185 index 44f8cd3..7a71049 100644\r
186 --- a/util/string-util.c\r
187 +++ b/util/string-util.c\r
188 @@ -20,6 +20,9 @@\r
189  \r
190  \r
191  #include "string-util.h"\r
192 +#include "talloc.h"\r
193 +\r
194 +#include <errno.h>\r
195  \r
196  char *\r
197  strtok_len (char *s, const char *delim, size_t *len)\r
198 @@ -32,3 +35,75 @@ strtok_len (char *s, const char *delim, size_t *len)\r
199  \r
200      return *len ? s : NULL;\r
201  }\r
202 +\r
203 +static int\r
204 +is_unquoted_terminator (unsigned char c)\r
205 +{\r
206 +    return c == 0 || c <= ' ' || c == ')';\r
207 +}\r
208 +\r
209 +int\r
210 +make_boolean_term (void *ctx, const char *prefix, const char *term,\r
211 +                  char **buf, size_t *len)\r
212 +{\r
213 +    const char *in;\r
214 +    char *out;\r
215 +    size_t needed = 3;\r
216 +    int need_quoting = 0;\r
217 +\r
218 +    /* Do we need quoting?  To be paranoid, we quote anything\r
219 +     * containing a quote, even though it only matters at the\r
220 +     * beginning, and anything containing non-ASCII text. */\r
221 +    for (in = term; *in && !need_quoting; in++)\r
222 +       if (is_unquoted_terminator (*in) || *in == '"'\r
223 +           || (unsigned char)*in > 127)\r
224 +           need_quoting = 1;\r
225 +\r
226 +    if (need_quoting)\r
227 +       for (in = term; *in; in++)\r
228 +           needed += (*in == '"') ? 2 : 1;\r
229 +    else\r
230 +       needed = strlen (term) + 1;\r
231 +\r
232 +    /* Reserve space for the prefix */\r
233 +    if (prefix)\r
234 +       needed += strlen (prefix) + 1;\r
235 +\r
236 +    if ((*buf == NULL) || (needed > *len)) {\r
237 +       *len = 2 * needed;\r
238 +       *buf = talloc_realloc (ctx, *buf, char, *len);\r
239 +    }\r
240 +\r
241 +    if (! *buf) {\r
242 +       errno = ENOMEM;\r
243 +       return -1;\r
244 +    }\r
245 +\r
246 +    out = *buf;\r
247 +\r
248 +    /* Copy in the prefix */\r
249 +    if (prefix) {\r
250 +       strcpy (out, prefix);\r
251 +       out += strlen (prefix);\r
252 +       *out++ = ':';\r
253 +    }\r
254 +\r
255 +    if (! need_quoting) {\r
256 +       strcpy (out, term);\r
257 +       return 0;\r
258 +    }\r
259 +\r
260 +    /* Quote term by enclosing it in double quotes and doubling any\r
261 +     * internal double quotes. */\r
262 +    *out++ = '"';\r
263 +    in = term;\r
264 +    while (*in) {\r
265 +       if (*in == '"')\r
266 +           *out++ = '"';\r
267 +       *out++ = *in++;\r
268 +    }\r
269 +    *out++ = '"';\r
270 +    *out = '\0';\r
271 +\r
272 +    return 0;\r
273 +}\r
274 diff --git a/util/string-util.h b/util/string-util.h\r
275 index ac7676c..719c276 100644\r
276 --- a/util/string-util.h\r
277 +++ b/util/string-util.h\r
278 @@ -19,4 +19,19 @@\r
279  \r
280  char *strtok_len (char *s, const char *delim, size_t *len);\r
281  \r
282 +/* Construct a boolean term query with the specified prefix (e.g.,\r
283 + * "id") and search term, quoting term as necessary.  Specifically, if\r
284 + * term contains any non-printable ASCII characters, non-ASCII\r
285 + * characters, close parenthesis or double quotes, it will be enclosed\r
286 + * in double quotes and any internal double quotes will be doubled\r
287 + * (e.g. a"b -> "a""b").  The result will be a valid notmuch query and\r
288 + * can be parsed by parse_boolean_term.\r
289 + *\r
290 + * Output is into buf; it may be talloc_realloced.\r
291 + * Return: 0 on success, -1 on error.  errno will be set to ENOMEM if\r
292 + * there is an allocation failure.\r
293 + */\r
294 +int make_boolean_term (void *talloc_ctx, const char *prefix, const char *term,\r
295 +                      char **buf, size_t *len);\r
296 +\r
297  #endif\r
298 -- \r
299 1.7.10.4\r
300 \r