summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/maildir
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/maildir') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver.c676
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached.c1158
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c334
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_message.c255
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_tools.c198
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_tools.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_types.h96
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirstorage.c193
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirstorage.h69
13 files changed, 3242 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver.c b/libetpan/src/driver/implementation/maildir/maildirdriver.c
new file mode 100644
index 0000000..a97fd43
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver.c
@@ -0,0 +1,676 @@
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
37/*
38 flags directory MUST be kept so that we can have other flags
39 than standards
40*/
41
42#include "maildirdriver.h"
43
44#include <stdio.h>
45#include <sys/types.h>
46#include <dirent.h>
47#include <unistd.h>
48#include <sys/stat.h>
49#include <ctype.h>
50#include <fcntl.h>
51#include <sys/mman.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include "maildir.h"
56#include "maildriver_tools.h"
57#include "maildirdriver_message.h"
58#include "maildirdriver_tools.h"
59#include "mailmessage.h"
60#include "generic_cache.h"
61
62static int initialize(mailsession * session);
63
64static void uninitialize(mailsession * session);
65
66static int connect_path(mailsession * session, char * path);
67
68static int logout(mailsession * session);
69
70static int expunge_folder(mailsession * session);
71
72static int status_folder(mailsession * session, char * mb,
73 uint32_t * result_messages, uint32_t * result_recent,
74 uint32_t * result_unseen);
75
76static int recent_number(mailsession * session, char * mb,
77 uint32_t * result);
78
79static int unseen_number(mailsession * session, char * mb,
80 uint32_t * result);
81
82static int messages_number(mailsession * session, char * mb,
83 uint32_t * result);
84
85static int append_message(mailsession * session,
86 char * message, size_t size);
87
88static int append_message_flags(mailsession * session,
89 char * message, size_t size, struct mail_flags * flags);
90
91static int get_messages_list(mailsession * session,
92 struct mailmessage_list ** result);
93
94static int get_envelopes_list(mailsession * session,
95 struct mailmessage_list * env_list);
96
97static int check_folder(mailsession * session);
98
99static int get_message_by_uid(mailsession * session,
100 const char * uid, mailmessage ** result);
101
102static mailsession_driver local_maildir_session_driver = {
103 .sess_name = "maildir",
104
105 .sess_initialize = initialize,
106 .sess_uninitialize = uninitialize,
107
108 .sess_parameters = NULL,
109
110 .sess_connect_stream = NULL,
111 .sess_connect_path = connect_path,
112 .sess_starttls = NULL,
113 .sess_login = NULL,
114 .sess_logout = logout,
115 .sess_noop = NULL,
116
117 .sess_build_folder_name = NULL,
118 .sess_create_folder = NULL,
119 .sess_delete_folder = NULL,
120 .sess_rename_folder = NULL,
121 .sess_check_folder = check_folder,
122 .sess_examine_folder = NULL,
123 .sess_select_folder = NULL,
124 .sess_expunge_folder = expunge_folder,
125 .sess_status_folder = status_folder,
126 .sess_messages_number = messages_number,
127 .sess_recent_number = recent_number,
128 .sess_unseen_number = unseen_number,
129 .sess_list_folders = NULL,
130 .sess_lsub_folders = NULL,
131 .sess_subscribe_folder = NULL,
132 .sess_unsubscribe_folder = NULL,
133
134 .sess_append_message = append_message,
135 .sess_append_message_flags = append_message_flags,
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 = NULL,
147 .sess_get_message_by_uid = get_message_by_uid,
148};
149
150mailsession_driver * maildir_session_driver = &local_maildir_session_driver;
151
152
153static int flags_store_process(struct maildir * md,
154 struct mail_flags_store * flags_store);
155
156
157static inline struct maildir_session_state_data * get_data(mailsession * session)
158{
159 return session->sess_data;
160}
161
162static struct maildir * get_maildir_session(mailsession * session)
163{
164 return get_data(session)->md_session;
165}
166
167static int initialize(mailsession * session)
168{
169 struct maildir_session_state_data * data;
170
171 data = malloc(sizeof(* data));
172 if (data == NULL)
173 goto err;
174
175 data->md_session = NULL;
176
177 data->md_flags_store = mail_flags_store_new();
178 if (data->md_flags_store == NULL)
179 goto free;
180
181 session->sess_data = data;
182
183 return MAIL_NO_ERROR;
184
185 free:
186 free(data);
187 err:
188 return MAIL_ERROR_MEMORY;
189}
190
191static void uninitialize(mailsession * session)
192{
193 struct maildir_session_state_data * data;
194
195 data = get_data(session);
196
197 if (data->md_session != NULL)
198 flags_store_process(data->md_session, data->md_flags_store);
199
200 mail_flags_store_free(data->md_flags_store);
201 if (data->md_session != NULL)
202 maildir_free(data->md_session);
203
204 free(data);
205
206 session->sess_data = NULL;
207}
208
209
210static int connect_path(mailsession * session, char * path)
211{
212 struct maildir * md;
213 int res;
214 int r;
215
216 if (get_maildir_session(session) != NULL) {
217 res = MAIL_ERROR_BAD_STATE;
218 goto err;
219 }
220
221 md = maildir_new(path);
222 if (md == NULL) {
223 res = MAIL_ERROR_MEMORY;
224 goto err;
225 }
226
227 r = maildir_update(md);
228 if (r != MAILDIR_NO_ERROR) {
229 res = maildirdriver_maildir_error_to_mail_error(r);
230 goto free;
231 }
232
233 get_data(session)->md_session = md;
234
235 return MAIL_NO_ERROR;
236
237 free:
238 maildir_free(md);
239 err:
240 return res;
241}
242
243static int logout(mailsession * session)
244{
245 struct maildir * md;
246
247 check_folder(session);
248
249 md = get_maildir_session(session);
250 if (md == NULL)
251 return MAIL_ERROR_BAD_STATE;
252
253 maildir_free(md);
254 get_data(session)->md_session = NULL;
255
256 return MAIL_NO_ERROR;
257}
258
259/* folders operations */
260
261static int status_folder(mailsession * session, char * mb,
262 uint32_t * result_messages, uint32_t * result_recent,
263 uint32_t * result_unseen)
264{
265 int r;
266 struct maildir * md;
267 unsigned int i;
268 uint32_t messages;
269 uint32_t recent;
270 uint32_t unseen;
271
272 check_folder(session);
273
274 md = get_maildir_session(session);
275 if (md == NULL)
276 return MAIL_ERROR_BAD_STATE;
277
278 r = maildir_update(md);
279 if (r != MAILDIR_NO_ERROR)
280 return maildirdriver_maildir_error_to_mail_error(r);
281
282 messages = 0;
283 recent = 0;
284 unseen = 0;
285 for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i ++) {
286 struct maildir_msg * msg;
287
288 msg = carray_get(md->mdir_msg_list, i);
289 if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
290 recent ++;
291 if ((msg->msg_flags & MAILDIR_FLAG_SEEN) == 0)
292 unseen ++;
293 messages ++;
294 }
295
296 * result_messages = messages;
297 * result_recent = recent;
298 * result_unseen = unseen;
299
300 return MAIL_NO_ERROR;
301}
302
303static int messages_number(mailsession * session, char * mb,
304 uint32_t * result)
305{
306 struct maildir * md;
307 int r;
308
309 md = get_maildir_session(session);
310 if (md == NULL)
311 return MAIL_ERROR_BAD_STATE;
312
313 r = maildir_update(md);
314 if (r != MAILDIR_NO_ERROR)
315 return maildirdriver_maildir_error_to_mail_error(r);
316
317 * result = carray_count(md->mdir_msg_list);
318
319 return MAIL_NO_ERROR;
320}
321
322static int unseen_number(mailsession * session, char * mb,
323 uint32_t * result)
324{
325 uint32_t messages;
326 uint32_t recent;
327 uint32_t unseen;
328 int r;
329
330 r = status_folder(session, mb, &messages, &recent, &unseen);
331 if (r != MAIL_NO_ERROR)
332 return r;
333
334 * result = unseen;
335
336 return MAIL_NO_ERROR;
337}
338
339static int recent_number(mailsession * session, char * mb,
340 uint32_t * result)
341{
342 uint32_t messages;
343 uint32_t recent;
344 uint32_t unseen;
345 int r;
346
347 r = status_folder(session, mb, &messages, &recent, &unseen);
348 if (r != MAIL_NO_ERROR)
349 return r;
350
351 * result = recent;
352
353 return MAIL_NO_ERROR;
354}
355
356
357/* messages operations */
358
359static int append_message(mailsession * session,
360 char * message, size_t size)
361{
362#if 0
363 struct maildir * md;
364 int r;
365
366 md = get_maildir_session(session);
367 if (md == NULL)
368 return MAIL_ERROR_BAD_STATE;
369
370 r = maildir_message_add(md, message, size);
371 if (r != MAILDIR_NO_ERROR)
372 return maildirdriver_maildir_error_to_mail_error(r);
373
374 return MAIL_NO_ERROR;
375#endif
376
377 return append_message_flags(session, message, size, NULL);
378}
379
380static int append_message_flags(mailsession * session,
381 char * message, size_t size, struct mail_flags * flags)
382{
383 struct maildir * md;
384 int r;
385 char uid[PATH_MAX];
386 struct maildir_msg * md_msg;
387 chashdatum key;
388 chashdatum value;
389 uint32_t md_flags;
390
391 md = get_maildir_session(session);
392 if (md == NULL)
393 return MAIL_ERROR_BAD_STATE;
394
395 r = maildir_message_add_uid(md, message, size,
396 uid, sizeof(uid));
397 if (r != MAILDIR_NO_ERROR)
398 return maildirdriver_maildir_error_to_mail_error(r);
399
400 if (flags == NULL)
401 goto exit;
402
403 key.data = uid;
404 key.len = strlen(uid);
405 r = chash_get(md->mdir_msg_hash, &key, &value);
406 if (r < 0)
407 goto exit;
408
409 md_msg = value.data;
410
411 md_flags = maildirdriver_flags_to_maildir_flags(flags->fl_flags);
412
413 r = maildir_message_change_flags(md, uid, md_flags);
414 if (r != MAILDIR_NO_ERROR)
415 goto exit;
416
417 return MAIL_NO_ERROR;
418
419 exit:
420 return MAIL_NO_ERROR;
421}
422
423static int get_messages_list(mailsession * session,
424 struct mailmessage_list ** result)
425{
426 struct maildir * md;
427 int r;
428 struct mailmessage_list * env_list;
429 int res;
430
431 md = get_maildir_session(session);
432 if (md == NULL)
433 return MAIL_ERROR_BAD_STATE;
434
435 r = maildir_update(md);
436 if (r != MAILDIR_NO_ERROR) {
437 res = maildirdriver_maildir_error_to_mail_error(r);
438 goto err;
439 }
440
441 r = maildir_get_messages_list(session, md,
442 maildir_message_driver, &env_list);
443 if (r != MAILDIR_NO_ERROR) {
444 res = r;
445 goto free_list;
446 }
447
448 * result = env_list;
449
450 return MAIL_NO_ERROR;
451
452 free_list:
453 mailmessage_list_free(env_list);
454 err:
455 return res;
456}
457
458static int get_envelopes_list(mailsession * session,
459 struct mailmessage_list * env_list)
460{
461 int r;
462 struct maildir * md;
463 unsigned int i;
464 int res;
465
466 check_folder(session);
467
468 md = get_maildir_session(session);
469 if (md == NULL) {
470 res = MAIL_ERROR_BAD_STATE;
471 goto err;
472 }
473
474 r = maildir_update(md);
475 if (r != MAILDIR_NO_ERROR) {
476 res = maildirdriver_maildir_error_to_mail_error(r);
477 goto err;
478 }
479
480 r = maildriver_generic_get_envelopes_list(session, env_list);
481 if (r != MAIL_NO_ERROR) {
482 res = r;
483 goto err;
484 }
485
486 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) {
487 struct maildir_msg * md_msg;
488 mailmessage * msg;
489 uint32_t driver_flags;
490 clist * ext;
491 chashdatum key;
492 chashdatum value;
493
494 msg = carray_get(env_list->msg_tab, i);
495
496 key.data = msg->msg_uid;
497 key.len = strlen(msg->msg_uid);
498 r = chash_get(md->mdir_msg_hash, &key, &value);
499 if (r < 0)
500 continue;
501
502 md_msg = value.data;
503
504 driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags);
505
506 if (msg->msg_flags == NULL) {
507 ext = clist_new();
508 if (ext == NULL) {
509 res = MAIL_ERROR_MEMORY;
510 continue;
511 }
512
513 msg->msg_flags = mail_flags_new(driver_flags, ext);
514 if (msg->msg_flags == NULL) {
515 clist_free(ext);
516 res = MAIL_ERROR_MEMORY;
517 continue;
518 }
519
520 if ((md_msg->msg_flags & MAILDIR_FLAG_NEW) != 0) {
521 mail_flags_store_set(get_data(session)->md_flags_store, msg);
522 }
523 }
524 else {
525 msg->msg_flags->fl_flags &= MAIL_FLAG_FORWARDED;
526 msg->msg_flags->fl_flags |= driver_flags;
527 }
528 }
529
530 return MAIL_NO_ERROR;
531
532 err:
533 return res;
534}
535
536
537static int expunge_folder(mailsession * session)
538{
539 unsigned int i;
540 int r;
541 int res;
542 struct maildir * md;
543
544 check_folder(session);
545
546 md = get_maildir_session(session);
547 if (md == NULL)
548 return MAIL_ERROR_BAD_STATE;
549
550 r = maildir_update(md);
551 if (r != MAILDIR_NO_ERROR) {
552 res = maildirdriver_maildir_error_to_mail_error(r);
553 goto err;
554 }
555
556 for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i++) {
557 struct maildir_msg * md_msg;
558
559 md_msg = carray_get(md->mdir_msg_list, i);
560
561 if ((md_msg->msg_flags & MAILDIR_FLAG_TRASHED) != 0)
562 maildir_message_remove(md, md_msg->msg_uid);
563 }
564
565 return MAIL_NO_ERROR;
566
567 err:
568 return res;
569}
570
571
572static int flags_store_process(struct maildir * md,
573 struct mail_flags_store * flags_store)
574{
575 unsigned int i;
576
577 if (carray_count(flags_store->fls_tab) == 0)
578 return MAIL_NO_ERROR;
579
580 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
581 mailmessage * msg;
582 uint32_t md_flags;
583
584 msg = carray_get(flags_store->fls_tab, i);
585 md_flags = maildirdriver_flags_to_maildir_flags(msg->msg_flags->fl_flags);
586 md_flags &= ~MAILDIR_FLAG_NEW;
587
588 maildir_message_change_flags(md, msg->msg_uid, md_flags);
589 }
590
591 mail_flags_store_clear(flags_store);
592
593 return MAIL_NO_ERROR;
594}
595
596
597
598static int check_folder(mailsession * session)
599{
600 struct mail_flags_store * flags_store;
601 struct maildir_session_state_data * data;
602 struct maildir * md;
603
604 md = get_maildir_session(session);
605 if (md == NULL)
606 return MAIL_ERROR_BAD_STATE;
607
608 data = get_data(session);
609 flags_store = data->md_flags_store;
610
611 return flags_store_process(md, flags_store);
612}
613
614static int get_message_by_uid(mailsession * session,
615 const char * uid, mailmessage ** result)
616{
617 int r;
618 struct maildir * md;
619 int res;
620 mailmessage * msg;
621 char * msg_filename;
622 struct stat stat_info;
623
624 md = get_maildir_session(session);
625
626 /* update maildir data */
627
628 r = maildir_update(md);
629 if (r != MAILDIR_NO_ERROR) {
630 res = maildirdriver_maildir_error_to_mail_error(r);
631 goto err;
632 }
633
634 msg_filename = maildir_message_get(md, uid);
635 if (msg_filename == NULL) {
636 res = MAIL_ERROR_INVAL;
637 goto err;
638 }
639
640 r = stat(msg_filename, &stat_info);
641 free(msg_filename);
642 if (r < 0) {
643 res = MAIL_ERROR_INVAL;
644 goto err;
645 }
646
647 /* create message */
648
649 msg = mailmessage_new();
650 if (msg == NULL) {
651 res = MAIL_ERROR_MEMORY;
652 goto err;
653 }
654
655 r = mailmessage_init(msg, session, maildir_message_driver,
656 0, stat_info.st_size);
657 if (r != MAIL_NO_ERROR) {
658 mailmessage_free(msg);
659 res = r;
660 goto err;
661 }
662
663 msg->msg_uid = strdup(uid);
664 if (msg->msg_uid == NULL) {
665 mailmessage_free(msg);
666 res = r;
667 goto err;
668 }
669
670 * result = msg;
671
672 return MAIL_NO_ERROR;
673
674 err:
675 return res;
676}
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver.h b/libetpan/src/driver/implementation/maildir/maildirdriver.h
new file mode 100644
index 0000000..0abe09d
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver.h
@@ -0,0 +1,53 @@
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#ifndef MAILDIRDRIVER_H
37
38#define MAILDIRDRIVER_H
39
40#include <libetpan/maildriver.h>
41#include <libetpan/maildirdriver_types.h>
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47extern mailsession_driver * maildir_session_driver;
48
49#ifdef __cplusplus
50}
51#endif
52
53#endif
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}
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h
new file mode 100644
index 0000000..5c3d8a9
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h
@@ -0,0 +1,53 @@
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#ifndef MAILDIRDRIVER_CACHED_H
37
38#define MAILDIRDRIVER_CACHED_H
39
40#include <libetpan/maildriver.h>
41#include <libetpan/maildirdriver_types.h>
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47extern mailsession_driver * maildir_cached_session_driver;
48
49#ifdef __cplusplus
50}
51#endif
52
53#endif
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c
new file mode 100644
index 0000000..d2c30cc
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c
@@ -0,0 +1,334 @@
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_message.h"
37
38#include "mailmessage_tools.h"
39#include "maildirdriver.h"
40#include "maildir.h"
41#include "generic_cache.h"
42#include "mail_cache_db.h"
43#include "maildirdriver_tools.h"
44
45#include <unistd.h>
46#include <sys/mman.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <fcntl.h>
50#include <string.h>
51#include <stdlib.h>
52
53static int get_flags(mailmessage * msg_info,
54 struct mail_flags ** result);
55
56static int prefetch(mailmessage * msg_info);
57
58static void prefetch_free(struct generic_message_t * msg);
59
60static int initialize(mailmessage * msg_info);
61
62static void check(mailmessage * msg_info);
63
64static mailmessage_driver local_maildir_cached_message_driver = {
65 .msg_name = "maildir-cached",
66
67 .msg_initialize = initialize,
68 .msg_uninitialize = mailmessage_generic_uninitialize,
69
70 .msg_flush = mailmessage_generic_flush,
71 .msg_check = check,
72
73 .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
74
75 .msg_fetch = mailmessage_generic_fetch,
76 .msg_fetch_header = mailmessage_generic_fetch_header,
77 .msg_fetch_body = mailmessage_generic_fetch_header,
78 .msg_fetch_size = NULL,
79 .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
80 .msg_fetch_section = mailmessage_generic_fetch_section,
81 .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
82 .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
83 .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
84 .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
85
86 .msg_get_flags = get_flags,
87};
88
89mailmessage_driver * maildir_cached_message_driver =
90&local_maildir_cached_message_driver;
91
92struct maildir_msg_data {
93 int fd;
94};
95
96#if 0
97static inline struct maildir_cached_session_state_data *
98get_cached_session_data(mailmessage * msg)
99{
100 return msg->session->data;
101}
102
103static inline mailsession * cached_session_get_ancestor(mailsession * session)
104{
105 return get_data(session)->session;
106}
107
108static inline struct maildir_session_state_data *
109cached_session_get_ancestor_data(mailsession * session)
110{
111 return get_ancestor(session)->data;
112}
113
114static struct maildir * get_maildir_session(mailmessage * msg)
115{
116 return cached_session_get_ancestor_data(msg->session)->session;
117}
118#endif
119static inline struct maildir_cached_session_state_data *
120get_cached_session_data(mailmessage * msg)
121{
122 return msg->msg_session->sess_data;
123}
124
125static inline struct maildir_cached_session_state_data *
126cached_session_get_data(mailsession * s)
127{
128 return s->sess_data;
129}
130
131static inline mailsession * cached_session_get_ancestor(mailsession * s)
132{
133 return cached_session_get_data(s)->md_ancestor;
134}
135
136static inline struct maildir_session_state_data *
137cached_session_get_ancestor_data(mailsession * s)
138{
139 return cached_session_get_ancestor(s)->sess_data;
140}
141
142static inline struct maildir_session_state_data *
143get_session_ancestor_data(mailmessage * msg)
144{
145 return cached_session_get_ancestor_data(msg->msg_session);
146}
147
148static inline struct maildir *
149cached_session_get_maildir_session(mailsession * session)
150{
151 return cached_session_get_ancestor_data(session)->md_session;
152}
153
154static inline struct maildir * get_maildir_session(mailmessage * msg)
155{
156 return cached_session_get_maildir_session(msg->msg_session);
157}
158
159static int prefetch(mailmessage * msg_info)
160{
161 struct generic_message_t * msg;
162 int res;
163 struct maildir_msg_data * data;
164 char * filename;
165 int fd;
166 char * mapping;
167 struct maildir * md;
168
169 md = get_maildir_session(msg_info);
170
171 filename = maildir_message_get(md, msg_info->msg_uid);
172 if (filename == NULL) {
173 res = MAIL_ERROR_MEMORY;
174 goto err;
175 }
176
177 fd = open(filename, O_RDONLY);
178 free(filename);
179 if (fd == -1) {
180 res = MAIL_ERROR_FILE;
181 goto err;
182 }
183
184 mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0);
185 if (mapping == MAP_FAILED) {
186 res = MAIL_ERROR_FILE;
187 goto close;
188 }
189
190 data = malloc(sizeof(* data));
191 if (data == NULL) {
192 res = MAIL_ERROR_MEMORY;
193 goto unmap;
194 }
195
196 data->fd = fd;
197
198 msg = msg_info->msg_data;
199
200 msg->msg_data = data;
201 msg->msg_message = mapping;
202 msg->msg_length = msg_info->msg_size;
203
204 return MAIL_NO_ERROR;
205
206 unmap:
207 munmap(mapping, msg_info->msg_size);
208 close:
209 close(fd);
210 err:
211 return res;
212}
213
214static void prefetch_free(struct generic_message_t * msg)
215{
216 if (msg->msg_message != NULL) {
217 struct maildir_msg_data * data;
218
219 munmap(msg->msg_message, msg->msg_length);
220 msg->msg_message = NULL;
221 data = msg->msg_data;
222 close(data->fd);
223 free(data);
224 }
225}
226
227static int initialize(mailmessage * msg_info)
228{
229 struct generic_message_t * msg;
230 int r;
231
232 r = mailmessage_generic_initialize(msg_info);
233 if (r != MAIL_NO_ERROR)
234 return r;
235
236 msg = msg_info->msg_data;
237 msg->msg_prefetch = prefetch;
238 msg->msg_prefetch_free = prefetch_free;
239
240 return MAIL_NO_ERROR;
241}
242
243static void check(mailmessage * msg_info)
244{
245 int r;
246
247 if (msg_info->msg_flags != NULL) {
248 r = mail_flags_store_set(get_session_ancestor_data(msg_info)->md_flags_store, msg_info);
249
250 r = mail_flags_store_set(get_cached_session_data(msg_info)->md_flags_store, msg_info);
251 /* ignore errors */
252 }
253}
254
255#define FLAGS_NAME "flags.db"
256
257static int get_flags(mailmessage * msg_info,
258 struct mail_flags ** result)
259{
260 struct mail_cache_db * cache_db_flags;
261 chashdatum key;
262 chashdatum value;
263 struct maildir * md;
264 struct mail_flags * flags;
265 struct maildir_cached_session_state_data * data;
266 struct maildir_msg * md_msg;
267 int r;
268 uint32_t driver_flags;
269 char filename_flags[PATH_MAX];
270 char keyname[PATH_MAX];
271 MMAPString * mmapstr;
272
273 if (msg_info->msg_flags != NULL) {
274 * result = msg_info->msg_flags;
275 return MAIL_NO_ERROR;
276 }
277
278 data = get_cached_session_data(msg_info);
279 flags = mail_flags_store_get(data->md_flags_store,
280 msg_info->msg_index);
281 if (flags != NULL) {
282 msg_info->msg_flags = flags;
283 * result = msg_info->msg_flags;
284 return MAIL_NO_ERROR;
285 }
286
287 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
288 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
289 MAIL_DIR_SEPARATOR, FLAGS_NAME);
290
291 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
292 if (r < 0)
293 return MAIL_ERROR_FILE;
294
295 snprintf(keyname, PATH_MAX, "%s-flags", msg_info->msg_uid);
296
297 mmapstr = mmap_string_new("");
298 if (mmapstr == NULL) {
299 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
300 return MAIL_ERROR_MEMORY;
301 }
302
303 r = generic_cache_flags_read(cache_db_flags, mmapstr, keyname, &flags);
304 mmap_string_free(mmapstr);
305
306 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
307
308 if (r != MAIL_NO_ERROR) {
309 flags = mail_flags_new_empty();
310 if (flags == NULL)
311 return MAIL_ERROR_MEMORY;
312 }
313
314 md = get_maildir_session(msg_info);
315 if (md == NULL)
316 return MAIL_ERROR_BAD_STATE;
317
318 key.data = msg_info->msg_uid;
319 key.len = strlen(msg_info->msg_uid);
320 r = chash_get(md->mdir_msg_hash, &key, &value);
321 if (r < 0)
322 return MAIL_ERROR_MSG_NOT_FOUND;
323
324 md_msg = value.data;
325
326 driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags);
327
328 flags->fl_flags = driver_flags;
329 msg_info->msg_flags = flags;
330
331 * result = msg_info->msg_flags;
332
333 return MAIL_NO_ERROR;
334}
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h
new file mode 100644
index 0000000..b9e0215
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h
@@ -0,0 +1,52 @@
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#ifndef MAILDIRDRIVER_CACHED_MESSAGE_H
37
38#define MAILDIRDRIVER_CACHED_MESSAGE_H
39
40#include <libetpan/maildirdriver_types.h>
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46extern mailmessage_driver * maildir_cached_message_driver;
47
48#ifdef __cplusplus
49}
50#endif
51
52#endif
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_message.c b/libetpan/src/driver/implementation/maildir/maildirdriver_message.c
new file mode 100644
index 0000000..58bc6bd
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_message.c
@@ -0,0 +1,255 @@
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_message.h"
37#include "maildirdriver_tools.h"
38
39#include "mailmessage_tools.h"
40#include "maildirdriver.h"
41#include "maildir.h"
42#include "generic_cache.h"
43
44#include <unistd.h>
45#include <sys/mman.h>
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <string.h>
50#include <stdlib.h>
51
52static int get_flags(mailmessage * msg_info,
53 struct mail_flags ** result);
54
55static int prefetch(mailmessage * msg_info);
56
57static void prefetch_free(struct generic_message_t * msg);
58
59static int initialize(mailmessage * msg_info);
60
61static void check(mailmessage * msg_info);
62
63static mailmessage_driver local_maildir_message_driver = {
64 .msg_name = "maildir",
65
66 .msg_initialize = initialize,
67 .msg_uninitialize = mailmessage_generic_uninitialize,
68
69 .msg_flush = mailmessage_generic_flush,
70 .msg_check = check,
71
72 .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
73
74 .msg_fetch = mailmessage_generic_fetch,
75 .msg_fetch_header = mailmessage_generic_fetch_header,
76 .msg_fetch_body = mailmessage_generic_fetch_header,
77 .msg_fetch_size = NULL,
78 .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
79 .msg_fetch_section = mailmessage_generic_fetch_section,
80 .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
81 .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
82 .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
83 .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
84
85 .msg_get_flags = get_flags,
86};
87
88mailmessage_driver * maildir_message_driver = &local_maildir_message_driver;
89
90struct maildir_msg_data {
91 int fd;
92};
93
94static inline struct maildir_session_state_data *
95get_session_data(mailmessage * msg)
96{
97 return msg->msg_session->sess_data;
98}
99
100static struct maildir * get_maildir_session(mailmessage * msg)
101{
102 return get_session_data(msg)->md_session;
103}
104
105static int prefetch(mailmessage * msg_info)
106{
107 struct generic_message_t * msg;
108 int res;
109 struct maildir_msg_data * data;
110 char * filename;
111 int fd;
112 char * mapping;
113 struct maildir * md;
114
115 md = get_maildir_session(msg_info);
116
117 if (msg_info->msg_uid == NULL) {
118 res = MAIL_ERROR_INVAL;
119 goto err;
120 }
121
122 filename = maildir_message_get(md, msg_info->msg_uid);
123 if (filename == NULL) {
124 res = MAIL_ERROR_MEMORY;
125 goto err;
126 }
127
128 fd = open(filename, O_RDONLY);
129 free(filename);
130 if (fd == -1) {
131 res = MAIL_ERROR_FILE;
132 goto err;
133 }
134
135 mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0);
136 if (mapping == MAP_FAILED) {
137 res = MAIL_ERROR_FILE;
138 goto close;
139 }
140
141 data = malloc(sizeof(* data));
142 if (data == NULL) {
143 res = MAIL_ERROR_MEMORY;
144 goto unmap;
145 }
146
147 data->fd = fd;
148
149 msg = msg_info->msg_data;
150
151 msg->msg_data = data;
152 msg->msg_message = mapping;
153 msg->msg_length = msg_info->msg_size;
154
155 return MAIL_NO_ERROR;
156
157 unmap:
158 munmap(mapping, msg_info->msg_size);
159 close:
160 close(fd);
161 err:
162 return res;
163}
164
165static void prefetch_free(struct generic_message_t * msg)
166{
167 if (msg->msg_message != NULL) {
168 struct maildir_msg_data * data;
169
170 munmap(msg->msg_message, msg->msg_length);
171 msg->msg_message = NULL;
172 data = msg->msg_data;
173 close(data->fd);
174 free(data);
175 }
176}
177
178static int initialize(mailmessage * msg_info)
179{
180 struct generic_message_t * msg;
181 int r;
182
183 r = mailmessage_generic_initialize(msg_info);
184 if (r != MAIL_NO_ERROR)
185 return r;
186
187 msg = msg_info->msg_data;
188 msg->msg_prefetch = prefetch;
189 msg->msg_prefetch_free = prefetch_free;
190
191 return MAIL_NO_ERROR;
192}
193
194static void check(mailmessage * msg_info)
195{
196 int r;
197
198 if (msg_info->msg_flags != NULL) {
199 r = mail_flags_store_set(get_session_data(msg_info)->md_flags_store,
200 msg_info);
201 /* ignore errors */
202 }
203}
204
205static int get_flags(mailmessage * msg_info,
206 struct mail_flags ** result)
207{
208 chashdatum key;
209 chashdatum value;
210 struct maildir * md;
211 struct mail_flags * flags;
212 struct maildir_session_state_data * data;
213 struct maildir_msg * md_msg;
214 int r;
215 uint32_t driver_flags;
216 clist * ext;
217
218 if (msg_info->msg_flags != NULL) {
219 * result = msg_info->msg_flags;
220 return MAIL_NO_ERROR;
221 }
222
223 data = get_session_data(msg_info);
224 flags = mail_flags_store_get(data->md_flags_store,
225 msg_info->msg_index);
226 if (flags != NULL) {
227 msg_info->msg_flags = flags;
228 * result = msg_info->msg_flags;
229 return MAIL_NO_ERROR;
230 }
231
232 md = get_maildir_session(msg_info);
233 if (md == NULL)
234 return MAIL_ERROR_BAD_STATE;
235
236 key.data = msg_info->msg_uid;
237 key.len = strlen(msg_info->msg_uid);
238 r = chash_get(md->mdir_msg_hash, &key, &value);
239 if (r < 0)
240 return MAIL_ERROR_MSG_NOT_FOUND;
241
242 md_msg = value.data;
243
244 driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags);
245
246 ext = clist_new();
247 if (ext == NULL)
248 return MAIL_ERROR_MEMORY;
249
250 msg_info->msg_flags = mail_flags_new(driver_flags, ext);
251
252 * result = msg_info->msg_flags;
253
254 return MAIL_NO_ERROR;
255}
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_message.h b/libetpan/src/driver/implementation/maildir/maildirdriver_message.h
new file mode 100644
index 0000000..ed0a4d1
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_message.h
@@ -0,0 +1,52 @@
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#ifndef MAILDIRDRIVER_MESSAGE_H
37
38#define MAILDIRDRIVER_MESSAGE_H
39
40#include <libetpan/maildirdriver_types.h>
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46extern mailmessage_driver * maildir_message_driver;
47
48#ifdef __cplusplus
49}
50#endif
51
52#endif
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c
new file mode 100644
index 0000000..e3036e8
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c
@@ -0,0 +1,198 @@
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 "mailmessage.h"
37#include "maildirdriver_tools.h"
38#include "maildir.h"
39#include "generic_cache.h"
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <stdlib.h>
43#include <string.h>
44
45int maildirdriver_maildir_error_to_mail_error(int error)
46{
47 switch (error) {
48 case MAILDIR_NO_ERROR:
49 return MAIL_NO_ERROR;
50
51 case MAILDIR_ERROR_CREATE:
52 return MAIL_ERROR_FILE;
53
54 case MAILDIR_ERROR_DIRECTORY:
55 return MAIL_ERROR_FILE;
56
57 case MAILDIR_ERROR_MEMORY:
58 return MAIL_ERROR_MEMORY;
59
60 case MAILDIR_ERROR_FILE:
61 return MAIL_ERROR_FILE;
62
63 case MAILDIR_ERROR_FOLDER:
64 return MAIL_ERROR_FOLDER;
65
66 case MAILDIR_ERROR_NOT_FOUND:
67 return MAIL_ERROR_MSG_NOT_FOUND;
68
69 default:
70 return MAIL_ERROR_INVAL;
71 }
72}
73
74
75
76uint32_t maildirdriver_maildir_flags_to_flags(uint32_t md_flags)
77{
78 uint32_t flags;
79
80 flags = 0;
81 if ((md_flags & MAILDIR_FLAG_NEW) != 0)
82 flags |= MAIL_FLAG_NEW;
83
84 if ((md_flags & MAILDIR_FLAG_SEEN) != 0)
85 flags |= MAIL_FLAG_SEEN;
86
87 if ((md_flags & MAILDIR_FLAG_REPLIED) != 0)
88 flags |= MAIL_FLAG_ANSWERED;
89
90 if ((md_flags & MAILDIR_FLAG_FLAGGED) != 0)
91 flags |= MAIL_FLAG_FLAGGED;
92
93 if ((md_flags & MAILDIR_FLAG_TRASHED) != 0)
94 flags |= MAIL_FLAG_DELETED;
95
96 return flags;
97}
98
99uint32_t maildirdriver_flags_to_maildir_flags(uint32_t flags)
100{
101 uint32_t md_flags;
102
103 md_flags = 0;
104 if ((flags & MAIL_FLAG_NEW) != 0)
105 md_flags |= MAILDIR_FLAG_NEW;
106
107 if ((flags & MAIL_FLAG_SEEN) != 0)
108 md_flags |= MAILDIR_FLAG_SEEN;
109
110 if ((flags & MAIL_FLAG_ANSWERED) != 0)
111 md_flags |= MAILDIR_FLAG_REPLIED;
112
113 if ((flags & MAIL_FLAG_FLAGGED) != 0)
114 md_flags |= MAILDIR_FLAG_FLAGGED;
115
116 if ((flags & MAIL_FLAG_DELETED) != 0)
117 md_flags |= MAILDIR_FLAG_TRASHED;
118
119 return md_flags;
120}
121
122
123int maildir_get_messages_list(mailsession * session, struct maildir * md,
124 mailmessage_driver * message_driver,
125 struct mailmessage_list ** result)
126{
127 unsigned int i;
128 struct mailmessage_list * env_list;
129 int r;
130 carray * tab;
131 int res;
132
133 tab = carray_new(128);
134 if (tab == NULL) {
135 res = MAIL_ERROR_MEMORY;
136 goto err;
137 }
138
139 for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i++) {
140 struct maildir_msg * md_msg;
141 mailmessage * msg;
142 char * filename;
143 struct stat stat_info;
144
145 md_msg = carray_get(md->mdir_msg_list, i);
146
147 filename = maildir_message_get(md, md_msg->msg_uid);
148 r = stat(filename, &stat_info);
149 free(filename);
150 if (r < 0)
151 continue;
152
153 msg = mailmessage_new();
154 if (msg == NULL) {
155 res = MAIL_ERROR_MEMORY;
156 goto free_list;
157 }
158
159 r = mailmessage_init(msg, session, message_driver,
160 i + 1, stat_info.st_size);
161 if (r != MAIL_NO_ERROR) {
162 mailmessage_free(msg);
163 res = r;
164 goto free_list;
165 }
166
167 msg->msg_uid = strdup(md_msg->msg_uid);
168 if (msg->msg_uid == NULL) {
169 mailmessage_free(msg);
170 res = MAIL_ERROR_MEMORY;
171 goto free_list;
172 }
173
174 r = carray_add(tab, msg, NULL);
175 if (r < 0) {
176 mailmessage_free(msg);
177 res = MAIL_ERROR_MEMORY;
178 goto free_list;
179 }
180 }
181
182 env_list = mailmessage_list_new(tab);
183 if (env_list == NULL) {
184 res = MAIL_ERROR_MEMORY;
185 goto free_list;
186 }
187
188 * result = env_list;
189
190 return MAIL_NO_ERROR;
191
192 free_list:
193 for(i = 0 ; i < carray_count(tab) ; i ++)
194 mailmessage_free(carray_get(tab, i));
195 carray_free(tab);
196 err:
197 return res;
198}
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h
new file mode 100644
index 0000000..0a738c9
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h
@@ -0,0 +1,53 @@
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#ifndef MAILDIRDRIVER_TOOLS_H
37
38#define MAILDIRDRIVER_TOOLS_H
39
40#include "maildriver_types.h"
41#include "maildir.h"
42
43int maildirdriver_maildir_error_to_mail_error(int error);
44
45uint32_t maildirdriver_maildir_flags_to_flags(uint32_t md_flags);
46
47uint32_t maildirdriver_flags_to_maildir_flags(uint32_t flags);
48
49int maildir_get_messages_list(mailsession * session, struct maildir * md,
50 mailmessage_driver * message_driver,
51 struct mailmessage_list ** result);
52
53#endif
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_types.h b/libetpan/src/driver/implementation/maildir/maildirdriver_types.h
new file mode 100644
index 0000000..c965b3e
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_types.h
@@ -0,0 +1,96 @@
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#ifndef MAILDIRDRIVER_TYPES_H
37
38#define MAILDIRDRIVER_TYPES_H
39
40#include <libetpan/libetpan-config.h>
41
42#include <libetpan/maildriver_types.h>
43#include <libetpan/maildir.h>
44#include <libetpan/generic_cache_types.h>
45#include <libetpan/mailstorage_types.h>
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
51struct maildir_session_state_data {
52 struct maildir * md_session;
53 struct mail_flags_store * md_flags_store;
54};
55
56enum {
57 MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY = 1,
58 MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY,
59};
60
61struct maildir_cached_session_state_data {
62 mailsession * md_ancestor;
63 char * md_quoted_mb;
64 struct mail_flags_store * md_flags_store;
65 char md_cache_directory[PATH_MAX];
66 char md_flags_directory[PATH_MAX];
67};
68
69/* maildir storage */
70
71/*
72 maildir_mailstorage is the state data specific to the maildir storage.
73
74 - pathname is the path of the maildir storage.
75
76 - cached if this value is != 0, a persistant cache will be
77 stored on local system.
78
79 - cache_directory is the location of the cache.
80
81 - flags_directory is the location of the flags.
82*/
83
84struct maildir_mailstorage {
85 char * md_pathname;
86
87 int md_cached;
88 char * md_cache_directory;
89 char * md_flags_directory;
90};
91
92#ifdef __cplusplus
93}
94#endif
95
96#endif
diff --git a/libetpan/src/driver/implementation/maildir/maildirstorage.c b/libetpan/src/driver/implementation/maildir/maildirstorage.c
new file mode 100644
index 0000000..09f95c7
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirstorage.c
@@ -0,0 +1,193 @@
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 "maildirstorage.h"
37#include "mailstorage.h"
38
39#include "mail.h"
40#include "mailmessage.h"
41#include "maildirdriver.h"
42#include "maildirdriver_cached.h"
43#include "maildriver.h"
44
45#include <stdlib.h>
46#include <string.h>
47
48/* maildir storage */
49
50static int maildir_mailstorage_connect(struct mailstorage * storage);
51static int
52maildir_mailstorage_get_folder_session(struct mailstorage * storage,
53 char * pathname, mailsession ** result);
54static void maildir_mailstorage_uninitialize(struct mailstorage * storage);
55
56static mailstorage_driver maildir_mailstorage_driver = {
57 .sto_name = "maildir",
58 .sto_connect = maildir_mailstorage_connect,
59 .sto_get_folder_session = maildir_mailstorage_get_folder_session,
60 .sto_uninitialize = maildir_mailstorage_uninitialize,
61};
62
63int maildir_mailstorage_init(struct mailstorage * storage,
64 char * md_pathname, int md_cached,
65 char * md_cache_directory, char * md_flags_directory)
66{
67 struct maildir_mailstorage * maildir_storage;
68
69 maildir_storage = malloc(sizeof(* maildir_storage));
70 if (maildir_storage == NULL)
71 goto err;
72
73 maildir_storage->md_pathname = strdup(md_pathname);
74 if (maildir_storage->md_pathname == NULL)
75 goto free;
76
77 maildir_storage->md_cached = md_cached;
78
79 if (md_cached && (md_cache_directory != NULL) &&
80 (md_flags_directory != NULL)) {
81 maildir_storage->md_cache_directory = strdup(md_cache_directory);
82 if (maildir_storage->md_cache_directory == NULL)
83 goto free_pathname;
84
85 maildir_storage->md_flags_directory = strdup(md_flags_directory);
86 if (maildir_storage->md_flags_directory == NULL)
87 goto free_cache_directory;
88 }
89 else {
90 maildir_storage->md_cached = FALSE;
91 maildir_storage->md_cache_directory = NULL;
92 maildir_storage->md_flags_directory = NULL;
93 }
94
95 storage->sto_data = maildir_storage;
96 storage->sto_driver = &maildir_mailstorage_driver;
97
98 return MAIL_NO_ERROR;
99
100 free_cache_directory:
101 free(maildir_storage->md_cache_directory);
102 free_pathname:
103 free(maildir_storage->md_pathname);
104 free:
105 free(maildir_storage);
106 err:
107 return MAIL_ERROR_MEMORY;
108}
109
110static void maildir_mailstorage_uninitialize(struct mailstorage * storage)
111{
112 struct maildir_mailstorage * maildir_storage;
113
114 maildir_storage = storage->sto_data;
115 if (maildir_storage->md_flags_directory != NULL)
116 free(maildir_storage->md_flags_directory);
117 if (maildir_storage->md_cache_directory != NULL)
118 free(maildir_storage->md_cache_directory);
119 free(maildir_storage->md_pathname);
120 free(maildir_storage);
121
122 storage->sto_data = NULL;
123}
124
125static int maildir_mailstorage_connect(struct mailstorage * storage)
126{
127 struct maildir_mailstorage * maildir_storage;
128 mailsession_driver * driver;
129 int r;
130 int res;
131 mailsession * session;
132
133 maildir_storage = storage->sto_data;
134
135 if (maildir_storage->md_cached)
136 driver = maildir_cached_session_driver;
137 else
138 driver = maildir_session_driver;
139
140 session = mailsession_new(driver);
141 if (session == NULL) {
142 res = MAIL_ERROR_MEMORY;
143 goto err;
144 }
145
146 if (maildir_storage->md_cached) {
147 r = mailsession_parameters(session,
148 MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY,
149 maildir_storage->md_cache_directory);
150 if (r != MAIL_NO_ERROR) {
151 res = r;
152 goto free;
153 }
154
155 r = mailsession_parameters(session,
156 MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY,
157 maildir_storage->md_flags_directory);
158 if (r != MAIL_NO_ERROR) {
159 res = r;
160 goto free;
161 }
162 }
163
164 r = mailsession_connect_path(session, maildir_storage->md_pathname);
165 switch (r) {
166 case MAIL_NO_ERROR_NON_AUTHENTICATED:
167 case MAIL_NO_ERROR_AUTHENTICATED:
168 case MAIL_NO_ERROR:
169 break;
170 default:
171 res = r;
172 goto free;
173 }
174
175 storage->sto_session = session;
176
177 return MAIL_NO_ERROR;
178
179 free:
180 mailsession_free(session);
181 err:
182 return res;
183}
184
185static int
186maildir_mailstorage_get_folder_session(struct mailstorage * storage,
187 char * pathname, mailsession ** result)
188{
189 * result = storage->sto_session;
190
191 return MAIL_NO_ERROR;
192}
193
diff --git a/libetpan/src/driver/implementation/maildir/maildirstorage.h b/libetpan/src/driver/implementation/maildir/maildirstorage.h
new file mode 100644
index 0000000..0ad04b9
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirstorage.h
@@ -0,0 +1,69 @@
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#ifndef MAILDIRSTORAGE_H
37
38#define MAILDIRSTORAGE_H
39
40#include <libetpan/maildirdriver_types.h>
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/*
47 maildir_mailstorage_init is the constructor for a maildir storage.
48
49 @param storage this is the storage to initialize.
50
51 @param pathname is the directory that contains the mailbox.
52
53 @param cached if this value is != 0, a persistant cache will be
54 stored on local system.
55
56 @param cache_directory is the location of the cache
57
58 @param flags_directory is the location of the flags
59*/
60
61int maildir_mailstorage_init(struct mailstorage * storage,
62 char * md_pathname, int md_cached,
63 char * md_cache_directory, char * md_flags_directory);
64
65#ifdef __cplusplus
66}
67#endif
68
69#endif