summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/imap/imapdriver.c
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/imap/imapdriver.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver.c1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/imap/imapdriver.c b/libetpan/src/driver/implementation/imap/imapdriver.c
new file mode 100644
index 0000000..815e077
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver.c
@@ -0,0 +1,1226 @@
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.h"
37
38#include "mail.h"
39#include "imapdriver_tools.h"
40#include "mailmessage.h"
41#include "imapdriver_message.h"
42#include "imapdriver_types.h"
43#include "maildriver.h"
44#include "maildriver_tools.h"
45#include "generic_cache.h"
46
47#include <stdlib.h>
48#include <string.h>
49
50static int imapdriver_initialize(mailsession * session);
51
52static void imapdriver_uninitialize(mailsession * session);
53
54static int imapdriver_connect_stream(mailsession * session, mailstream * s);
55
56static int imapdriver_starttls(mailsession * session);
57
58static int imapdriver_login(mailsession * session,
59 char * userid, char * password);
60
61static int imapdriver_logout(mailsession * session);
62
63static int imapdriver_noop(mailsession * session);
64
65static int imapdriver_build_folder_name(mailsession * session, char * mb,
66 char * name, char ** result);
67
68static int imapdriver_create_folder(mailsession * session, char * mb);
69
70static int imapdriver_delete_folder(mailsession * session, char * mb);
71
72static int imapdriver_rename_folder(mailsession * session, char * mb,
73 char * new_name);
74
75static int imapdriver_check_folder(mailsession * session);
76
77static int imapdriver_examine_folder(mailsession * session, char * mb);
78
79static int imapdriver_select_folder(mailsession * session, char * mb);
80static int imapdriver_expunge_folder(mailsession * session);
81
82static int imapdriver_status_folder(mailsession * session, char * mb,
83 uint32_t * result_messages, uint32_t * result_recent,
84 uint32_t * result_unseen);
85
86static int imapdriver_messages_number(mailsession * session, char * mb,
87 uint32_t * result);
88
89static int imapdriver_recent_number(mailsession * session, char * mb,
90 uint32_t * result);
91
92static int imapdriver_unseen_number(mailsession * session, char * mb,
93 uint32_t * result);
94
95static int imapdriver_list_folders(mailsession * session, char * mb,
96 struct mail_list ** result);
97static int imapdriver_lsub_folders(mailsession * session, char * mb,
98 struct mail_list ** result);
99static int imapdriver_subscribe_folder(mailsession * session, char * mb);
100static int imapdriver_unsubscribe_folder(mailsession * session, char * mb);
101static int imapdriver_append_message(mailsession * session,
102 char * message, size_t size);
103static int imapdriver_append_message_flags(mailsession * session,
104 char * message, size_t size, struct mail_flags * flags);
105static int imapdriver_copy_message(mailsession * session,
106 uint32_t num, char * mb);
107
108static int imapdriver_get_messages_list(mailsession * session,
109 struct mailmessage_list ** result);
110
111static int
112imapdriver_get_envelopes_list(mailsession * session,
113 struct mailmessage_list * env_list);
114
115
116#if 0
117static int imapdriver_search_messages(mailsession * session, char * charset,
118 struct mail_search_key * key,
119 struct mail_search_result ** result);
120#endif
121
122static int imapdriver_get_message(mailsession * session,
123 uint32_t num, mailmessage ** result);
124
125static int imapdriver_get_message_by_uid(mailsession * session,
126 const char * uid,
127 mailmessage ** result);
128
129static mailsession_driver local_imap_session_driver = {
130 .sess_name = "imap",
131
132 .sess_initialize = imapdriver_initialize,
133 .sess_uninitialize = imapdriver_uninitialize,
134
135 .sess_parameters = NULL,
136
137 .sess_connect_stream = imapdriver_connect_stream,
138 .sess_connect_path = NULL,
139 .sess_starttls = imapdriver_starttls,
140 .sess_login = imapdriver_login,
141 .sess_logout = imapdriver_logout,
142 .sess_noop = imapdriver_noop,
143
144 .sess_build_folder_name = imapdriver_build_folder_name,
145 .sess_create_folder = imapdriver_create_folder,
146 .sess_delete_folder = imapdriver_delete_folder,
147 .sess_rename_folder = imapdriver_rename_folder,
148 .sess_check_folder = imapdriver_check_folder,
149 .sess_examine_folder = imapdriver_examine_folder,
150 .sess_select_folder = imapdriver_select_folder,
151 .sess_expunge_folder = imapdriver_expunge_folder,
152 .sess_status_folder = imapdriver_status_folder,
153 .sess_messages_number = imapdriver_messages_number,
154 .sess_recent_number = imapdriver_recent_number,
155 .sess_unseen_number = imapdriver_unseen_number,
156 .sess_list_folders = imapdriver_list_folders,
157 .sess_lsub_folders = imapdriver_lsub_folders,
158 .sess_subscribe_folder = imapdriver_subscribe_folder,
159 .sess_unsubscribe_folder = imapdriver_unsubscribe_folder,
160
161 .sess_append_message = imapdriver_append_message,
162 .sess_append_message_flags = imapdriver_append_message_flags,
163 .sess_copy_message = imapdriver_copy_message,
164 .sess_move_message = NULL,
165
166 .sess_get_messages_list = imapdriver_get_messages_list,
167 .sess_get_envelopes_list = imapdriver_get_envelopes_list,
168 .sess_remove_message = NULL,
169#if 0
170 .sess_search_messages = imapdriver_search_messages,
171#endif
172
173 .sess_get_message = imapdriver_get_message,
174 .sess_get_message_by_uid = imapdriver_get_message_by_uid,
175};
176
177mailsession_driver * imap_session_driver = &local_imap_session_driver;
178
179static inline struct imap_session_state_data * get_data(mailsession * session)
180{
181 return session->sess_data;
182}
183
184static mailimap * get_imap_session(mailsession * session)
185{
186 return get_data(session)->imap_session;
187}
188
189static int imapdriver_initialize(mailsession * session)
190{
191 struct imap_session_state_data * data;
192 mailimap * imap;
193 struct mail_flags_store * flags_store;
194
195 imap = mailimap_new(0, NULL);
196 if (imap == NULL)
197 goto err;
198
199 flags_store = mail_flags_store_new();
200 if (flags_store == NULL)
201 goto free_session;
202
203 data = malloc(sizeof(* data));
204 if (data == NULL)
205 goto free_flags_store;
206
207 data->imap_mailbox = NULL;
208 data->imap_session = imap;
209 data->imap_flags_store = flags_store;
210
211 session->sess_data = data;
212
213 return MAIL_NO_ERROR;
214
215 free_flags_store:
216 mail_flags_store_free(flags_store);
217 free_session:
218 mailimap_free(imap);
219 err:
220 return MAIL_ERROR_MEMORY;
221}
222
223static void imap_flags_store_process(mailimap * imap,
224 struct mail_flags_store * flags_store)
225{
226 unsigned int i;
227 int r;
228 mailmessage * first;
229 mailmessage * last;
230
231 mail_flags_store_sort(flags_store);
232
233 if (carray_count(flags_store->fls_tab) == 0)
234 return;
235
236 first = carray_get(flags_store->fls_tab, 0);
237 last = first;
238
239 for(i = 1 ; i < carray_count(flags_store->fls_tab) ; i ++) {
240 mailmessage * msg;
241
242 msg = carray_get(flags_store->fls_tab, i);
243
244 if (last->msg_index + 1 == msg->msg_index) {
245 r = mail_flags_compare(first->msg_flags, msg->msg_flags);
246 if (r == 0) {
247 last = msg;
248 continue;
249 }
250 }
251
252 r = imap_store_flags(imap, first->msg_index,
253 last->msg_index, first->msg_flags);
254
255 first = msg;
256 last = msg;
257 }
258
259 r = imap_store_flags(imap, first->msg_index, last->msg_index,
260 first->msg_flags);
261
262 mail_flags_store_clear(flags_store);
263}
264
265static void imapdriver_uninitialize(mailsession * session)
266{
267 struct imap_session_state_data * data;
268
269 data = get_data(session);
270
271 imap_flags_store_process(data->imap_session,
272 data->imap_flags_store);
273 mail_flags_store_free(data->imap_flags_store);
274
275 mailimap_free(data->imap_session);
276 if (data->imap_mailbox != NULL)
277 free(data->imap_mailbox);
278 free(data);
279
280 session->sess_data = NULL;
281}
282
283static int imapdriver_connect_stream(mailsession * session, mailstream * s)
284{
285 int r;
286
287 r = mailimap_connect(get_imap_session(session), s);
288
289 return imap_error_to_mail_error(r);
290}
291
292static int imapdriver_login(mailsession * session,
293 char * userid, char * password)
294{
295 int r;
296
297 r = mailimap_login(get_imap_session(session), userid, password);
298
299 return imap_error_to_mail_error(r);
300}
301
302static int imapdriver_logout(mailsession * session)
303{
304 int r;
305
306 imap_flags_store_process(get_imap_session(session),
307 get_data(session)->imap_flags_store);
308
309 r = mailimap_logout(get_imap_session(session));
310
311 return imap_error_to_mail_error(r);
312}
313
314static int imapdriver_noop(mailsession * session)
315{
316 int r;
317
318 r = mailimap_noop(get_imap_session(session));
319
320 return imap_error_to_mail_error(r);
321}
322
323static int imapdriver_build_folder_name(mailsession * session, char * mb,
324 char * name, char ** result)
325{
326 char delimiter[2] = "X";
327 char * folder_name;
328 mailimap * imap;
329 struct mailimap_mailbox_list * mb_list;
330 int r;
331 clist * imap_list;
332
333 imap = get_imap_session(session);
334
335 r = mailimap_list(imap, mb, "", &imap_list);
336 if (r != MAILIMAP_NO_ERROR)
337 return r;
338
339 if (clist_begin(imap_list) == NULL)
340 return MAIL_ERROR_LIST;
341
342 mb_list = clist_begin(imap_list)->data;
343 delimiter[0] = mb_list->mb_delimiter;
344
345 folder_name = malloc(strlen(mb) + strlen(delimiter) + strlen(name) + 1);
346 if (folder_name == NULL)
347 return MAIL_ERROR_MEMORY;
348
349 strcpy(folder_name, mb);
350 strcat(folder_name, delimiter);
351 strcat(folder_name, name);
352
353 * result = folder_name;
354
355 return MAIL_NO_ERROR;
356}
357
358/* folders operations */
359
360static int imapdriver_create_folder(mailsession * session, char * mb)
361{
362 int r;
363
364 r = mailimap_create(get_imap_session(session), mb);
365
366 return imap_error_to_mail_error(r);
367}
368
369static int imapdriver_delete_folder(mailsession * session, char * mb)
370{
371 int r;
372
373 r = mailimap_delete(get_imap_session(session), mb);
374
375 return imap_error_to_mail_error(r);
376}
377
378static int imapdriver_rename_folder(mailsession * session, char * mb,
379 char * new_name)
380{
381 int r;
382
383 r = mailimap_rename(get_imap_session(session), mb, new_name);
384
385 return imap_error_to_mail_error(r);
386}
387
388static int imapdriver_check_folder(mailsession * session)
389{
390 int r;
391
392 imap_flags_store_process(get_imap_session(session),
393 get_data(session)->imap_flags_store);
394
395 r = mailimap_check(get_imap_session(session));
396
397 return imap_error_to_mail_error(r);
398}
399
400static int imapdriver_examine_folder(mailsession * session, char * mb)
401{
402 int r;
403
404 r = mailimap_examine(get_imap_session(session), mb);
405
406 return imap_error_to_mail_error(r);
407}
408
409static int imapdriver_select_folder(mailsession * session, char * mb)
410{
411 int r;
412 char * new_mb;
413 char * old_mb;
414
415 old_mb = get_data(session)->imap_mailbox;
416 if (old_mb != NULL)
417 if (strcmp(mb, old_mb) == 0)
418 return MAIL_NO_ERROR;
419
420 imap_flags_store_process(get_imap_session(session),
421 get_data(session)->imap_flags_store);
422
423 r = mailimap_select(get_imap_session(session), mb);
424
425 switch (r) {
426 case MAILIMAP_NO_ERROR:
427 new_mb = strdup(mb);
428 if (new_mb == NULL) {
429 if (old_mb != NULL)
430 free(old_mb);
431 get_data(session)->imap_mailbox = NULL;
432 return MAIL_ERROR_MEMORY;
433 }
434
435 get_data(session)->imap_mailbox = new_mb;
436
437 return MAIL_NO_ERROR;
438 default:
439 return imap_error_to_mail_error(r);
440 }
441}
442
443static int imapdriver_expunge_folder(mailsession * session)
444{
445 int r;
446
447 imap_flags_store_process(get_imap_session(session),
448 get_data(session)->imap_flags_store);
449
450 r = mailimap_expunge(get_imap_session(session));
451
452 return imap_error_to_mail_error(r);
453}
454
455static int status_selected_folder(mailsession * session, char * mb,
456 uint32_t * result_messages, uint32_t * result_recent,
457 uint32_t * result_unseen)
458{
459 int r;
460 int res;
461 mailimap * imap;
462 uint32_t exists;
463 uint32_t unseen;
464 uint32_t recent;
465 struct mailimap_search_key * search_key;
466 clist * search_result;
467
468 imap = get_imap_session(session);
469
470 exists = imap->imap_selection_info->sel_exists;
471 recent = imap->imap_selection_info->sel_recent;
472
473 search_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
474 NULL, NULL, NULL, NULL, NULL,
475 NULL, NULL, NULL, NULL, NULL,
476 NULL, NULL, NULL, NULL, 0,
477 NULL, NULL, NULL, NULL, NULL,
478 NULL, 0, NULL, NULL, NULL);
479 if (search_key == NULL) {
480 res = MAIL_ERROR_MEMORY;
481 goto err;
482 }
483
484 /* default : use the RECENT count if search fails */
485 unseen = recent;
486 r = mailimap_search(imap, NULL, search_key, &search_result);
487 mailimap_search_key_free(search_key);
488 if (r == MAILIMAP_NO_ERROR) {
489 /* if this succeed, we use the real count */
490 unseen = clist_count(search_result);
491 mailimap_mailbox_data_search_free(search_result);
492 }
493
494 * result_messages = exists;
495 * result_unseen = unseen;
496 * result_recent = recent;
497
498 return MAIL_NO_ERROR;
499
500 err:
501 return res;
502}
503
504static int status_unselected_folder(mailsession * session, char * mb,
505 uint32_t * result_messages, uint32_t * result_recent,
506 uint32_t * result_unseen)
507{
508 struct mailimap_status_att_list * att_list;
509 struct mailimap_mailbox_data_status * status;
510 int r;
511 int res;
512 clistiter * cur;
513 mailimap * imap;
514
515 imap = get_imap_session(session);
516
517 att_list = mailimap_status_att_list_new_empty();
518 if (att_list == NULL) {
519 res = MAIL_ERROR_MEMORY;
520 goto err;
521 }
522
523 r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_MESSAGES);
524 switch (r) {
525 case MAILIMAP_NO_ERROR:
526 break;
527 default:
528 res = MAIL_ERROR_MEMORY;
529 goto free;
530 }
531
532 r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_RECENT);
533 switch (r) {
534 case MAILIMAP_NO_ERROR:
535 break;
536 default:
537 res = MAIL_ERROR_MEMORY;
538 goto free;
539 }
540
541 r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_UNSEEN);
542 switch (r) {
543 case MAILIMAP_NO_ERROR:
544 break;
545 default:
546 res = MAIL_ERROR_MEMORY;
547 goto free;
548 }
549
550 r = mailimap_status(imap, mb, att_list, &status);
551
552 switch (r) {
553 case MAILIMAP_NO_ERROR:
554 break;
555 default:
556 res = imap_error_to_mail_error(r);
557 goto free;
558 }
559
560 * result_messages = 0;
561 * result_recent = 0;
562 * result_unseen = 0;
563
564 for (cur = clist_begin(status->st_info_list);
565 cur != NULL ; cur = clist_next(cur)) {
566 struct mailimap_status_info * status_info;
567
568 status_info = clist_content(cur);
569 switch (status_info->st_att) {
570 case MAILIMAP_STATUS_ATT_MESSAGES:
571 * result_messages = status_info->st_value;
572 break;
573 case MAILIMAP_STATUS_ATT_RECENT:
574 * result_recent = status_info->st_value;
575 break;
576 case MAILIMAP_STATUS_ATT_UNSEEN:
577 * result_unseen = status_info->st_value;
578 break;
579 }
580 }
581
582 mailimap_mailbox_data_status_free(status);
583 mailimap_status_att_list_free(att_list);
584
585 return MAIL_NO_ERROR;
586
587 free:
588 mailimap_status_att_list_free(att_list);
589 err:
590 return res;
591}
592
593static int imapdriver_status_folder(mailsession * session, char * mb,
594 uint32_t * result_messages, uint32_t * result_recent,
595 uint32_t * result_unseen)
596{
597 int res;
598 int current_folder;
599 char * current_mb;
600
601 if (mb == NULL) {
602 mb = get_data(session)->imap_mailbox;
603 if (mb == NULL) {
604 res = MAIL_ERROR_BAD_STATE;
605 goto err;
606 }
607 }
608
609 current_mb = get_data(session)->imap_mailbox;
610 if (strcmp(mb, current_mb) == 0)
611 current_folder = 1;
612 else
613 current_folder = 0;
614
615 if (current_folder)
616 return status_selected_folder(session, mb, result_messages,
617 result_recent, result_unseen);
618 else
619 return status_unselected_folder(session, mb, result_messages,
620 result_recent, result_unseen);
621
622 err:
623 return res;
624}
625
626/* TODO : more efficient functions */
627
628static int imapdriver_messages_number(mailsession * session, char * mb,
629 uint32_t * result)
630{
631 uint32_t messages;
632 uint32_t recent;
633 uint32_t unseen;
634 int r;
635
636 r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
637 if (r != MAIL_NO_ERROR)
638 return r;
639
640 * result = messages;
641
642 return MAIL_NO_ERROR;
643}
644
645static int imapdriver_recent_number(mailsession * session, char * mb,
646 uint32_t * result)
647{
648 uint32_t messages;
649 uint32_t recent;
650 uint32_t unseen;
651 int r;
652
653 r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
654 if (r != MAIL_NO_ERROR)
655 return r;
656
657 * result = recent;
658
659 return MAIL_NO_ERROR;
660}
661
662static int imapdriver_unseen_number(mailsession * session, char * mb,
663 uint32_t * result)
664{
665 uint32_t messages;
666 uint32_t recent;
667 uint32_t unseen;
668 int r;
669
670 r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
671 if (r != MAIL_NO_ERROR)
672 return r;
673
674 * result = unseen;
675
676 return MAIL_NO_ERROR;
677}
678
679enum {
680 IMAP_LIST, IMAP_LSUB
681};
682
683static int imapdriver_list_lsub_folders(mailsession * session, int type,
684 char * mb,
685 struct mail_list ** result)
686{
687 clist * imap_list;
688 struct mail_list * resp;
689 int r;
690 int res;
691
692 switch (type) {
693 case IMAP_LIST:
694 r = mailimap_list(get_imap_session(session), mb,
695 "*", &imap_list);
696 break;
697 case IMAP_LSUB:
698 r = mailimap_lsub(get_imap_session(session), mb,
699 "*", &imap_list);
700 break;
701 default:
702 res = MAIL_ERROR_LIST;
703 goto err;
704 }
705
706 switch (r) {
707 case MAILIMAP_NO_ERROR:
708 break;
709 default:
710 res = imap_error_to_mail_error(r);
711 goto err;
712 }
713
714 r = imap_list_to_list(imap_list, &resp);
715 if (r != MAIL_NO_ERROR) {
716 mailimap_list_result_free(imap_list);
717 res = r;
718 goto err;
719 }
720
721 mailimap_list_result_free(imap_list);
722
723 * result = resp;
724
725 return MAIL_NO_ERROR;
726
727 err:
728 return res;
729}
730
731static int imapdriver_list_folders(mailsession * session, char * mb,
732 struct mail_list ** result)
733{
734 return imapdriver_list_lsub_folders(session, IMAP_LIST, mb,
735 result);
736}
737
738static int imapdriver_lsub_folders(mailsession * session, char * mb,
739 struct mail_list ** result)
740{
741 return imapdriver_list_lsub_folders(session, IMAP_LSUB, mb,
742 result);
743}
744
745static int imapdriver_subscribe_folder(mailsession * session, char * mb)
746{
747 int r;
748
749 r = mailimap_subscribe(get_imap_session(session), mb);
750
751 return imap_error_to_mail_error(r);
752}
753
754static int imapdriver_unsubscribe_folder(mailsession * session, char * mb)
755{
756 int r;
757
758 r = mailimap_unsubscribe(get_imap_session(session), mb);
759
760 return imap_error_to_mail_error(r);
761}
762
763/* messages operations */
764
765static int imapdriver_append_message(mailsession * session,
766 char * message, size_t size)
767{
768 int r;
769
770 r = mailimap_append_simple(get_imap_session(session),
771 get_data(session)->imap_mailbox,
772 message, size);
773
774 return imap_error_to_mail_error(r);
775}
776
777static int imapdriver_append_message_flags(mailsession * session,
778 char * message, size_t size, struct mail_flags * flags)
779{
780 struct mailimap_flag_list * flag_list;
781 int r;
782
783 if (flags != NULL) {
784 r = imap_flags_to_imap_flags(flags, &flag_list);
785 if (r != MAIL_NO_ERROR)
786 return r;
787 }
788 else {
789 flag_list = NULL;
790 }
791
792 r = mailimap_append(get_imap_session(session),
793 get_data(session)->imap_mailbox,
794 flag_list, NULL, message, size);
795
796 if (flag_list != NULL)
797 mailimap_flag_list_free(flag_list);
798
799 return imap_error_to_mail_error(r);
800}
801
802static int imapdriver_copy_message(mailsession * session,
803 uint32_t num, char * mb)
804{
805 int r;
806 struct mailimap_set * set;
807 int res;
808
809 set = mailimap_set_new_single(num);
810 if (set == NULL) {
811 res = MAIL_ERROR_MEMORY;
812 goto err;
813 }
814
815 r = mailimap_uid_copy(get_imap_session(session), set, mb);
816
817 mailimap_set_free(set);
818
819 return imap_error_to_mail_error(r);
820
821 err:
822 return res;
823}
824
825static int imapdriver_get_messages_list(mailsession * session,
826 struct mailmessage_list ** result)
827{
828 return imap_get_messages_list(get_imap_session(session),
829 session, imap_message_driver, 1,
830 result);
831}
832
833
834
835#define IMAP_SET_MAX_COUNT 100
836
837static int
838imapdriver_get_envelopes_list(mailsession * session,
839 struct mailmessage_list * env_list)
840{
841 struct mailimap_set * set;
842 struct mailimap_fetch_att * fetch_att;
843 struct mailimap_fetch_type * fetch_type;
844 int res;
845 clist * fetch_result;
846 int r;
847 uint32_t exists;
848 clist * msg_list;
849 clistiter * set_iter;
850
851 if (get_imap_session(session)->imap_selection_info == NULL) {
852 res = MAIL_ERROR_BAD_STATE;
853 goto err;
854 }
855
856 imap_flags_store_process(get_imap_session(session),
857 get_data(session)->imap_flags_store);
858
859 exists = get_imap_session(session)->imap_selection_info->sel_exists;
860
861 if (exists == 0)
862 return MAIL_NO_ERROR;
863
864 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
865 if (fetch_type == NULL) {
866 res = MAIL_ERROR_MEMORY;
867 goto err;
868 }
869
870 fetch_att = mailimap_fetch_att_new_uid();
871 if (fetch_att == NULL) {
872 res = MAIL_ERROR_MEMORY;
873 goto free_fetch_type;
874 }
875
876 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
877 if (r != MAILIMAP_NO_ERROR) {
878 mailimap_fetch_att_free(fetch_att);
879 res = MAIL_ERROR_MEMORY;
880 goto free_fetch_type;
881 }
882
883 fetch_att = mailimap_fetch_att_new_flags();
884 if (fetch_att == NULL) {
885 res = MAIL_ERROR_MEMORY;
886 goto free_fetch_type;
887 }
888
889 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
890 if (r != MAILIMAP_NO_ERROR) {
891 mailimap_fetch_att_free(fetch_att);
892 res = MAIL_ERROR_MEMORY;
893 goto free_fetch_type;
894 }
895
896 r = imap_add_envelope_fetch_att(fetch_type);
897 if (r != MAIL_NO_ERROR) {
898 res = r;
899 goto free_fetch_type;
900 }
901
902 r = maildriver_env_list_to_msg_list(env_list, &msg_list);
903 if (r != MAIL_NO_ERROR) {
904 res = MAIL_ERROR_MEMORY;
905 goto free_fetch_type;
906 }
907
908 if (clist_begin(msg_list) == NULL) {
909 /* no need to fetch envelopes */
910
911 mailimap_fetch_type_free(fetch_type);
912 clist_free(msg_list);
913 return MAIL_NO_ERROR;
914 }
915
916 r = msg_list_to_imap_set(msg_list, &set);
917 if (r != MAIL_NO_ERROR) {
918 clist_foreach(msg_list, (clist_func) free, NULL);
919 clist_free(msg_list);
920 res = MAIL_ERROR_MEMORY;
921 goto free_fetch_type;
922 }
923 clist_foreach(msg_list, (clist_func) free, NULL);
924 clist_free(msg_list);
925
926 set_iter = clist_begin(set->set_list);
927 while (set_iter != NULL) {
928 struct mailimap_set * subset;
929 unsigned int count;
930
931 subset = mailimap_set_new_empty();
932 if (subset == NULL) {
933 res = MAIL_ERROR_MEMORY;
934 mailimap_fetch_type_free(fetch_type);
935 mailimap_set_free(set);
936 res = MAIL_ERROR_MEMORY;
937 goto err;
938 }
939
940 count = 0;
941 while (count < IMAP_SET_MAX_COUNT) {
942 struct mailimap_set_item * item;
943
944 item = clist_content(set_iter);
945 set_iter = clist_delete(set->set_list, set_iter);
946
947 r = mailimap_set_add(subset, item);
948 if (r != MAILIMAP_NO_ERROR) {
949 mailimap_set_item_free(item);
950 mailimap_set_free(subset);
951 mailimap_fetch_type_free(fetch_type);
952 mailimap_set_free(set);
953 res = MAIL_ERROR_MEMORY;
954 goto err;
955 }
956
957 count ++;
958
959 if (set_iter == NULL)
960 break;
961 }
962
963 r = mailimap_uid_fetch(get_imap_session(session), subset,
964 fetch_type, &fetch_result);
965
966 mailimap_set_free(subset);
967
968 switch (r) {
969 case MAILIMAP_NO_ERROR:
970 break;
971 default:
972 mailimap_fetch_type_free(fetch_type);
973 mailimap_set_free(set);
974 return imap_error_to_mail_error(r);
975 }
976
977 if (clist_begin(fetch_result) == NULL) {
978 res = MAIL_ERROR_FETCH;
979 goto err;
980 }
981
982 r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
983 mailimap_fetch_list_free(fetch_result);
984
985 if (r != MAIL_NO_ERROR) {
986 mailimap_fetch_type_free(fetch_type);
987 mailimap_set_free(set);
988 res = MAIL_ERROR_MEMORY;
989 goto err;
990 }
991 }
992
993#if 0
994 r = mailimap_uid_fetch(get_imap_session(session), set,
995 fetch_type, &fetch_result);
996#endif
997
998 mailimap_fetch_type_free(fetch_type);
999 mailimap_set_free(set);
1000#if 0
1001 switch (r) {
1002 case MAILIMAP_NO_ERROR:
1003 break;
1004 default:
1005 return imap_error_to_mail_error(r);
1006 }
1007
1008 r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
1009 mailimap_fetch_list_free(fetch_result);
1010
1011 if (r != MAIL_NO_ERROR) {
1012 res = MAIL_ERROR_MEMORY;
1013 goto err;
1014 }
1015#endif
1016
1017 return MAIL_NO_ERROR;
1018
1019 free_fetch_type:
1020 mailimap_fetch_type_free(fetch_type);
1021 err:
1022 return res;
1023}
1024
1025
1026#if 0
1027static int imapdriver_search_messages(mailsession * session, char * charset,
1028 struct mail_search_key * key,
1029 struct mail_search_result ** result)
1030{
1031 struct mailimap_search_key * imap_key;
1032 int r;
1033 clist * imap_result;
1034 clist * result_list;
1035 struct mail_search_result * search_result;
1036 clistiter * cur;
1037
1038 r = mail_search_to_imap_search(key, &imap_key);
1039 if (r != MAIL_NO_ERROR)
1040 return MAIL_ERROR_MEMORY;
1041
1042 r = mailimap_uid_search(get_imap_session(session), charset, imap_key,
1043 &imap_result);
1044
1045 mailimap_search_key_free(imap_key);
1046
1047 switch (r) {
1048 case MAILIMAP_NO_ERROR:
1049 break;
1050 default:
1051 return imap_error_to_mail_error(r);
1052 }
1053
1054 result_list = clist_new();
1055 if (result_list == NULL)
1056 return MAIL_ERROR_MEMORY;
1057
1058 for(cur = clist_begin(imap_result) ; cur != NULL ; cur = clist_next(cur)) {
1059 uint32_t val = * (uint32_t *) clist_content(cur);
1060 uint32_t * new;
1061
1062 new = malloc(sizeof(* new));
1063 if (new == NULL) {
1064 goto free_imap_result;
1065 }
1066
1067 * new = val;
1068
1069 r = clist_append(result_list, new);
1070 if (r != 0) {
1071 free(new);
1072 goto free_imap_result;
1073 }
1074 }
1075
1076 search_result = mail_search_result_new(result_list);
1077 if (search_result == NULL)
1078 goto free_imap_result;
1079
1080 mailimap_search_result_free(imap_result);
1081
1082 * result = search_result;
1083
1084 return MAIL_NO_ERROR;
1085
1086 free_imap_result:
1087 mailimap_search_result_free(imap_result);
1088 return MAIL_ERROR_MEMORY;
1089}
1090#endif
1091
1092static int imapdriver_starttls(mailsession * session)
1093{
1094 mailimap * imap;
1095 int r;
1096 struct mailimap_capability_data * cap_data;
1097 clistiter * cur;
1098 int starttls;
1099 int fd;
1100 mailstream_low * low;
1101 mailstream_low * new_low;
1102 int capability_available;
1103
1104 imap = get_imap_session(session);
1105
1106 capability_available = FALSE;
1107 if (imap->imap_connection_info != NULL)
1108 if (imap->imap_connection_info->imap_capability != NULL) {
1109 capability_available = TRUE;
1110 cap_data = imap->imap_connection_info->imap_capability;
1111 }
1112
1113 if (!capability_available) {
1114 r = mailimap_capability(imap, &cap_data);
1115 switch (r) {
1116 case MAILIMAP_NO_ERROR:
1117 break;
1118 default:
1119 return imap_error_to_mail_error(r);
1120 }
1121 }
1122
1123 starttls = FALSE;
1124 for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ;
1125 cur = clist_next(cur)) {
1126 struct mailimap_capability * cap;
1127
1128 cap = clist_content(cur);
1129
1130 if (cap->cap_type == MAILIMAP_CAPABILITY_NAME)
1131 if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) {
1132 starttls = TRUE;
1133 break;
1134 }
1135 }
1136
1137 if (!capability_available)
1138 mailimap_capability_data_free(cap_data);
1139
1140 if (!starttls)
1141 return MAIL_ERROR_NO_TLS;
1142
1143 r = mailimap_starttls(imap);
1144
1145 switch (r) {
1146 case MAILIMAP_NO_ERROR:
1147 break;
1148 default:
1149 return imap_error_to_mail_error(r);
1150 }
1151
1152 low = mailstream_get_low(imap->imap_stream);
1153 fd = mailstream_low_get_fd(low);
1154 if (fd == -1)
1155 return MAIL_ERROR_STREAM;
1156
1157 new_low = mailstream_low_ssl_open(fd);
1158 if (new_low == NULL)
1159 return MAIL_ERROR_STREAM;
1160
1161 mailstream_low_free(low);
1162 mailstream_set_low(imap->imap_stream, new_low);
1163
1164 return MAIL_NO_ERROR;
1165}
1166
1167static int imapdriver_get_message(mailsession * session,
1168 uint32_t num, mailmessage ** result)
1169{
1170 mailmessage * msg_info;
1171 int r;
1172
1173 msg_info = mailmessage_new();
1174 if (msg_info == NULL)
1175 return MAIL_ERROR_MEMORY;
1176
1177 r = mailmessage_init(msg_info, session, imap_message_driver, num, 0);
1178 if (r != MAIL_NO_ERROR) {
1179 mailmessage_free(msg_info);
1180 return r;
1181 }
1182
1183 * result = msg_info;
1184
1185 return MAIL_NO_ERROR;
1186}
1187
1188/* Retrieve a message by UID
1189
1190 libEtPan! uid format for IMAP is "UIDVALIDITY-UID"
1191 where UIDVALIDITY and UID are decimal representation of
1192 respectively uidvalidity and uid numbers.
1193
1194 Return value:
1195 MAIL_ERROR_INVAL if uid is NULL or has an incorrect format.
1196 MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found
1197 MAIL_NO_ERROR if message was found. Result is in result
1198*/
1199
1200static int imapdriver_get_message_by_uid(mailsession * session,
1201 const char * uid,
1202 mailmessage ** result)
1203{
1204 uint32_t uidvalidity;
1205 uint32_t num;
1206 char * p1, * p2;
1207 mailimap * imap;
1208
1209 if (uid == NULL)
1210 return MAIL_ERROR_INVAL;
1211
1212 uidvalidity = strtoul(uid, &p1, 10);
1213 if (p1 == uid || * p1 != '-')
1214 return MAIL_ERROR_INVAL;
1215
1216 p1++;
1217 num = strtoul(p1, &p2, 10);
1218 if (p2 == p1 || * p2 != '\0')
1219 return MAIL_ERROR_INVAL;
1220
1221 imap = get_imap_session(session);
1222 if (imap->imap_selection_info->sel_uidvalidity != uidvalidity)
1223 return MAIL_ERROR_MSG_NOT_FOUND;
1224
1225 return imapdriver_get_message(session, num, result);
1226}