[PATCH 6/8] CLI: refactor dumping of tags.
[notmuch-archives.git] / c4 / 4507b7983437745ab3bbac44552b227cd54a54
1 Return-Path: <bremner@tesseract.cs.unb.ca>\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 arlo.cworth.org (Postfix) with ESMTP id 05ADB6DE02D1\r
6  for <notmuch@notmuchmail.org>; Sat, 26 Mar 2016 11:23:23 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at cworth.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.02\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.02 tagged_above=-999 required=5 tests=[AWL=-0.021,\r
12   HEADER_FROM_DIFFERENT_DOMAINS=0.001] autolearn=disabled\r
13 Received: from arlo.cworth.org ([127.0.0.1])\r
14  by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
15  with ESMTP id HnfBKghIrKfx for <notmuch@notmuchmail.org>;\r
16  Sat, 26 Mar 2016 11:23:14 -0700 (PDT)\r
17 X-Greylist: delayed 1543 seconds by postgrey-1.35 at arlo;\r
18  Sat, 26 Mar 2016 11:23:14 PDT\r
19 Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
20  by arlo.cworth.org (Postfix) with ESMTPS id 6EB066DE026C\r
21  for <notmuch@notmuchmail.org>; Sat, 26 Mar 2016 11:23:14 -0700 (PDT)\r
22 Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
23  (envelope-from <bremner@tesseract.cs.unb.ca>)\r
24  id 1ajsTN-0000u8-Fp; Sat, 26 Mar 2016 13:58:05 -0400\r
25 Received: (nullmailer pid 8816 invoked by uid 1000);\r
26  Sat, 26 Mar 2016 17:57:27 -0000\r
27 From: David Bremner <david@tethera.net>\r
28 To: notmuch@notmuchmail.org\r
29 Subject: [Patch v2 07/13] lib: config list iterators\r
30 Date: Sat, 26 Mar 2016 14:57:17 -0300\r
31 Message-Id: <1459015043-8460-8-git-send-email-david@tethera.net>\r
32 X-Mailer: git-send-email 2.6.4\r
33 In-Reply-To: <1459015043-8460-1-git-send-email-david@tethera.net>\r
34 References: <1459015043-8460-1-git-send-email-david@tethera.net>\r
35 X-BeenThere: notmuch@notmuchmail.org\r
36 X-Mailman-Version: 2.1.20\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: <https://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: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
46  <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
47 X-List-Received-Date: Sat, 26 Mar 2016 18:23:23 -0000\r
48 \r
49 Since xapian provides the ability to restrict the iterator to a given\r
50 prefix, we expose this ability to the user. Otherwise we mimic the other\r
51 iterator interfances in notmuch (e.g. tags.c).\r
52 ---\r
53  lib/config.cc          | 104 +++++++++++++++++++++++++++++++++++++++++++++++++\r
54  lib/notmuch.h          |  44 +++++++++++++++++++++\r
55  test/T590-libconfig.sh |  60 ++++++++++++++++++++++++++++\r
56  3 files changed, 208 insertions(+)\r
57 \r
58 diff --git a/lib/config.cc b/lib/config.cc\r
59 index af00d6f..e581f32 100644\r
60 --- a/lib/config.cc\r
61 +++ b/lib/config.cc\r
62 @@ -24,6 +24,19 @@\r
63  \r
64  static const std::string CONFIG_PREFIX="C";\r
65  \r
66 +struct _notmuch_config_list {\r
67 +    notmuch_database_t *notmuch;\r
68 +    Xapian::TermIterator *iterator;\r
69 +    char *current_key;\r
70 +    char *current_val;\r
71 +};\r
72 +\r
73 +static int\r
74 +_notmuch_config_list_destroy (notmuch_config_list_t *list) {\r
75 +    delete list->iterator;\r
76 +    return 0;\r
77 +}\r
78 +\r
79  notmuch_status_t\r
80  notmuch_database_set_config (notmuch_database_t *notmuch,\r
81                              const char *key,\r
82 @@ -88,3 +101,94 @@ notmuch_database_get_config (notmuch_database_t *notmuch,\r
83  \r
84      return NOTMUCH_STATUS_SUCCESS;\r
85  }\r
86 +\r
87 +notmuch_status_t\r
88 +notmuch_database_get_config_list (notmuch_database_t *notmuch,\r
89 +                                const char *prefix,\r
90 +                                notmuch_config_list_t **out)\r
91 +{\r
92 +    notmuch_config_list_t *list = NULL;\r
93 +    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;\r
94 +\r
95 +    list = talloc (notmuch, notmuch_config_list_t);\r
96 +    if (!list) {\r
97 +       status = NOTMUCH_STATUS_OUT_OF_MEMORY;\r
98 +       goto DONE;\r
99 +    }\r
100 +\r
101 +    talloc_set_destructor (list, _notmuch_config_list_destroy);\r
102 +    list->iterator = new Xapian::TermIterator;\r
103 +    list->notmuch = notmuch;\r
104 +    list->current_key = NULL;\r
105 +    list->current_val = NULL;\r
106 +\r
107 +    try {\r
108 +\r
109 +       *list->iterator = notmuch->xapian_db->metadata_keys_begin (CONFIG_PREFIX + (prefix ? prefix : ""));\r
110 +\r
111 +    } catch (const Xapian::Error &error) {\r
112 +       _notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n",\r
113 +                              error.get_msg().c_str());\r
114 +       notmuch->exception_reported = TRUE;\r
115 +       status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;\r
116 +    }\r
117 +\r
118 +    *out = list;\r
119 +\r
120 + DONE:\r
121 +    if (status && list)\r
122 +       talloc_free (list);\r
123 +\r
124 +    return status;\r
125 +}\r
126 +\r
127 +notmuch_bool_t\r
128 +notmuch_config_list_valid (notmuch_config_list_t *metadata)\r
129 +{\r
130 +    if (*(metadata->iterator) == metadata->notmuch->xapian_db->metadata_keys_end())\r
131 +       return FALSE;\r
132 +\r
133 +    return TRUE;\r
134 +}\r
135 +\r
136 +const char *\r
137 +notmuch_config_list_key (notmuch_config_list_t *list)\r
138 +{\r
139 +    if (list->current_key)\r
140 +       talloc_free (list->current_key);\r
141 +\r
142 +    list->current_key = talloc_strdup (list, (**(list->iterator)).c_str () + CONFIG_PREFIX.length ());\r
143 +\r
144 +    return  list->current_key;\r
145 +}\r
146 +\r
147 +const char *\r
148 +notmuch_config_list_value (notmuch_config_list_t *list)\r
149 +{\r
150 +    std::string strval;\r
151 +    notmuch_status_t status;\r
152 +    const char *key = notmuch_config_list_key (list);\r
153 +\r
154 +    /* TODO: better error reporting?? */\r
155 +    status = _metadata_value (list->notmuch, key, strval);\r
156 +    if (status)\r
157 +       return NULL;\r
158 +\r
159 +    if (list->current_val)\r
160 +       talloc_free(list->current_val);\r
161 +\r
162 +    list->current_val = talloc_strdup(list, strval.c_str ());\r
163 +    return list->current_val;\r
164 +}\r
165 +\r
166 +void\r
167 +notmuch_config_list_move_to_next (notmuch_config_list_t *list)\r
168 +{\r
169 +    (*(list->iterator))++;\r
170 +}\r
171 +\r
172 +void\r
173 +notmuch_config_list_destroy (notmuch_config_list_t *list)\r
174 +{\r
175 +    talloc_free (list);\r
176 +}\r
177 diff --git a/lib/notmuch.h b/lib/notmuch.h\r
178 index e416fb4..2278822 100644\r
179 --- a/lib/notmuch.h\r
180 +++ b/lib/notmuch.h\r
181 @@ -206,6 +206,7 @@ typedef struct _notmuch_message notmuch_message_t;\r
182  typedef struct _notmuch_tags notmuch_tags_t;\r
183  typedef struct _notmuch_directory notmuch_directory_t;\r
184  typedef struct _notmuch_filenames notmuch_filenames_t;\r
185 +typedef struct _notmuch_config_list notmuch_config_list_t;\r
186  #endif /* __DOXYGEN__ */\r
187  \r
188  /**\r
189 @@ -1858,6 +1859,49 @@ notmuch_database_set_config (notmuch_database_t *db, const char *key, const char\r
190  notmuch_status_t\r
191  notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value);\r
192  \r
193 +/**\r
194 + * Create an iterator for all config items with keys matching a given prefix\r
195 + */\r
196 +notmuch_status_t\r
197 +notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out);\r
198 +\r
199 +/**\r
200 + * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called).\r
201 + */\r
202 +notmuch_bool_t\r
203 +notmuch_config_list_valid (notmuch_config_list_t *config_list);\r
204 +\r
205 +/**\r
206 + * return key for current config pair\r
207 + *\r
208 + * return value is owned by the iterator, and will be destroyed by the\r
209 + * next call to notmuch_config_list_key or notmuch_config_list_destroy.\r
210 + */\r
211 +const char *\r
212 +notmuch_config_list_key (notmuch_config_list_t *config_list);\r
213 +\r
214 +/**\r
215 + * return 'value' for current config pair\r
216 + *\r
217 + * return value is owned by the iterator, and will be destroyed by the\r
218 + * next call to notmuch_config_list_value or notmuch config_list_destroy\r
219 + */\r
220 +const char *\r
221 +notmuch_config_list_value (notmuch_config_list_t *config_list);\r
222 +\r
223 +\r
224 +/**\r
225 + * move 'config_list' iterator to the next pair\r
226 + */\r
227 +void\r
228 +notmuch_config_list_move_to_next (notmuch_config_list_t *config_list);\r
229 +\r
230 +/**\r
231 + * free any resources held by 'config_list'\r
232 + */\r
233 +void\r
234 +notmuch_config_list_destroy (notmuch_config_list_t *config_list);\r
235 +\r
236  typedef enum {\r
237      NOTMUCH_OPTION_COMPACT = 1,\r
238      NOTMUCH_OPTION_FIELD_PROCESSOR = 2\r
239 diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh\r
240 index 85e4497..8ca6883 100755\r
241 --- a/test/T590-libconfig.sh\r
242 +++ b/test/T590-libconfig.sh\r
243 @@ -55,4 +55,64 @@ testkey2 = testvalue2\r
244  EOF\r
245  test_expect_equal_file EXPECTED OUTPUT\r
246  \r
247 +\r
248 +test_begin_subtest "notmuch_database_get_config_list: empty list"\r
249 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
250 +{\r
251 +   notmuch_config_list_t *list;\r
252 +   RUN(notmuch_database_get_config_list (db, "nonexistent", &list));\r
253 +   printf("valid = %d\n", notmuch_config_list_valid (list));\r
254 +   notmuch_config_list_destroy (list);\r
255 +}\r
256 +EOF\r
257 +cat <<'EOF' >EXPECTED\r
258 +== stdout ==\r
259 +valid = 0\r
260 +== stderr ==\r
261 +EOF\r
262 +test_expect_equal_file EXPECTED OUTPUT\r
263 +\r
264 +\r
265 +test_begin_subtest "notmuch_database_get_config_list: all pairs"\r
266 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
267 +{\r
268 +   notmuch_config_list_t *list;\r
269 +   RUN(notmuch_database_set_config (db, "zzzafter", "afterval"));\r
270 +   RUN(notmuch_database_set_config (db, "aaabefore", "beforeval"));\r
271 +   RUN(notmuch_database_get_config_list (db, "", &list));\r
272 +   for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {\r
273 +      printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));\r
274 +   }\r
275 +   notmuch_config_list_destroy (list);\r
276 +}\r
277 +EOF\r
278 +cat <<'EOF' >EXPECTED\r
279 +== stdout ==\r
280 +aaabefore beforeval\r
281 +testkey1 testvalue1\r
282 +testkey2 testvalue2\r
283 +zzzafter afterval\r
284 +== stderr ==\r
285 +EOF\r
286 +test_expect_equal_file EXPECTED OUTPUT\r
287 +\r
288 +test_begin_subtest "notmuch_database_get_config_list: one prefix"\r
289 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}\r
290 +{\r
291 +   notmuch_config_list_t *list;\r
292 +   RUN(notmuch_database_get_config_list (db, "testkey", &list));\r
293 +   for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {\r
294 +      printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));\r
295 +   }\r
296 +   notmuch_config_list_destroy (list);\r
297 +}\r
298 +EOF\r
299 +cat <<'EOF' >EXPECTED\r
300 +== stdout ==\r
301 +testkey1 testvalue1\r
302 +testkey2 testvalue2\r
303 +== stderr ==\r
304 +EOF\r
305 +test_expect_equal_file EXPECTED OUTPUT\r
306 +\r
307  test_done\r
308 -- \r
309 2.6.4\r
310 \r