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