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 <stdlib.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <mailutils/debug.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/error.h>
30 #include <mailutils/folder.h>
31 #include <mailutils/iterator.h>
32 #include <mailutils/list.h>
33 #include <mailutils/locker.h>
34 #include <mailutils/observer.h>
35 #include <mailutils/property.h>
36 #include <mailutils/registrar.h>
37 #include <mailutils/stream.h>
38 #include <mailutils/url.h>
39 #include <mailutils/attribute.h>
40 #include <mailutils/message.h>
41 #include <mailutils/util.h>
42
43 #include <mailutils/sys/mailbox.h>
44 #include <mailutils/sys/folder.h>
45 #include <mailutils/sys/url.h>
46
47 static int
mailbox_folder_create(mu_mailbox_t mbox,const char * name,mu_record_t record)48 mailbox_folder_create (mu_mailbox_t mbox, const char *name,
49 mu_record_t record)
50 {
51 int rc;
52 mu_url_t url;
53
54 if ((rc = mu_url_uplevel (mbox->url, &url)))
55 {
56 if (rc == MU_ERR_NOENT)
57 {
58 rc = mu_url_dup (mbox->url, &url);
59 if (rc)
60 return rc;
61 }
62 else
63 return rc;
64 }
65
66 rc = mu_folder_create_from_record (&mbox->folder, url, record);
67 if (rc)
68 mu_url_destroy (&url);
69 return rc;
70 }
71
72 int
_mailbox_create_from_record(mu_mailbox_t * pmbox,mu_record_t record,mu_url_t url,mu_folder_t folder,const char * name)73 _mailbox_create_from_record (mu_mailbox_t *pmbox,
74 mu_record_t record,
75 mu_url_t url,
76 mu_folder_t folder,
77 const char *name)
78 {
79 int (*m_init) (mu_mailbox_t) = NULL;
80
81 mu_record_get_mailbox (record, &m_init);
82 if (m_init)
83 {
84 int status;
85 int (*u_init) (mu_url_t) = NULL;
86 mu_mailbox_t mbox;
87
88 /* Allocate memory for mbox. */
89 mbox = calloc (1, sizeof (*mbox));
90 if (mbox == NULL)
91 return ENOMEM;
92 mbox->notify_fd = -1;
93
94 /* Initialize the internal lock now, so the concrete mailbox
95 could use it. */
96 status = mu_monitor_create (&mbox->monitor, 0, mbox);
97 if (status != 0)
98 {
99 mu_mailbox_destroy (&mbox);
100 return status;
101 }
102
103 /* Make sure scheme contains actual mailbox scheme */
104 /* FIXME: It is appropriate not for all record types. For now we
105 assume that if the record scheme ends with a plus sign, this
106 should not be done. Probably it requires some flag in struct
107 _mu_record? */
108 if (strcmp (url->scheme, record->scheme))
109 {
110 char *p = strdup (record->scheme);
111 if (!p)
112 {
113 mu_mailbox_destroy (&mbox);
114 return errno;
115 }
116 free (url->scheme);
117 url->scheme = p;
118 }
119
120 mu_record_get_url (record, &u_init);
121 if (u_init && (status = u_init (url)) != 0)
122 {
123 mu_mailbox_destroy (&mbox);
124 return status;
125 }
126
127 mbox->url = url;
128
129 if (folder)
130 {
131 folder->ref++; /* FIXME: No ref/unref function for folders */
132 mbox->folder = folder;
133 }
134 else
135 /* Create the folder before initializing the concrete mailbox.
136 The mailbox needs it's back pointer. */
137 status = mailbox_folder_create (mbox, name, record);
138
139 if (status == 0)
140 status = m_init (mbox); /* Create the concrete mailbox type. */
141
142 if (status != 0)
143 {
144 /* Take care not to destroy url. Leave it to caller. */
145 mbox->url = NULL;
146 mu_mailbox_destroy (&mbox);
147 }
148 else
149 *pmbox = mbox;
150 return status;
151 }
152 return ENOSYS;
153 }
154
155 static int
_create_mailbox0(mu_mailbox_t * pmbox,mu_url_t url,const char * name)156 _create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name)
157 {
158 mu_record_t record = NULL;
159 int rc;
160
161 rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL);
162 if (rc == 0)
163 rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
164 return rc;
165 }
166
167 static int
_create_mailbox(mu_mailbox_t * pmbox,const char * name)168 _create_mailbox (mu_mailbox_t *pmbox, const char *name)
169 {
170 int status;
171 mu_url_t url;
172
173 status = mu_url_create (&url, name);
174 if (status)
175 return status;
176 status = _create_mailbox0 (pmbox, url, name);
177 if (status)
178 mu_url_destroy (&url);
179 return status;
180 }
181
182 /* The Mailbox Factory.
183 */
184 int
mu_mailbox_create(mu_mailbox_t * pmbox,const char * name)185 mu_mailbox_create (mu_mailbox_t *pmbox, const char *name)
186 {
187 if (pmbox == NULL)
188 return MU_ERR_OUT_PTR_NULL;
189
190 return _create_mailbox (pmbox, name);
191 }
192
193 int
mu_mailbox_create_from_url(mu_mailbox_t * pmbox,mu_url_t url)194 mu_mailbox_create_from_url (mu_mailbox_t *pmbox, mu_url_t url)
195 {
196 if (pmbox == NULL)
197 return MU_ERR_OUT_PTR_NULL;
198 return _create_mailbox0 (pmbox, url, mu_url_to_string (url));
199 }
200
201 int
mu_mailbox_create_from_record(mu_mailbox_t * pmbox,mu_record_t record,const char * name)202 mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record,
203 const char *name)
204 {
205 mu_url_t url;
206 int rc;
207
208 rc = mu_url_create (&url, name);
209 if (rc)
210 return rc;
211 rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
212 if (rc)
213 mu_url_destroy (&url);
214 return rc;
215 }
216
217 int
mu_mailbox_create_at(mu_mailbox_t * pmbox,mu_folder_t folder,const char * name)218 mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
219 const char *name)
220 {
221 int rc;
222 mu_url_t url;
223 const char *oldpath;
224
225 rc = mu_url_dup (folder->url, &url);
226 if (rc)
227 return rc;
228 do
229 {
230 char *path;
231 size_t oldlen, len;
232 mu_record_t record;
233
234 rc = mu_url_sget_path (url, &oldpath);
235 if (rc)
236 break;
237
238 oldlen = strlen (oldpath);
239 if (oldlen == 0)
240 {
241 path = strdup (name);
242 if (!path)
243 {
244 rc = ENOMEM;
245 break;
246 }
247 }
248 else
249 {
250 if (oldpath[oldlen-1] == '/')
251 oldlen--;
252 len = oldlen + 1 + strlen (name) + 1;
253 path = malloc (len);
254 if (!path)
255 {
256 rc = ENOMEM;
257 break;
258 }
259 memcpy (path, oldpath, oldlen);
260 path[oldlen++] = '/';
261 strcpy (path + oldlen, name);
262 }
263 rc = mu_url_set_path (url, path);
264 free (path);
265 if (rc)
266 break;
267
268 rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE,
269 &record, NULL);
270 if (rc)
271 break;
272 rc = _mailbox_create_from_record (pmbox, record, url, folder, name);
273 }
274 while (0);
275
276 if (rc)
277 mu_url_destroy (&url);
278 return rc;
279 }
280
281 void
mu_mailbox_destroy(mu_mailbox_t * pmbox)282 mu_mailbox_destroy (mu_mailbox_t *pmbox)
283 {
284 if (pmbox && *pmbox)
285 {
286 mu_mailbox_t mbox = *pmbox;
287 mu_monitor_t monitor = mbox->monitor;
288
289 /* Notify the observers. */
290 if (mbox->observable)
291 {
292 mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY,
293 mbox);
294 mu_observable_destroy (&mbox->observable, mbox);
295 }
296
297 /* Call the concrete mailbox _destroy method. So it can clean itself. */
298 if (mbox->_destroy)
299 mbox->_destroy (mbox);
300
301 mu_monitor_wrlock (monitor);
302
303 /* Close the stream and nuke it */
304 if (mbox->stream)
305 {
306 /* FIXME: Is this right, should the client be responsible
307 for closing the stream? */
308 /* mu_stream_close (mbox->stream); */
309 mu_stream_destroy (&mbox->stream);
310 }
311
312 mu_url_destroy (&mbox->url);
313 mu_locker_destroy (&mbox->locker);
314 mu_folder_destroy (&mbox->folder);
315 mu_property_destroy (&mbox->property);
316 free (mbox->notify_user);
317 free (mbox->notify_sa);
318
319 free (mbox);
320 *pmbox = NULL;
321 mu_monitor_unlock (monitor);
322 mu_monitor_destroy (&monitor, mbox);
323 }
324 }
325
326
327 /* -------------- stub functions ------------------- */
328
329 int
mu_mailbox_open(mu_mailbox_t mbox,int flag)330 mu_mailbox_open (mu_mailbox_t mbox, int flag)
331 {
332 int rc;
333
334 if (!mbox)
335 return EINVAL;
336 if (mbox->_open == NULL)
337 return MU_ERR_EMPTY_VFN;
338 if (mbox->flags & _MU_MAILBOX_OPEN)
339 return MU_ERR_OPEN;
340 if (flag & MU_STREAM_QACCESS)
341 {
342 /* Quick access mailboxes are read-only */
343 if (flag & (MU_STREAM_WRITE
344 | MU_STREAM_APPEND | MU_STREAM_CREAT))
345 return EACCES;
346 }
347 rc = mbox->_open (mbox, flag);
348 if (rc == 0)
349 mbox->flags |= _MU_MAILBOX_OPEN;
350 return rc;
351 }
352
353 int
mu_mailbox_close(mu_mailbox_t mbox)354 mu_mailbox_close (mu_mailbox_t mbox)
355 {
356 int rc;
357
358 if (!mbox)
359 return EINVAL;
360 if (!(mbox->flags & _MU_MAILBOX_OPEN))
361 return MU_ERR_NOT_OPEN;
362 if (mbox == NULL || mbox->_close == NULL)
363 return MU_ERR_EMPTY_VFN;
364
365 rc = mbox->_close (mbox);
366 if (rc == 0)
367 {
368 if (mbox->notify_fd >= 0)
369 close (mbox->notify_fd);
370 mbox->flags &= ~_MU_MAILBOX_OPEN;
371 }
372 return rc;
373 }
374
375 int
mu_mailbox_remove(mu_mailbox_t mbox)376 mu_mailbox_remove (mu_mailbox_t mbox)
377 {
378 if (!mbox)
379 return EINVAL;
380 if (mbox->flags & _MU_MAILBOX_OPEN)
381 return MU_ERR_OPEN;
382 if (mbox->flags & _MU_MAILBOX_REMOVED)
383 return MU_ERR_MBX_REMOVED;
384 if (!mbox->_remove)
385 {
386 /* Try the owning folder delete method. See comment to mu_folder_delete
387 in folder.c. This may result in a recursive call to mu_mailbox_remove
388 which is blocked by setting the _MU_MAILBOX_REMOVED flag. */
389
390 int rc;
391 const char *path;
392
393 rc = mu_url_sget_path (mbox->url, &path);
394 if (rc == 0)
395 {
396 mbox->flags |= _MU_MAILBOX_REMOVED;
397 rc = mu_folder_delete (mbox->folder, path);
398 if (rc)
399 mbox->flags &= ~_MU_MAILBOX_REMOVED;
400 }
401 return rc;
402 }
403 return mbox->_remove (mbox);
404 }
405
406 int
mu_mailbox_flush(mu_mailbox_t mbox,int expunge)407 mu_mailbox_flush (mu_mailbox_t mbox, int expunge)
408 {
409 if (!mbox)
410 return EINVAL;
411 if (mbox->flags & _MU_MAILBOX_REMOVED)
412 return MU_ERR_MBX_REMOVED;
413 if (!(mbox->flags & _MU_MAILBOX_OPEN))
414 return _MU_MAILBOX_OPEN;
415 if (!(mbox->flags & (MU_STREAM_WRITE|MU_STREAM_APPEND)))
416 return 0;
417
418 if (!(mbox->flags & MU_STREAM_APPEND))
419 {
420 size_t i, total = 0;
421
422 mu_mailbox_messages_count (mbox, &total);
423 for (i = 1; i <= total; i++)
424 {
425 mu_message_t msg = NULL;
426 mu_attribute_t attr = NULL;
427 mu_mailbox_get_message (mbox, i, &msg);
428 mu_message_get_attribute (msg, &attr);
429 mu_attribute_set_seen (attr);
430 }
431 if (expunge)
432 return mu_mailbox_expunge (mbox);
433 }
434 return mu_mailbox_sync (mbox);
435 }
436
437 #define _MBOX_CHECK_FLAGS(mbox) \
438 if (mbox == NULL) \
439 return EINVAL; \
440 if (mbox->flags & _MU_MAILBOX_REMOVED) \
441 return MU_ERR_MBX_REMOVED; \
442 if (!(mbox->flags & _MU_MAILBOX_OPEN)) \
443 return MU_ERR_NOT_OPEN
444
445 #define _MBOX_CHECK(mbox,method) \
446 _MBOX_CHECK_FLAGS(mbox); \
447 if (mbox->method == NULL) \
448 return MU_ERR_EMPTY_VFN
449
450 #define _MBOX_CHECK_Q(mbox,method) \
451 _MBOX_CHECK(mbox,method); \
452 if (mbox->flags & MU_STREAM_QACCESS) \
453 return MU_ERR_BADOP
454
455 /* messages */
456 int
mu_mailbox_append_message(mu_mailbox_t mbox,mu_message_t msg)457 mu_mailbox_append_message (mu_mailbox_t mbox, mu_message_t msg)
458 {
459 _MBOX_CHECK_Q (mbox, _append_message);
460 if (!(mbox->flags & (MU_STREAM_WRITE|MU_STREAM_APPEND)))
461 return EACCES;
462 return mbox->_append_message (mbox, msg);
463 }
464
465 int
mu_mailbox_get_message(mu_mailbox_t mbox,size_t msgno,mu_message_t * pmsg)466 mu_mailbox_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
467 {
468 _MBOX_CHECK_Q (mbox, _get_message);
469 return mbox->_get_message (mbox, msgno, pmsg);
470 }
471
472 int
mu_mailbox_quick_get_message(mu_mailbox_t mbox,mu_message_qid_t qid,mu_message_t * pmsg)473 mu_mailbox_quick_get_message (mu_mailbox_t mbox, mu_message_qid_t qid,
474 mu_message_t *pmsg)
475 {
476 _MBOX_CHECK (mbox, _quick_get_message);
477 if (!(mbox->flags & MU_STREAM_QACCESS))
478 return MU_ERR_BADOP;
479 return mbox->_quick_get_message (mbox, qid, pmsg);
480 }
481
482 int
mu_mailbox_messages_count(mu_mailbox_t mbox,size_t * num)483 mu_mailbox_messages_count (mu_mailbox_t mbox, size_t *num)
484 {
485 _MBOX_CHECK_Q (mbox, _messages_count);
486 return mbox->_messages_count (mbox, num);
487 }
488
489 int
mu_mailbox_messages_recent(mu_mailbox_t mbox,size_t * num)490 mu_mailbox_messages_recent (mu_mailbox_t mbox, size_t *num)
491 {
492 size_t i, count, n;
493 int rc;
494
495 _MBOX_CHECK_FLAGS (mbox);
496 if (mbox->flags & MU_STREAM_QACCESS)
497 return MU_ERR_BADOP;
498 if (mbox->_messages_recent)
499 return mbox->_messages_recent (mbox, num);
500
501 rc = mu_mailbox_messages_count (mbox, &count);
502 if (rc)
503 return rc;
504 n = 0;
505 for (i = 1; i < count; i++)
506 {
507 mu_message_t msg;
508 mu_attribute_t attr;
509
510 rc = mu_mailbox_get_message (mbox, i, &msg);
511 if (rc)
512 return rc;
513 rc = mu_message_get_attribute (msg, &attr);
514 if (rc)
515 return rc;
516 if (mu_attribute_is_recent (attr))
517 n++;
518 }
519 *num = n;
520 return 0;
521 }
522
523 int
mu_mailbox_message_unseen(mu_mailbox_t mbox,size_t * num)524 mu_mailbox_message_unseen (mu_mailbox_t mbox, size_t *num)
525 {
526 int rc;
527 size_t i, count;
528
529 _MBOX_CHECK_FLAGS (mbox);
530 if (mbox->flags & MU_STREAM_QACCESS)
531 return MU_ERR_BADOP;
532 if (mbox->_message_unseen)
533 return mbox->_message_unseen (mbox, num);
534
535 rc = mu_mailbox_messages_count (mbox, &count);
536 if (rc)
537 return rc;
538 for (i = 1; i < count; i++)
539 {
540 mu_message_t msg;
541 mu_attribute_t attr;
542 int rc;
543
544 rc = mu_mailbox_get_message (mbox, i, &msg);
545 if (rc)
546 return rc;
547 rc = mu_message_get_attribute (msg, &attr);
548 if (rc)
549 return rc;
550 if (!mu_attribute_is_seen (attr))
551 {
552 *num = i;
553 return 0;
554 }
555 }
556
557 *num = 0;
558 return 0;
559 }
560
561 int
mu_mailbox_sync(mu_mailbox_t mbox)562 mu_mailbox_sync (mu_mailbox_t mbox)
563 {
564 _MBOX_CHECK_Q (mbox, _sync);
565 if (!(mbox->flags & (MU_STREAM_WRITE|MU_STREAM_APPEND)))
566 return 0;
567 return mbox->_sync (mbox);
568 }
569
570 /* Historic alias: */
571 int
mu_mailbox_expunge(mu_mailbox_t mbox)572 mu_mailbox_expunge (mu_mailbox_t mbox)
573 {
574 _MBOX_CHECK_Q (mbox, _expunge);
575 if (!(mbox->flags & (MU_STREAM_WRITE|MU_STREAM_APPEND)))
576 return EACCES;
577 return mbox->_expunge (mbox);
578 }
579
580 int
mu_mailbox_is_updated(mu_mailbox_t mbox)581 mu_mailbox_is_updated (mu_mailbox_t mbox)
582 {
583 if (mbox == NULL ||
584 !(mbox->flags & _MU_MAILBOX_OPEN) ||
585 (mbox->flags & _MU_MAILBOX_REMOVED) ||
586 mbox->_is_updated == NULL)
587 return 1;
588 if (mbox->flags & MU_STREAM_QACCESS)
589 return 1;
590 return mbox->_is_updated (mbox);
591 }
592
593 int
mu_mailbox_scan(mu_mailbox_t mbox,size_t msgno,size_t * pcount)594 mu_mailbox_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
595 {
596 _MBOX_CHECK_Q (mbox, _scan);
597 return mbox->_scan (mbox, msgno, pcount);
598 }
599
600 int
mu_mailbox_get_size(mu_mailbox_t mbox,mu_off_t * psize)601 mu_mailbox_get_size (mu_mailbox_t mbox, mu_off_t *psize)
602 {
603 int status;
604
605 _MBOX_CHECK_FLAGS (mbox);
606 if (mbox->flags & MU_STREAM_QACCESS)
607 return MU_ERR_BADOP;
608 if (mbox->_get_size == NULL
609 || (status = mbox->_get_size (mbox, psize)) == ENOSYS)
610 {
611 /* Fall back to brute-force method */
612 size_t i, total;
613 mu_off_t size = 0;
614
615 status = mu_mailbox_messages_count (mbox, &total);
616 if (status)
617 return status;
618 for (i = 1; i <= total; i++)
619 {
620 mu_message_t msg;
621 size_t msgsize;
622 status = mu_mailbox_get_message (mbox, i, &msg);
623 if (status)
624 return status;
625 status = mu_message_size (msg, &msgsize);
626 if (status)
627 return status;
628 size += msgsize;
629 }
630 *psize = size;
631 }
632 return status;
633 }
634
635 int
mu_mailbox_uidvalidity(mu_mailbox_t mbox,unsigned long * pvalid)636 mu_mailbox_uidvalidity (mu_mailbox_t mbox, unsigned long *pvalid)
637 {
638 _MBOX_CHECK_Q (mbox, _get_uidvalidity);
639 return mbox->_get_uidvalidity (mbox, pvalid);
640 }
641
642 int
mu_mailbox_uidvalidity_reset(mu_mailbox_t mbox)643 mu_mailbox_uidvalidity_reset (mu_mailbox_t mbox)
644 {
645 _MBOX_CHECK_Q (mbox, _set_uidvalidity);
646 return mbox->_set_uidvalidity (mbox, time (NULL));
647 }
648
649 int
mu_mailbox_uidnext(mu_mailbox_t mbox,size_t * puidnext)650 mu_mailbox_uidnext (mu_mailbox_t mbox, size_t *puidnext)
651 {
652 _MBOX_CHECK_Q (mbox, _uidnext);
653 return mbox->_uidnext (mbox, puidnext);
654 }
655
656 /* locking */
657 int
mu_mailbox_set_locker(mu_mailbox_t mbox,mu_locker_t locker)658 mu_mailbox_set_locker (mu_mailbox_t mbox, mu_locker_t locker)
659 {
660 if (mbox == NULL)
661 return EINVAL;
662 if (mbox->locker)
663 mu_locker_destroy (&mbox->locker);
664 mbox->locker = locker;
665 return 0;
666 }
667
668 int
mu_mailbox_get_locker(mu_mailbox_t mbox,mu_locker_t * plocker)669 mu_mailbox_get_locker (mu_mailbox_t mbox, mu_locker_t *plocker)
670 {
671 if (mbox == NULL)
672 return EINVAL;
673 if (plocker == NULL)
674 return MU_ERR_OUT_PTR_NULL;
675 *plocker = mbox->locker;
676 return 0;
677 }
678
679 int
mu_mailbox_get_flags(mu_mailbox_t mbox,int * flags)680 mu_mailbox_get_flags (mu_mailbox_t mbox, int *flags)
681 {
682 if (mbox == NULL)
683 return EINVAL;
684 if (!flags)
685 return MU_ERR_OUT_PTR_NULL;
686 *flags = mbox->flags & ~_MU_MAILBOX_MASK;
687 return 0;
688 }
689
690 int
mu_mailbox_set_stream(mu_mailbox_t mbox,mu_stream_t stream)691 mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t stream)
692 {
693 if (mbox == NULL)
694 return EINVAL;
695 if (mbox->flags & MU_STREAM_QACCESS)
696 return MU_ERR_BADOP;
697 if (mbox->stream)
698 mu_stream_destroy (&mbox->stream);
699 mbox->stream = stream;
700 return 0;
701 }
702
703 int
mu_mailbox_get_observable(mu_mailbox_t mbox,mu_observable_t * pobservable)704 mu_mailbox_get_observable (mu_mailbox_t mbox, mu_observable_t *pobservable)
705 {
706 if (mbox == NULL)
707 return EINVAL;
708 if (pobservable == NULL)
709 return MU_ERR_OUT_PTR_NULL;
710
711 if (mbox->observable == NULL)
712 {
713 int status = mu_observable_create (&mbox->observable, mbox);
714 if (status != 0)
715 return status;
716 }
717 *pobservable = mbox->observable;
718 return 0;
719 }
720
721 int
mu_mailbox_set_property(mu_mailbox_t mbox,mu_property_t property)722 mu_mailbox_set_property (mu_mailbox_t mbox, mu_property_t property)
723 {
724 if (mbox == NULL)
725 return EINVAL;
726 if (mbox->property)
727 mu_property_unref (mbox->property);
728 mbox->property = property;
729 mu_property_ref (property);
730 return 0;
731 }
732
733 int
mu_mailbox_get_property(mu_mailbox_t mbox,mu_property_t * pproperty)734 mu_mailbox_get_property (mu_mailbox_t mbox, mu_property_t *pproperty)
735 {
736 if (mbox == NULL)
737 return EINVAL;
738 if (pproperty == NULL)
739 return MU_ERR_OUT_PTR_NULL;
740
741 if (mbox->property == NULL)
742 {
743 int status;
744
745 if (mbox->_get_property)
746 status = mbox->_get_property (mbox, &mbox->property);
747 else
748 status = mu_property_create_init (&mbox->property,
749 mu_assoc_property_init, NULL);
750 if (status != 0)
751 return status;
752 }
753 *pproperty = mbox->property;
754 return 0;
755 }
756
757 int
mu_mailbox_get_url(mu_mailbox_t mbox,mu_url_t * purl)758 mu_mailbox_get_url (mu_mailbox_t mbox, mu_url_t *purl)
759 {
760 if (mbox == NULL)
761 return EINVAL;
762 if (purl == NULL)
763 return MU_ERR_OUT_PTR_NULL;
764 *purl = mbox->url;
765 return 0;
766 }
767
768 int
mu_mailbox_get_folder(mu_mailbox_t mbox,mu_folder_t * pfolder)769 mu_mailbox_get_folder (mu_mailbox_t mbox, mu_folder_t *pfolder)
770 {
771 if (mbox == NULL)
772 return EINVAL;
773 if (pfolder == NULL)
774 return MU_ERR_OUT_PTR_NULL;
775 *pfolder = mbox->folder;
776 return 0;
777 }
778
779 int
mu_mailbox_set_folder(mu_mailbox_t mbox,mu_folder_t folder)780 mu_mailbox_set_folder (mu_mailbox_t mbox, mu_folder_t folder)
781 {
782 if (mbox == NULL)
783 return EINVAL;
784 mbox->folder = folder;
785 return 0;
786 }
787
788 int
mu_mailbox_lock(mu_mailbox_t mbox)789 mu_mailbox_lock (mu_mailbox_t mbox)
790 {
791 mu_locker_t lock = NULL;
792 mu_mailbox_get_locker (mbox, &lock);
793 return mu_locker_lock (lock);
794 }
795
796 int
mu_mailbox_unlock(mu_mailbox_t mbox)797 mu_mailbox_unlock (mu_mailbox_t mbox)
798 {
799 mu_locker_t lock = NULL;
800 mu_mailbox_get_locker (mbox, &lock);
801 return mu_locker_unlock (lock);
802 }
803
804 int
mu_mailbox_get_uidls(mu_mailbox_t mbox,mu_list_t * plist)805 mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
806 {
807 mu_list_t list;
808 int status;
809
810 if (mbox == NULL)
811 return EINVAL;
812 if (plist == NULL)
813 return MU_ERR_OUT_PTR_NULL;
814 status = mu_list_create (&list);
815 if (status)
816 return status;
817 mu_list_set_destroy_item (list, mu_list_free_item);
818 if (mbox->_get_uidls)
819 status = mbox->_get_uidls (mbox, list);
820 else
821 {
822 size_t i, total;
823
824 status = mu_mailbox_messages_count (mbox, &total);
825 if (status)
826 return status;
827 for (i = 1; i <= total; i++)
828 {
829 mu_message_t msg = NULL;
830 char buf[MU_UIDL_BUFFER_SIZE];
831 size_t n;
832 struct mu_uidl *uidl;
833
834 status = mu_mailbox_get_message (mbox, i, &msg);
835 if (status)
836 break;
837 status = mu_message_get_uidl (msg, buf, sizeof (buf), &n);
838 if (status)
839 break;
840 uidl = malloc (sizeof (uidl[0]));
841 if (!uidl)
842 {
843 status = ENOMEM;
844 break;
845 }
846 uidl->msgno = i;
847 strncpy (uidl->uidl, buf, MU_UIDL_BUFFER_SIZE);
848 status = mu_list_append (list, uidl);
849 if (status)
850 {
851 free (uidl);
852 break;
853 }
854 }
855 }
856 *plist = list;
857 return status;
858 }
859
860
861 /* Auxiliary function. Performs binary search for a message with the
862 given UID number */
863 static int
_uid_bsearch(mu_mailbox_t mbox,size_t start,size_t stop,size_t uid,size_t * msgno)864 _uid_bsearch (mu_mailbox_t mbox, size_t start, size_t stop, size_t uid,
865 size_t *msgno)
866 {
867 mu_message_t mid_msg = NULL;
868 size_t num = 0, middle;
869 int rc;
870
871 middle = (start + stop) / 2;
872 rc = mu_mailbox_get_message (mbox, middle, &mid_msg);
873 if (rc)
874 return rc;
875 rc = mu_message_get_uid (mid_msg, &num);
876 if (rc)
877 return rc;
878
879 if (num == uid)
880 {
881 *msgno = middle;
882 return 0;
883 }
884
885 if (start >= stop)
886 return MU_ERR_NOENT;
887
888 if (num > uid)
889 return _uid_bsearch (mbox, start, middle - 1, uid, msgno);
890 else /*if (num < seqno)*/
891 return _uid_bsearch (mbox, middle + 1, stop, uid, msgno);
892 }
893
894 static int
_search_message_uid(mu_mailbox_t mbox,size_t uid,size_t * result)895 _search_message_uid (mu_mailbox_t mbox, size_t uid, size_t *result)
896 {
897 int rc;
898 size_t num, count;
899 mu_message_t msg;
900
901 rc = mu_mailbox_get_message (mbox, 1, &msg);
902 if (rc)
903 return rc;
904 rc = mu_message_get_uid (msg, &num);
905 if (rc)
906 return rc;
907 if (uid < num)
908 return MU_ERR_NOENT;
909 else if (uid == num)
910 {
911 *result = 1;
912 return 0;
913 }
914
915 rc = mu_mailbox_messages_count (mbox, &count);
916 if (rc)
917 return rc;
918 rc = mu_mailbox_get_message (mbox, count, &msg);
919 if (rc)
920 return rc;
921 rc = mu_message_get_uid (msg, &num);
922 if (rc)
923 return rc;
924
925 if (uid > num)
926 return MU_ERR_NOENT;
927 else if (uid == num)
928 {
929 *result = count;
930 return 0;
931 }
932 return _uid_bsearch (mbox, 1, count, uid, result);
933 }
934
935 /* Translate message UIDs to message numbers and vice versa. */
936 int
mu_mailbox_translate(mu_mailbox_t mbox,int cmd,size_t from,size_t * to)937 mu_mailbox_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to)
938 {
939 int rc = ENOSYS;
940 mu_message_t msg;
941
942 if (mbox == NULL)
943 return EINVAL;
944 if (to == NULL)
945 return MU_ERR_OUT_PTR_NULL;
946 if (mbox->flags & MU_STREAM_QACCESS)
947 return MU_ERR_BADOP;
948
949 if (mbox->_translate)
950 rc = mbox->_translate (mbox, cmd, from, to);
951 if (rc == ENOSYS)
952 {
953 switch (cmd)
954 {
955 case MU_MAILBOX_UID_TO_MSGNO:
956 rc = _search_message_uid (mbox, from, to);
957 break;
958
959 case MU_MAILBOX_MSGNO_TO_UID:
960 rc = mu_mailbox_get_message (mbox, from, &msg);
961 if (rc)
962 return rc;
963 rc = mu_message_get_uid (msg, to);
964 break;
965
966 default:
967 break;
968 }
969 }
970 return rc;
971 }
972
973 int
mu_mailbox_access_time(mu_mailbox_t mbox,time_t * return_time)974 mu_mailbox_access_time (mu_mailbox_t mbox, time_t *return_time)
975 {
976 _MBOX_CHECK_Q (mbox, _get_atime);
977 if (!return_time)
978 return MU_ERR_OUT_PTR_NULL;
979 return mbox->_get_atime (mbox, return_time);
980 }
981
982