summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/generic/mboxdriver_cached.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/generic/mboxdriver_cached.c') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/generic/mboxdriver_cached.c1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/kmicromail/libetpan/generic/mboxdriver_cached.c b/kmicromail/libetpan/generic/mboxdriver_cached.c
new file mode 100644
index 0000000..07871fa
--- a/dev/null
+++ b/kmicromail/libetpan/generic/mboxdriver_cached.c
@@ -0,0 +1,1253 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2002 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mboxdriver_cached.h"
37
38#include <stdio.h>
39#include <string.h>
40#include <dirent.h>
41#include <unistd.h>
42#include <ctype.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <stdlib.h>
47
48#include "mail.h"
49#include "mail_cache_db.h"
50#include "mboxdriver.h"
51#include "mboxdriver_tools.h"
52#include "maildriver_tools.h"
53#include "mailmbox.h"
54#include "maildriver.h"
55#include "carray.h"
56#include "generic_cache.h"
57#include "imfcache.h"
58#include "mboxdriver_cached_message.h"
59#include "libetpan-config.h"
60
61static int mboxdriver_cached_initialize(mailsession * session);
62
63static void mboxdriver_cached_uninitialize(mailsession * session);
64
65static int mboxdriver_cached_parameters(mailsession * session,
66 int id, void * value);
67
68static int mboxdriver_cached_connect_path(mailsession * session, char * path);
69
70static int mboxdriver_cached_logout(mailsession * session);
71
72static int mboxdriver_cached_check_folder(mailsession * session);
73
74static int mboxdriver_cached_expunge_folder(mailsession * session);
75
76static int mboxdriver_cached_status_folder(mailsession * session, char * mb,
77 uint32_t * result_messages, uint32_t * result_recent,
78 uint32_t * result_unseen);
79static int mboxdriver_cached_messages_number(mailsession * session, char * mb,
80 uint32_t * result);
81static int mboxdriver_cached_recent_number(mailsession * session, char * mb,
82 uint32_t * result);
83static int mboxdriver_cached_unseen_number(mailsession * session, char * mb,
84 uint32_t * result);
85
86static int mboxdriver_cached_append_message(mailsession * session,
87 char * message, size_t size);
88
89static int
90mboxdriver_cached_get_messages_list(mailsession * session,
91 struct mailmessage_list ** result);
92
93static int
94mboxdriver_cached_get_envelopes_list(mailsession * session,
95 struct mailmessage_list * env_list);
96
97static int mboxdriver_cached_remove_message(mailsession * session,
98 uint32_t num);
99
100static int mboxdriver_cached_get_message(mailsession * session,
101 uint32_t num, mailmessage ** result);
102
103static int mboxdriver_cached_get_message_by_uid(mailsession * session,
104 const char * uid,
105 mailmessage ** result);
106
107static mailsession_driver local_mbox_cached_session_driver = {
108 .sess_name = "mbox-cached",
109
110 .sess_initialize = mboxdriver_cached_initialize,
111 .sess_uninitialize = mboxdriver_cached_uninitialize,
112
113 .sess_parameters = mboxdriver_cached_parameters,
114
115 .sess_connect_path = mboxdriver_cached_connect_path,
116 .sess_connect_stream = NULL,
117 .sess_starttls = NULL,
118 .sess_login = NULL,
119 .sess_logout = mboxdriver_cached_logout,
120 .sess_noop = NULL,
121
122 .sess_build_folder_name = NULL,
123 .sess_create_folder = NULL,
124 .sess_delete_folder = NULL,
125 .sess_rename_folder = NULL,
126 .sess_check_folder = mboxdriver_cached_check_folder,
127 .sess_examine_folder = NULL,
128 .sess_select_folder = NULL,
129 .sess_expunge_folder = mboxdriver_cached_expunge_folder,
130 .sess_status_folder = mboxdriver_cached_status_folder,
131 .sess_messages_number = mboxdriver_cached_messages_number,
132 .sess_recent_number = mboxdriver_cached_recent_number,
133 .sess_unseen_number = mboxdriver_cached_unseen_number,
134 .sess_list_folders = NULL,
135 .sess_lsub_folders = NULL,
136 .sess_subscribe_folder = NULL,
137 .sess_unsubscribe_folder = NULL,
138
139 .sess_append_message = mboxdriver_cached_append_message,
140 .sess_copy_message = NULL,
141 .sess_move_message = NULL,
142
143 .sess_get_messages_list = mboxdriver_cached_get_messages_list,
144 .sess_get_envelopes_list = mboxdriver_cached_get_envelopes_list,
145 .sess_remove_message = mboxdriver_cached_remove_message,
146#if 0
147 .sess_search_messages = maildriver_generic_search_messages,
148#endif
149
150 .sess_get_message = mboxdriver_cached_get_message,
151 .sess_get_message_by_uid = mboxdriver_cached_get_message_by_uid,
152};
153
154mailsession_driver * mbox_cached_session_driver =
155&local_mbox_cached_session_driver;
156
157
158#define ENV_NAME "env.db"
159#define FLAGS_NAME "flags.db"
160
161
162
163static int mbox_error_to_mail_error(int error)
164{
165 switch (error) {
166 case MAILMBOX_NO_ERROR:
167 return MAIL_NO_ERROR;
168
169 case MAILMBOX_ERROR_PARSE:
170 return MAIL_ERROR_PARSE;
171
172 case MAILMBOX_ERROR_INVAL:
173 return MAIL_ERROR_INVAL;
174
175 case MAILMBOX_ERROR_FILE_NOT_FOUND:
176 return MAIL_ERROR_PARSE;
177
178 case MAILMBOX_ERROR_MEMORY:
179 return MAIL_ERROR_MEMORY;
180
181 case MAILMBOX_ERROR_TEMPORARY_FILE:
182 return MAIL_ERROR_PARSE;
183
184 case MAILMBOX_ERROR_FILE:
185 return MAIL_ERROR_FILE;
186
187 case MAILMBOX_ERROR_MSG_NOT_FOUND:
188 return MAIL_ERROR_MSG_NOT_FOUND;
189
190 case MAILMBOX_ERROR_READONLY:
191 return MAIL_ERROR_READONLY;
192
193 default:
194 return MAIL_ERROR_INVAL;
195 }
196}
197
198
199
200
201static inline struct mbox_cached_session_state_data *
202get_cached_data(mailsession * session)
203{
204 return session->sess_data;
205}
206
207static inline mailsession * get_ancestor(mailsession * session)
208{
209 return get_cached_data(session)->mbox_ancestor;
210}
211
212static inline struct mbox_session_state_data *
213get_ancestor_data(mailsession * session)
214{
215 return get_ancestor(session)->sess_data;
216}
217
218static inline struct mailmbox_folder *
219get_mbox_session(mailsession * session)
220{
221 return get_ancestor_data(session)->mbox_folder;
222}
223
224static int mboxdriver_cached_initialize(mailsession * session)
225{
226 struct mbox_cached_session_state_data * cached_data;
227 struct mbox_session_state_data * mbox_data;
228
229 cached_data = malloc(sizeof(* cached_data));
230 if (cached_data == NULL)
231 goto err;
232
233 cached_data->mbox_flags_store = mail_flags_store_new();
234 if (cached_data->mbox_flags_store == NULL)
235 goto free;
236
237 cached_data->mbox_ancestor = mailsession_new(mbox_session_driver);
238 if (cached_data->mbox_ancestor == NULL)
239 goto free_store;
240
241 cached_data->mbox_quoted_mb = NULL;
242 /*
243 UID must be enabled to take advantage of the cache
244 */
245 mbox_data = cached_data->mbox_ancestor->sess_data;
246 mbox_data->mbox_force_no_uid = FALSE;
247
248 session->sess_data = cached_data;
249
250 return MAIL_NO_ERROR;
251
252 free_store:
253 mail_flags_store_free(cached_data->mbox_flags_store);
254 free:
255 free(cached_data);
256 err:
257 return MAIL_ERROR_MEMORY;
258}
259
260static void free_state(struct mbox_cached_session_state_data * mbox_data)
261{
262 if (mbox_data->mbox_quoted_mb) {
263 free(mbox_data->mbox_quoted_mb);
264 mbox_data->mbox_quoted_mb = NULL;
265 }
266}
267
268static int mbox_flags_store_process(char * flags_directory, char * quoted_mb,
269 struct mail_flags_store * flags_store)
270{
271 char filename_flags[PATH_MAX];
272 struct mail_cache_db * cache_db_flags;
273 MMAPString * mmapstr;
274 unsigned int i;
275 int r;
276 int res;
277
278 if (carray_count(flags_store->fls_tab) == 0)
279 return MAIL_NO_ERROR;
280
281 if (quoted_mb == NULL)
282 return MAIL_NO_ERROR;
283
284 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
285 flags_directory, MAIL_DIR_SEPARATOR, quoted_mb,
286 MAIL_DIR_SEPARATOR, FLAGS_NAME);
287
288 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
289 if (r < 0) {
290 res = MAIL_ERROR_FILE;
291 goto err;
292 }
293
294 mmapstr = mmap_string_new("");
295 if (mmapstr == NULL) {
296 res = MAIL_ERROR_MEMORY;
297 goto close_db_flags;
298 }
299
300 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
301 mailmessage * msg;
302
303 msg = carray_get(flags_store->fls_tab, i);
304
305 r = mboxdriver_write_cached_flags(cache_db_flags, mmapstr,
306 msg->msg_uid, msg->msg_flags);
307 if (r != MAIL_NO_ERROR) {
308 /* ignore errors */
309 }
310 }
311
312 mmap_string_free(mmapstr);
313 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
314
315 mail_flags_store_clear(flags_store);
316
317 return MAIL_NO_ERROR;
318
319 close_db_flags:
320 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
321 err:
322 return res;
323}
324
325static void mboxdriver_cached_uninitialize(mailsession * session)
326{
327 struct mbox_cached_session_state_data * data;
328
329 data = get_cached_data(session);
330
331 mbox_flags_store_process(data->mbox_flags_directory,
332 data->mbox_quoted_mb,
333 data->mbox_flags_store);
334
335 mail_flags_store_free(data->mbox_flags_store);
336
337 free_state(data);
338 mailsession_free(data->mbox_ancestor);
339 free(data);
340
341 session->sess_data = NULL;
342}
343
344static int mboxdriver_cached_parameters(mailsession * session,
345 int id, void * value)
346{
347 struct mbox_cached_session_state_data * data;
348 int r;
349
350 data = get_cached_data(session);
351
352 switch (id) {
353 case MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY:
354 strncpy(data->mbox_cache_directory, value, PATH_MAX);
355 data->mbox_cache_directory[PATH_MAX - 1] = '\0';
356
357 r = generic_cache_create_dir(data->mbox_cache_directory);
358 if (r != MAIL_NO_ERROR)
359 return r;
360
361 return MAIL_NO_ERROR;
362
363 case MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY:
364 strncpy(data->mbox_flags_directory, value, PATH_MAX);
365 data->mbox_flags_directory[PATH_MAX - 1] = '\0';
366
367 r = generic_cache_create_dir(data->mbox_flags_directory);
368 if (r != MAIL_NO_ERROR)
369 return r;
370
371 return MAIL_NO_ERROR;
372
373 case MBOXDRIVER_SET_NO_UID:
374 return MAIL_ERROR_INVAL;
375
376 default:
377 return mailsession_parameters(data->mbox_ancestor, id, value);
378 }
379}
380
381
382static int get_cache_directory(mailsession * session,
383 char * path, char ** result)
384{
385 char * quoted_mb;
386 char dirname[PATH_MAX];
387 int res;
388 int r;
389 struct mbox_cached_session_state_data * cached_data;
390
391 cached_data = get_cached_data(session);
392
393 quoted_mb = maildriver_quote_mailbox(path);
394 if (quoted_mb == NULL) {
395 res = MAIL_ERROR_MEMORY;
396 goto err;
397 }
398
399 snprintf(dirname, PATH_MAX, "%s%c%s",
400 cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR, quoted_mb);
401
402 r = generic_cache_create_dir(dirname);
403 if (r != MAIL_NO_ERROR) {
404 res = r;
405 goto free;
406 }
407
408 snprintf(dirname, PATH_MAX, "%s%c%s",
409 cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, quoted_mb);
410
411 r = generic_cache_create_dir(dirname);
412 if (r != MAIL_NO_ERROR) {
413 res = r;
414 goto free;
415 }
416
417 * result = quoted_mb;
418
419 return MAIL_NO_ERROR;
420
421 free:
422 free(quoted_mb);
423 err:
424 return res;
425}
426
427
428
429
430#define FILENAME_MAX_UID "max-uid"
431
432/* write max uid current value */
433
434static int write_max_uid_value(mailsession * session)
435{
436 int r;
437 char filename[PATH_MAX];
438 FILE * f;
439 int res;
440
441#if 0
442 struct mbox_session_state_data * mbox_data;
443#endif
444 struct mbox_cached_session_state_data * cached_data;
445 int fd;
446
447 MMAPString * mmapstr;
448 size_t cur_token;
449 struct mailmbox_folder * folder;
450
451 /* expunge the mailbox */
452
453#if 0
454 mbox_data = get_ancestor(session)->data;
455#endif
456 folder = get_mbox_session(session);
457
458 r = mailmbox_validate_write_lock(folder);
459 if (r != MAILMBOX_NO_ERROR) {
460 res = mbox_error_to_mail_error(r);
461 goto err;
462 }
463
464 r = mailmbox_expunge_no_lock(folder);
465 if (r != MAILMBOX_NO_ERROR) {
466 res = r;
467 goto unlock;
468 }
469
470 cached_data = get_cached_data(session);
471
472 snprintf(filename, PATH_MAX, "%s%c%s%c%s",
473 cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR,
474 cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FILENAME_MAX_UID);
475
476 fd = creat(filename, S_IRUSR | S_IWUSR);
477 if (fd < 0) {
478 res = MAIL_ERROR_FILE;
479 goto err;
480 }
481
482 f = fdopen(fd, "w");
483 if (f == NULL) {
484 close(fd);
485 res = MAIL_ERROR_FILE;
486 goto unlock;
487 }
488
489 mmapstr = mmap_string_new("");
490 if (mmapstr == NULL) {
491 res = MAIL_ERROR_MEMORY;
492 goto close;
493 }
494
495 r = mail_serialize_clear(mmapstr, &cur_token);
496 if (r != MAIL_NO_ERROR) {
497 res = r;
498 goto free_mmapstr;
499 }
500
501 r = mailimf_cache_int_write(mmapstr, &cur_token,
502 folder->mb_written_uid);
503 if (r != MAIL_NO_ERROR) {
504 res = r;
505 goto free_mmapstr;
506 }
507
508 fwrite(mmapstr->str, 1, mmapstr->len, f);
509
510 mmap_string_free(mmapstr);
511 fclose(f);
512 mailmbox_write_unlock(folder);
513
514 return MAIL_NO_ERROR;
515
516 free_mmapstr:
517 mmap_string_free(mmapstr);
518 close:
519 fclose(f);
520 unlock:
521 mailmbox_read_unlock(folder);
522 err:
523 return res;
524}
525
526static int read_max_uid_value(mailsession * session, uint32_t * result)
527{
528 int r;
529 char filename[PATH_MAX];
530 FILE * f;
531 uint32_t written_uid;
532 int res;
533
534 struct mbox_cached_session_state_data * cached_data;
535
536 MMAPString * mmapstr;
537 size_t cur_token;
538 char buf[sizeof(uint32_t)];
539 size_t read_size;
540
541 cached_data = get_cached_data(session);
542
543 snprintf(filename, PATH_MAX, "%s%c%s%c%s",
544 cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR,
545 cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FILENAME_MAX_UID);
546
547 f = fopen(filename, "r");
548 if (f == NULL) {
549 res = MAIL_ERROR_FILE;
550 goto err;
551 }
552
553 read_size = fread(buf, 1, sizeof(uint32_t), f);
554
555 mmapstr = mmap_string_new_len(buf, read_size);
556 if (mmapstr == NULL) {
557 res = MAIL_ERROR_MEMORY;
558 goto close;
559 }
560
561 cur_token = 0;
562
563 r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid);
564 if (r != MAIL_NO_ERROR) {
565 fclose(f);
566 res = r;
567 goto free_mmapstr;
568 }
569
570 mmap_string_free(mmapstr);
571 fclose(f);
572
573 * result = written_uid;
574
575 return MAIL_NO_ERROR;
576
577 free_mmapstr:
578 mmap_string_free(mmapstr);
579 close:
580 fclose(f);
581 err:
582 return res;
583}
584
585static int mboxdriver_cached_connect_path(mailsession * session, char * path)
586{
587 int r;
588 int res;
589 char * quoted_mb;
590 struct mbox_cached_session_state_data * cached_data;
591 struct mbox_session_state_data * ancestor_data;
592 struct mailmbox_folder * folder;
593 uint32_t written_uid;
594
595 folder = get_mbox_session(session);
596 if (folder != NULL) {
597 res = MAIL_ERROR_BAD_STATE;
598 goto err;
599 }
600
601 r = get_cache_directory(session, path, &quoted_mb);
602 if (r != MAIL_NO_ERROR) {
603 res = r;
604 goto err;
605 }
606
607 cached_data = get_cached_data(session);
608 free_state(cached_data);
609
610 cached_data->mbox_quoted_mb = quoted_mb;
611
612 written_uid = 0;
613 r = read_max_uid_value(session, &written_uid);
614 /* ignore errors */
615
616 ancestor_data = get_ancestor_data(session);
617
618 r = mailmbox_init(path,
619 ancestor_data->mbox_force_read_only,
620 ancestor_data->mbox_force_no_uid,
621 written_uid,
622 &folder);
623
624 if (r != MAILMBOX_NO_ERROR) {
625 cached_data->mbox_quoted_mb = NULL;
626
627 res = mboxdriver_mbox_error_to_mail_error(r);
628 goto free;
629 }
630
631 ancestor_data->mbox_folder = folder;
632
633 return MAIL_NO_ERROR;
634
635 free:
636 free(quoted_mb);
637 err:
638 return res;
639}
640
641
642static int mboxdriver_cached_logout(mailsession * session)
643{
644 struct mbox_cached_session_state_data * cached_data;
645 int r;
646
647 r = write_max_uid_value(session);
648
649 cached_data = get_cached_data(session);
650
651 mbox_flags_store_process(cached_data->mbox_flags_directory,
652 cached_data->mbox_quoted_mb,
653 cached_data->mbox_flags_store);
654
655 r = mailsession_logout(get_ancestor(session));
656 if (r != MAIL_NO_ERROR)
657 return r;
658
659 free_state(cached_data);
660
661 return MAIL_NO_ERROR;
662}
663
664static int mboxdriver_cached_check_folder(mailsession * session)
665{
666 struct mbox_cached_session_state_data * cached_data;
667
668 cached_data = get_cached_data(session);
669
670 mbox_flags_store_process(cached_data->mbox_flags_directory,
671 cached_data->mbox_quoted_mb,
672 cached_data->mbox_flags_store);
673
674 return MAIL_NO_ERROR;
675}
676
677static int mboxdriver_cached_expunge_folder(mailsession * session)
678{
679 struct mailmbox_folder * folder;
680 int res;
681 char filename_flags[PATH_MAX];
682 struct mail_cache_db * cache_db_flags;
683 MMAPString * mmapstr;
684 struct mbox_cached_session_state_data * data;
685 int r;
686 unsigned int i;
687
688 folder = get_mbox_session(session);
689 if (folder == NULL) {
690 res = MAIL_ERROR_BAD_STATE;
691 goto err;
692 }
693
694 data = get_cached_data(session);
695 if (data->mbox_quoted_mb == NULL) {
696 res = MAIL_ERROR_BAD_STATE;
697 goto err;
698 }
699
700 mbox_flags_store_process(data->mbox_flags_directory,
701 data->mbox_quoted_mb,
702 data->mbox_flags_store);
703
704 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
705 data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb,
706 MAIL_DIR_SEPARATOR, FLAGS_NAME);
707
708 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
709 if (r < 0) {
710 res = MAIL_ERROR_FILE;
711 goto err;
712 }
713
714 mmapstr = mmap_string_new("");
715 if (mmapstr == NULL) {
716 res = MAIL_ERROR_MEMORY;
717 goto close_db_flags;
718 }
719
720 for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
721 struct mailmbox_msg_info * msg_info;
722 struct mail_flags * flags;
723
724 msg_info = carray_get(folder->mb_tab, i);
725 if (msg_info == NULL)
726 continue;
727
728 if (msg_info->msg_deleted)
729 continue;
730
731 r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr,
732 session, msg_info->msg_uid, &flags);
733 if (r != MAIL_NO_ERROR)
734 continue;
735
736 if (flags->fl_flags & MAIL_FLAG_DELETED) {
737 r = mailmbox_delete_msg(folder, msg_info->msg_uid);
738 }
739
740 mail_flags_free(flags);
741 }
742
743 mmap_string_free(mmapstr);
744 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
745
746 r = mailmbox_expunge(folder);
747
748 return MAIL_NO_ERROR;
749
750 close_db_flags:
751 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
752 err:
753 return res;
754}
755
756static int mboxdriver_cached_status_folder(mailsession * session, char * mb,
757 uint32_t * result_messages, uint32_t * result_recent,
758 uint32_t * result_unseen)
759{
760 struct mailmbox_folder * folder;
761 int res;
762 char filename_flags[PATH_MAX];
763 struct mail_cache_db * cache_db_flags;
764 MMAPString * mmapstr;
765 struct mbox_cached_session_state_data * data;
766 int r;
767 unsigned int i;
768 uint32_t recent;
769 uint32_t unseen;
770 uint32_t num;
771
772 num = 0;
773 recent = 0;
774 unseen = 0;
775
776 folder = get_mbox_session(session);
777 if (folder == NULL) {
778 res = MAIL_ERROR_BAD_STATE;
779 goto err;
780 }
781
782 data = get_cached_data(session);
783 if (data->mbox_quoted_mb == NULL) {
784 res = MAIL_ERROR_BAD_STATE;
785 goto err;
786 }
787
788 r = mailmbox_validate_read_lock(folder);
789 if (r != MAIL_NO_ERROR) {
790 res = MAIL_ERROR_BAD_STATE;
791 goto err;
792 }
793
794 mailmbox_read_unlock(folder);
795
796 mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb,
797 data->mbox_flags_store);
798
799 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
800 data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb,
801 MAIL_DIR_SEPARATOR, FLAGS_NAME);
802
803 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
804 if (r < 0) {
805 res = MAIL_ERROR_FILE;
806 goto err;
807 }
808
809 mmapstr = mmap_string_new("");
810 if (mmapstr == NULL) {
811 res = MAIL_ERROR_MEMORY;
812 goto close_db_flags;
813 }
814
815 for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
816 struct mailmbox_msg_info * msg_info;
817 struct mail_flags * flags;
818
819 msg_info = carray_get(folder->mb_tab, i);
820 if (msg_info == NULL)
821 continue;
822
823 if (msg_info->msg_deleted)
824 continue;
825
826 r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr,
827 session, msg_info->msg_uid, &flags);
828 if (r != MAIL_NO_ERROR) {
829 recent ++;
830 unseen ++;
831 num ++;
832 continue;
833 }
834
835 if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
836 recent ++;
837 }
838 if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
839 unseen ++;
840 }
841
842 num ++;
843
844 mail_flags_free(flags);
845 }
846
847 mmap_string_free(mmapstr);
848 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
849
850 * result_messages = num;
851 * result_recent = recent;
852 * result_unseen = unseen;
853
854 return MAIL_NO_ERROR;
855
856 close_db_flags:
857 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
858 err:
859 return res;
860}
861
862static int mboxdriver_cached_messages_number(mailsession * session, char * mb,
863 uint32_t * result)
864{
865 return mailsession_messages_number(get_ancestor(session), mb, result);
866}
867
868
869static int mboxdriver_cached_recent_number(mailsession * session, char * mb,
870 uint32_t * result)
871{
872 uint32_t messages;
873 uint32_t recent;
874 uint32_t unseen;
875 int r;
876
877 r = mboxdriver_cached_status_folder(session, mb, &messages, &recent, &unseen);
878 if (r != MAIL_NO_ERROR)
879 return r;
880
881 * result = recent;
882
883 return MAIL_NO_ERROR;
884}
885
886static int mboxdriver_cached_unseen_number(mailsession * session, char * mb,
887 uint32_t * result)
888{
889 uint32_t messages;
890 uint32_t recent;
891 uint32_t unseen;
892 int r;
893
894 r = mboxdriver_cached_status_folder(session, mb,
895 &messages, &recent, &unseen);
896 if (r != MAIL_NO_ERROR)
897 return r;
898
899 * result = unseen;
900
901 return MAIL_NO_ERROR;
902}
903
904/* messages operations */
905
906static int mboxdriver_cached_append_message(mailsession * session,
907 char * message, size_t size)
908{
909 return mailsession_append_message(get_ancestor(session), message, size);
910}
911
912static int
913mboxdriver_cached_get_messages_list(mailsession * session,
914 struct mailmessage_list ** result)
915{
916 struct mailmbox_folder * folder;
917 int res;
918
919 folder = get_mbox_session(session);
920 if (folder == NULL) {
921 res = MAIL_ERROR_BAD_STATE;
922 goto err;
923 }
924
925 return mbox_get_uid_messages_list(folder,
926 session, mbox_cached_message_driver, result);
927
928 err:
929 return res;
930}
931
932static int
933get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
934 mailsession * session, uint32_t num,
935 struct mailimf_fields ** result)
936{
937 int r;
938 char keyname[PATH_MAX];
939 struct mailimf_fields * fields;
940 int res;
941 struct mailmbox_msg_info * info;
942 struct mailmbox_folder * folder;
943 chashdatum key;
944 chashdatum data;
945
946 folder = get_mbox_session(session);
947 if (folder == NULL) {
948 res = MAIL_ERROR_BAD_STATE;
949 goto err;
950 }
951
952 key.data = &num;
953 key.len = sizeof(num);
954
955 r = chash_get(folder->mb_hash, &key, &data);
956 if (r < 0) {
957 res = MAIL_ERROR_MSG_NOT_FOUND;
958 goto err;
959 }
960
961 info = data.data;
962
963 snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len);
964
965 r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields);
966 if (r != MAIL_NO_ERROR) {
967 res = r;
968 goto err;
969 }
970
971 * result = fields;
972
973 return MAIL_NO_ERROR;
974
975 err:
976 return res;
977}
978
979static int
980write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
981 mailsession * session, uint32_t num,
982 struct mailimf_fields * fields)
983{
984 int r;
985 char keyname[PATH_MAX];
986 int res;
987 struct mailmbox_msg_info * info;
988 struct mailmbox_folder * folder;
989 chashdatum key;
990 chashdatum data;
991
992 folder = get_mbox_session(session);
993 if (folder == NULL) {
994 res = MAIL_ERROR_BAD_STATE;
995 goto err;
996 }
997
998 key.data = &num;
999 key.len = sizeof(num);
1000
1001 r = chash_get(folder->mb_hash, &key, &data);
1002 if (r < 0) {
1003 res = MAIL_ERROR_MSG_NOT_FOUND;
1004 goto err;
1005 }
1006
1007 info = data.data;
1008
1009 snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len);
1010
1011 r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields);
1012 if (r != MAIL_NO_ERROR) {
1013 res = r;
1014 goto err;
1015 }
1016
1017 return MAIL_NO_ERROR;
1018
1019 err:
1020 return res;
1021}
1022
1023static int
1024mboxdriver_cached_get_envelopes_list(mailsession * session,
1025 struct mailmessage_list * env_list)
1026{
1027 int r;
1028 unsigned int i;
1029 struct mbox_cached_session_state_data * cached_data;
1030 char filename_env[PATH_MAX];
1031 char filename_flags[PATH_MAX];
1032 struct mail_cache_db * cache_db_env;
1033 struct mail_cache_db * cache_db_flags;
1034 MMAPString * mmapstr;
1035 int res;
1036 struct mailmbox_folder * folder;
1037
1038 folder = get_mbox_session(session);
1039 if (folder == NULL) {
1040 res = MAIL_ERROR_BAD_STATE;
1041 goto err;
1042 }
1043
1044 cached_data = get_cached_data(session);
1045 if (cached_data->mbox_quoted_mb == NULL) {
1046 res = MAIL_ERROR_BAD_STATE;
1047 goto err;
1048 }
1049
1050 mbox_flags_store_process(cached_data->mbox_flags_directory,
1051 cached_data->mbox_quoted_mb,
1052 cached_data->mbox_flags_store);
1053
1054 mmapstr = mmap_string_new("");
1055 if (mmapstr == NULL) {
1056 res = MAIL_ERROR_MEMORY;
1057 goto err;
1058 }
1059
1060 snprintf(filename_env, PATH_MAX, "%s%c%s%c%s",
1061 cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR,
1062 cached_data->mbox_quoted_mb,
1063 MAIL_DIR_SEPARATOR, ENV_NAME);
1064
1065 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
1066 if (r < 0) {
1067 res = MAIL_ERROR_MEMORY;
1068 goto free_mmapstr;
1069 }
1070
1071 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
1072 cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR,
1073 cached_data->mbox_quoted_mb,
1074 MAIL_DIR_SEPARATOR, FLAGS_NAME);
1075
1076 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
1077 if (r < 0) {
1078 res = MAIL_ERROR_FILE;
1079 goto close_db_env;
1080 }
1081
1082 /* fill with cached */
1083
1084 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1085 mailmessage * msg;
1086 struct mailimf_fields * fields;
1087 struct mail_flags * flags;
1088
1089 msg = carray_get(env_list->msg_tab, i);
1090
1091 if (msg->msg_fields == NULL) {
1092 r = get_cached_envelope(cache_db_env, mmapstr, session,
1093 msg->msg_index, &fields);
1094 if (r == MAIL_NO_ERROR) {
1095 msg->msg_cached = TRUE;
1096 msg->msg_fields = fields;
1097 }
1098 }
1099
1100 if (msg->msg_flags == NULL) {
1101 r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr,
1102 session, msg->msg_index,
1103 &flags);
1104 if (r == MAIL_NO_ERROR) {
1105 msg->msg_flags = flags;
1106 }
1107 }
1108 }
1109
1110 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
1111 mail_cache_db_close_unlock(filename_env, cache_db_env);
1112
1113 r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
1114
1115 if (r != MAIL_NO_ERROR) {
1116 res = r;
1117 goto free_mmapstr;
1118 }
1119
1120 /* add flags */
1121
1122 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1123 mailmessage * msg;
1124
1125 msg = carray_get(env_list->msg_tab, i);
1126
1127 if (msg->msg_flags == NULL)
1128 msg->msg_flags = mail_flags_new_empty();
1129 }
1130
1131 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
1132 if (r < 0) {
1133 res = MAIL_ERROR_MEMORY;
1134 goto free_mmapstr;
1135 }
1136
1137 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
1138 if (r < 0) {
1139 res = MAIL_ERROR_FILE;
1140 goto close_db_env;
1141 }
1142
1143 /* must write cache */
1144
1145 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1146 mailmessage * msg;
1147
1148 msg = carray_get(env_list->msg_tab, i);
1149
1150 if (msg->msg_fields != NULL) {
1151 if (!msg->msg_cached) {
1152 /* msg->msg_index is the numerical UID of the message */
1153 r = write_cached_envelope(cache_db_env, mmapstr,
1154 session, msg->msg_index, msg->msg_fields);
1155 }
1156 }
1157
1158 if (msg->msg_flags != NULL) {
1159 r = mboxdriver_write_cached_flags(cache_db_flags, mmapstr,
1160 msg->msg_uid, msg->msg_flags);
1161 }
1162 }
1163
1164 /* flush cache */
1165
1166 maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list);
1167
1168 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
1169 mail_cache_db_close_unlock(filename_env, cache_db_env);
1170
1171 mmap_string_free(mmapstr);
1172
1173 return MAIL_NO_ERROR;
1174
1175 close_db_env:
1176 mail_cache_db_close_unlock(filename_env, cache_db_env);
1177 free_mmapstr:
1178 mmap_string_free(mmapstr);
1179 err:
1180 return res;
1181}
1182
1183
1184static int
1185mboxdriver_cached_remove_message(mailsession * session, uint32_t num)
1186{
1187 return mailsession_remove_message(get_ancestor(session), num);
1188}
1189
1190static int mboxdriver_cached_get_message(mailsession * session,
1191 uint32_t num, mailmessage ** result)
1192{
1193 mailmessage * msg_info;
1194 int r;
1195
1196 msg_info = mailmessage_new();
1197 if (msg_info == NULL)
1198 return MAIL_ERROR_MEMORY;
1199
1200 r = mailmessage_init(msg_info, session, mbox_cached_message_driver, num, 0);
1201 if (r != MAIL_NO_ERROR) {
1202 mailmessage_free(msg_info);
1203 return r;
1204 }
1205
1206 * result = msg_info;
1207
1208 return MAIL_NO_ERROR;
1209}
1210
1211static int mboxdriver_cached_get_message_by_uid(mailsession * session,
1212 const char * uid,
1213 mailmessage ** result)
1214{
1215 uint32_t num;
1216 char * p;
1217 chashdatum key;
1218 chashdatum data;
1219 struct mailmbox_msg_info * info;
1220 struct mailmbox_folder * folder;
1221 int r;
1222
1223 if (uid == NULL)
1224 return MAIL_ERROR_INVAL;
1225
1226 num = strtoul(uid, &p, 10);
1227 if (p == uid || * p != '-')
1228 return MAIL_ERROR_INVAL;
1229
1230 folder = get_mbox_session(session);
1231 if (folder == NULL)
1232 return MAIL_ERROR_BAD_STATE;
1233
1234 key.data = &num;
1235 key.len = sizeof(num);
1236
1237 r = chash_get(folder->mb_hash, &key, &data);
1238 if (r == 0) {
1239 char * body_len_p = p + 1;
1240 size_t body_len;
1241
1242 info = data.data;
1243 /* Check if the cached message has the same UID */
1244 body_len = strtoul(body_len_p, &p, 10);
1245 if (p == body_len_p || * p != '\0')
1246 return MAIL_ERROR_INVAL;
1247
1248 if (body_len == info->msg_body_len)
1249 return mboxdriver_cached_get_message(session, num, result);
1250 }
1251
1252 return MAIL_ERROR_MSG_NOT_FOUND;
1253}