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