notmuch-mutt: replace shell pipeline with internal pipe processing
[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 notmuch_status_t
29 notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value)
30 {
31     if (! value)
32         return NOTMUCH_STATUS_NULL_POINTER;
33
34     *value = _notmuch_string_map_get (_notmuch_message_property_map (message), key);
35
36     return NOTMUCH_STATUS_SUCCESS;
37 }
38
39 notmuch_status_t
40 notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count)
41 {
42     if (! count || ! key || ! message)
43         return NOTMUCH_STATUS_NULL_POINTER;
44
45     notmuch_string_map_t *map;
46     map = _notmuch_message_property_map (message);
47     if (! map)
48         return NOTMUCH_STATUS_NULL_POINTER;
49
50     notmuch_string_map_iterator_t *matcher = _notmuch_string_map_iterator_create (map, key, true);
51     if (! matcher)
52         return NOTMUCH_STATUS_OUT_OF_MEMORY;
53
54     *count = 0;
55     while (_notmuch_string_map_iterator_valid (matcher)) {
56         (*count)++;
57         _notmuch_string_map_iterator_move_to_next (matcher);
58     }
59
60     _notmuch_string_map_iterator_destroy (matcher);
61     return NOTMUCH_STATUS_SUCCESS;
62 }
63
64 static notmuch_status_t
65 _notmuch_message_modify_property (notmuch_message_t *message, const char *key, const char *value,
66                                   bool delete_it)
67 {
68     notmuch_private_status_t private_status;
69     notmuch_status_t status;
70     char *term = NULL;
71
72     status = _notmuch_database_ensure_writable (notmuch_message_get_database (message));
73     if (status)
74         return status;
75
76     if (key == NULL || value == NULL)
77         return NOTMUCH_STATUS_NULL_POINTER;
78
79     if (strchr (key, '='))
80         return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
81
82     term = talloc_asprintf (message, "%s=%s", key, value);
83
84     if (delete_it)
85         private_status = _notmuch_message_remove_term (message, "property", term);
86     else
87         private_status = _notmuch_message_add_term (message, "property", term);
88
89     if (private_status)
90         return COERCE_STATUS (private_status,
91                               "Unhandled error modifying message property");
92     if (! _notmuch_message_frozen (message))
93         _notmuch_message_sync (message);
94
95     if (term)
96         talloc_free (term);
97
98     return NOTMUCH_STATUS_SUCCESS;
99 }
100
101 notmuch_status_t
102 notmuch_message_add_property (notmuch_message_t *message, const char *key, const char *value)
103 {
104     return _notmuch_message_modify_property (message, key, value, false);
105 }
106
107 notmuch_status_t
108 notmuch_message_remove_property (notmuch_message_t *message, const char *key, const char *value)
109 {
110     return _notmuch_message_modify_property (message, key, value, true);
111 }
112
113 static
114 notmuch_status_t
115 _notmuch_message_remove_all_properties (notmuch_message_t *message, const char *key, bool prefix)
116 {
117     notmuch_status_t status;
118     const char *term_prefix;
119
120     status = _notmuch_database_ensure_writable (notmuch_message_get_database (message));
121     if (status)
122         return status;
123
124     _notmuch_message_invalidate_metadata (message, "property");
125     if (key)
126         term_prefix = talloc_asprintf (message, "%s%s%s", _find_prefix ("property"), key,
127                                        prefix ? "" : "=");
128     else
129         term_prefix = _find_prefix ("property");
130
131     /* XXX better error reporting ? */
132     _notmuch_message_remove_terms (message, term_prefix);
133
134     return NOTMUCH_STATUS_SUCCESS;
135 }
136
137 notmuch_status_t
138 notmuch_message_remove_all_properties (notmuch_message_t *message, const char *key)
139 {
140     return _notmuch_message_remove_all_properties (message, key, false);
141 }
142
143 notmuch_status_t
144 notmuch_message_remove_all_properties_with_prefix (notmuch_message_t *message, const char *prefix)
145 {
146     return _notmuch_message_remove_all_properties (message, prefix, true);
147 }
148
149 notmuch_message_properties_t *
150 notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact)
151 {
152     notmuch_string_map_t *map;
153
154     map = _notmuch_message_property_map (message);
155     return _notmuch_string_map_iterator_create (map, key, exact);
156 }
157
158 notmuch_bool_t
159 notmuch_message_properties_valid (notmuch_message_properties_t *properties)
160 {
161     return _notmuch_string_map_iterator_valid (properties);
162 }
163
164 void
165 notmuch_message_properties_move_to_next (notmuch_message_properties_t *properties)
166 {
167     return _notmuch_string_map_iterator_move_to_next (properties);
168 }
169
170 const char *
171 notmuch_message_properties_key (notmuch_message_properties_t *properties)
172 {
173     return _notmuch_string_map_iterator_key (properties);
174 }
175
176 const char *
177 notmuch_message_properties_value (notmuch_message_properties_t *properties)
178 {
179     return _notmuch_string_map_iterator_value (properties);
180 }
181
182 void
183 notmuch_message_properties_destroy (notmuch_message_properties_t *properties)
184 {
185     _notmuch_string_map_iterator_destroy (properties);
186 }