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