]> git.notmuchmail.org Git - notmuch/blob - lib/message-property.cc
emacs: Add new option notmuch-search-hide-excluded
[notmuch] / lib / message-property.cc
1 /* message-property.cc - Properties are like tags, but (key,value) pairs.
2  * keys are allowed to repeat.
3  *
4  * This file is part of notmuch.
5  *
6  * Copyright © 2016 David Bremner
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see https://www.gnu.org/licenses/ .
20  *
21  * Author: David Bremner <david@tethera.net>
22  */
23
24 #include "notmuch-private.h"
25 #include "database-private.h"
26 #include "message-private.h"
27
28 #define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error)
29
30 static void
31 _log_xapian_exception (const char *where, notmuch_message_t *message,  const Xapian::Error error)
32 {
33     notmuch_database_t *notmuch = notmuch_message_get_database (message);
34
35     _notmuch_database_log (notmuch,
36                            "A Xapian exception occurred at %s: %s\n",
37                            where,
38                            error.get_msg ().c_str ());
39     notmuch->exception_reported = true;
40 }
41
42 notmuch_status_t
43 notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
44 {
45     if (! value)
46         return NOTMUCH_STATUS_NULL_POINTER;
47
48     *value = _notmuch_string_map_get (_notmuch_message_property_map (message), key);
49
50     return NOTMUCH_STATUS_SUCCESS;
51 }
52
53 notmuch_status_t
54 notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count)
55 {
56     if (! count || ! key || ! message)
57         return NOTMUCH_STATUS_NULL_POINTER;
58
59     notmuch_string_map_t *map;
60
61     map = _notmuch_message_property_map (message);
62     if (! map)
63         return NOTMUCH_STATUS_NULL_POINTER;
64
65     notmuch_string_map_iterator_t *matcher = _notmuch_string_map_iterator_create (map, key, true);
66
67     if (! matcher)
68         return NOTMUCH_STATUS_OUT_OF_MEMORY;
69
70     *count = 0;
71     while (_notmuch_string_map_iterator_valid (matcher)) {
72         (*count)++;
73         _notmuch_string_map_iterator_move_to_next (matcher);
74     }
75
76     _notmuch_string_map_iterator_destroy (matcher);
77     return NOTMUCH_STATUS_SUCCESS;
78 }
79
80 static notmuch_status_t
81 _notmuch_message_modify_property (notmuch_message_t *message, const char *key, const char *value,
82                                   bool delete_it)
83 {
84     notmuch_private_status_t private_status;
85     notmuch_status_t status;
86     char *term = NULL;
87
88     status = _notmuch_database_ensure_writable (notmuch_message_get_database (message));
89     if (status)
90         return status;
91
92     if (key == NULL || value == NULL)
93         return NOTMUCH_STATUS_NULL_POINTER;
94
95     if (strchr (key, '='))
96         return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
97
98     term = talloc_asprintf (message, "%s=%s", key, value);
99
100     try {
101         if (delete_it)
102             private_status = _notmuch_message_remove_term (message, "property", term);
103         else
104             private_status = _notmuch_message_add_term (message, "property", term);
105     } catch (Xapian::Error &error) {
106         LOG_XAPIAN_EXCEPTION (message, error);
107         return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
108     }
109
110     if (private_status)
111         return COERCE_STATUS (private_status,
112                               "Unhandled error modifying message property");
113     if (! _notmuch_message_frozen (message))
114         _notmuch_message_sync (message);
115
116     if (term)
117         talloc_free (term);
118
119     return NOTMUCH_STATUS_SUCCESS;
120 }
121
122 notmuch_status_t
123 notmuch_message_add_property (notmuch_message_t *message, const char *key, const char *value)
124 {
125     return _notmuch_message_modify_property (message, key, value, false);
126 }
127
128 notmuch_status_t
129 notmuch_message_remove_property (notmuch_message_t *message, const char *key, const char *value)
130 {
131     return _notmuch_message_modify_property (message, key, value, true);
132 }
133
134 static
135 notmuch_status_t
136 _notmuch_message_remove_all_properties (notmuch_message_t *message, const char *key, bool prefix)
137 {
138     notmuch_status_t status;
139     const char *term_prefix;
140
141     status = _notmuch_database_ensure_writable (notmuch_message_get_database (message));
142     if (status)
143         return status;
144
145     if (key)
146         term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
147                                        prefix ? "" : "=");
148     else
149         term_prefix = _find_prefix ("property");
150
151     try {
152         /* XXX better error reporting ? */
153         _notmuch_message_remove_terms (message, term_prefix);
154     } catch (Xapian::Error &error) {
155         LOG_XAPIAN_EXCEPTION (message, error);
156         return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
157     }
158
159     if (! _notmuch_message_frozen (message))
160         _notmuch_message_sync (message);
161
162     return NOTMUCH_STATUS_SUCCESS;
163 }
164
165 notmuch_status_t
166 notmuch_message_remove_all_properties (notmuch_message_t *message, const char *key)
167 {
168     return _notmuch_message_remove_all_properties (message, key, false);
169 }
170
171 notmuch_status_t
172 notmuch_message_remove_all_properties_with_prefix (notmuch_message_t *message, const char *prefix)
173 {
174     return _notmuch_message_remove_all_properties (message, prefix, true);
175 }
176
177 notmuch_message_properties_t *
178 notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact)
179 {
180     notmuch_string_map_t *map;
181
182     map = _notmuch_message_property_map (message);
183     return _notmuch_string_map_iterator_create (map, key, exact);
184 }
185
186 notmuch_bool_t
187 notmuch_message_properties_valid (notmuch_message_properties_t *properties)
188 {
189     return _notmuch_string_map_iterator_valid (properties);
190 }
191
192 void
193 notmuch_message_properties_move_to_next (notmuch_message_properties_t *properties)
194 {
195     return _notmuch_string_map_iterator_move_to_next (properties);
196 }
197
198 const char *
199 notmuch_message_properties_key (notmuch_message_properties_t *properties)
200 {
201     return _notmuch_string_map_iterator_key (properties);
202 }
203
204 const char *
205 notmuch_message_properties_value (notmuch_message_properties_t *properties)
206 {
207     return _notmuch_string_map_iterator_value (properties);
208 }
209
210 void
211 notmuch_message_properties_destroy (notmuch_message_properties_t *properties)
212 {
213     _notmuch_string_map_iterator_destroy (properties);
214 }