Merge tag 'debian/0.29.3-1'
[notmuch] / lib / config.cc
1 /* config.cc - API for database metadata
2  *
3  * Copyright © 2016 David Bremner
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see https://www.gnu.org/licenses/ .
17  *
18  * Author: David Bremner <david@tethera.net>
19  */
20
21 #include "notmuch.h"
22 #include "notmuch-private.h"
23 #include "database-private.h"
24
25 static const std::string CONFIG_PREFIX = "C";
26
27 struct _notmuch_config_list {
28     notmuch_database_t *notmuch;
29     Xapian::TermIterator iterator;
30     char *current_key;
31     char *current_val;
32 };
33
34 static int
35 _notmuch_config_list_destroy (notmuch_config_list_t *list)
36 {
37     /* invoke destructor w/o deallocating memory */
38     list->iterator.~TermIterator();
39     return 0;
40 }
41
42 notmuch_status_t
43 notmuch_database_set_config (notmuch_database_t *notmuch,
44                              const char *key,
45                              const char *value)
46 {
47     notmuch_status_t status;
48     Xapian::WritableDatabase *db;
49
50     status = _notmuch_database_ensure_writable (notmuch);
51     if (status)
52         return status;
53
54     try {
55         db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
56         db->set_metadata (CONFIG_PREFIX + key, value);
57     } catch (const Xapian::Error &error) {
58         status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
59         notmuch->exception_reported = true;
60         _notmuch_database_log (notmuch, "Error: A Xapian exception occurred setting metadata: %s\n",
61                                error.get_msg ().c_str ());
62     }
63     return NOTMUCH_STATUS_SUCCESS;
64 }
65
66 static notmuch_status_t
67 _metadata_value (notmuch_database_t *notmuch,
68                  const char *key,
69                  std::string &value)
70 {
71     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
72
73     try {
74         value = notmuch->xapian_db->get_metadata (CONFIG_PREFIX + key);
75     } catch (const Xapian::Error &error) {
76         status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
77         notmuch->exception_reported = true;
78         _notmuch_database_log (notmuch, "Error: A Xapian exception occurred getting metadata: %s\n",
79                                error.get_msg ().c_str ());
80     }
81     return status;
82 }
83
84 notmuch_status_t
85 notmuch_database_get_config (notmuch_database_t *notmuch,
86                              const char *key,
87                              char **value)
88 {
89     std::string strval;
90     notmuch_status_t status;
91
92     if (! value)
93         return NOTMUCH_STATUS_NULL_POINTER;
94
95     status = _metadata_value (notmuch, key, strval);
96     if (status)
97         return status;
98
99     *value = strdup (strval.c_str ());
100
101     return NOTMUCH_STATUS_SUCCESS;
102 }
103
104 notmuch_status_t
105 notmuch_database_get_config_list (notmuch_database_t *notmuch,
106                                   const char *prefix,
107                                   notmuch_config_list_t **out)
108 {
109     notmuch_config_list_t *list = NULL;
110     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
111
112     list = talloc (notmuch, notmuch_config_list_t);
113     if (! list) {
114         status = NOTMUCH_STATUS_OUT_OF_MEMORY;
115         goto DONE;
116     }
117
118     talloc_set_destructor (list, _notmuch_config_list_destroy);
119     list->notmuch = notmuch;
120     list->current_key = NULL;
121     list->current_val = NULL;
122
123     try {
124
125         new(&(list->iterator)) Xapian::TermIterator (notmuch->xapian_db->metadata_keys_begin
126                                                          (CONFIG_PREFIX + (prefix ? prefix : "")));
127
128     } catch (const Xapian::Error &error) {
129         _notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n",
130                                error.get_msg ().c_str ());
131         notmuch->exception_reported = true;
132         status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
133     }
134
135     *out = list;
136
137   DONE:
138     if (status && list)
139         talloc_free (list);
140
141     return status;
142 }
143
144 notmuch_bool_t
145 notmuch_config_list_valid (notmuch_config_list_t *metadata)
146 {
147     if (metadata->iterator == metadata->notmuch->xapian_db->metadata_keys_end ())
148         return false;
149
150     return true;
151 }
152
153 static inline char * _key_from_iterator (notmuch_config_list_t *list) {
154     return talloc_strdup (list, (*list->iterator).c_str () + CONFIG_PREFIX.length ());
155 }
156
157 const char *
158 notmuch_config_list_key (notmuch_config_list_t *list)
159 {
160     if (list->current_key)
161         talloc_free (list->current_key);
162
163     list->current_key = _key_from_iterator (list);
164
165     return list->current_key;
166 }
167
168 const char *
169 notmuch_config_list_value (notmuch_config_list_t *list)
170 {
171     std::string strval;
172     notmuch_status_t status;
173     char *key = _key_from_iterator (list);
174
175     /* TODO: better error reporting?? */
176     status = _metadata_value (list->notmuch, key, strval);
177     if (status)
178         return NULL;
179
180     if (list->current_val)
181         talloc_free (list->current_val);
182
183     list->current_val = talloc_strdup (list, strval.c_str ());
184     talloc_free (key);
185     return list->current_val;
186 }
187
188 void
189 notmuch_config_list_move_to_next (notmuch_config_list_t *list)
190 {
191     list->iterator++;
192 }
193
194 void
195 notmuch_config_list_destroy (notmuch_config_list_t *list)
196 {
197     talloc_free (list);
198 }