summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/generic/mhdriver_cached.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/generic/mhdriver_cached.c') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/generic/mhdriver_cached.c1232
1 files changed, 1232 insertions, 0 deletions
diff --git a/kmicromail/libetpan/generic/mhdriver_cached.c b/kmicromail/libetpan/generic/mhdriver_cached.c
new file mode 100644
index 0000000..5c35089
--- a/dev/null
+++ b/kmicromail/libetpan/generic/mhdriver_cached.c
@@ -0,0 +1,1232 @@
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 "mhdriver_cached.h"
37
38#include <stdio.h>
39#include <sys/types.h>
40#include <dirent.h>
41#include <unistd.h>
42#include <sys/stat.h>
43#include <ctype.h>
44#include <fcntl.h>
45#include <sys/mman.h>
46#include <stdlib.h>
47#include <string.h>
48
49#include "mail.h"
50#include "mail_cache_db.h"
51
52#include "generic_cache.h"
53#include "imfcache.h"
54#include "mhdriver.h"
55
56#include "mhdriver_cached_message.h"
57#include "mailmh.h"
58#include "maildriver_tools.h"
59#include "mhdriver_tools.h"
60#include "mailmessage.h"
61
62static int mhdriver_cached_initialize(mailsession * session);
63
64static void mhdriver_cached_uninitialize(mailsession * session);
65
66static int mhdriver_cached_parameters(mailsession * session,
67 int id, void * value);
68
69static int mhdriver_cached_connect_path(mailsession * session, char * path);
70static int mhdriver_cached_logout(mailsession * session);
71
72static int mhdriver_cached_build_folder_name(mailsession * session, char * mb,
73 char * name, char ** result);
74static int mhdriver_cached_create_folder(mailsession * session, char * mb);
75
76static int mhdriver_cached_delete_folder(mailsession * session, char * mb);
77
78static int mhdriver_cached_rename_folder(mailsession * session, char * mb,
79 char * new_name);
80
81static int mhdriver_cached_check_folder(mailsession * session);
82
83static int mhdriver_cached_select_folder(mailsession * session, char * mb);
84
85static int mhdriver_cached_expunge_folder(mailsession * session);
86
87static int mhdriver_cached_status_folder(mailsession * session, char * mb,
88 uint32_t * result_messages, uint32_t * result_recent,
89 uint32_t * result_unseen);
90
91static int mhdriver_cached_messages_number(mailsession * session, char * mb,
92 uint32_t * result);
93static int mhdriver_cached_recent_number(mailsession * session, char * mb,
94 uint32_t * result);
95static int mhdriver_cached_unseen_number(mailsession * session, char * mb,
96 uint32_t * result);
97
98static int mhdriver_cached_list_folders(mailsession * session, char * mb,
99 struct mail_list ** result);
100
101static int mhdriver_cached_lsub_folders(mailsession * session, char * mb,
102 struct mail_list ** result);
103
104static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb);
105
106static int mhdriver_cached_unsubscribe_folder(mailsession * session,
107 char * mb);
108
109static int mhdriver_cached_append_message(mailsession * session,
110 char * message, size_t size);
111static int mhdriver_cached_copy_message(mailsession * session,
112 uint32_t num, char * mb);
113
114static int mhdriver_cached_remove_message(mailsession * session,
115 uint32_t num);
116
117static int mhdriver_cached_move_message(mailsession * session,
118 uint32_t num, char * mb);
119
120static int
121mhdriver_cached_get_messages_list(mailsession * session,
122 struct mailmessage_list ** result);
123
124static int
125mhdriver_cached_get_envelopes_list(mailsession * session,
126 struct mailmessage_list * env_list);
127
128static int mhdriver_cached_get_message(mailsession * session,
129 uint32_t num, mailmessage ** result);
130
131static int mhdriver_cached_get_message_by_uid(mailsession * session,
132 const char * uid,
133 mailmessage ** result);
134
135static mailsession_driver local_mh_cached_session_driver = {
136 .sess_name = "mh-cached",
137
138 .sess_initialize = mhdriver_cached_initialize,
139 .sess_uninitialize = mhdriver_cached_uninitialize,
140
141 .sess_parameters = mhdriver_cached_parameters,
142
143 .sess_connect_stream = NULL,
144 .sess_connect_path = mhdriver_cached_connect_path,
145 .sess_starttls = NULL,
146 .sess_login = NULL,
147 .sess_logout = mhdriver_cached_logout,
148 .sess_noop = NULL,
149
150 .sess_build_folder_name = mhdriver_cached_build_folder_name,
151 .sess_create_folder = mhdriver_cached_create_folder,
152 .sess_delete_folder = mhdriver_cached_delete_folder,
153 .sess_rename_folder = mhdriver_cached_rename_folder,
154 .sess_check_folder = mhdriver_cached_check_folder,
155 .sess_examine_folder = NULL,
156 .sess_select_folder = mhdriver_cached_select_folder,
157 .sess_expunge_folder = mhdriver_cached_expunge_folder,
158 .sess_status_folder = mhdriver_cached_status_folder,
159 .sess_messages_number = mhdriver_cached_messages_number,
160 .sess_recent_number = mhdriver_cached_recent_number,
161 .sess_unseen_number = mhdriver_cached_unseen_number,
162 .sess_list_folders = mhdriver_cached_list_folders,
163 .sess_lsub_folders = mhdriver_cached_lsub_folders,
164 .sess_subscribe_folder = mhdriver_cached_subscribe_folder,
165 .sess_unsubscribe_folder = mhdriver_cached_unsubscribe_folder,
166
167 .sess_append_message = mhdriver_cached_append_message,
168 .sess_copy_message = mhdriver_cached_copy_message,
169 .sess_move_message = mhdriver_cached_move_message,
170
171 .sess_get_messages_list = mhdriver_cached_get_messages_list,
172 .sess_get_envelopes_list = mhdriver_cached_get_envelopes_list,
173 .sess_remove_message = mhdriver_cached_remove_message,
174#if 0
175 .sess_search_messages = maildriver_generic_search_messages,
176#endif
177
178 .sess_get_message = mhdriver_cached_get_message,
179 .sess_get_message_by_uid = mhdriver_cached_get_message_by_uid,
180};
181
182mailsession_driver * mh_cached_session_driver =
183&local_mh_cached_session_driver;
184
185#define ENV_NAME "env.db"
186#define FLAGS_NAME "flags.db"
187
188
189static inline struct mh_cached_session_state_data *
190get_cached_data(mailsession * session)
191{
192 return session->sess_data;
193}
194
195static inline mailsession * get_ancestor(mailsession * session)
196{
197 return get_cached_data(session)->mh_ancestor;
198}
199
200static inline struct mh_session_state_data *
201get_ancestor_data(mailsession * session)
202{
203 return get_ancestor(session)->sess_data;
204}
205
206static inline struct mailmh *
207get_mh_session(mailsession * session)
208{
209 return get_ancestor_data(session)->mh_session;
210}
211
212static inline struct mailmh_folder *
213get_mh_cur_folder(mailsession * session)
214{
215 return get_ancestor_data(session)->mh_cur_folder;
216}
217
218
219#define FILENAME_MAX_UID "max-uid"
220
221/* write max uid current value */
222
223static int write_max_uid_value(mailsession * session)
224{
225 int r;
226 char filename[PATH_MAX];
227 FILE * f;
228 int res;
229 struct mh_cached_session_state_data * cached_data;
230 struct mh_session_state_data * ancestor_data;
231 int fd;
232
233 MMAPString * mmapstr;
234 size_t cur_token;
235
236 cached_data = get_cached_data(session);
237 ancestor_data = get_ancestor_data(session);
238
239 if (cached_data->mh_quoted_mb == NULL)
240 return MAIL_ERROR_BAD_STATE;
241
242 snprintf(filename, PATH_MAX, "%s/%s/%s",
243 cached_data->mh_cache_directory,
244 cached_data->mh_quoted_mb, FILENAME_MAX_UID);
245
246 fd = creat(filename, S_IRUSR | S_IWUSR);
247 if (fd < 0) {
248 res = MAIL_ERROR_FILE;
249 goto err;
250 }
251
252 f = fdopen(fd, "w");
253 if (f == NULL) {
254 close(fd);
255 res = MAIL_ERROR_FILE;
256 goto err;
257 }
258
259 mmapstr = mmap_string_new("");
260 if (mmapstr == NULL) {
261 res = MAIL_ERROR_MEMORY;
262 goto close;
263 }
264
265 r = mail_serialize_clear(mmapstr, &cur_token);
266 if (r != MAIL_NO_ERROR) {
267 res = r;
268 goto free_mmapstr;
269 }
270
271 r = mailimf_cache_int_write(mmapstr, &cur_token,
272 ancestor_data->mh_cur_folder->fl_max_index);
273 if (r != MAIL_NO_ERROR) {
274 res = r;
275 goto free_mmapstr;
276 }
277
278 fwrite(mmapstr->str, 1, mmapstr->len, f);
279
280 mmap_string_free(mmapstr);
281 fclose(f);
282
283 return MAIL_NO_ERROR;
284
285 free_mmapstr:
286 mmap_string_free(mmapstr);
287 close:
288 fclose(f);
289 err:
290 return res;
291}
292
293static int read_max_uid_value(mailsession * session)
294{
295 int r;
296 char filename[PATH_MAX];
297 FILE * f;
298 uint32_t written_uid;
299 int res;
300 struct mh_cached_session_state_data * cached_data;
301 struct mh_session_state_data * ancestor_data;
302
303 MMAPString * mmapstr;
304 size_t cur_token;
305 char buf[sizeof(uint32_t)];
306 size_t read_size;
307
308 cached_data = get_cached_data(session);
309 ancestor_data = get_ancestor_data(session);
310
311 snprintf(filename, PATH_MAX, "%s/%s/%s",
312 cached_data->mh_cache_directory,
313 cached_data->mh_quoted_mb, FILENAME_MAX_UID);
314
315 f = fopen(filename, "r");
316 if (f == NULL) {
317 res = MAIL_ERROR_FILE;
318 goto err;
319 }
320
321 read_size = fread(buf, 1, sizeof(uint32_t), f);
322
323 mmapstr = mmap_string_new_len(buf, read_size);
324 if (mmapstr == NULL) {
325 res = MAIL_ERROR_MEMORY;
326 goto close;
327 }
328
329 cur_token = 0;
330
331 r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid);
332 if (r != MAIL_NO_ERROR) {
333 fclose(f);
334 res = r;
335 goto free_mmapstr;
336 }
337
338 mmap_string_free(mmapstr);
339 fclose(f);
340
341 if (written_uid > ancestor_data->mh_cur_folder->fl_max_index)
342 ancestor_data->mh_cur_folder->fl_max_index = written_uid;
343
344 return MAIL_NO_ERROR;
345
346 free_mmapstr:
347 mmap_string_free(mmapstr);
348 close:
349 fclose(f);
350 err:
351 return res;
352}
353
354
355static int mhdriver_cached_initialize(mailsession * session)
356{
357 struct mh_cached_session_state_data * data;
358
359 data = malloc(sizeof(* data));
360 if (data == NULL)
361 goto err;
362
363 data->mh_flags_store = mail_flags_store_new();
364 if (data->mh_flags_store == NULL)
365 goto free;
366
367 data->mh_ancestor = mailsession_new(mh_session_driver);
368 if (data->mh_ancestor == NULL)
369 goto free_store;
370
371 data->mh_quoted_mb = NULL;
372
373 session->sess_data = data;
374
375 return MAIL_NO_ERROR;
376
377 free_store:
378 mail_flags_store_free(data->mh_flags_store);
379 free:
380 free(data);
381 err:
382 return MAIL_ERROR_MEMORY;
383}
384
385static void free_state(struct mh_cached_session_state_data * mh_data)
386{
387 if (mh_data->mh_quoted_mb) {
388 free(mh_data->mh_quoted_mb);
389 mh_data->mh_quoted_mb = NULL;
390 }
391}
392
393static int mh_flags_store_process(char * flags_directory, char * quoted_mb,
394 struct mail_flags_store * flags_store)
395{
396 char filename_flags[PATH_MAX];
397 struct mail_cache_db * cache_db_flags;
398 MMAPString * mmapstr;
399 unsigned int i;
400 int r;
401 int res;
402
403 if (carray_count(flags_store->fls_tab) == 0)
404 return MAIL_NO_ERROR;
405
406 if (quoted_mb == NULL)
407 return MAIL_NO_ERROR;
408
409 snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
410 flags_directory, quoted_mb, FLAGS_NAME);
411
412 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
413 if (r < 0) {
414 res = MAIL_ERROR_FILE;
415 goto err;
416 }
417
418 mmapstr = mmap_string_new("");
419 if (mmapstr == NULL) {
420 res = MAIL_ERROR_MEMORY;
421 goto close_db_flags;
422 }
423
424 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
425 mailmessage * msg;
426
427 msg = carray_get(flags_store->fls_tab, i);
428
429 r = mhdriver_write_cached_flags(cache_db_flags, mmapstr,
430 msg->msg_uid, msg->msg_flags);
431 }
432
433 mmap_string_free(mmapstr);
434 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
435
436 mail_flags_store_clear(flags_store);
437
438 return MAIL_NO_ERROR;
439
440 close_db_flags:
441 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
442 err:
443 return res;
444}
445
446static void mhdriver_cached_uninitialize(mailsession * session)
447{
448 struct mh_cached_session_state_data * data;
449
450 data = get_cached_data(session);
451
452 mh_flags_store_process(data->mh_flags_directory, data->mh_quoted_mb,
453 data->mh_flags_store);
454
455 mail_flags_store_free(data->mh_flags_store);
456
457 free_state(data);
458 mailsession_free(data->mh_ancestor);
459 free(data);
460
461 session->sess_data = NULL;
462}
463
464static int mhdriver_cached_parameters(mailsession * session,
465 int id, void * value)
466{
467 struct mh_cached_session_state_data * cached_data;
468 int r;
469
470 cached_data = get_cached_data(session);
471
472 switch (id) {
473 case MHDRIVER_CACHED_SET_CACHE_DIRECTORY:
474 strncpy(cached_data->mh_cache_directory, value, PATH_MAX);
475 cached_data->mh_cache_directory[PATH_MAX - 1] = '\0';
476
477 r = generic_cache_create_dir(cached_data->mh_cache_directory);
478 if (r != MAIL_NO_ERROR)
479 return r;
480
481 return MAIL_NO_ERROR;
482
483 case MHDRIVER_CACHED_SET_FLAGS_DIRECTORY:
484 strncpy(cached_data->mh_flags_directory, value, PATH_MAX);
485 cached_data->mh_flags_directory[PATH_MAX - 1] = '\0';
486
487 r = generic_cache_create_dir(cached_data->mh_flags_directory);
488 if (r != MAIL_NO_ERROR)
489 return r;
490
491 return MAIL_NO_ERROR;
492 }
493
494 return MAIL_ERROR_INVAL;
495}
496
497static int mhdriver_cached_connect_path(mailsession * session, char * path)
498{
499 return mailsession_connect_path(get_ancestor(session), path);
500}
501
502static int mhdriver_cached_logout(mailsession * session)
503{
504 int r;
505 struct mh_cached_session_state_data * cached_data;
506
507 r = write_max_uid_value(session);
508
509 cached_data = get_cached_data(session);
510
511 mh_flags_store_process(cached_data->mh_flags_directory,
512 cached_data->mh_quoted_mb,
513 cached_data->mh_flags_store);
514
515 return mailsession_logout(get_ancestor(session));
516}
517
518static int mhdriver_cached_check_folder(mailsession * session)
519{
520 struct mh_cached_session_state_data * cached_data;
521
522 cached_data = get_cached_data(session);
523
524 mh_flags_store_process(cached_data->mh_flags_directory,
525 cached_data->mh_quoted_mb,
526 cached_data->mh_flags_store);
527
528 return MAIL_NO_ERROR;
529}
530
531/* folders operations */
532
533static int mhdriver_cached_build_folder_name(mailsession * session, char * mb,
534 char * name, char ** result)
535{
536 return mailsession_build_folder_name(get_ancestor(session),
537 mb, name, result);
538}
539
540static int mhdriver_cached_create_folder(mailsession * session, char * mb)
541{
542 return mailsession_create_folder(get_ancestor(session), mb);
543}
544
545static int mhdriver_cached_delete_folder(mailsession * session, char * mb)
546{
547 return mailsession_delete_folder(get_ancestor(session), mb);
548}
549
550static int mhdriver_cached_rename_folder(mailsession * session, char * mb,
551 char * new_name)
552{
553 return mailsession_rename_folder(get_ancestor(session), mb, new_name);
554}
555
556static int get_cache_directory(mailsession * session,
557 char * path, char ** result)
558{
559 char * quoted_mb;
560 char dirname[PATH_MAX];
561 int res;
562 int r;
563 struct mh_cached_session_state_data * cached_data;
564
565 cached_data = get_cached_data(session);
566
567 quoted_mb = maildriver_quote_mailbox(path);
568 if (quoted_mb == NULL) {
569 res = MAIL_ERROR_MEMORY;
570 goto err;
571 }
572
573 snprintf(dirname, PATH_MAX, "%s/%s",
574 cached_data->mh_cache_directory, quoted_mb);
575
576 r = generic_cache_create_dir(dirname);
577 if (r != MAIL_NO_ERROR) {
578 res = r;
579 goto free;
580 }
581
582 snprintf(dirname, PATH_MAX, "%s/%s",
583 cached_data->mh_flags_directory, quoted_mb);
584
585 r = generic_cache_create_dir(dirname);
586 if (r != MAIL_NO_ERROR) {
587 res = r;
588 goto free;
589 }
590
591 * result = quoted_mb;
592
593 return MAIL_NO_ERROR;
594
595 free:
596 free(quoted_mb);
597 err:
598 return res;
599}
600
601static int mhdriver_cached_select_folder(mailsession * session, char * mb)
602{
603 int r;
604 int res;
605 char * quoted_mb;
606 struct mh_cached_session_state_data * cached_data;
607
608 cached_data = get_cached_data(session);
609
610 mh_flags_store_process(cached_data->mh_flags_directory,
611 cached_data->mh_quoted_mb,
612 cached_data->mh_flags_store);
613
614 r = get_cache_directory(session, mb, &quoted_mb);
615 if (r != MAIL_NO_ERROR) {
616 res = r;
617 goto err;
618 }
619
620 r = mailsession_select_folder(get_ancestor(session), mb);
621 if (r != MAIL_NO_ERROR) {
622 res = r;
623 goto free;
624 }
625
626 r = write_max_uid_value(session);
627
628 free_state(cached_data);
629 cached_data->mh_quoted_mb = quoted_mb;
630
631 r = read_max_uid_value(session);
632
633 return MAIL_NO_ERROR;
634
635 free:
636 free(quoted_mb);
637 err:
638 return res;
639}
640
641static int mhdriver_cached_expunge_folder(mailsession * session)
642{
643 struct mailmh_folder * folder;
644 int res;
645 char filename_flags[PATH_MAX];
646 struct mail_cache_db * cache_db_flags;
647 MMAPString * mmapstr;
648 struct mh_cached_session_state_data * cached_data;
649 unsigned int i;
650 int r;
651
652 cached_data = get_cached_data(session);
653 if (cached_data->mh_quoted_mb == NULL) {
654 res = MAIL_ERROR_BAD_STATE;
655 goto err;
656 }
657
658 mh_flags_store_process(cached_data->mh_flags_directory,
659 cached_data->mh_quoted_mb,
660 cached_data->mh_flags_store);
661
662 folder = get_mh_cur_folder(session);
663 if (folder == NULL) {
664 res = MAIL_ERROR_BAD_STATE;
665 goto err;
666 }
667
668 snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
669 cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME);
670
671 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
672 if (r < 0) {
673 res = MAIL_ERROR_FILE;
674 goto err;
675 }
676
677 mmapstr = mmap_string_new("");
678 if (mmapstr == NULL) {
679 res = MAIL_ERROR_MEMORY;
680 goto close_db_flags;
681 }
682
683 for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
684 struct mailmh_msg_info * mh_info;
685 struct mail_flags * flags;
686
687 mh_info = carray_get(folder->fl_msgs_tab, i);
688 if (mh_info == NULL)
689 continue;
690
691 r = mhdriver_get_cached_flags(cache_db_flags, mmapstr,
692 session, mh_info->msg_index, &flags);
693 if (r != MAIL_NO_ERROR)
694 continue;
695
696 if (flags->fl_flags & MAIL_FLAG_DELETED) {
697 r = mailmh_folder_remove_message(folder, mh_info->msg_index);
698 }
699
700 mail_flags_free(flags);
701 }
702
703 mmap_string_free(mmapstr);
704 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
705
706 mailmh_folder_update(folder);
707
708 return MAIL_NO_ERROR;
709
710 close_db_flags:
711 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
712 err:
713 return res;
714}
715
716
717static int mhdriver_cached_status_folder(mailsession * session, char * mb,
718 uint32_t * result_messages,
719 uint32_t * result_recent,
720 uint32_t * result_unseen)
721{
722 struct mailmh_folder * folder;
723 int res;
724 char filename_flags[PATH_MAX];
725 struct mail_cache_db * cache_db_flags;
726 MMAPString * mmapstr;
727 struct mh_cached_session_state_data * cached_data;
728 unsigned int i;
729 int r;
730 uint32_t count;
731 uint32_t recent;
732 uint32_t unseen;
733
734 r = mhdriver_cached_select_folder(session, mb);
735 if (r != MAIL_NO_ERROR) {
736 res = r;
737 goto err;
738 }
739
740 count = 0;
741 recent = 0;
742 unseen = 0;
743
744 folder = get_mh_cur_folder(session);
745 if (folder == NULL) {
746 res = MAIL_ERROR_BAD_STATE;
747 goto err;
748 }
749
750 cached_data = get_cached_data(session);
751 if (cached_data->mh_quoted_mb == NULL) {
752 res = MAIL_ERROR_BAD_STATE;
753 goto err;
754 }
755
756 snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
757 cached_data->mh_flags_directory,
758 cached_data->mh_quoted_mb, FLAGS_NAME);
759
760 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
761 if (r < 0) {
762 res = MAIL_ERROR_FILE;
763 goto err;
764 }
765
766 mmapstr = mmap_string_new("");
767 if (mmapstr == NULL) {
768 res = MAIL_ERROR_MEMORY;
769 goto close_db_flags;
770 }
771
772 for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
773 struct mailmh_msg_info * mh_info;
774 struct mail_flags * flags;
775
776 mh_info = carray_get(folder->fl_msgs_tab, i);
777 if (mh_info == NULL)
778 continue;
779
780 count ++;
781
782 r = mhdriver_get_cached_flags(cache_db_flags, mmapstr,
783 session, mh_info->msg_index,
784 &flags);
785
786 if (r != MAIL_NO_ERROR) {
787 recent ++;
788 unseen ++;
789 continue;
790 }
791
792 if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
793 recent ++;
794 }
795 if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
796 unseen ++;
797 }
798 mail_flags_free(flags);
799 }
800
801 mmap_string_free(mmapstr);
802 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
803
804 * result_messages = count;
805 * result_recent = recent;
806 * result_unseen = unseen;
807
808 return MAIL_NO_ERROR;
809
810 close_db_flags:
811 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
812 err:
813 return res;
814}
815
816static int mhdriver_cached_messages_number(mailsession * session, char * mb,
817 uint32_t * result)
818{
819 return mailsession_messages_number(get_ancestor(session), mb, result);
820}
821
822static int mhdriver_cached_recent_number(mailsession * session, char * mb,
823 uint32_t * result)
824{
825 uint32_t messages;
826 uint32_t recent;
827 uint32_t unseen;
828 int r;
829
830 r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen);
831 if (r != MAIL_NO_ERROR)
832 return r;
833
834 * result = recent;
835
836 return MAIL_NO_ERROR;
837}
838
839
840static int mhdriver_cached_unseen_number(mailsession * session, char * mb,
841 uint32_t * result)
842{
843 uint32_t messages;
844 uint32_t recent;
845 uint32_t unseen;
846 int r;
847
848 r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen);
849 if (r != MAIL_NO_ERROR)
850 return r;
851
852 * result = recent;
853
854 return MAIL_NO_ERROR;
855}
856
857
858static int mhdriver_cached_list_folders(mailsession * session, char * mb,
859 struct mail_list ** result)
860{
861 return mailsession_list_folders(get_ancestor(session), mb, result);
862}
863
864static int mhdriver_cached_lsub_folders(mailsession * session, char * mb,
865 struct mail_list ** result)
866{
867 return mailsession_lsub_folders(get_ancestor(session), mb, result);
868}
869
870static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb)
871{
872 return mailsession_subscribe_folder(get_ancestor(session), mb);
873}
874
875static int mhdriver_cached_unsubscribe_folder(mailsession * session,
876 char * mb)
877{
878 return mailsession_unsubscribe_folder(get_ancestor(session), mb);
879}
880
881/* messages operations */
882
883static int mhdriver_cached_append_message(mailsession * session,
884 char * message, size_t size)
885{
886 return mailsession_append_message(get_ancestor(session), message, size);
887}
888
889static int mhdriver_cached_copy_message(mailsession * session,
890 uint32_t num, char * mb)
891{
892 return mailsession_copy_message(get_ancestor(session), num, mb);
893}
894
895static int mhdriver_cached_remove_message(mailsession * session, uint32_t num)
896{
897 return mailsession_remove_message(get_ancestor(session), num);
898}
899
900static int mhdriver_cached_move_message(mailsession * session,
901 uint32_t num, char * mb)
902{
903 return mailsession_move_message(get_ancestor(session), num, mb);
904}
905
906static int
907mhdriver_cached_get_messages_list(mailsession * session,
908 struct mailmessage_list ** result)
909{
910 struct mailmh_folder * folder;
911 int res;
912
913 folder = get_mh_cur_folder(session);
914 if (folder == NULL) {
915 res = MAIL_ERROR_BAD_STATE;
916 goto err;
917 }
918
919 return mh_get_messages_list(folder, session,
920 mh_cached_message_driver, result);
921
922 err:
923 return res;
924}
925
926
927
928static int
929get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
930 mailsession * session, uint32_t num,
931 struct mailimf_fields ** result)
932{
933 int r;
934 char keyname[PATH_MAX];
935 struct mailimf_fields * fields;
936 int res;
937 struct mailmh_folder * folder;
938 struct mailmh_msg_info * msg_info;
939 chashdatum key;
940 chashdatum data;
941
942 folder = get_mh_cur_folder(session);
943
944#if 0
945 msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num);
946 if (msg_info == NULL)
947 return MAIL_ERROR_CACHE_MISS;
948#endif
949 key.data = &num;
950 key.len = sizeof(num);
951 r = chash_get(folder->fl_msgs_hash, &key, &data);
952 if (r < 0)
953 return MAIL_ERROR_CACHE_MISS;
954 msg_info = data.data;
955
956 snprintf(keyname, PATH_MAX, "%u-%u-%u-envelope",
957 num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size);
958
959 r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields);
960 if (r != MAIL_NO_ERROR) {
961 res = r;
962 goto err;
963 }
964
965 * result = fields;
966
967 return MAIL_NO_ERROR;
968
969 err:
970 return res;
971}
972
973static int
974write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
975 mailsession * session, uint32_t num,
976 struct mailimf_fields * fields)
977{
978 int r;
979 char keyname[PATH_MAX];
980 int res;
981 struct mailmh_folder * folder;
982 chashdatum key;
983 chashdatum data;
984 struct mailmh_msg_info * msg_info;
985
986 folder = get_mh_cur_folder(session);
987#if 0
988 msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num);
989 if (msg_info == NULL) {
990 res = MAIL_ERROR_CACHE_MISS;
991 goto err;
992 }
993#endif
994 key.data = &num;
995 key.len = sizeof(num);
996 r = chash_get(folder->fl_msgs_hash, &key, &data);
997 if (r < 0)
998 return MAIL_ERROR_CACHE_MISS;
999 msg_info = data.data;
1000
1001 snprintf(keyname, PATH_MAX, "%u-%u-%u-envelope",
1002 num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size);
1003
1004 r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields);
1005 if (r != MAIL_NO_ERROR) {
1006 res = r;
1007 goto err;
1008 }
1009
1010 return MAIL_NO_ERROR;
1011
1012 err:
1013 return res;
1014}
1015
1016static int
1017mhdriver_cached_get_envelopes_list(mailsession * session,
1018 struct mailmessage_list * env_list)
1019{
1020 int r;
1021 unsigned int i;
1022 char filename_env[PATH_MAX];
1023 char filename_flags[PATH_MAX];
1024 struct mail_cache_db * cache_db_env;
1025 struct mail_cache_db * cache_db_flags;
1026 MMAPString * mmapstr;
1027 int res;
1028 struct mh_cached_session_state_data * cached_data;
1029
1030 cached_data = get_cached_data(session);
1031 if (cached_data->mh_quoted_mb == NULL) {
1032 res = MAIL_ERROR_BAD_STATE;
1033 goto err;
1034 }
1035
1036 mh_flags_store_process(cached_data->mh_flags_directory,
1037 cached_data->mh_quoted_mb,
1038 cached_data->mh_flags_store);
1039
1040 mmapstr = mmap_string_new("");
1041 if (mmapstr == NULL) {
1042 res = MAIL_ERROR_MEMORY;
1043 goto err;
1044 }
1045
1046 snprintf(filename_env, PATH_MAX, "%s/%s/%s",
1047 cached_data->mh_cache_directory,
1048 cached_data->mh_quoted_mb, ENV_NAME);
1049
1050 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
1051 if (r < 0) {
1052 res = MAIL_ERROR_MEMORY;
1053 goto free_mmapstr;
1054 }
1055
1056 snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
1057 cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME);
1058
1059 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
1060 if (r < 0) {
1061 res = MAIL_ERROR_MEMORY;
1062 goto close_db_env;
1063 }
1064
1065 /* fill with cached */
1066
1067 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1068 mailmessage * msg;
1069 struct mailimf_fields * fields;
1070 struct mail_flags * flags;
1071
1072 msg = carray_get(env_list->msg_tab, i);
1073
1074 if (msg->msg_fields == NULL) {
1075 r = get_cached_envelope(cache_db_env, mmapstr,
1076 msg->msg_session, msg->msg_index, &fields);
1077 if (r == MAIL_NO_ERROR) {
1078 msg->msg_cached = TRUE;
1079 msg->msg_fields = fields;
1080 }
1081 }
1082
1083 if (msg->msg_flags == NULL) {
1084 r = mhdriver_get_cached_flags(cache_db_flags, mmapstr,
1085 session, msg->msg_index, &flags);
1086 if (r == MAIL_NO_ERROR) {
1087 msg->msg_flags = flags;
1088 }
1089 }
1090 }
1091
1092 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
1093 mail_cache_db_close_unlock(filename_env, cache_db_env);
1094
1095 r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
1096
1097 if (r != MAIL_NO_ERROR) {
1098 res = r;
1099 goto free_mmapstr;
1100 }
1101
1102 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
1103 if (r < 0) {
1104 res = MAIL_ERROR_MEMORY;
1105 goto free_mmapstr;
1106 }
1107
1108 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
1109 if (r < 0) {
1110 res = MAIL_ERROR_MEMORY;
1111 goto close_db_env;
1112 }
1113
1114 /* add flags */
1115
1116 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1117 mailmessage * msg;
1118
1119 msg = carray_get(env_list->msg_tab, i);
1120
1121 if (msg->msg_flags == NULL)
1122 msg->msg_flags = mail_flags_new_empty();
1123 }
1124
1125 /* must write cache */
1126
1127 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1128 mailmessage * msg;
1129
1130 msg = carray_get(env_list->msg_tab, i);
1131
1132 if (msg->msg_fields != NULL) {
1133 if (!msg->msg_cached) {
1134 r = write_cached_envelope(cache_db_env, mmapstr,
1135 session, msg->msg_index, msg->msg_fields);
1136 }
1137 }
1138
1139 if (msg->msg_flags != NULL) {
1140 r = mhdriver_write_cached_flags(cache_db_flags, mmapstr,
1141 msg->msg_uid, msg->msg_flags);
1142 }
1143 }
1144
1145 /* flush cache */
1146
1147 maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list);
1148
1149 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
1150 mail_cache_db_close_unlock(filename_env, cache_db_env);
1151
1152 mmap_string_free(mmapstr);
1153
1154 return MAIL_NO_ERROR;
1155
1156 close_db_env:
1157 mail_cache_db_close_unlock(filename_env, cache_db_env);
1158 free_mmapstr:
1159 mmap_string_free(mmapstr);
1160 err:
1161 return res;
1162}
1163
1164static int mhdriver_cached_get_message(mailsession * session,
1165 uint32_t num, mailmessage ** result)
1166{
1167 mailmessage * msg_info;
1168 int r;
1169
1170 msg_info = mailmessage_new();
1171 if (msg_info == NULL)
1172 return MAIL_ERROR_MEMORY;
1173
1174 r = mailmessage_init(msg_info, session, mh_cached_message_driver, num, 0);
1175 if (r != MAIL_NO_ERROR)
1176 return r;
1177
1178 * result = msg_info;
1179
1180 return MAIL_NO_ERROR;
1181}
1182
1183static int mhdriver_cached_get_message_by_uid(mailsession * session,
1184 const char * uid,
1185 mailmessage ** result)
1186{
1187 uint32_t index;
1188 char *p;
1189 struct mailmh_msg_info * mh_msg_info;
1190 struct mailmh_folder * folder;
1191 time_t mtime;
1192 char * mtime_p;
1193 chashdatum key;
1194 chashdatum data;
1195 int r;
1196
1197 if (uid == NULL)
1198 return MAIL_ERROR_INVAL;
1199
1200 index = strtoul(uid, &p, 10);
1201 if (p == uid || * p != '-')
1202 return MAIL_ERROR_INVAL;
1203
1204 folder = get_mh_cur_folder(session);
1205
1206 mh_msg_info = NULL;
1207 key.data = &index;
1208 key.len = sizeof(index);
1209 r = chash_get(folder->fl_msgs_hash, &key, &data);
1210 if (r < 0)
1211 return MAIL_ERROR_MSG_NOT_FOUND;
1212
1213 mh_msg_info = data.data;
1214
1215 mtime_p = p + 1;
1216
1217 mtime = strtoul(mtime_p, &p, 10);
1218 if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) {
1219 size_t size;
1220 char *size_p;
1221
1222 size_p = p + 1;
1223 size = strtoul(size_p, &p, 10);
1224 if ((* p == '\0') && (size == mh_msg_info->msg_size))
1225 return mhdriver_cached_get_message(session, index, result);
1226 }
1227 else if (*p != '-') {
1228 return MAIL_ERROR_INVAL;
1229 }
1230
1231 return MAIL_ERROR_MSG_NOT_FOUND;
1232}