summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/imap/imapdriver_cached.c
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/imap/imapdriver_cached.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached.c1370
1 files changed, 1370 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached.c b/libetpan/src/driver/implementation/imap/imapdriver_cached.c
new file mode 100644
index 0000000..806b282
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.c
@@ -0,0 +1,1370 @@
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 "imapdriver_cached.h"
37
38#include "libetpan-config.h"
39
40#include <stdio.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <fcntl.h>
44#include <string.h>
45#include <unistd.h>
46#include <stdlib.h>
47
48#include "mail.h"
49#include "imapdriver_tools.h"
50#include "mail_cache_db.h"
51#include "mailmessage.h"
52#include "imapdriver_cached_message.h"
53#include "maildriver.h"
54#include "imapdriver_types.h"
55#include "generic_cache.h"
56#include "imfcache.h"
57#include "maildriver_tools.h"
58#include "imapdriver.h"
59
60static int imapdriver_cached_initialize(mailsession * session);
61static void imapdriver_cached_uninitialize(mailsession * session);
62
63static int imapdriver_cached_parameters(mailsession * session,
64 int id, void * value);
65
66static int imapdriver_cached_connect_stream(mailsession * session,
67 mailstream * s);
68
69static int imapdriver_cached_starttls(mailsession * session);
70
71static int imapdriver_cached_login(mailsession * session,
72 char * userid, char * password);
73static int imapdriver_cached_logout(mailsession * session);
74static int imapdriver_cached_noop(mailsession * session);
75static int imapdriver_cached_build_folder_name(mailsession * session,
76 char * mb,
77 char * name, char ** result);
78static int imapdriver_cached_create_folder(mailsession * session, char * mb);
79static int imapdriver_cached_delete_folder(mailsession * session, char * mb);
80static int imapdriver_cached_rename_folder(mailsession * session, char * mb,
81 char * new_name);
82static int imapdriver_cached_check_folder(mailsession * session);
83static int imapdriver_cached_examine_folder(mailsession * session,
84 char * mb);
85static int imapdriver_cached_select_folder(mailsession * session, char * mb);
86static int imapdriver_cached_expunge_folder(mailsession * session);
87static int imapdriver_cached_status_folder(mailsession * session, char * mb,
88 uint32_t * result_messages,
89 uint32_t * result_recent,
90 uint32_t * result_unseen);
91static int imapdriver_cached_messages_number(mailsession * session,
92 char * mb,
93 uint32_t * result);
94static int imapdriver_cached_recent_number(mailsession * session, char * mb,
95 uint32_t * result);
96static int imapdriver_cached_unseen_number(mailsession * session, char * mb,
97 uint32_t * result);
98static int imapdriver_cached_list_folders(mailsession * session, char * mb,
99 struct mail_list ** result);
100static int imapdriver_cached_lsub_folders(mailsession * session, char * mb,
101 struct mail_list ** result);
102static int imapdriver_cached_subscribe_folder(mailsession * session,
103 char * mb);
104static int imapdriver_cached_unsubscribe_folder(mailsession * session,
105 char * mb);
106static int imapdriver_cached_append_message(mailsession * session,
107 char * message, size_t size);
108static int imapdriver_cached_append_message_flags(mailsession * session,
109 char * message, size_t size, struct mail_flags * flags);
110static int imapdriver_cached_copy_message(mailsession * session,
111 uint32_t num, char * mb);
112
113static int imapdriver_cached_get_messages_list(mailsession * session,
114 struct mailmessage_list **
115 result);
116static int
117imapdriver_cached_get_envelopes_list(mailsession * session,
118 struct mailmessage_list * env_list);
119static int imapdriver_cached_remove_message(mailsession * session,
120 uint32_t num);
121
122#if 0
123static int imapdriver_cached_search_messages(mailsession * session,
124 char * charset,
125 struct mail_search_key * key,
126 struct mail_search_result **
127 result);
128#endif
129
130static int imapdriver_cached_get_message(mailsession * session,
131 uint32_t num, mailmessage ** result);
132
133static int imapdriver_cached_get_message_by_uid(mailsession * session,
134 const char * uid,
135 mailmessage ** result);
136
137static mailsession_driver local_imap_cached_session_driver = {
138 .sess_name = "imap-cached",
139
140 .sess_initialize = imapdriver_cached_initialize,
141 .sess_uninitialize = imapdriver_cached_uninitialize,
142
143 .sess_parameters = imapdriver_cached_parameters,
144
145 .sess_connect_stream = imapdriver_cached_connect_stream,
146 .sess_connect_path = NULL,
147 .sess_starttls = imapdriver_cached_starttls,
148 .sess_login = imapdriver_cached_login,
149 .sess_logout = imapdriver_cached_logout,
150 .sess_noop = imapdriver_cached_noop,
151
152 .sess_build_folder_name = imapdriver_cached_build_folder_name,
153 .sess_create_folder = imapdriver_cached_create_folder,
154 .sess_delete_folder = imapdriver_cached_delete_folder,
155 .sess_rename_folder = imapdriver_cached_rename_folder,
156 .sess_check_folder = imapdriver_cached_check_folder,
157 .sess_examine_folder = imapdriver_cached_examine_folder,
158 .sess_select_folder = imapdriver_cached_select_folder,
159 .sess_expunge_folder = imapdriver_cached_expunge_folder,
160 .sess_status_folder = imapdriver_cached_status_folder,
161 .sess_messages_number = imapdriver_cached_messages_number,
162 .sess_recent_number = imapdriver_cached_recent_number,
163 .sess_unseen_number = imapdriver_cached_unseen_number,
164 .sess_list_folders = imapdriver_cached_list_folders,
165 .sess_lsub_folders = imapdriver_cached_lsub_folders,
166 .sess_subscribe_folder = imapdriver_cached_subscribe_folder,
167 .sess_unsubscribe_folder = imapdriver_cached_unsubscribe_folder,
168
169 .sess_append_message = imapdriver_cached_append_message,
170 .sess_append_message_flags = imapdriver_cached_append_message_flags,
171 .sess_copy_message = imapdriver_cached_copy_message,
172 .sess_move_message = NULL,
173
174 .sess_get_messages_list = imapdriver_cached_get_messages_list,
175 .sess_get_envelopes_list = imapdriver_cached_get_envelopes_list,
176 .sess_remove_message = imapdriver_cached_remove_message,
177#if 0
178 .sess_search_messages = imapdriver_cached_search_messages,
179#endif
180
181 .sess_get_message = imapdriver_cached_get_message,
182 .sess_get_message_by_uid = imapdriver_cached_get_message_by_uid,
183};
184
185mailsession_driver * imap_cached_session_driver =
186&local_imap_cached_session_driver;
187
188#define CACHE_MESSAGE_LIST
189
190static inline struct imap_cached_session_state_data *
191get_cached_data(mailsession * session)
192{
193 return session->sess_data;
194}
195
196static inline mailsession * get_ancestor(mailsession * s)
197{
198 return get_cached_data(s)->imap_ancestor;
199}
200
201static inline
202struct imap_session_state_data * get_ancestor_data(mailsession * s)
203{
204 return get_ancestor(s)->sess_data;
205}
206
207static inline mailimap * get_imap_session(mailsession * session)
208{
209 return get_ancestor_data(session)->imap_session;
210}
211
212static int imapdriver_cached_initialize(mailsession * session)
213{
214 struct imap_cached_session_state_data * data;
215
216 data = malloc(sizeof(* data));
217 if (data == NULL)
218 goto err;
219
220 data->imap_ancestor = mailsession_new(imap_session_driver);
221 if (data->imap_ancestor == NULL)
222 goto free_data;
223 data->imap_quoted_mb = NULL;
224 data->imap_cache_directory[0] = '\0';
225 data->imap_uid_list = carray_new(128);
226 if (data->imap_uid_list == NULL)
227 goto free_session;
228
229 session->sess_data = data;
230
231 return MAIL_NO_ERROR;
232
233 free_session:
234 mailsession_free(data->imap_ancestor);
235 free_data:
236 free(data);
237 err:
238 return MAIL_ERROR_MEMORY;
239}
240
241static void
242free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data)
243{
244 if (imap_cached_data->imap_quoted_mb != NULL) {
245 free(imap_cached_data->imap_quoted_mb);
246 imap_cached_data->imap_quoted_mb = NULL;
247 }
248}
249
250struct uid_cache_item {
251 uint32_t uid;
252 uint32_t size;
253};
254
255static int update_uid_cache(mailsession * session,
256 struct mailmessage_list * env_list)
257{
258 unsigned int i;
259 int r;
260 struct imap_cached_session_state_data * data;
261 int res;
262
263 data = get_cached_data(session);
264
265 /* free all UID cache */
266 for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
267 struct uid_cache_item * cache_item;
268
269 cache_item = carray_get(data->imap_uid_list, i);
270 free(cache_item);
271 }
272
273 /* build UID cache */
274 r = carray_set_size(data->imap_uid_list,
275 carray_count(env_list->msg_tab));
276 if (r < 0) {
277 res = MAIL_ERROR_MEMORY;
278 goto err;
279 }
280
281 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
282 struct uid_cache_item * cache_item;
283 mailmessage * msg;
284
285 cache_item = malloc(sizeof(* cache_item));
286 if (cache_item == NULL) {
287 res = MAIL_ERROR_MEMORY;
288 goto err;
289 }
290 msg = carray_get(env_list->msg_tab, i);
291 cache_item->uid = msg->msg_index;
292 cache_item->size = msg->msg_size;
293
294 carray_set(data->imap_uid_list, i, cache_item);
295 }
296
297 return MAIL_NO_ERROR;
298
299 err:
300 return res;
301}
302
303static void check_for_uid_cache(mailsession * session)
304{
305#if 0
306 mailsession * imap;
307#endif
308 mailimap * imap;
309#if 0
310 struct imap_session_state_data * imap_data;
311#endif
312 clist * list;
313 clistiter * cur;
314 struct imap_cached_session_state_data * data;
315 unsigned int i;
316 unsigned dest;
317
318 data = get_cached_data(session);
319#if 0
320 imap = get_ancestor(session);
321
322 imap_data = imap->data;
323#endif
324
325 imap = get_imap_session(session);
326
327 if (imap->imap_response_info == NULL)
328 return;
329
330 list = imap->imap_response_info->rsp_expunged;
331 if (list == NULL)
332 return;
333
334 dest = 0;
335 i = 0;
336 /* remove expunged */
337 for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
338 uint32_t expunged;
339
340 expunged = * (uint32_t *) clist_content(cur);
341
342 while (i < carray_count(data->imap_uid_list)) {
343 struct uid_cache_item * cache_item;
344
345 if (dest + 1 == expunged) {
346 cache_item = carray_get(data->imap_uid_list, i);
347 free(cache_item);
348 i ++;
349 break;
350 }
351 else {
352 cache_item = carray_get(data->imap_uid_list, i);
353 carray_set(data->imap_uid_list, dest, cache_item);
354 i ++;
355 dest ++;
356 }
357 }
358 }
359 /* complete list */
360 while (i < carray_count(data->imap_uid_list)) {
361 struct uid_cache_item * cache_item;
362
363 cache_item = carray_get(data->imap_uid_list, i);
364 carray_set(data->imap_uid_list, dest, cache_item);
365 i ++;
366 dest ++;
367 }
368 carray_set_size(data->imap_uid_list, dest);
369}
370
371static void imapdriver_cached_uninitialize(mailsession * session)
372{
373 struct imap_cached_session_state_data * data;
374 unsigned int i;
375
376 data = get_cached_data(session);
377
378 for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
379 struct uid_cache_item * cache_item;
380
381 cache_item = carray_get(data->imap_uid_list, i);
382 free(cache_item);
383 }
384 carray_free(data->imap_uid_list);
385 free_quoted_mb(data);
386 mailsession_free(data->imap_ancestor);
387 free(data);
388
389 session->sess_data = NULL;
390}
391
392
393static int imapdriver_cached_parameters(mailsession * session,
394 int id, void * value)
395{
396 struct imap_cached_session_state_data * data;
397 int r;
398
399 data = get_cached_data(session);
400
401 switch (id) {
402 case IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY:
403 strncpy(data->imap_cache_directory, value, PATH_MAX);
404 data->imap_cache_directory[PATH_MAX - 1] = '\0';
405
406 r = generic_cache_create_dir(data->imap_cache_directory);
407 if (r != MAIL_NO_ERROR)
408 return r;
409
410 return MAIL_NO_ERROR;
411 }
412
413 return MAIL_ERROR_INVAL;
414}
415
416
417static int imapdriver_cached_connect_stream(mailsession * session,
418 mailstream * s)
419{
420 int r;
421
422 check_for_uid_cache(session);
423
424 r = mailsession_connect_stream(get_ancestor(session), s);
425
426 check_for_uid_cache(session);
427
428 return r;
429}
430
431static int imapdriver_cached_starttls(mailsession * session)
432{
433 int r;
434
435 r = mailsession_starttls(get_ancestor(session));
436
437 check_for_uid_cache(session);
438
439 return r;
440}
441
442static int imapdriver_cached_login(mailsession * session,
443 char * userid, char * password)
444{
445 int r;
446
447 r = mailsession_login(get_ancestor(session), userid, password);
448
449 check_for_uid_cache(session);
450
451 return r;
452}
453
454static int imapdriver_cached_logout(mailsession * session)
455{
456 int r;
457
458 r = mailsession_logout(get_ancestor(session));
459
460 check_for_uid_cache(session);
461
462 if (r == MAIL_NO_ERROR) {
463 struct imap_cached_session_state_data * imap_cached_data;
464
465 imap_cached_data = get_cached_data(session);
466
467 free_quoted_mb(imap_cached_data);
468 }
469
470 return r;
471}
472
473static int imapdriver_cached_noop(mailsession * session)
474{
475 int r;
476
477 r = mailsession_noop(get_ancestor(session));
478
479 check_for_uid_cache(session);
480
481 return r;
482}
483
484static int imapdriver_cached_build_folder_name(mailsession * session,
485 char * mb,
486 char * name, char ** result)
487{
488 int r;
489
490 r = mailsession_build_folder_name(get_ancestor(session), mb,
491 name, result);
492
493 check_for_uid_cache(session);
494
495 return r;
496}
497
498static int imapdriver_cached_create_folder(mailsession * session, char * mb)
499{
500 int r;
501
502 r = mailsession_create_folder(get_ancestor(session), mb);
503
504 check_for_uid_cache(session);
505
506 return r;
507}
508
509static int imapdriver_cached_delete_folder(mailsession * session, char * mb)
510{
511 int r;
512
513 r = mailsession_delete_folder(get_ancestor(session), mb);
514
515 check_for_uid_cache(session);
516
517 return r;
518}
519
520static int imapdriver_cached_rename_folder(mailsession * session, char * mb,
521 char * new_name)
522{
523 int r;
524
525 r = mailsession_rename_folder(get_ancestor(session), mb, new_name);
526
527 check_for_uid_cache(session);
528
529 return r;
530}
531
532static int imapdriver_cached_check_folder(mailsession * session)
533{
534 int r;
535
536 r = mailsession_check_folder(get_ancestor(session));
537
538 check_for_uid_cache(session);
539
540 return r;
541}
542
543static int imapdriver_cached_examine_folder(mailsession * session,
544 char * mb)
545{
546 int r;
547
548 r = mailsession_examine_folder(get_ancestor(session), mb);
549
550 check_for_uid_cache(session);
551
552 return r;
553}
554
555static int get_cache_folder(mailsession * session, char ** result)
556{
557#if 0
558 mailsession * imap_session;
559#endif
560 mailimap * imap;
561 char * mb;
562 char * cache_dir;
563 char * dirname;
564 char * quoted_mb;
565 int res;
566 int r;
567 char key[PATH_MAX];
568#if 0
569 struct imap_session_state_data * imap_data;
570 struct imap_cached_session_state_data * cached_data;
571#endif
572
573#if 0
574 imap_session = get_ancestor(session);
575 imap_data = imap_session->data;
576 imap = imap_data->session;
577#endif
578 imap = get_imap_session(session);
579
580 mb = get_ancestor_data(session)->imap_mailbox;
581
582 cache_dir = get_cached_data(session)->imap_cache_directory;
583
584 if (imap->imap_state != MAILIMAP_STATE_SELECTED)
585 return MAIL_ERROR_BAD_STATE;
586
587 if (imap->imap_selection_info == NULL)
588 return MAIL_ERROR_BAD_STATE;
589
590 quoted_mb = maildriver_quote_mailbox(mb);
591 if (quoted_mb == NULL) {
592 res = MAIL_ERROR_MEMORY;
593 goto err;
594 }
595
596 snprintf(key, PATH_MAX, "%s/%s", cache_dir, quoted_mb);
597
598 dirname = strdup(key);
599 if (dirname == NULL) {
600 res = MAIL_ERROR_MEMORY;
601 goto free_mb;
602 }
603
604 r = generic_cache_create_dir(dirname);
605 if (r != MAIL_NO_ERROR) {
606 res = r;
607 goto free_dirname;
608 }
609
610 free(quoted_mb);
611
612 * result = dirname;
613
614 return MAIL_NO_ERROR;
615
616 free_dirname:
617 free(dirname);
618 free_mb:
619 free(quoted_mb);
620 err:
621 return res;
622}
623
624static int imapdriver_cached_select_folder(mailsession * session, char * mb)
625{
626 int r;
627 char * quoted_mb;
628 struct imap_cached_session_state_data * data;
629 mailsession * imap;
630 char * old_mb;
631
632 imap = get_ancestor(session);
633
634 old_mb = get_ancestor_data(session)->imap_mailbox;
635 if (old_mb != NULL)
636 if (strcmp(mb, old_mb) == 0)
637 return MAIL_NO_ERROR;
638
639 r = mailsession_select_folder(get_ancestor(session), mb);
640 if (r != MAIL_NO_ERROR)
641 return r;
642
643 check_for_uid_cache(session);
644
645 r = get_cache_folder(session, &quoted_mb);
646 if (r != MAIL_NO_ERROR)
647 return r;
648
649 data = get_cached_data(session);
650 if (data->imap_quoted_mb != NULL)
651 free(data->imap_quoted_mb);
652 data->imap_quoted_mb = quoted_mb;
653
654 /* clear UID cache */
655 carray_set_size(data->imap_uid_list, 0);
656
657 return MAIL_NO_ERROR;
658}
659
660static int imapdriver_cached_expunge_folder(mailsession * session)
661{
662 int r;
663
664 r = mailsession_expunge_folder(get_ancestor(session));
665
666 check_for_uid_cache(session);
667
668 return r;
669}
670
671static int imapdriver_cached_status_folder(mailsession * session, char * mb,
672 uint32_t * result_messages, uint32_t * result_recent,
673 uint32_t * result_unseen)
674{
675 int r;
676
677 r = mailsession_status_folder(get_ancestor(session), mb, result_messages,
678 result_recent, result_unseen);
679
680 check_for_uid_cache(session);
681
682 return r;
683}
684
685static int imapdriver_cached_messages_number(mailsession * session,
686 char * mb,
687 uint32_t * result)
688{
689 int r;
690
691 r = mailsession_messages_number(get_ancestor(session), mb, result);
692
693 check_for_uid_cache(session);
694
695 return r;
696}
697
698static int imapdriver_cached_recent_number(mailsession * session, char * mb,
699 uint32_t * result)
700{
701 int r;
702
703 r = mailsession_recent_number(get_ancestor(session), mb, result);
704
705 check_for_uid_cache(session);
706
707 return r;
708}
709
710static int imapdriver_cached_unseen_number(mailsession * session, char * mb,
711 uint32_t * result)
712{
713 int r;
714
715 r = mailsession_unseen_number(get_ancestor(session), mb, result);
716
717 check_for_uid_cache(session);
718
719 return r;
720}
721
722static int imapdriver_cached_list_folders(mailsession * session, char * mb,
723 struct mail_list ** result)
724{
725 int r;
726
727 r = mailsession_list_folders(get_ancestor(session), mb, result);
728
729 check_for_uid_cache(session);
730
731 return r;
732}
733
734static int imapdriver_cached_lsub_folders(mailsession * session, char * mb,
735 struct mail_list ** result)
736{
737 int r;
738
739 r = mailsession_lsub_folders(get_ancestor(session), mb, result);
740
741 check_for_uid_cache(session);
742
743 return r;
744}
745
746static int imapdriver_cached_subscribe_folder(mailsession * session,
747 char * mb)
748{
749 int r;
750
751 r = mailsession_subscribe_folder(get_ancestor(session), mb);
752
753 check_for_uid_cache(session);
754
755 return r;
756}
757
758static int imapdriver_cached_unsubscribe_folder(mailsession * session,
759 char * mb)
760{
761 int r;
762
763 r = mailsession_unsubscribe_folder(get_ancestor(session), mb);
764
765 check_for_uid_cache(session);
766
767 return r;
768}
769
770static int imapdriver_cached_append_message(mailsession * session,
771 char * message, size_t size)
772{
773 int r;
774
775 r = mailsession_append_message(get_ancestor(session), message, size);
776
777 check_for_uid_cache(session);
778
779 return r;
780}
781
782static int imapdriver_cached_append_message_flags(mailsession * session,
783 char * message, size_t size, struct mail_flags * flags)
784{
785 int r;
786
787 r = mailsession_append_message_flags(get_ancestor(session),
788 message, size, flags);
789
790 check_for_uid_cache(session);
791
792 return r;
793}
794
795static int imapdriver_cached_copy_message(mailsession * session,
796 uint32_t num, char * mb)
797{
798 int r;
799
800 r = mailsession_copy_message(get_ancestor(session), num, mb);
801
802 check_for_uid_cache(session);
803
804 return r;
805}
806
807static int cmp_uid(uint32_t ** pa, uint32_t ** pb)
808{
809 uint32_t * a;
810 uint32_t * b;
811
812 a = * pa;
813 b = * pb;
814
815 return * a - * b;
816}
817
818
819static int imapdriver_cached_get_messages_list(mailsession * session,
820 struct mailmessage_list **
821 result)
822{
823#if 0
824 mailsession * imap_session;
825#endif
826 mailimap * imap;
827 uint32_t uid_max;
828 struct imap_cached_session_state_data * data;
829 struct mailmessage_list * env_list;
830 unsigned i;
831 int r;
832 int res;
833 carray * tab;
834
835#if 0
836 data = session->data;
837 imap_session = get_ancestor(session);
838 imap = ((struct imap_session_state_data *) (imap_session->data))->session;
839#endif
840 data = get_cached_data(session);
841 imap = get_imap_session(session);
842
843 uid_max = 0;
844
845#ifdef CACHE_MESSAGE_LIST
846 /* get UID max */
847 uid_max = 0;
848 for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
849 struct uid_cache_item * cache_item;
850
851 cache_item = carray_get(data->imap_uid_list, i);
852 if (cache_item->uid > uid_max)
853 uid_max = cache_item->uid;
854 }
855#endif
856
857 r = imap_get_messages_list(imap, session, imap_cached_message_driver,
858 uid_max + 1, &env_list);
859
860 check_for_uid_cache(session);
861
862 if (r != MAIL_NO_ERROR) {
863 res = r;
864 goto err;
865 }
866
867#ifdef CACHE_MESSAGE_LIST
868 /* remove unsollicited message */
869 i = 0;
870 while (i < carray_count(env_list->msg_tab)) {
871 mailmessage * msg;
872
873 msg = carray_get(env_list->msg_tab, i);
874 if (msg->msg_index < uid_max + 1) {
875 mailmessage * msg;
876
877 msg = carray_get(env_list->msg_tab, i);
878 mailmessage_free(msg);
879 carray_delete(env_list->msg_tab, i);
880 }
881 else {
882 i ++;
883 }
884 }
885
886 tab = carray_new(carray_count(env_list->msg_tab) +
887 carray_count(data->imap_uid_list));
888 if (tab == NULL) {
889 res = MAIL_ERROR_MEMORY;
890 goto free;
891 }
892 carray_set_size(tab,
893 carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list));
894
895 /* sort cached data before adding them to the list */
896 qsort(carray_data(data->imap_uid_list), carray_count(data->imap_uid_list),
897 sizeof(* carray_data(data->imap_uid_list)),
898 (int (*)(const void *, const void *)) cmp_uid);
899
900 /* adds cached UID */
901 for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
902 struct uid_cache_item * cache_item;
903 mailmessage * msg;
904
905 cache_item = carray_get(data->imap_uid_list, i);
906
907 msg = mailmessage_new();
908 if (msg == NULL) {
909 res = MAIL_ERROR_MEMORY;
910 goto free;
911 }
912
913 r = mailmessage_init(msg, session, imap_cached_message_driver,
914 cache_item->uid, cache_item->size);
915 if (r != MAIL_NO_ERROR) {
916 mailmessage_free(msg);
917 res = r;
918 goto free;
919 }
920
921 carray_set(tab, i, msg);
922 }
923
924 /* adds new elements */
925 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
926 mailmessage * msg;
927
928 msg = carray_get(env_list->msg_tab, i);
929 carray_set(tab, carray_count(data->imap_uid_list) + i, msg);
930 }
931
932 /* replace list of messages in env_list */
933 carray_free(env_list->msg_tab);
934 env_list->msg_tab = tab;
935
936 r = update_uid_cache(session, env_list);
937 if (r != MAIL_NO_ERROR) {
938 res = r;
939 goto free;
940 }
941#endif
942
943 * result = env_list;
944
945 return MAIL_NO_ERROR;
946
947 free:
948 mailmessage_list_free(env_list);
949 err:
950 return res;
951}
952
953#define IMAP_SET_MAX_COUNT 100
954
955static int get_flags_list(mailsession * session,
956 struct mailmessage_list * env_list)
957{
958 struct mailimap_set * set;
959 struct mailimap_fetch_att * fetch_att;
960 struct mailimap_fetch_type * fetch_type;
961 int res;
962 clist * fetch_result;
963 int r;
964 clist * msg_list;
965#if 0
966 struct imap_session_state_data * data;
967#endif
968 unsigned i;
969 unsigned dest;
970 clistiter * set_iter;
971
972#if 0
973 data = session->data;
974#endif
975
976 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
977 if (fetch_type == NULL) {
978 res = MAIL_ERROR_MEMORY;
979 goto err;
980 }
981
982 fetch_att = mailimap_fetch_att_new_uid();
983 if (fetch_att == NULL) {
984 res = MAIL_ERROR_MEMORY;
985 goto free_fetch_type;
986 }
987
988 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
989 if (r != MAILIMAP_NO_ERROR) {
990 mailimap_fetch_att_free(fetch_att);
991 res = MAIL_ERROR_MEMORY;
992 goto free_fetch_type;
993 }
994
995 fetch_att = mailimap_fetch_att_new_flags();
996 if (fetch_att == NULL) {
997 res = MAIL_ERROR_MEMORY;
998 goto free_fetch_type;
999 }
1000
1001 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1002 if (r != MAILIMAP_NO_ERROR) {
1003 mailimap_fetch_att_free(fetch_att);
1004 res = MAIL_ERROR_MEMORY;
1005 goto free_fetch_type;
1006 }
1007
1008 r = maildriver_env_list_to_msg_list_no_flags(env_list, &msg_list);
1009 if (r != MAIL_NO_ERROR) {
1010 res = MAIL_ERROR_MEMORY;
1011 goto free_fetch_type;
1012 }
1013
1014 if (clist_begin(msg_list) == NULL) {
1015 /* no need to fetch envelopes */
1016
1017 clist_free(msg_list);
1018 mailimap_fetch_type_free(fetch_type);
1019 return MAIL_NO_ERROR;
1020 }
1021
1022 r = msg_list_to_imap_set(msg_list, &set);
1023 if (r != MAIL_NO_ERROR) {
1024 clist_foreach(msg_list, (clist_func) free, NULL);
1025 clist_free(msg_list);
1026 res = MAIL_ERROR_MEMORY;
1027 goto free_fetch_type;
1028 }
1029 clist_foreach(msg_list, (clist_func) free, NULL);
1030 clist_free(msg_list);
1031
1032 set_iter = clist_begin(set->set_list);
1033 while (set_iter != NULL) {
1034 struct mailimap_set * subset;
1035 unsigned int count;
1036
1037 subset = mailimap_set_new_empty();
1038 if (subset == NULL) {
1039 res = MAIL_ERROR_MEMORY;
1040 mailimap_fetch_type_free(fetch_type);
1041 mailimap_set_free(set);
1042 res = MAIL_ERROR_MEMORY;
1043 goto err;
1044 }
1045
1046 count = 0;
1047 while (count < IMAP_SET_MAX_COUNT) {
1048 struct mailimap_set_item * item;
1049
1050 item = clist_content(set_iter);
1051 set_iter = clist_delete(set->set_list, set_iter);
1052
1053 r = mailimap_set_add(subset, item);
1054 if (r != MAILIMAP_NO_ERROR) {
1055 mailimap_set_item_free(item);
1056 mailimap_set_free(subset);
1057 mailimap_fetch_type_free(fetch_type);
1058 mailimap_set_free(set);
1059 res = MAIL_ERROR_MEMORY;
1060 goto err;
1061 }
1062
1063 count ++;
1064
1065 if (set_iter == NULL)
1066 break;
1067 }
1068
1069 r = mailimap_uid_fetch(get_imap_session(session), subset,
1070 fetch_type, &fetch_result);
1071
1072 mailimap_set_free(subset);
1073
1074 switch (r) {
1075 case MAILIMAP_NO_ERROR:
1076 break;
1077 default:
1078 mailimap_fetch_type_free(fetch_type);
1079 mailimap_set_free(set);
1080 return imap_error_to_mail_error(r);
1081 }
1082
1083 if (clist_begin(fetch_result) == NULL) {
1084 res = MAIL_ERROR_FETCH;
1085 goto err;
1086 }
1087
1088 r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
1089 mailimap_fetch_list_free(fetch_result);
1090
1091 if (r != MAIL_NO_ERROR) {
1092 mailimap_fetch_type_free(fetch_type);
1093 mailimap_set_free(set);
1094 res = MAIL_ERROR_MEMORY;
1095 goto err;
1096 }
1097 }
1098
1099#if 0
1100 r = mailimap_uid_fetch(get_imap_session(session), set,
1101 fetch_type, &fetch_result);
1102#endif
1103
1104 mailimap_fetch_type_free(fetch_type);
1105 mailimap_set_free(set);
1106
1107#if 0
1108 switch (r) {
1109 case MAILIMAP_NO_ERROR:
1110 break;
1111 default:
1112 return imap_error_to_mail_error(r);
1113 }
1114
1115 r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
1116 mailimap_fetch_list_free(fetch_result);
1117
1118 if (r != MAIL_NO_ERROR) {
1119 res = MAIL_ERROR_MEMORY;
1120 goto err;
1121 }
1122#endif
1123
1124 /* remove messages that don't have flags */
1125 i = 0;
1126 dest = 0;
1127 while (i < carray_count(env_list->msg_tab)) {
1128 mailmessage * msg;
1129
1130 msg = carray_get(env_list->msg_tab, i);
1131 if (msg->msg_flags != NULL) {
1132 carray_set(env_list->msg_tab, dest, msg);
1133 dest ++;
1134 }
1135 else {
1136 mailmessage_free(msg);
1137 }
1138 i ++;
1139 }
1140 carray_set_size(env_list->msg_tab, dest);
1141
1142 return MAIL_NO_ERROR;
1143
1144 free_fetch_type:
1145 mailimap_fetch_type_free(fetch_type);
1146 err:
1147 return res;
1148}
1149
1150
1151#define ENV_NAME "env.db"
1152
1153static void get_uid_from_filename(char * filename)
1154{
1155 char * p;
1156
1157 p = strstr(filename, "-part");
1158 if (p != NULL)
1159 * p = 0;
1160 p = strstr(filename, "-envelope");
1161 if (p != NULL)
1162 * p = 0;
1163 p = strstr(filename, "-rfc822");
1164 if (p != NULL)
1165 * p = 0;
1166}
1167
1168static int
1169imapdriver_cached_get_envelopes_list(mailsession * session,
1170 struct mailmessage_list * env_list)
1171{
1172 int r;
1173 int res;
1174 uint32_t i;
1175 struct imap_cached_session_state_data * data;
1176 MMAPString * mmapstr;
1177 struct mail_cache_db * cache_db;
1178 char filename[PATH_MAX];
1179
1180 data = get_cached_data(session);
1181 if (data->imap_quoted_mb == NULL) {
1182 res = MAIL_ERROR_BAD_STATE;
1183 goto err;
1184 }
1185
1186 mmapstr = mmap_string_new("");
1187 if (mmapstr == NULL) {
1188 res = MAIL_ERROR_MEMORY;
1189 goto err;
1190 }
1191
1192 snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME);
1193
1194 r = mail_cache_db_open_lock(filename, &cache_db);
1195 if (r < 0) {
1196 res = MAIL_ERROR_MEMORY;
1197 goto free_mmapstr;
1198 }
1199
1200 /* fill with cached */
1201
1202 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1203 mailmessage * msg;
1204 struct mailimf_fields * fields;
1205
1206 msg = carray_get(env_list->msg_tab, i);
1207
1208 if (msg->msg_fields == NULL) {
1209 r = imapdriver_get_cached_envelope(cache_db, mmapstr,
1210 session, msg, &fields);
1211 if (r == MAIL_NO_ERROR) {
1212 msg->msg_cached = TRUE;
1213 msg->msg_fields = fields;
1214 }
1215 }
1216 }
1217
1218 mail_cache_db_close_unlock(filename, cache_db);
1219
1220 r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
1221
1222 check_for_uid_cache(session);
1223
1224 if (r != MAIL_NO_ERROR) {
1225 res = r;
1226 goto free_mmapstr;
1227 }
1228
1229 r = get_flags_list(session, env_list);
1230
1231 if (r != MAIL_NO_ERROR) {
1232 res = r;
1233 goto free_mmapstr;
1234 }
1235
1236#ifdef CACHE_MESSAGE_LIST
1237 r = update_uid_cache(session, env_list);
1238 if (r != MAIL_NO_ERROR) {
1239 res = r;
1240 goto free_mmapstr;
1241 }
1242#endif
1243
1244 /* must write cache */
1245
1246 r = mail_cache_db_open_lock(filename, &cache_db);
1247 if (r < 0) {
1248 res = MAIL_ERROR_MEMORY;
1249 goto free_mmapstr;
1250 }
1251
1252 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1253 mailmessage * msg;
1254
1255 msg = carray_get(env_list->msg_tab, i);
1256
1257 if (msg->msg_fields != NULL) {
1258 if (!msg->msg_cached) {
1259 r = imapdriver_write_cached_envelope(cache_db, mmapstr,
1260 session, msg, msg->msg_fields);
1261 }
1262 }
1263 }
1264
1265 /* flush cache */
1266
1267 maildriver_cache_clean_up(cache_db, NULL, env_list);
1268
1269 mail_cache_db_close_unlock(filename, cache_db);
1270 mmap_string_free(mmapstr);
1271
1272 /* remove cache files */
1273
1274 maildriver_message_cache_clean_up(data->imap_quoted_mb, env_list,
1275 get_uid_from_filename);
1276
1277 return MAIL_NO_ERROR;
1278
1279 free_mmapstr:
1280 mmap_string_free(mmapstr);
1281 err:
1282 return res;
1283}
1284
1285static int imapdriver_cached_remove_message(mailsession * session,
1286 uint32_t num)
1287{
1288 int r;
1289
1290 r = mailsession_remove_message(get_ancestor(session), num);
1291
1292 check_for_uid_cache(session);
1293
1294 return r;
1295}
1296
1297#if 0
1298static int imapdriver_cached_search_messages(mailsession * session,
1299 char * charset,
1300 struct mail_search_key * key,
1301 struct mail_search_result **
1302 result)
1303{
1304 int r;
1305
1306 r = mailsession_search_messages(get_ancestor(session), charset, key, result);
1307
1308 check_for_uid_cache(session);
1309
1310 return r;
1311}
1312#endif
1313
1314static int imapdriver_cached_get_message(mailsession * session,
1315 uint32_t num, mailmessage ** result)
1316{
1317 mailmessage * msg_info;
1318 int r;
1319
1320 msg_info = mailmessage_new();
1321 if (msg_info == NULL)
1322 return MAIL_ERROR_MEMORY;
1323
1324 r = mailmessage_init(msg_info, session, imap_cached_message_driver, num, 0);
1325 if (r != MAIL_NO_ERROR) {
1326 mailmessage_free(msg_info);
1327 return r;
1328 }
1329
1330 * result = msg_info;
1331
1332 return MAIL_NO_ERROR;
1333}
1334
1335/* Retrieve a message by UID
1336 * libEtPan! uid format for IMAP is "UIDVALIDITY-UID"
1337 * where UIDVALIDITY and UID are decimal representation of
1338 * respectively uidvalidity and uid numbers.
1339 * Return value:
1340 * MAIL_ERROR_INVAL if uid is NULL or has an incorrect format.
1341 * MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found
1342 * MAIL_NO_ERROR if message was found. Result is in result
1343 */
1344static int imapdriver_cached_get_message_by_uid(mailsession * session,
1345 const char * uid,
1346 mailmessage ** result)
1347{
1348 uint32_t uidvalidity;
1349 uint32_t num;
1350 char * p1, * p2;
1351 mailimap *imap;
1352
1353 if (uid == NULL)
1354 return MAIL_ERROR_INVAL;
1355
1356 uidvalidity = strtoul(uid, &p1, 10);
1357 if (p1 == uid || * p1 != '-')
1358 return MAIL_ERROR_INVAL;
1359
1360 p1++;
1361 num = strtoul(p1, &p2, 10);
1362 if (p2 == p1 || * p2 != '\0')
1363 return MAIL_ERROR_INVAL;
1364
1365 imap = get_imap_session(session);
1366 if (imap->imap_selection_info->sel_uidvalidity != uidvalidity)
1367 return MAIL_ERROR_MSG_NOT_FOUND;
1368
1369 return imapdriver_cached_get_message(session, num, result);
1370}