summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/generic/maildirdriver_cached.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/generic/maildirdriver_cached.c') (more/less context) (ignore whitespace changes)
-rw-r--r--kmicromail/libetpan/generic/maildirdriver_cached.c1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/kmicromail/libetpan/generic/maildirdriver_cached.c b/kmicromail/libetpan/generic/maildirdriver_cached.c
new file mode 100644
index 0000000..503d1c9
--- a/dev/null
+++ b/kmicromail/libetpan/generic/maildirdriver_cached.c
@@ -0,0 +1,1080 @@
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 "maildirdriver.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 "maildir.h"
51#include "maildriver_tools.h"
52#include "maildirdriver_tools.h"
53#include "maildirdriver_cached_message.h"
54#include "mailmessage.h"
55#include "generic_cache.h"
56#include "imfcache.h"
57#include "mail_cache_db.h"
58#include "libetpan-config.h"
59
60static int initialize(mailsession * session);
61
62static void uninitialize(mailsession * session);
63
64static int parameters(mailsession * session,
65 int id, void * value);
66
67static int connect_path(mailsession * session, char * path);
68
69static int logout(mailsession * session);
70
71static int expunge_folder(mailsession * session);
72
73static int status_folder(mailsession * session, char * mb,
74 uint32_t * result_messages, uint32_t * result_recent,
75 uint32_t * result_unseen);
76
77static int recent_number(mailsession * session, char * mb,
78 uint32_t * result);
79
80static int unseen_number(mailsession * session, char * mb,
81 uint32_t * result);
82
83static int messages_number(mailsession * session, char * mb,
84 uint32_t * result);
85
86static int append_message(mailsession * session,
87 char * message, size_t size);
88
89static int get_messages_list(mailsession * session,
90 struct mailmessage_list ** result);
91
92static int get_envelopes_list(mailsession * session,
93 struct mailmessage_list * env_list);
94
95static int check_folder(mailsession * session);
96
97static int get_message(mailsession * session,
98 uint32_t num, mailmessage ** result);
99
100static int get_message_by_uid(mailsession * session,
101 const char * uid, mailmessage ** result);
102
103static mailsession_driver local_maildir_cached_session_driver = {
104 .sess_name = "maildir-cached",
105
106 .sess_initialize = initialize,
107 .sess_uninitialize = uninitialize,
108
109 .sess_parameters = parameters,
110
111 .sess_connect_stream = NULL,
112 .sess_connect_path = connect_path,
113 .sess_starttls = NULL,
114 .sess_login = NULL,
115 .sess_logout = logout,
116 .sess_noop = NULL,
117
118 .sess_build_folder_name = NULL,
119 .sess_create_folder = NULL,
120 .sess_delete_folder = NULL,
121 .sess_rename_folder = NULL,
122 .sess_check_folder = check_folder,
123 .sess_examine_folder = NULL,
124 .sess_select_folder = NULL,
125 .sess_expunge_folder = expunge_folder,
126 .sess_status_folder = status_folder,
127 .sess_messages_number = messages_number,
128 .sess_recent_number = recent_number,
129 .sess_unseen_number = unseen_number,
130 .sess_list_folders = NULL,
131 .sess_lsub_folders = NULL,
132 .sess_subscribe_folder = NULL,
133 .sess_unsubscribe_folder = NULL,
134
135 .sess_append_message = append_message,
136 .sess_copy_message = NULL,
137 .sess_move_message = NULL,
138
139 .sess_get_messages_list = get_messages_list,
140 .sess_get_envelopes_list = get_envelopes_list,
141 .sess_remove_message = NULL,
142#if 0
143 .sess_search_messages = maildriver_generic_search_messages,
144#endif
145
146 .sess_get_message = get_message,
147 .sess_get_message_by_uid = get_message_by_uid,
148};
149
150mailsession_driver * maildir_cached_session_driver =
151&local_maildir_cached_session_driver;
152
153
154static inline struct maildir_cached_session_state_data *
155get_cached_data(mailsession * session)
156{
157 return session->sess_data;
158}
159
160static inline mailsession * get_ancestor(mailsession * session)
161{
162 return get_cached_data(session)->md_ancestor;
163}
164
165static inline struct maildir_session_state_data *
166get_ancestor_data(mailsession * session)
167{
168 return get_ancestor(session)->sess_data;
169}
170
171
172static struct maildir * get_maildir_session(mailsession * session)
173{
174 return get_ancestor_data(session)->md_session;
175}
176
177static int initialize(mailsession * session)
178{
179 struct maildir_cached_session_state_data * data;
180
181 data = malloc(sizeof(* data));
182 if (data == NULL)
183 goto err;
184
185 data->md_ancestor = mailsession_new(maildir_session_driver);
186 if (data->md_ancestor == NULL)
187 goto free;
188
189 data->md_flags_store = mail_flags_store_new();
190 if (data->md_flags_store == NULL)
191 goto free_session;
192
193 data->md_quoted_mb = NULL;
194 data->md_cache_directory[0] = '\0';
195 data->md_flags_directory[0] = '\0';
196
197 session->sess_data = data;
198
199 return MAIL_NO_ERROR;
200
201 free_session:
202 mailsession_free(data->md_ancestor);
203 free:
204 free(data);
205 err:
206 return MAIL_ERROR_MEMORY;
207}
208
209static void
210free_quoted_mb(struct maildir_cached_session_state_data * maildir_cached_data)
211{
212 if (maildir_cached_data->md_quoted_mb != NULL) {
213 free(maildir_cached_data->md_quoted_mb);
214 maildir_cached_data->md_quoted_mb = NULL;
215 }
216}
217
218static int
219write_cached_flags(struct mail_cache_db * cache_db,
220 MMAPString * mmapstr,
221 char * uid, struct mail_flags * flags);
222
223#define ENV_NAME "env.db"
224#define FLAGS_NAME "flags.db"
225
226static int flags_store_process(char * flags_directory, char * quoted_mb,
227 struct mail_flags_store * flags_store)
228{
229 char filename_flags[PATH_MAX];
230 struct mail_cache_db * cache_db_flags;
231 MMAPString * mmapstr;
232 unsigned int i;
233 int r;
234 int res;
235
236 if (carray_count(flags_store->fls_tab) == 0)
237 return MAIL_NO_ERROR;
238
239 if (quoted_mb == NULL)
240 return MAIL_NO_ERROR;
241
242 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
243 flags_directory, MAIL_DIR_SEPARATOR, quoted_mb,
244 MAIL_DIR_SEPARATOR, FLAGS_NAME);
245
246 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
247 if (r < 0) {
248 res = MAIL_ERROR_FILE;
249 goto err;
250 }
251
252 mmapstr = mmap_string_new("");
253 if (mmapstr == NULL) {
254 res = MAIL_ERROR_MEMORY;
255 goto close_db_flags;
256 }
257
258 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
259 mailmessage * msg;
260
261 msg = carray_get(flags_store->fls_tab, i);
262
263 r = write_cached_flags(cache_db_flags, mmapstr,
264 msg->msg_uid, msg->msg_flags);
265 if (r != MAIL_NO_ERROR) {
266 /* ignore errors */
267 }
268 }
269
270 mmap_string_free(mmapstr);
271 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
272
273 mail_flags_store_clear(flags_store);
274
275 return MAIL_NO_ERROR;
276
277 close_db_flags:
278 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
279 err:
280 return res;
281}
282
283static void uninitialize(mailsession * session)
284{
285 struct maildir_cached_session_state_data * data;
286
287 data = get_cached_data(session);
288
289 flags_store_process(data->md_flags_directory,
290 data->md_quoted_mb,
291 data->md_flags_store);
292
293 mail_flags_store_free(data->md_flags_store);
294 mailsession_free(data->md_ancestor);
295 free_quoted_mb(data);
296 free(data);
297
298 session->sess_data = data;
299}
300
301
302static int parameters(mailsession * session,
303 int id, void * value)
304{
305 struct maildir_cached_session_state_data * data;
306 int r;
307
308 data = get_cached_data(session);
309
310 switch (id) {
311 case MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY:
312 strncpy(data->md_cache_directory, value, PATH_MAX);
313 data->md_cache_directory[PATH_MAX - 1] = '\0';
314
315 r = generic_cache_create_dir(data->md_cache_directory);
316 if (r != MAIL_NO_ERROR)
317 return r;
318
319 return MAIL_NO_ERROR;
320
321 case MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY:
322 strncpy(data->md_flags_directory, value, PATH_MAX);
323 data->md_flags_directory[PATH_MAX - 1] = '\0';
324
325 r = generic_cache_create_dir(data->md_flags_directory);
326 if (r != MAIL_NO_ERROR)
327 return r;
328
329 return MAIL_NO_ERROR;
330
331 default:
332 return mailsession_parameters(data->md_ancestor, id, value);
333 }
334}
335
336
337static int get_cache_folder(mailsession * session, char ** result)
338{
339 struct maildir * md;
340 char * quoted_mb;
341 int res;
342 int r;
343 char key[PATH_MAX];
344 struct maildir_cached_session_state_data * data;
345
346 md = get_maildir_session(session);
347 data = get_cached_data(session);
348
349 quoted_mb = maildriver_quote_mailbox(md->mdir_path);
350 if (quoted_mb == NULL) {
351 res = MAIL_ERROR_MEMORY;
352 goto err;
353 }
354
355 snprintf(key, PATH_MAX, "%s/%s", data->md_cache_directory, quoted_mb);
356 r = generic_cache_create_dir(key);
357 if (r != MAIL_NO_ERROR) {
358 res = r;
359 goto free_quoted_mb;
360 }
361
362 snprintf(key, PATH_MAX, "%s/%s", data->md_flags_directory, quoted_mb);
363 r = generic_cache_create_dir(key);
364 if (r != MAIL_NO_ERROR) {
365 res = r;
366 goto free_quoted_mb;
367 }
368
369 * result = quoted_mb;
370
371 return MAIL_NO_ERROR;
372
373 free_quoted_mb:
374 free(quoted_mb);
375 err:
376 return res;
377}
378
379
380static int connect_path(mailsession * session, char * path)
381{
382 int r;
383 int res;
384 char * quoted_mb;
385
386 r = mailsession_connect_path(get_ancestor(session), path);
387 if (r != MAIL_NO_ERROR) {
388 res = r;
389 goto err;
390 }
391
392 r = get_cache_folder(session, &quoted_mb);
393 if (r != MAIL_NO_ERROR) {
394 res = r;
395 goto logout;
396 }
397
398 get_cached_data(session)->md_quoted_mb = quoted_mb;
399
400 return MAILDIR_NO_ERROR;
401
402 logout:
403 mailsession_logout(get_ancestor(session));
404 err:
405 return res;
406}
407
408static int logout(mailsession * session)
409{
410 struct maildir_cached_session_state_data * data;
411 int r;
412
413 data = get_cached_data(session);
414
415 flags_store_process(data->md_flags_directory,
416 data->md_quoted_mb, data->md_flags_store);
417
418 r = mailsession_logout(get_ancestor(session));
419 if (r != MAIL_NO_ERROR)
420 return r;
421
422 free_quoted_mb(get_cached_data(session));
423
424 return MAIL_NO_ERROR;
425}
426
427static int status_folder(mailsession * session, char * mb,
428 uint32_t * result_messages, uint32_t * result_recent,
429 uint32_t * result_unseen)
430{
431 return mailsession_status_folder(get_ancestor(session), mb,
432 result_messages, result_recent, result_unseen);
433}
434
435static int messages_number(mailsession * session, char * mb,
436 uint32_t * result)
437{
438 return mailsession_messages_number(get_ancestor(session), mb, result);
439}
440
441static int unseen_number(mailsession * session, char * mb,
442 uint32_t * result)
443{
444 return mailsession_unseen_number(get_ancestor(session), mb, result);
445}
446
447static int recent_number(mailsession * session, char * mb,
448 uint32_t * result)
449{
450 return mailsession_recent_number(get_ancestor(session), mb, result);
451}
452
453
454static int append_message(mailsession * session,
455 char * message, size_t size)
456{
457 return mailsession_append_message(get_ancestor(session), message, size);
458}
459
460
461#define UID_NAME "uid.db"
462
463static int uid_clean_up(struct mail_cache_db * uid_db,
464 struct mailmessage_list * env_list)
465{
466 chash * hash_exist;
467 int res;
468 int r;
469 unsigned int i;
470 chashdatum key;
471 chashdatum value;
472 char key_str[PATH_MAX];
473
474 /* flush cache */
475
476 hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
477 if (hash_exist == NULL) {
478 res = MAIL_ERROR_MEMORY;
479 goto err;
480 }
481
482 value.data = NULL;
483 value.len = 0;
484
485 key.data = "max-uid";
486 key.len = strlen("max-uid");
487 r = chash_set(hash_exist, &key, &value, NULL);
488
489 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
490 mailmessage * msg;
491
492 msg = carray_get(env_list->msg_tab, i);
493
494 value.data = NULL;
495 value.len = 0;
496
497 key.data = msg->msg_uid;
498 key.len = strlen(msg->msg_uid);
499 r = chash_set(hash_exist, &key, &value, NULL);
500 if (r < 0) {
501 res = MAIL_ERROR_MEMORY;
502 goto free;
503 }
504
505 snprintf(key_str, sizeof(key_str), "uid-%lu",
506 (unsigned long) msg->msg_index);
507 key.data = key_str;
508 key.len = strlen(key_str);
509 r = chash_set(hash_exist, &key, &value, NULL);
510 if (r < 0) {
511 res = MAIL_ERROR_MEMORY;
512 goto free;
513 }
514 }
515
516 mail_cache_db_clean_up(uid_db, hash_exist);
517
518 chash_free(hash_exist);
519
520 return MAIL_NO_ERROR;
521
522 free:
523 chash_free(hash_exist);
524 err:
525 return res;
526}
527
528static int get_messages_list(mailsession * session,
529 struct mailmessage_list ** result)
530{
531 struct maildir * md;
532 int r;
533 struct mailmessage_list * env_list;
534 int res;
535 uint32_t max_uid;
536 char filename[PATH_MAX];
537 struct mail_cache_db * uid_db;
538 void * value;
539 size_t value_len;
540 unsigned long i;
541 struct maildir_cached_session_state_data * data;
542 char key[PATH_MAX];
543
544 data = get_cached_data(session);
545
546 md = get_maildir_session(session);
547 if (md == NULL) {
548 res = MAIL_ERROR_BAD_STATE;
549 goto err;
550 }
551
552 check_folder(session);
553
554 r = maildir_update(md);
555 if (r != MAILDIR_NO_ERROR) {
556 res = maildirdriver_maildir_error_to_mail_error(r);
557 goto err;
558 }
559
560 r = maildir_get_messages_list(session, md,
561 maildir_cached_message_driver, &env_list);
562 if (r != MAILDIR_NO_ERROR) {
563 res = r;
564 goto err;
565 }
566
567 /* read/write DB */
568
569 snprintf(filename, sizeof(filename), "%s%c%s%c%s",
570 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
571 MAIL_DIR_SEPARATOR, UID_NAME);
572
573 r = mail_cache_db_open_lock(filename, &uid_db);
574 if (r < 0) {
575 res = MAIL_ERROR_MEMORY;
576 goto free_list;
577 }
578
579 max_uid = 0;
580 r = mail_cache_db_get(uid_db, "max-uid", sizeof("max-uid") - 1,
581 &value, &value_len);
582 if (r == 0) {
583 memcpy(&max_uid, value, sizeof(max_uid));
584 }
585
586 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
587 mailmessage * msg;
588 uint32_t index;
589
590 msg = carray_get(env_list->msg_tab, i);
591
592 r = mail_cache_db_get(uid_db, msg->msg_uid,
593 strlen(msg->msg_uid), &value, &value_len);
594 if (r < 0) {
595 max_uid ++;
596 msg->msg_index = max_uid;
597 mail_cache_db_put(uid_db, msg->msg_uid,
598 strlen(msg->msg_uid), &msg->msg_index, sizeof(msg->msg_index));
599
600 snprintf(key, sizeof(key), "uid-%lu", (unsigned long) msg->msg_index);
601 mail_cache_db_put(uid_db, key, strlen(key),
602 msg->msg_uid, strlen(msg->msg_uid));
603 }
604 else {
605 memcpy(&index, value, sizeof(index));
606 msg->msg_index = index;
607 }
608 }
609
610 mail_cache_db_put(uid_db, "max-uid", sizeof("max-uid") - 1,
611 &max_uid, sizeof(max_uid));
612
613 uid_clean_up(uid_db, env_list);
614
615 mail_cache_db_close_unlock(filename, uid_db);
616
617 * result = env_list;
618
619 return MAIL_NO_ERROR;
620
621 free_list:
622 mailmessage_list_free(env_list);
623 err:
624 return res;
625}
626
627static int
628get_cached_flags(struct mail_cache_db * cache_db,
629 MMAPString * mmapstr,
630 mailsession * session,
631 char * uid,
632 struct mail_flags ** result)
633{
634 int r;
635 char keyname[PATH_MAX];
636 struct mail_flags * flags;
637 int res;
638
639 snprintf(keyname, PATH_MAX, "%s-flags", uid);
640
641 r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
642 if (r != MAIL_NO_ERROR) {
643 res = r;
644 goto err;
645 }
646
647 * result = flags;
648
649 return MAIL_NO_ERROR;
650
651 err:
652 return res;
653}
654
655static int
656get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
657 mailsession * session, char * uid,
658 struct mailimf_fields ** result)
659{
660 int r;
661 char keyname[PATH_MAX];
662 struct mailimf_fields * fields;
663 int res;
664
665 snprintf(keyname, PATH_MAX, "%s-envelope", uid);
666
667 r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields);
668 if (r != MAIL_NO_ERROR) {
669 res = r;
670 goto err;
671 }
672
673 * result = fields;
674
675 return MAIL_NO_ERROR;
676
677 err:
678 return res;
679}
680
681static int
682write_cached_envelope(struct mail_cache_db * cache_db,
683 MMAPString * mmapstr,
684 mailsession * session, char * uid,
685 struct mailimf_fields * fields)
686{
687 int r;
688 char keyname[PATH_MAX];
689 int res;
690
691 snprintf(keyname, PATH_MAX, "%s-envelope", uid);
692
693 r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields);
694 if (r != MAIL_NO_ERROR) {
695 res = r;
696 goto err;
697 }
698
699 return MAIL_NO_ERROR;
700
701 err:
702 return res;
703}
704
705static int
706write_cached_flags(struct mail_cache_db * cache_db,
707 MMAPString * mmapstr,
708 char * uid, struct mail_flags * flags)
709{
710 int r;
711 char keyname[PATH_MAX];
712 int res;
713
714 snprintf(keyname, PATH_MAX, "%s-flags", uid);
715
716 r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
717 if (r != MAIL_NO_ERROR) {
718 res = r;
719 goto err;
720 }
721
722 return MAIL_NO_ERROR;
723
724 err:
725 return res;
726}
727
728
729static int get_envelopes_list(mailsession * session,
730 struct mailmessage_list * env_list)
731{
732 int r;
733 unsigned int i;
734 int res;
735 struct maildir_cached_session_state_data * data;
736 char filename_env[PATH_MAX];
737 char filename_flags[PATH_MAX];
738 struct mail_cache_db * cache_db_env;
739 struct mail_cache_db * cache_db_flags;
740 MMAPString * mmapstr;
741
742 data = get_cached_data(session);
743
744 flags_store_process(data->md_flags_directory,
745 data->md_quoted_mb, data->md_flags_store);
746
747 mmapstr = mmap_string_new("");
748 if (mmapstr == NULL) {
749 res = MAIL_ERROR_MEMORY;
750 goto err;
751 }
752
753 snprintf(filename_env, PATH_MAX, "%s%c%s%c%s",
754 data->md_cache_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
755 MAIL_DIR_SEPARATOR, ENV_NAME);
756
757 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
758 if (r < 0) {
759 res = MAIL_ERROR_MEMORY;
760 goto free_mmapstr;
761 }
762
763 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
764 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
765 MAIL_DIR_SEPARATOR, FLAGS_NAME);
766
767 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
768 if (r < 0) {
769 res = MAIL_ERROR_FILE;
770 goto close_db_env;
771 }
772
773 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) {
774 mailmessage * msg;
775 struct mailimf_fields * fields;
776 struct mail_flags * flags;
777
778 msg = carray_get(env_list->msg_tab, i);
779
780 if (msg->msg_fields == NULL) {
781 r = get_cached_envelope(cache_db_env, mmapstr, session,
782 msg->msg_uid, &fields);
783 if (r == MAIL_NO_ERROR) {
784 msg->msg_cached = TRUE;
785 msg->msg_fields = fields;
786 }
787 }
788
789 if (msg->msg_flags == NULL) {
790 r = get_cached_flags(cache_db_flags, mmapstr,
791 session, msg->msg_uid, &flags);
792 if (r == MAIL_NO_ERROR) {
793 msg->msg_flags = flags;
794 }
795 }
796 }
797
798 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
799 mail_cache_db_close_unlock(filename_env, cache_db_env);
800
801 r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
802 if (r != MAIL_NO_ERROR) {
803 res = r;
804 goto free_mmapstr;
805 }
806
807 r = mail_cache_db_open_lock(filename_env, &cache_db_env);
808 if (r < 0) {
809 res = MAIL_ERROR_MEMORY;
810 goto free_mmapstr;
811 }
812
813 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
814 if (r < 0) {
815 res = MAIL_ERROR_FILE;
816 goto close_db_env;
817 }
818
819 /* must write cache */
820
821 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
822 mailmessage * msg;
823
824 msg = carray_get(env_list->msg_tab, i);
825
826 if (msg->msg_fields != NULL) {
827 if (!msg->msg_cached) {
828 /* msg->index is the numerical UID of the message */
829 r = write_cached_envelope(cache_db_env, mmapstr,
830 session, msg->msg_uid, msg->msg_fields);
831 }
832 }
833
834 if (msg->msg_flags != NULL) {
835 r = write_cached_flags(cache_db_flags, mmapstr,
836 msg->msg_uid, msg->msg_flags);
837 }
838 }
839
840 /* flush cache */
841
842 maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list);
843
844 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
845 mail_cache_db_close_unlock(filename_env, cache_db_env);
846
847 mmap_string_free(mmapstr);
848
849 return MAIL_NO_ERROR;
850
851 close_db_env:
852 mail_cache_db_close_unlock(filename_env, cache_db_env);
853 free_mmapstr:
854 mmap_string_free(mmapstr);
855 err:
856 return res;
857}
858
859static int expunge_folder(mailsession * session)
860{
861 return mailsession_expunge_folder(get_ancestor(session));
862}
863
864static int check_folder(mailsession * session)
865{
866 struct maildir_cached_session_state_data * data;
867
868 data = get_cached_data(session);
869
870 flags_store_process(data->md_flags_directory,
871 data->md_quoted_mb, data->md_flags_store);
872
873 return mailsession_check_folder(get_ancestor(session));
874}
875
876static int get_message(mailsession * session,
877 uint32_t num, mailmessage ** result)
878{
879 struct maildir * md;
880 int res;
881 mailmessage * msg;
882 char filename[PATH_MAX];
883 struct mail_cache_db * uid_db;
884 char * msg_filename;
885 struct stat stat_info;
886 char key_str[PATH_MAX];
887 void * value;
888 size_t value_len;
889 char uid[PATH_MAX];
890 struct maildir_cached_session_state_data * data;
891 int r;
892
893 data = get_cached_data(session);
894
895 md = get_maildir_session(session);
896
897 /* a get_messages_list() should have been done once before */
898
899 /* read DB */
900
901 snprintf(filename, sizeof(filename), "%s%c%s%c%s",
902 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
903 MAIL_DIR_SEPARATOR, UID_NAME);
904
905 r = mail_cache_db_open_lock(filename, &uid_db);
906 if (r < 0) {
907 res = MAIL_ERROR_MEMORY;
908 goto err;
909 }
910
911 snprintf(key_str, sizeof(key_str), "uid-%lu", (unsigned long) num);
912
913 r = mail_cache_db_get(uid_db, key_str, strlen(key_str), &value, &value_len);
914 if (r < 0) {
915 res = MAIL_ERROR_INVAL;
916 goto close_db;
917 }
918
919 if (value_len >= PATH_MAX) {
920 res = MAIL_ERROR_INVAL;
921 goto close_db;
922 }
923
924 memcpy(uid, value, value_len);
925 uid[value_len] = '\0';
926
927 mail_cache_db_close_unlock(filename, uid_db);
928
929 /* update maildir data */
930
931 r = maildir_update(md);
932 if (r != MAILDIR_NO_ERROR) {
933 res = maildirdriver_maildir_error_to_mail_error(r);
934 goto err;
935 }
936
937 msg_filename = maildir_message_get(md, uid);
938 if (msg_filename == NULL) {
939 res = MAIL_ERROR_INVAL;
940 goto err;
941 }
942
943 r = stat(msg_filename, &stat_info);
944 free(msg_filename);
945 if (r < 0) {
946 res = MAIL_ERROR_INVAL;
947 goto err;
948 }
949
950 /* create message */
951
952 msg = mailmessage_new();
953 if (msg == NULL) {
954 res = MAIL_ERROR_MEMORY;
955 goto err;
956 }
957
958 r = mailmessage_init(msg, session, maildir_cached_message_driver,
959 num, stat_info.st_size);
960 if (r != MAIL_NO_ERROR) {
961 mailmessage_free(msg);
962 res = r;
963 goto err;
964 }
965
966 msg->msg_uid = strdup(uid);
967 if (msg->msg_uid == NULL) {
968 mailmessage_free(msg);
969 res = r;
970 goto err;
971 }
972
973 * result = msg;
974
975 return MAIL_NO_ERROR;
976
977 close_db:
978 mail_cache_db_close_unlock(filename, uid_db);
979 err:
980 return res;
981}
982
983
984static int get_message_by_uid(mailsession * session,
985 const char * uid, mailmessage ** result)
986{
987 int r;
988 struct maildir * md;
989 int res;
990 mailmessage * msg;
991 char filename[PATH_MAX];
992 struct mail_cache_db * uid_db;
993 char * msg_filename;
994 struct stat stat_info;
995 void * value;
996 size_t value_len;
997 struct maildir_cached_session_state_data * data;
998 uint32_t index;
999
1000 data = get_cached_data(session);
1001
1002 md = get_maildir_session(session);
1003
1004 /* a get_messages_list() should have been done once before */
1005
1006 /* read DB */
1007
1008 snprintf(filename, sizeof(filename), "%s%c%s%c%s",
1009 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
1010 MAIL_DIR_SEPARATOR, UID_NAME);
1011
1012 r = mail_cache_db_open_lock(filename, &uid_db);
1013 if (r < 0) {
1014 res = MAIL_ERROR_MEMORY;
1015 goto err;
1016 }
1017
1018 r = mail_cache_db_get(uid_db, uid, strlen(uid), &value, &value_len);
1019 if (r < 0) {
1020 res = MAIL_ERROR_INVAL;
1021 goto close_db;
1022 }
1023
1024 memcpy(&index, value, sizeof(index));
1025
1026 mail_cache_db_close_unlock(filename, uid_db);
1027
1028 /* update maildir data */
1029
1030 r = maildir_update(md);
1031 if (r != MAILDIR_NO_ERROR) {
1032 res = maildirdriver_maildir_error_to_mail_error(r);
1033 goto err;
1034 }
1035
1036 msg_filename = maildir_message_get(md, uid);
1037 if (msg_filename == NULL) {
1038 res = MAIL_ERROR_INVAL;
1039 goto err;
1040 }
1041
1042 r = stat(msg_filename, &stat_info);
1043 free(msg_filename);
1044 if (r < 0) {
1045 res = MAIL_ERROR_INVAL;
1046 goto err;
1047 }
1048
1049 /* create message */
1050
1051 msg = mailmessage_new();
1052 if (msg == NULL) {
1053 res = MAIL_ERROR_MEMORY;
1054 goto err;
1055 }
1056
1057 r = mailmessage_init(msg, session, maildir_cached_message_driver,
1058 index, stat_info.st_size);
1059 if (r != MAIL_NO_ERROR) {
1060 mailmessage_free(msg);
1061 res = r;
1062 goto err;
1063 }
1064
1065 msg->msg_uid = strdup(uid);
1066 if (msg->msg_uid == NULL) {
1067 mailmessage_free(msg);
1068 res = r;
1069 goto err;
1070 }
1071
1072 * result = msg;
1073
1074 return MAIL_NO_ERROR;
1075
1076 close_db:
1077 mail_cache_db_close_unlock(filename, uid_db);
1078 err:
1079 return res;
1080}