1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <sys/types.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #ifdef HAVE_STRINGS_H
28 # include <strings.h>
29 #endif
30
31 #include <mailutils/errno.h>
32 #include <mailutils/util.h>
33 #include <mailutils/cstr.h>
34 #include <mailutils/sys/attribute.h>
35
36 int
mu_attribute_create(mu_attribute_t * pattr,void * owner)37 mu_attribute_create (mu_attribute_t *pattr, void *owner)
38 {
39 mu_attribute_t attr;
40 if (pattr == NULL)
41 return MU_ERR_OUT_PTR_NULL;
42 attr = calloc (1, sizeof(*attr));
43 if (attr == NULL)
44 return ENOMEM;
45 attr->owner = owner;
46 *pattr = attr;
47 return 0;
48 }
49
50 void
mu_attribute_destroy(mu_attribute_t * pattr,void * owner)51 mu_attribute_destroy (mu_attribute_t *pattr, void *owner)
52 {
53 if (pattr && *pattr)
54 {
55 mu_attribute_t attr = *pattr;
56 if (attr->owner == owner)
57 free (*pattr);
58 /* Loose the link */
59 *pattr = NULL;
60 }
61 }
62
63 void *
mu_attribute_get_owner(mu_attribute_t attr)64 mu_attribute_get_owner (mu_attribute_t attr)
65 {
66 return (attr) ? attr->owner : NULL;
67 }
68
69 int
mu_attribute_is_modified(mu_attribute_t attr)70 mu_attribute_is_modified (mu_attribute_t attr)
71 {
72 return (attr) ? attr->flags & MU_ATTRIBUTE_MODIFIED : 0;
73 }
74
75 int
mu_attribute_clear_modified(mu_attribute_t attr)76 mu_attribute_clear_modified (mu_attribute_t attr)
77 {
78 if (attr)
79 attr->flags &= ~MU_ATTRIBUTE_MODIFIED;
80 return 0;
81 }
82
83 int
mu_attribute_set_modified(mu_attribute_t attr)84 mu_attribute_set_modified (mu_attribute_t attr)
85 {
86 if (attr)
87 attr->flags |= MU_ATTRIBUTE_MODIFIED;
88 return 0;
89 }
90
91 int
mu_attribute_get_flags(mu_attribute_t attr,int * pflags)92 mu_attribute_get_flags (mu_attribute_t attr, int *pflags)
93 {
94 if (attr == NULL)
95 return EINVAL;
96 if (pflags == NULL)
97 return MU_ERR_OUT_PTR_NULL;
98 if (attr->_get_flags)
99 return attr->_get_flags (attr, pflags);
100 *pflags = attr->flags;
101 return 0;
102 }
103
104 int
mu_attribute_set_flags(mu_attribute_t attr,int flags)105 mu_attribute_set_flags (mu_attribute_t attr, int flags)
106 {
107 int status = 0;
108 int oflags = 0;
109
110 if (attr == NULL)
111 return EINVAL;
112
113 /* If the required bits are already set, do not modify anything */
114 mu_attribute_get_flags (attr, &oflags);
115 if ((oflags & flags) == flags)
116 return 0;
117
118 if (attr->_set_flags)
119 status = attr->_set_flags (attr, flags);
120 else
121 attr->flags |= flags;
122 if (status == 0)
123 mu_attribute_set_modified (attr);
124 return 0;
125 }
126
127 int
mu_attribute_unset_flags(mu_attribute_t attr,int flags)128 mu_attribute_unset_flags (mu_attribute_t attr, int flags)
129 {
130 int status = 0;
131 int oflags = 0;
132
133 if (attr == NULL)
134 return EINVAL;
135
136 /* If the required bits are already cleared, do not modify anything */
137 mu_attribute_get_flags (attr, &oflags);
138 if ((oflags & flags) == 0)
139 return 0;
140
141 if (attr->_unset_flags)
142 status = attr->_unset_flags (attr, flags);
143 else
144 attr->flags &= ~flags;
145 if (status == 0)
146 mu_attribute_set_modified (attr);
147 return 0;
148 }
149
150 int
mu_attribute_set_get_flags(mu_attribute_t attr,int (* _get_flags)(mu_attribute_t,int *),void * owner)151 mu_attribute_set_get_flags (mu_attribute_t attr, int (*_get_flags)
152 (mu_attribute_t, int *), void *owner)
153 {
154 if (attr == NULL)
155 return EINVAL;
156 if (attr->owner != owner)
157 return EACCES;
158 attr->_get_flags = _get_flags;
159 return 0;
160 }
161
162 int
mu_attribute_set_set_flags(mu_attribute_t attr,int (* _set_flags)(mu_attribute_t,int),void * owner)163 mu_attribute_set_set_flags (mu_attribute_t attr, int (*_set_flags)
164 (mu_attribute_t, int), void *owner)
165 {
166 if (attr == NULL)
167 return EINVAL;
168 if (attr->owner != owner)
169 return EACCES;
170 attr->_set_flags = _set_flags;
171 return 0;
172 }
173
174 int
mu_attribute_set_unset_flags(mu_attribute_t attr,int (* _unset_flags)(mu_attribute_t,int),void * owner)175 mu_attribute_set_unset_flags (mu_attribute_t attr, int (*_unset_flags)
176 (mu_attribute_t, int), void *owner)
177 {
178 if (attr == NULL)
179 return EINVAL;
180 if (attr->owner != owner)
181 return EACCES;
182 attr->_unset_flags = _unset_flags;
183 return 0;
184 }
185
186 /* We add support for "USER" flag, it is a way for external objects
187 Not being the owner to add custom flags. */
188 int
mu_attribute_set_userflag(mu_attribute_t attr,int flag)189 mu_attribute_set_userflag (mu_attribute_t attr, int flag)
190 {
191 if (attr == NULL)
192 return EINVAL;
193 attr->user_flags |= flag;
194 return 0;
195 }
196
197 int
mu_attribute_set_seen(mu_attribute_t attr)198 mu_attribute_set_seen (mu_attribute_t attr)
199 {
200 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_SEEN);
201 }
202
203 int
mu_attribute_set_answered(mu_attribute_t attr)204 mu_attribute_set_answered (mu_attribute_t attr)
205 {
206 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_ANSWERED);
207 }
208
209 int
mu_attribute_set_flagged(mu_attribute_t attr)210 mu_attribute_set_flagged (mu_attribute_t attr)
211 {
212 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_FLAGGED);
213 }
214
215 int
mu_attribute_set_read(mu_attribute_t attr)216 mu_attribute_set_read (mu_attribute_t attr)
217 {
218 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_READ);
219 }
220
221 int
mu_attribute_set_deleted(mu_attribute_t attr)222 mu_attribute_set_deleted (mu_attribute_t attr)
223 {
224 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_DELETED);
225 }
226
227 int
mu_attribute_set_draft(mu_attribute_t attr)228 mu_attribute_set_draft (mu_attribute_t attr)
229 {
230 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_DRAFT);
231 }
232
233 int
mu_attribute_set_recent(mu_attribute_t attr)234 mu_attribute_set_recent (mu_attribute_t attr)
235 {
236 int status = mu_attribute_unset_flags (attr, MU_ATTRIBUTE_READ);
237 if (status == 0)
238 status = mu_attribute_unset_flags (attr, MU_ATTRIBUTE_SEEN);
239 return status;
240 }
241
242 int
mu_attribute_set_forwarded(mu_attribute_t attr)243 mu_attribute_set_forwarded (mu_attribute_t attr)
244 {
245 return mu_attribute_set_flags (attr, MU_ATTRIBUTE_FORWARDED);
246 }
247
248 int
mu_attribute_is_userflag(mu_attribute_t attr,int flag)249 mu_attribute_is_userflag (mu_attribute_t attr, int flag)
250 {
251 if (attr == NULL)
252 return 0;
253 return attr->user_flags & flag;
254 }
255
256 int
mu_attribute_is_seen(mu_attribute_t attr)257 mu_attribute_is_seen (mu_attribute_t attr)
258 {
259 int flags = 0;
260 if (mu_attribute_get_flags (attr, &flags) == 0)
261 return flags & MU_ATTRIBUTE_SEEN;
262 return 0;
263 }
264
265 int
mu_attribute_is_answered(mu_attribute_t attr)266 mu_attribute_is_answered (mu_attribute_t attr)
267 {
268 int flags = 0;
269 if (mu_attribute_get_flags (attr, &flags) == 0)
270 return flags & MU_ATTRIBUTE_ANSWERED;
271 return 0;
272 }
273
274 int
mu_attribute_is_flagged(mu_attribute_t attr)275 mu_attribute_is_flagged (mu_attribute_t attr)
276 {
277 int flags = 0;
278 if (mu_attribute_get_flags (attr, &flags) == 0)
279 return flags & MU_ATTRIBUTE_FLAGGED;
280 return 0;
281 }
282
283 int
mu_attribute_is_read(mu_attribute_t attr)284 mu_attribute_is_read (mu_attribute_t attr)
285 {
286 int flags = 0;
287 if (mu_attribute_get_flags (attr, &flags) == 0)
288 return flags & MU_ATTRIBUTE_READ;
289 return 0;
290 }
291
292 int
mu_attribute_is_deleted(mu_attribute_t attr)293 mu_attribute_is_deleted (mu_attribute_t attr)
294 {
295 int flags = 0;
296 if (mu_attribute_get_flags (attr, &flags) == 0)
297 return flags & MU_ATTRIBUTE_DELETED;
298 return 0;
299 }
300
301 int
mu_attribute_is_draft(mu_attribute_t attr)302 mu_attribute_is_draft (mu_attribute_t attr)
303 {
304 int flags = 0;
305 if (mu_attribute_get_flags (attr, &flags) == 0)
306 return flags & MU_ATTRIBUTE_DRAFT;
307 return 0;
308 }
309
310 int
mu_attribute_is_recent(mu_attribute_t attr)311 mu_attribute_is_recent (mu_attribute_t attr)
312 {
313 int flags = 0;
314 if (mu_attribute_get_flags (attr, &flags) == 0)
315 return MU_ATTRIBUTE_IS_UNSEEN(flags);
316 return 0;
317 }
318
319 int
mu_attribute_is_forwarded(mu_attribute_t attr)320 mu_attribute_is_forwarded (mu_attribute_t attr)
321 {
322 int flags = 0;
323 if (mu_attribute_get_flags (attr, &flags) == 0)
324 return flags & MU_ATTRIBUTE_FORWARDED;
325 return 0;
326 }
327
328 int
mu_attribute_unset_userflag(mu_attribute_t attr,int flag)329 mu_attribute_unset_userflag (mu_attribute_t attr, int flag)
330 {
331 if (attr == NULL)
332 return 0;
333 attr->user_flags &= ~flag;
334 return 0;
335 }
336
337 int
mu_attribute_unset_seen(mu_attribute_t attr)338 mu_attribute_unset_seen (mu_attribute_t attr)
339 {
340 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_SEEN);
341 }
342
343 int
mu_attribute_unset_answered(mu_attribute_t attr)344 mu_attribute_unset_answered (mu_attribute_t attr)
345 {
346 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_ANSWERED);
347 }
348
349 int
mu_attribute_unset_flagged(mu_attribute_t attr)350 mu_attribute_unset_flagged (mu_attribute_t attr)
351 {
352 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_FLAGGED);
353 }
354
355 int
mu_attribute_unset_read(mu_attribute_t attr)356 mu_attribute_unset_read (mu_attribute_t attr)
357 {
358 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_READ);
359 }
360
361 int
mu_attribute_unset_deleted(mu_attribute_t attr)362 mu_attribute_unset_deleted (mu_attribute_t attr)
363 {
364 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_DELETED);
365 }
366
367 int
mu_attribute_unset_draft(mu_attribute_t attr)368 mu_attribute_unset_draft (mu_attribute_t attr)
369 {
370 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_DRAFT);
371 }
372
373 int
mu_attribute_unset_recent(mu_attribute_t attr)374 mu_attribute_unset_recent (mu_attribute_t attr)
375 {
376 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_SEEN);
377 }
378
379 int
mu_attribute_unset_forwarded(mu_attribute_t attr)380 mu_attribute_unset_forwarded (mu_attribute_t attr)
381 {
382 return mu_attribute_unset_flags (attr, MU_ATTRIBUTE_FORWARDED);
383 }
384
385 int
mu_attribute_is_equal(mu_attribute_t attr,mu_attribute_t attr2)386 mu_attribute_is_equal (mu_attribute_t attr, mu_attribute_t attr2)
387 {
388 int flags2 = 0, flags = 0;
389 mu_attribute_get_flags (attr, &flags);
390 mu_attribute_get_flags (attr2, &flags2);
391 return flags == flags2;
392 }
393
394 /* Miscellaneous. */
395 int
mu_attribute_copy(mu_attribute_t dest,mu_attribute_t src)396 mu_attribute_copy (mu_attribute_t dest, mu_attribute_t src)
397 {
398 if (dest == NULL || src == NULL)
399 return EINVAL;
400 /* Can not be a deep copy. */
401 /* memcpy (dest, src, sizeof (*dest)); */
402 dest->flags = src->flags;
403 return 0;
404 }
405
406 struct flagtrans
407 {
408 int flag;
409 char letter;
410 };
411
412 /* The two macros below are taken from gnulib module verify.h */
413 #define mu_verify_true(R) \
414 (!!sizeof \
415 (struct { unsigned int verify_error_if_negative_size__: (R) ? 1 : -1; }))
416 #define mu_verify(R) extern int (* verify_function__ (void)) [mu_verify_true (R)]
417
418 static struct flagtrans flagtrans[] = {
419 { MU_ATTRIBUTE_ANSWERED, 'A' },
420 { MU_ATTRIBUTE_FLAGGED, 'F' },
421 { MU_ATTRIBUTE_DELETED, 'D' },
422 { MU_ATTRIBUTE_DRAFT, 'd' },
423 { MU_ATTRIBUTE_SEEN, 'O' },
424 { MU_ATTRIBUTE_READ, 'R' },
425 { MU_ATTRIBUTE_FORWARDED, 'P' },
426 { 0 }
427 };
428
429 /* If cc reports an error in this statement, fix the MU_STATUS_BUF_SIZE
430 declaration in include/mailutils/attribute.h */
431 mu_verify (MU_ARRAY_SIZE (flagtrans) == MU_STATUS_BUF_SIZE);
432
433 int
mu_attribute_string_to_flags(const char * buffer,int * pflags)434 mu_attribute_string_to_flags (const char *buffer, int *pflags)
435 {
436 const char *sep;
437
438 if (pflags == NULL)
439 return EINVAL;
440
441 /* Skip the header name */
442 if (mu_c_strncasecmp (buffer, "Status:", 7) == 0)
443 {
444 sep = strchr (buffer, ':'); /* pass the ':' */
445 sep++;
446 }
447 else
448 sep = buffer;
449
450 for (; *sep; sep++)
451 {
452 struct flagtrans *ft;
453
454 for (ft = flagtrans; ft->flag; ft++)
455 if (ft->letter == *sep)
456 {
457 *pflags |= ft->flag;
458 break;
459 }
460 }
461 return 0;
462 }
463
464 int
mu_attribute_flags_to_string(int flags,char * buffer,size_t len,size_t * pn)465 mu_attribute_flags_to_string (int flags, char *buffer, size_t len, size_t *pn)
466 {
467 int i, j;
468 struct flagtrans *ft;
469
470 if (!buffer || len == 0)
471 return EINVAL;
472
473 len--;
474
475 i = j = 0;
476 for (ft = flagtrans; ft->flag; ft++)
477 {
478 if (ft->flag & flags)
479 {
480 if (buffer && i < len)
481 buffer[i++] = ft->letter;
482 j++;
483 }
484 }
485 if (buffer)
486 buffer[i++] = 0;
487
488 if (pn)
489 *pn = j;
490 return j <= len ? 0 : MU_ERR_BUFSPACE;
491 }
492
493 /* NOTE: When adding/removing flags, make sure to update the
494 MU_STATUS_BUF_SIZE define in include/mailutils/attribute.h */
495 int
mu_attribute_to_string(mu_attribute_t attr,char * buffer,size_t len,size_t * pn)496 mu_attribute_to_string (mu_attribute_t attr, char *buffer, size_t len,
497 size_t *pn)
498 {
499 int flags = 0;
500 int rc;
501
502 rc = mu_attribute_get_flags (attr, &flags);
503 if (rc)
504 return rc;
505 return mu_attribute_flags_to_string (flags, buffer, len, pn);
506 }
507
508