[PATCH 2/9] lib: private string map (associative array) API
[notmuch-archives.git] / b1 / f7e9aa8f08db98c8254f8ae30178940631a222
1 Return-Path: <prvs=jrosenthal=691fa5400@jhu.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 B203F4196F0\r
6         for <notmuch@notmuchmail.org>; Tue, 23 Mar 2010 12:48:17 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -2.8\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-2.8 tagged_above=-999 required=5\r
12         tests=[BAYES_05=-0.5, RCVD_IN_DNSWL_MED=-2.3] autolearn=ham\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 0stSLAseDfei for <notmuch@notmuchmail.org>;\r
16         Tue, 23 Mar 2010 12:48:15 -0700 (PDT)\r
17 Received: from ipex2.johnshopkins.edu (ipex2.johnshopkins.edu [162.129.8.151])\r
18         by olra.theworths.org (Postfix) with ESMTP id E6BE4431FC1\r
19         for <notmuch@notmuchmail.org>; Tue, 23 Mar 2010 12:48:14 -0700 (PDT)\r
20 X-IronPort-AV: E=Sophos;i="4.51,296,1267419600"; d="scan'208";a="315237919"\r
21 Received: from c-69-255-36-229.hsd1.md.comcast.net (HELO lucky)\r
22         ([69.255.36.229])\r
23         by ipex2.johnshopkins.edu with ESMTP/TLS/AES256-SHA;\r
24         23 Mar 2010 15:48:14 -0400\r
25 Received: from jkr by lucky with local (Exim 4.69)\r
26         (envelope-from <jrosenthal@jhu.edu>)\r
27         id 1NuA5O-0004g0-6O; Tue, 23 Mar 2010 15:48:22 -0400\r
28 From: Jesse Rosenthal <jrosenthal@jhu.edu>\r
29 To: notmuch@notmuchmail.org\r
30 Date: Tue, 23 Mar 2010 15:48:22 -0400\r
31 Message-ID: <87d3yulszd.fsf@jhu.edu>\r
32 MIME-Version: 1.0\r
33 Content-Type: text/plain; charset=us-ascii\r
34 Subject: [notmuch] [PATCH] Allow saved queries for searching.\r
35 X-BeenThere: notmuch@notmuchmail.org\r
36 X-Mailman-Version: 2.1.13\r
37 Precedence: list\r
38 List-Id: "Use and development of the notmuch mail system."\r
39         <notmuch.notmuchmail.org>\r
40 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
41         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
42 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
43 List-Post: <mailto:notmuch@notmuchmail.org>\r
44 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
45 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
46         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
47 X-List-Received-Date: Tue, 23 Mar 2010 19:48:17 -0000\r
48 \r
49 Add a "query:foo" term to the notmuch search syntax. Queries are "saved\r
50 searches", and are written in the config file:\r
51 \r
52 [queries]\r
53 foo=from:jrosenthal and to:notmuchmail and queries\r
54 bar=tag:personal or (tag:unread and from:whomever)\r
55 \r
56 Then, if you search with the query\r
57 \r
58 `tag:inbox or query:foo'\r
59 \r
60 it will be passed along to notmuch as\r
61 \r
62 `tag:inbox and (from:jrosenthal and to:notmuchmail and queries)'.\r
63 \r
64 At the moment, when you ask for a query that doesn't exist it just\r
65 treats it as blank. This seems more consistent than bailing out with an\r
66 error (since no other search term will do that, short of running out of\r
67 memory). This does mean, though, that non-existent queries, entered by\r
68 themselves, will lead to a blank-search-term error. It should be pretty\r
69 simple to improve this behavior, but I wanted to get the initial\r
70 functionality out there.\r
71 \r
72 Note that this changed the arguments to query_string_from_args to include\r
73 the hash-table of saved queries -- and since a lot functions call that\r
74 one, this patch affects all of them. \r
75 ---\r
76  notmuch-client.h      |   11 ++++++++---\r
77  notmuch-config.c      |   38 ++++++++++++++++++++++++++++++++++++++\r
78  notmuch-count.c       |    7 ++++++-\r
79  notmuch-reply.c       |    7 ++++++-\r
80  notmuch-search-tags.c |    7 ++++++-\r
81  notmuch-search.c      |    8 +++++++-\r
82  notmuch-show.c        |    7 ++++++-\r
83  notmuch-tag.c         |   20 +++++++++++++-------\r
84  query-string.c        |   21 +++++++++++++++++++--\r
85  9 files changed, 109 insertions(+), 17 deletions(-)\r
86 \r
87 diff --git a/notmuch-client.h b/notmuch-client.h\r
88 index c80b39c..daecbf4 100644\r
89 --- a/notmuch-client.h\r
90 +++ b/notmuch-client.h\r
91 @@ -116,9 +116,6 @@ notmuch_time_print_formatted_seconds (double seconds);\r
92  double\r
93  notmuch_time_elapsed (struct timeval start, struct timeval end);\r
94  \r
95 -char *\r
96 -query_string_from_args (void *ctx, int argc, char *argv[]);\r
97 -\r
98  notmuch_status_t\r
99  show_message_body (const char *filename,\r
100                    void (*show_part) (GMimeObject *part, int *part_count));\r
101 @@ -135,6 +132,10 @@ notmuch_config_open (void *ctx,\r
102                      const char *filename,\r
103                      notmuch_bool_t *is_new_ret);\r
104  \r
105 +char *\r
106 +query_string_from_args (void *ctx, GHashTable *queries_hash,\r
107 +                       int argc, char *argv[]);\r
108 +\r
109  void\r
110  notmuch_config_close (notmuch_config_t *config);\r
111  \r
112 @@ -162,6 +163,10 @@ void\r
113  notmuch_config_set_user_primary_email (notmuch_config_t *config,\r
114                                        const char *primary_email);\r
115  \r
116 +void \r
117 +notmuch_config_get_queries (notmuch_config_t *config, \r
118 +                           GHashTable *queries_hash);\r
119 +\r
120  char **\r
121  notmuch_config_get_user_other_email (notmuch_config_t *config,\r
122                                      size_t *length);\r
123 diff --git a/notmuch-config.c b/notmuch-config.c\r
124 index 95430db..ad81c25 100644\r
125 --- a/notmuch-config.c\r
126 +++ b/notmuch-config.c\r
127 @@ -62,6 +62,8 @@ struct _notmuch_config {\r
128      char *user_primary_email;\r
129      char **user_other_email;\r
130      size_t user_other_email_length;\r
131 +    \r
132 +    GHashTable *queries_hash;\r
133  };\r
134  \r
135  static int\r
136 @@ -70,6 +72,8 @@ notmuch_config_destructor (notmuch_config_t *config)\r
137      if (config->key_file)\r
138         g_key_file_free (config->key_file);\r
139  \r
140 +    g_hash_table_unref (config->queries_hash);\r
141 +\r
142      return 0;\r
143  }\r
144  \r
145 @@ -200,6 +204,11 @@ notmuch_config_open (void *ctx,\r
146      config->user_other_email = NULL;\r
147      config->user_other_email_length = 0;\r
148  \r
149 +    config->queries_hash =  g_hash_table_new_full (g_str_hash, \r
150 +                                                  g_str_equal,\r
151 +                                                  free, \r
152 +                                                  NULL);\r
153 +\r
154      if (! g_key_file_load_from_file (config->key_file,\r
155                                      config->filename,\r
156                                      G_KEY_FILE_KEEP_COMMENTS,\r
157 @@ -264,6 +273,8 @@ notmuch_config_open (void *ctx,\r
158         }\r
159      }\r
160  \r
161 +    notmuch_config_get_queries (config, config->queries_hash);\r
162 +\r
163      /* When we create a new configuration file here, we  add some\r
164       * comments to help the user understand what can be done. */\r
165      if (is_new) {\r
166 @@ -342,6 +353,33 @@ notmuch_config_get_database_path (notmuch_config_t *config)\r
167      return config->database_path;\r
168  }\r
169  \r
170 +\r
171 +void\r
172 +notmuch_config_get_queries (notmuch_config_t *config,\r
173 +                           GHashTable *queries_hash)\r
174 +{\r
175 +    char **keys;\r
176 +    gsize size;\r
177 +    keys = g_key_file_get_keys (config->key_file,\r
178 +                               "queries",\r
179 +                               &size,\r
180 +                               NULL);\r
181 +    gsize i;\r
182 +    for (i = 0; i < size; i++) {\r
183 +       char *value;\r
184 +       value = g_key_file_get_string (config->key_file,\r
185 +                                      "queries", \r
186 +                                      keys[i], \r
187 +                                      NULL);\r
188 +\r
189 +       g_hash_table_insert (queries_hash,\r
190 +                            keys[i],\r
191 +                            value);\r
192 +    }\r
193 +}\r
194 +    \r
195 +\r
196 +\r
197  void\r
198  notmuch_config_set_database_path (notmuch_config_t *config,\r
199                                   const char *database_path)\r
200 diff --git a/notmuch-count.c b/notmuch-count.c\r
201 index 77aa433..2e8463b 100644\r
202 --- a/notmuch-count.c\r
203 +++ b/notmuch-count.c\r
204 @@ -85,7 +85,12 @@ notmuch_count_command (void *ctx, int argc, char *argv[])\r
205      if (notmuch == NULL)\r
206         return 1;\r
207  \r
208 -    query_str = query_string_from_args (ctx, argc, argv);\r
209 +    GHashTable *queries_hash;\r
210 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
211 +                                   free, NULL);\r
212 +    notmuch_config_get_queries (config, queries_hash);\r
213 +\r
214 +    query_str = query_string_from_args (ctx, queries_hash, argc, argv);\r
215      if (query_str == NULL) {\r
216         fprintf (stderr, "Out of memory.\n");\r
217         return 1;\r
218 diff --git a/notmuch-reply.c b/notmuch-reply.c\r
219 index 6c15536..5b10c68 100644\r
220 --- a/notmuch-reply.c\r
221 +++ b/notmuch-reply.c\r
222 @@ -456,7 +456,12 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
223      if (config == NULL)\r
224         return 1;\r
225  \r
226 -    query_string = query_string_from_args (ctx, argc, argv);\r
227 +    GHashTable *queries_hash;\r
228 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
229 +                                   free, NULL);\r
230 +    notmuch_config_get_queries (config, queries_hash);\r
231 +\r
232 +    query_string = query_string_from_args (ctx, queries_hash, argc, argv);\r
233      if (query_string == NULL) {\r
234         fprintf (stderr, "Out of memory\n");\r
235         return 1;\r
236 diff --git a/notmuch-search-tags.c b/notmuch-search-tags.c\r
237 index 6f3cfcc..e021cc3 100644\r
238 --- a/notmuch-search-tags.c\r
239 +++ b/notmuch-search-tags.c\r
240 @@ -57,8 +57,13 @@ notmuch_search_tags_command (void *ctx, int argc, char *argv[])\r
241         goto error;\r
242      }\r
243  \r
244 +    GHashTable *queries_hash;\r
245 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
246 +                                   free, NULL);\r
247 +    notmuch_config_get_queries (config, queries_hash);\r
248 +\r
249      if (argc > 0) {\r
250 -       if ((query_str = query_string_from_args (ctx, argc, argv)) == NULL) {\r
251 +       if ((query_str = query_string_from_args (ctx, queries_hash, argc, argv)) == NULL) {\r
252             fprintf (stderr, "Out of memory.\n");\r
253             goto error;\r
254         }\r
255 diff --git a/notmuch-search.c b/notmuch-search.c\r
256 index 4e3514b..a35838b 100644\r
257 --- a/notmuch-search.c\r
258 +++ b/notmuch-search.c\r
259 @@ -244,12 +244,18 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
260      if (config == NULL)\r
261         return 1;\r
262  \r
263 +    GHashTable *queries_hash;\r
264 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
265 +                                   free, NULL);\r
266 +    notmuch_config_get_queries (config, queries_hash);\r
267 +\r
268      notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
269                                      NOTMUCH_DATABASE_MODE_READ_ONLY);\r
270      if (notmuch == NULL)\r
271         return 1;\r
272  \r
273 -    query_str = query_string_from_args (ctx, argc, argv);\r
274 +\r
275 +    query_str = query_string_from_args (ctx, queries_hash, argc, argv);\r
276      if (query_str == NULL) {\r
277         fprintf (stderr, "Out of memory.\n");\r
278         return 1;\r
279 diff --git a/notmuch-show.c b/notmuch-show.c\r
280 index ff1fecb..f324ca3 100644\r
281 --- a/notmuch-show.c\r
282 +++ b/notmuch-show.c\r
283 @@ -446,7 +446,12 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))\r
284      if (config == NULL)\r
285         return 1;\r
286  \r
287 -    query_string = query_string_from_args (ctx, argc, argv);\r
288 +    GHashTable *queries_hash;\r
289 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
290 +                                   free, NULL);\r
291 +    notmuch_config_get_queries (config, queries_hash);\r
292 +\r
293 +    query_string = query_string_from_args (ctx, queries_hash, argc, argv);\r
294      if (query_string == NULL) {\r
295         fprintf (stderr, "Out of memory\n");\r
296         return 1;\r
297 diff --git a/notmuch-tag.c b/notmuch-tag.c\r
298 index 8b6f7dc..f65bb53 100644\r
299 --- a/notmuch-tag.c\r
300 +++ b/notmuch-tag.c\r
301 @@ -85,13 +85,6 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))\r
302         return 1;\r
303      }\r
304  \r
305 -    query_string = query_string_from_args (ctx, argc - i, &argv[i]);\r
306 -\r
307 -    if (*query_string == '\0') {\r
308 -       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
309 -       return 1;\r
310 -    }\r
311 -\r
312      config = notmuch_config_open (ctx, NULL, NULL);\r
313      if (config == NULL)\r
314         return 1;\r
315 @@ -101,6 +94,19 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))\r
316      if (notmuch == NULL)\r
317         return 1;\r
318  \r
319 +    GHashTable *queries_hash;\r
320 +    queries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
321 +                                   free, NULL);\r
322 +    notmuch_config_get_queries (config, queries_hash);\r
323 +\r
324 +    query_string = query_string_from_args (ctx, queries_hash, argc - i, &argv[i]);\r
325 +\r
326 +    if (*query_string == '\0') {\r
327 +       fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
328 +       return 1;\r
329 +    }\r
330 +\r
331 +\r
332      query = notmuch_query_create (notmuch, query_string);\r
333      if (query == NULL) {\r
334         fprintf (stderr, "Out of memory.\n");\r
335 diff --git a/query-string.c b/query-string.c\r
336 index 6536512..2bd79c8 100644\r
337 --- a/query-string.c\r
338 +++ b/query-string.c\r
339 @@ -30,7 +30,8 @@\r
340   * This function returns NULL in case of insufficient memory.\r
341   */\r
342  char *\r
343 -query_string_from_args (void *ctx, int argc, char *argv[])\r
344 +query_string_from_args (void *ctx, GHashTable *queries_hash,\r
345 +                       int argc, char *argv[])\r
346  {\r
347      char *query_string;\r
348      int i;\r
349 @@ -46,7 +47,23 @@ query_string_from_args (void *ctx, int argc, char *argv[])\r
350                 return NULL;\r
351         }\r
352  \r
353 -       query_string = talloc_strdup_append (query_string, argv[i]);\r
354 +       if (STRNCMP_LITERAL (argv[i], "query:") == 0) {\r
355 +\r
356 +           char *saved_search;\r
357 +           char  *replacement;\r
358 +           char *replacement_string;\r
359 +\r
360 +           saved_search = argv[i] + sizeof ("query:") - 1;\r
361 +           \r
362 +           replacement = g_hash_table_lookup (queries_hash, saved_search);\r
363 +           replacement_string = talloc_asprintf (ctx, \r
364 +                                                 "(%s)",\r
365 +                                                 (char *) replacement);\r
366 +\r
367 +           query_string = talloc_strdup_append (query_string, replacement);\r
368 +       } else {\r
369 +           query_string = talloc_strdup_append (query_string, argv[i]);\r
370 +       }\r
371         if (query_string == NULL)\r
372             return NULL;\r
373      }\r
374 -- \r
375 1.6.3.3\r
376 \r