45f9b46343b0d616df53800ba00297469556b29d
[claws.git] / src / etpan / imap-thread.c
1 #ifdef HAVE_CONFIG_H
2 #  include "config.h"
3 #endif
4
5 #ifdef HAVE_LIBETPAN
6
7 #include "imap-thread.h"
8 #include <imap.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/mman.h>
13 #include <sys/wait.h>
14
15 #include <gtk/gtk.h>
16 #include "etpan-thread-manager.h"
17 #include "utils.h"
18
19 static struct etpan_thread_manager * thread_manager = NULL;
20 static chash * courier_workaround_hash = NULL;
21 static chash * imap_hash = NULL;
22 static chash * session_hash = NULL;
23 static guint thread_manager_signal = 0;
24 static GIOChannel * io_channel = NULL;
25
26
27 static gboolean thread_manager_event(GIOChannel * source,
28     GIOCondition condition,
29     gpointer data)
30 {
31         etpan_thread_manager_loop(thread_manager);
32         
33         return TRUE;
34 }
35
36
37 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
38
39 void imap_main_init(void)
40 {
41         int fd_thread_manager;
42         
43         mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
44         mailstream_network_delay.tv_usec = 0;
45         
46         if (debug_get_mode())
47                 mailstream_debug = 1;
48         
49         imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
50         session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
51         courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
52         
53         thread_manager = etpan_thread_manager_new();
54         
55         fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
56         
57         io_channel = g_io_channel_unix_new(fd_thread_manager);
58         
59         thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
60                                                     thread_manager_event,
61                                                     (gpointer) NULL,
62                                                     NULL);
63 }
64
65 void imap_main_set_timeout(int sec)
66 {
67         mailstream_network_delay.tv_sec = sec;
68         mailstream_network_delay.tv_usec = 0;
69 }
70
71 void imap_main_done(void)
72 {
73         etpan_thread_manager_stop(thread_manager);
74         etpan_thread_manager_join(thread_manager);
75         
76         g_source_remove(thread_manager_signal);
77         g_io_channel_unref(io_channel);
78         
79         etpan_thread_manager_free(thread_manager);
80         
81         chash_free(courier_workaround_hash);
82         chash_free(session_hash);
83         chash_free(imap_hash);
84 }
85
86 void imap_init(Folder * folder)
87 {
88         struct etpan_thread * thread;
89         chashdatum key;
90         chashdatum value;
91         
92         thread = etpan_thread_manager_get_thread(thread_manager);
93         
94         key.data = &folder;
95         key.len = sizeof(folder);
96         value.data = thread;
97         value.len = 0;
98         
99         chash_set(imap_hash, &key, &value, NULL);
100 }
101
102 void imap_done(Folder * folder)
103 {
104         struct etpan_thread * thread;
105         chashdatum key;
106         chashdatum value;
107         int r;
108         
109         key.data = &folder;
110         key.len = sizeof(folder);
111         
112         r = chash_get(imap_hash, &key, &value);
113         if (r < 0)
114                 return;
115         
116         thread = value.data;
117         
118         etpan_thread_unbind(thread);
119         
120         chash_delete(imap_hash, &key, NULL);
121         
122         debug_print("remove thread");
123 }
124
125 static struct etpan_thread * get_thread(Folder * folder)
126 {
127         struct etpan_thread * thread;
128         chashdatum key;
129         chashdatum value;
130         
131         key.data = &folder;
132         key.len = sizeof(folder);
133         
134         chash_get(imap_hash, &key, &value);
135         thread = value.data;
136         
137         return thread;
138 }
139
140 static mailimap * get_imap(Folder * folder)
141 {
142         mailimap * imap;
143         chashdatum key;
144         chashdatum value;
145         int r;
146         
147         key.data = &folder;
148         key.len = sizeof(folder);
149         
150         r = chash_get(session_hash, &key, &value);
151         if (r < 0)
152                 return NULL;
153         
154         imap = value.data;
155         
156         return imap;
157 }
158
159
160 static void generic_cb(int cancelled, void * result, void * callback_data)
161 {
162         int * p_finished;
163         
164         p_finished = callback_data;
165
166         debug_print("generic_cb\n");
167         
168         * p_finished = 1;
169 }
170
171 static void threaded_run(Folder * folder, void * param, void * result,
172                          void (* func)(struct etpan_thread_op * ))
173 {
174         struct etpan_thread_op * op;
175         struct etpan_thread * thread;
176         int finished;
177         
178         imap_folder_ref(folder);
179
180         op = etpan_thread_op_new();
181         op->param = param;
182         op->result = result;
183         
184         op->cancellable = 0;
185         op->run = func;
186         op->callback = generic_cb;
187         op->callback_data = &finished;
188         op->cleanup = NULL;
189         
190         finished = 0;
191         
192         thread = get_thread(folder);
193         etpan_thread_op_schedule(thread, op);
194         
195         while (!finished) {
196                 gtk_main_iteration();
197         }
198         
199         etpan_thread_op_free(op);
200
201         imap_folder_unref(folder);
202 }
203
204
205 /* connect */
206
207 struct connect_param {
208         mailimap * imap;
209         const char * server;
210         int port;
211 };
212
213 struct connect_result {
214         int error;
215 };
216
217 static void connect_run(struct etpan_thread_op * op)
218 {
219         int r;
220         struct connect_param * param;
221         struct connect_result * result;
222         
223         param = op->param;
224         result = op->result;
225         
226         r = mailimap_socket_connect(param->imap,
227                                     param->server, param->port);
228         
229         result->error = r;
230 }
231
232
233 int imap_threaded_connect(Folder * folder, const char * server, int port)
234 {
235         struct connect_param param;
236         struct connect_result result;
237         chashdatum key;
238         chashdatum value;
239         mailimap * imap;
240         
241         imap = mailimap_new(0, NULL);
242         
243         key.data = &folder;
244         key.len = sizeof(folder);
245         value.data = imap;
246         value.len = 0;
247         chash_set(session_hash, &key, &value, NULL);
248         
249         param.imap = imap;
250         param.server = server;
251         param.port = port;
252         
253         threaded_run(folder, &param, &result, connect_run);
254         
255         debug_print("connect ok %i\n", result.error);
256         
257         return result.error;
258 }
259
260
261 static void connect_ssl_run(struct etpan_thread_op * op)
262 {
263         int r;
264         struct connect_param * param;
265         struct connect_result * result;
266         
267         param = op->param;
268         result = op->result;
269         
270         r = mailimap_ssl_connect(param->imap,
271                                  param->server, param->port);
272         
273         result->error = r;
274 }
275
276 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
277 {
278         struct connect_param param;
279         struct connect_result result;
280         chashdatum key;
281         chashdatum value;
282         mailimap * imap;
283         
284         imap = mailimap_new(0, NULL);
285         
286         key.data = &folder;
287         key.len = sizeof(folder);
288         value.data = imap;
289         value.len = 0;
290         chash_set(session_hash, &key, &value, NULL);
291         
292         param.imap = imap;
293         param.server = server;
294         param.port = port;
295         
296         threaded_run(folder, &param, &result, connect_ssl_run);
297         
298         debug_print("connect ok\n");
299         
300         return result.error;
301 }
302         
303 struct disconnect_param {
304         mailimap * imap;
305 };
306
307 struct disconnect_result {
308         int error;
309 };
310
311 static void disconnect_run(struct etpan_thread_op * op)
312 {
313         int r;
314         struct disconnect_param * param;
315         struct disconnect_result * result;
316         
317         param = op->param;
318         result = op->result;
319         
320         r = mailimap_logout(param->imap);
321         
322         result->error = r;
323 }
324
325 void imap_threaded_disconnect(Folder * folder)
326 {
327         struct connect_param param;
328         struct connect_result result;
329         chashdatum key;
330         chashdatum value;
331         mailimap * imap;
332         
333         imap = get_imap(folder);
334         if (imap == NULL) {
335                 debug_print("was disconnected\n");
336                 return;
337         }
338         
339         param.imap = imap;
340         
341         threaded_run(folder, &param, &result, disconnect_run);
342         
343         key.data = &folder;
344         key.len = sizeof(folder);
345         value.data = imap;
346         value.len = 0;
347         chash_delete(session_hash, &key, NULL);
348         
349         key.data = &imap;
350         key.len = sizeof(imap);
351         chash_delete(courier_workaround_hash, &key, NULL);
352         
353         mailimap_free(imap);
354         
355         debug_print("disconnect ok\n");
356 }
357
358
359 struct list_param {
360         mailimap * imap;
361         const char * base;
362         const char * wildcard;
363 };
364
365 struct list_result {
366         int error;
367         clist * list;
368 };
369
370 static void list_run(struct etpan_thread_op * op)
371 {
372         struct list_param * param;
373         struct list_result * result;
374         int r;
375         clist * list;
376         
377         param = op->param;
378         list = NULL;
379         r = mailimap_list(param->imap, param->base,
380                           param->wildcard, &list);
381         
382         result = op->result;
383         result->error = r;
384         result->list = list;
385         debug_print("imap list run - end\n");
386 }
387
388 int imap_threaded_list(Folder * folder, const char * base,
389                        const char * wildcard,
390                        clist ** p_result)
391 {
392         struct list_param param;
393         struct list_result result;
394         
395         debug_print("imap list - begin\n");
396         
397         param.imap = get_imap(folder);
398         param.base = base;
399         param.wildcard = wildcard;
400         
401         threaded_run(folder, &param, &result, list_run);
402         
403         * p_result = result.list;
404         
405         debug_print("imap list - end %p\n", result.list);
406         
407         return result.error;
408 }
409
410
411
412 struct login_param {
413         mailimap * imap;
414         const char * login;
415         const char * password;
416 };
417
418 struct login_result {
419         int error;
420 };
421
422 static void login_run(struct etpan_thread_op * op)
423 {
424         struct login_param * param;
425         struct login_result * result;
426         int r;
427         
428         param = op->param;
429         r = mailimap_login(param->imap,
430                            param->login, param->password);
431         
432         result = op->result;
433         result->error = r;
434         debug_print("imap login run - end %i\n", r);
435 }
436
437 int imap_threaded_login(Folder * folder,
438                         const char * login, const char * password)
439 {
440         struct login_param param;
441         struct login_result result;
442         
443         debug_print("imap login - begin\n");
444         
445         param.imap = get_imap(folder);
446         param.login = login;
447         param.password = password;
448         
449         threaded_run(folder, &param, &result, login_run);
450         
451         debug_print("imap login - end\n");
452         
453         return result.error;
454 }
455
456
457 struct status_param {
458         mailimap * imap;
459         const char * mb;
460         struct mailimap_status_att_list * status_att_list;
461 };
462
463 struct status_result {
464         int error;
465         struct mailimap_mailbox_data_status * data_status;
466 };
467
468 static void status_run(struct etpan_thread_op * op)
469 {
470         struct status_param * param;
471         struct status_result * result;
472         int r;
473         
474         param = op->param;
475         result = op->result;
476         
477         r = mailimap_status(param->imap, param->mb,
478                             param->status_att_list,
479                             &result->data_status);
480         
481         result->error = r;
482         debug_print("imap status run - end %i\n", r);
483 }
484
485 int imap_threaded_status(Folder * folder, const char * mb,
486                          struct mailimap_mailbox_data_status ** data_status)
487 {
488         struct status_param param;
489         struct status_result result;
490         struct mailimap_status_att_list * status_att_list;
491         
492         debug_print("imap status - begin\n");
493         
494         status_att_list = mailimap_status_att_list_new_empty();
495         mailimap_status_att_list_add(status_att_list,
496                                      MAILIMAP_STATUS_ATT_MESSAGES);
497         mailimap_status_att_list_add(status_att_list,
498                                      MAILIMAP_STATUS_ATT_RECENT);
499         mailimap_status_att_list_add(status_att_list,
500                                      MAILIMAP_STATUS_ATT_UIDNEXT);
501         mailimap_status_att_list_add(status_att_list,
502                                      MAILIMAP_STATUS_ATT_UIDVALIDITY);
503         mailimap_status_att_list_add(status_att_list,
504                                      MAILIMAP_STATUS_ATT_UNSEEN);
505         
506         param.imap = get_imap(folder);
507         param.mb = mb;
508         param.status_att_list = status_att_list;
509         
510         threaded_run(folder, &param, &result, status_run);
511         
512         debug_print("imap status - end\n");
513         
514         * data_status = result.data_status;
515         
516         return result.error;
517 }
518
519
520
521 struct noop_param {
522         mailimap * imap;
523 };
524
525 struct noop_result {
526         int error;
527 };
528
529 static void noop_run(struct etpan_thread_op * op)
530 {
531         struct noop_param * param;
532         struct noop_result * result;
533         int r;
534         
535         param = op->param;
536         r = mailimap_noop(param->imap);
537         
538         result = op->result;
539         result->error = r;
540         debug_print("imap noop run - end %i\n", r);
541 }
542
543 int imap_threaded_noop(Folder * folder, unsigned int * p_exists)
544 {
545         struct noop_param param;
546         struct noop_result result;
547         mailimap * imap;
548         
549         debug_print("imap noop - begin\n");
550         
551         imap = get_imap(folder);
552         param.imap = imap;
553         
554         threaded_run(folder, &param, &result, noop_run);
555         
556         if (imap->imap_selection_info != NULL) {
557                 * p_exists = imap->imap_selection_info->sel_exists;
558         }
559         else {
560                 * p_exists = 0;
561         }
562         
563         debug_print("imap noop - end\n");
564         
565         return result.error;
566 }
567
568
569 struct starttls_param {
570         mailimap * imap;
571 };
572
573 struct starttls_result {
574         int error;
575 };
576
577 static void starttls_run(struct etpan_thread_op * op)
578 {
579         struct starttls_param * param;
580         struct starttls_result * result;
581         int r;
582         
583         param = op->param;
584         r = mailimap_starttls(param->imap);
585         
586         result = op->result;
587         result->error = r;
588         debug_print("imap starttls run - end %i\n", r);
589 }
590
591 int imap_threaded_starttls(Folder * folder)
592 {
593         struct starttls_param param;
594         struct starttls_result result;
595         
596         debug_print("imap starttls - begin\n");
597         
598         param.imap = get_imap(folder);
599         
600         threaded_run(folder, &param, &result, starttls_run);
601         
602         debug_print("imap starttls - end\n");
603         
604         return result.error;
605 }
606
607
608
609 struct create_param {
610         mailimap * imap;
611         const char * mb;
612 };
613
614 struct create_result {
615         int error;
616 };
617
618 static void create_run(struct etpan_thread_op * op)
619 {
620         struct create_param * param;
621         struct create_result * result;
622         int r;
623         
624         param = op->param;
625         r = mailimap_create(param->imap, param->mb);
626         
627         result = op->result;
628         result->error = r;
629         debug_print("imap create run - end %i\n", r);
630 }
631
632 int imap_threaded_create(Folder * folder, const char * mb)
633 {
634         struct create_param param;
635         struct create_result result;
636         
637         debug_print("imap create - begin\n");
638         
639         param.imap = get_imap(folder);
640         param.mb = mb;
641         
642         threaded_run(folder, &param, &result, create_run);
643         
644         debug_print("imap create - end\n");
645         
646         return result.error;
647 }
648
649
650
651
652 struct rename_param {
653         mailimap * imap;
654         const char * mb;
655         const char * new_name;
656 };
657
658 struct rename_result {
659         int error;
660 };
661
662 static void rename_run(struct etpan_thread_op * op)
663 {
664         struct rename_param * param;
665         struct rename_result * result;
666         int r;
667         
668         param = op->param;
669         r = mailimap_rename(param->imap, param->mb, param->new_name);
670         
671         result = op->result;
672         result->error = r;
673         debug_print("imap rename run - end %i\n", r);
674 }
675
676 int imap_threaded_rename(Folder * folder,
677                          const char * mb, const char * new_name)
678 {
679         struct rename_param param;
680         struct rename_result result;
681         
682         debug_print("imap rename - begin\n");
683         
684         param.imap = get_imap(folder);
685         param.mb = mb;
686         param.new_name = new_name;
687         
688         threaded_run(folder, &param, &result, rename_run);
689         
690         debug_print("imap rename - end\n");
691         
692         return result.error;
693 }
694
695
696
697
698 struct delete_param {
699         mailimap * imap;
700         const char * mb;
701 };
702
703 struct delete_result {
704         int error;
705 };
706
707 static void delete_run(struct etpan_thread_op * op)
708 {
709         struct delete_param * param;
710         struct delete_result * result;
711         int r;
712         
713         param = op->param;
714         r = mailimap_delete(param->imap, param->mb);
715         
716         result = op->result;
717         result->error = r;
718         debug_print("imap delete run - end %i\n", r);
719 }
720
721 int imap_threaded_delete(Folder * folder, const char * mb)
722 {
723         struct delete_param param;
724         struct delete_result result;
725         
726         debug_print("imap delete - begin\n");
727         
728         param.imap = get_imap(folder);
729         param.mb = mb;
730         
731         threaded_run(folder, &param, &result, delete_run);
732         
733         debug_print("imap delete - end\n");
734         
735         return result.error;
736 }
737
738
739
740 struct select_param {
741         mailimap * imap;
742         const char * mb;
743 };
744
745 struct select_result {
746         int error;
747 };
748
749 static void select_run(struct etpan_thread_op * op)
750 {
751         struct select_param * param;
752         struct select_result * result;
753         int r;
754         
755         param = op->param;
756         r = mailimap_select(param->imap, param->mb);
757         
758         result = op->result;
759         result->error = r;
760         debug_print("imap select run - end %i\n", r);
761 }
762
763 int imap_threaded_select(Folder * folder, const char * mb,
764                          gint * exists, gint * recent, gint * unseen,
765                          guint32 * uid_validity)
766 {
767         struct select_param param;
768         struct select_result result;
769         mailimap * imap;
770         
771         debug_print("imap select - begin\n");
772         
773         imap = get_imap(folder);
774         param.imap = imap;
775         param.mb = mb;
776         
777         threaded_run(folder, &param, &result, select_run);
778         
779         if (result.error != MAILIMAP_NO_ERROR)
780                 return result.error;
781         
782         if (imap->imap_selection_info == NULL)
783                 return MAILIMAP_ERROR_PARSE;
784         
785         * exists = imap->imap_selection_info->sel_exists;
786         * recent = imap->imap_selection_info->sel_recent;
787         * unseen = imap->imap_selection_info->sel_unseen;
788         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
789         
790         debug_print("imap select - end\n");
791         
792         return result.error;
793 }
794
795
796
797 struct examine_param {
798         mailimap * imap;
799         const char * mb;
800 };
801
802 struct examine_result {
803         int error;
804 };
805
806 static void examine_run(struct etpan_thread_op * op)
807 {
808         struct examine_param * param;
809         struct examine_result * result;
810         int r;
811         
812         param = op->param;
813         r = mailimap_examine(param->imap, param->mb);
814         
815         result = op->result;
816         result->error = r;
817         debug_print("imap examine run - end %i\n", r);
818 }
819
820 int imap_threaded_examine(Folder * folder, const char * mb,
821                           gint * exists, gint * recent, gint * unseen,
822                           guint32 * uid_validity)
823 {
824         struct examine_param param;
825         struct examine_result result;
826         mailimap * imap;
827         
828         debug_print("imap examine - begin\n");
829         
830         imap = get_imap(folder);
831         param.imap = imap;
832         param.mb = mb;
833         
834         threaded_run(folder, &param, &result, examine_run);
835         
836         if (result.error != MAILIMAP_NO_ERROR)
837                 return result.error;
838         
839         if (imap->imap_selection_info == NULL)
840                 return MAILIMAP_ERROR_PARSE;
841         
842         * exists = imap->imap_selection_info->sel_exists;
843         * recent = imap->imap_selection_info->sel_recent;
844         * unseen = imap->imap_selection_info->sel_unseen;
845         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
846         
847         debug_print("imap examine - end\n");
848         
849         return result.error;
850 }
851
852
853
854
855 struct search_param {
856         mailimap * imap;
857         int type;
858         struct mailimap_set * set;
859 };
860
861 struct search_result {
862         int error;
863         clist * search_result;
864 };
865
866 static void search_run(struct etpan_thread_op * op)
867 {
868         struct search_param * param;
869         struct search_result * result;
870         int r;
871         struct mailimap_search_key * key;
872         struct mailimap_search_key * uid_key;
873         struct mailimap_search_key * search_type_key;
874         clist * search_result;
875         
876         param = op->param;
877         
878         uid_key = mailimap_search_key_new_uid(param->set);
879         
880         search_type_key = NULL;
881         switch (param->type) {
882         case IMAP_SEARCH_TYPE_SIMPLE:
883                 search_type_key = NULL;
884                 break;
885                 
886         case IMAP_SEARCH_TYPE_SEEN:
887                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
888                                                           NULL, NULL, NULL, NULL, NULL,
889                                                           NULL, NULL, NULL, NULL, NULL,
890                                                           NULL, NULL, NULL, NULL, 0,
891                                                           NULL, NULL, NULL, NULL, NULL,
892                                                           NULL, 0, NULL, NULL, NULL);
893                 break;
894                 
895         case IMAP_SEARCH_TYPE_UNSEEN:
896                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
897                                                           NULL, NULL, NULL, NULL, NULL,
898                                                           NULL, NULL, NULL, NULL, NULL,
899                                                           NULL, NULL, NULL, NULL, 0,
900                                                           NULL, NULL, NULL, NULL, NULL,
901                                                           NULL, 0, NULL, NULL, NULL);
902                 break;
903                 
904         case IMAP_SEARCH_TYPE_ANSWERED:
905                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
906                                                           NULL, NULL, NULL, NULL, NULL,
907                                                           NULL, NULL, NULL, NULL, NULL,
908                                                           NULL, NULL, NULL, NULL, 0,
909                                                           NULL, NULL, NULL, NULL, NULL,
910                                                           NULL, 0, NULL, NULL, NULL);
911                 break;
912                 
913         case IMAP_SEARCH_TYPE_FLAGGED:
914                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
915                                                           NULL, NULL, NULL, NULL, NULL,
916                                                           NULL, NULL, NULL, NULL, NULL,
917                                                           NULL, NULL, NULL, NULL, 0,
918                                                           NULL, NULL, NULL, NULL, NULL,
919                                                           NULL, 0, NULL, NULL, NULL);
920                 break;
921         }
922         
923         if (search_type_key != NULL) {
924                 key = mailimap_search_key_new_multiple_empty();
925                 mailimap_search_key_multiple_add(key, search_type_key);
926                 mailimap_search_key_multiple_add(key, uid_key);
927         }
928         else {
929                 key = uid_key;
930         }
931         
932         r = mailimap_uid_search(param->imap, NULL, key, &search_result);
933         
934         result = op->result;
935         result->error = r;
936         result->search_result = search_result;
937         debug_print("imap search run - end %i\n", r);
938 }
939
940 int imap_threaded_search(Folder * folder, int search_type,
941                          struct mailimap_set * set, clist ** search_result)
942 {
943         struct search_param param;
944         struct search_result result;
945         mailimap * imap;
946         
947         debug_print("imap search - begin\n");
948         
949         imap = get_imap(folder);
950         param.imap = imap;
951         param.set = set;
952         param.type = search_type;
953         
954         threaded_run(folder, &param, &result, search_run);
955         
956         if (result.error != MAILIMAP_NO_ERROR)
957                 return result.error;
958         
959         debug_print("imap search - end\n");
960         
961         * search_result = result.search_result;
962         
963         return result.error;
964 }
965
966
967
968
969 static int
970 uid_list_to_env_list(clist * fetch_result, carray ** result)
971 {
972         clistiter * cur;
973         int r;
974         int res;
975         carray * tab;
976         unsigned int i;
977         
978         tab = carray_new(128);
979         if (tab == NULL) {
980                 res = MAILIMAP_ERROR_MEMORY;
981                 goto err;
982         }
983         
984         for(cur = clist_begin(fetch_result) ; cur != NULL ;
985             cur = clist_next(cur)) {
986                 struct mailimap_msg_att * msg_att;
987                 clistiter * item_cur;
988                 uint32_t uid;
989                 size_t size;
990                 uint32_t * puid;
991                 
992                 msg_att = clist_content(cur);
993                 
994                 uid = 0;
995                 size = 0;
996                 for(item_cur = clist_begin(msg_att->att_list) ;
997                     item_cur != NULL ;
998                     item_cur = clist_next(item_cur)) {
999                         struct mailimap_msg_att_item * item;
1000                         
1001                         item = clist_content(item_cur);
1002                         
1003                         switch (item->att_type) {
1004                         case MAILIMAP_MSG_ATT_ITEM_STATIC:
1005                                 switch (item->att_data.att_static->att_type) {
1006                                 case MAILIMAP_MSG_ATT_UID:
1007                                         uid = item->att_data.att_static->att_data.att_uid;
1008                                         break;
1009                                 }
1010                         }
1011                 }
1012                 
1013                 puid = malloc(sizeof(* puid));
1014                 if (puid == NULL) {
1015                         res = MAILIMAP_ERROR_MEMORY;
1016                         goto free_list;
1017                 }
1018                 * puid = uid;
1019                         
1020                 r = carray_add(tab, puid, NULL);
1021                 if (r < 0) {
1022                         free(puid);
1023                         res = MAILIMAP_ERROR_MEMORY;
1024                         goto free_list;
1025                 }
1026         }
1027                 
1028         * result = tab;
1029
1030         return MAILIMAP_NO_ERROR;
1031   
1032  free_list:
1033         for(i = 0 ; i < carray_count(tab) ; i++)
1034                 mailmessage_free(carray_get(tab, i));
1035  err:
1036         return res;
1037 }
1038
1039 static int imap_get_messages_list(mailimap * imap,
1040                                   uint32_t first_index,
1041                                   carray ** result)
1042 {
1043         carray * env_list;
1044         int r;
1045         struct mailimap_fetch_att * fetch_att;
1046         struct mailimap_fetch_type * fetch_type;
1047         struct mailimap_set * set;
1048         clist * fetch_result;
1049         int res;
1050         
1051         set = mailimap_set_new_interval(first_index, 0);
1052         if (set == NULL) {
1053                 res = MAILIMAP_ERROR_MEMORY;
1054                 goto err;
1055         }
1056
1057         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1058         if (fetch_type == NULL) {
1059                 res = MAILIMAP_ERROR_MEMORY;
1060                 goto free_set;
1061         }
1062
1063         fetch_att = mailimap_fetch_att_new_uid();
1064         if (fetch_att == NULL) {
1065                 res = MAILIMAP_ERROR_MEMORY;
1066                 goto free_fetch_type;
1067         }
1068
1069         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1070         if (r != MAILIMAP_NO_ERROR) {
1071                 mailimap_fetch_att_free(fetch_att);
1072                 res = MAILIMAP_ERROR_MEMORY;
1073                 goto free_fetch_type;
1074         }
1075
1076         r = mailimap_uid_fetch(imap, set,
1077                                fetch_type, &fetch_result);
1078
1079         mailimap_fetch_type_free(fetch_type);
1080         mailimap_set_free(set);
1081
1082         if (r != MAILIMAP_NO_ERROR) {
1083                 res = r;
1084                 goto err;
1085         }
1086
1087         env_list = NULL;
1088         r = uid_list_to_env_list(fetch_result, &env_list);
1089         mailimap_fetch_list_free(fetch_result);
1090         
1091         * result = env_list;
1092
1093         return MAILIMAP_NO_ERROR;
1094
1095  free_fetch_type:
1096         mailimap_fetch_type_free(fetch_type);
1097  free_set:
1098         mailimap_set_free(set);
1099  err:
1100         return res;
1101 }
1102
1103
1104
1105
1106 struct fetch_uid_param {
1107         mailimap * imap;
1108         uint32_t first_index;
1109 };
1110
1111 struct fetch_uid_result {
1112         int error;
1113         carray * fetch_result;
1114 };
1115
1116 static void fetch_uid_run(struct etpan_thread_op * op)
1117 {
1118         struct fetch_uid_param * param;
1119         struct fetch_uid_result * result;
1120         carray * fetch_result;
1121         int r;
1122         
1123         param = op->param;
1124         
1125         fetch_result = NULL;
1126         r = imap_get_messages_list(param->imap, param->first_index,
1127                                    &fetch_result);
1128         
1129         result = op->result;
1130         result->error = r;
1131         result->fetch_result = fetch_result;
1132         debug_print("imap fetch_uid run - end %i\n", r);
1133 }
1134
1135 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1136                             carray ** fetch_result)
1137 {
1138         struct fetch_uid_param param;
1139         struct fetch_uid_result result;
1140         mailimap * imap;
1141         
1142         debug_print("imap fetch_uid - begin\n");
1143         
1144         imap = get_imap(folder);
1145         param.imap = imap;
1146         param.first_index = first_index;
1147         
1148         threaded_run(folder, &param, &result, fetch_uid_run);
1149         
1150         if (result.error != MAILIMAP_NO_ERROR)
1151                 return result.error;
1152         
1153         debug_print("imap fetch_uid - end\n");
1154         
1155         * fetch_result = result.fetch_result;
1156         
1157         return result.error;
1158 }
1159
1160
1161 void imap_fetch_uid_list_free(carray * uid_list)
1162 {
1163         unsigned int i;
1164         
1165         for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1166                 uint32_t * puid;
1167                 
1168                 puid = carray_get(uid_list, i);
1169                 free(puid);
1170         }
1171         carray_free(uid_list);
1172 }
1173
1174
1175
1176 static int imap_fetch(mailimap * imap,
1177                       uint32_t msg_index,
1178                       char ** result,
1179                       size_t * result_len)
1180 {
1181         int r;
1182         struct mailimap_set * set;
1183         struct mailimap_fetch_att * fetch_att;
1184         struct mailimap_fetch_type * fetch_type;
1185         clist * fetch_result;
1186         struct mailimap_msg_att * msg_att;
1187         struct mailimap_msg_att_item * msg_att_item;
1188         char * text;
1189         size_t text_length;
1190         int res;
1191         clistiter * cur;
1192         struct mailimap_section * section;
1193
1194         set = mailimap_set_new_single(msg_index);
1195         if (set == NULL) {
1196                 res = MAILIMAP_ERROR_MEMORY;
1197                 goto err;
1198         }
1199
1200         section = mailimap_section_new(NULL);
1201         if (section == NULL) {
1202                 res = MAILIMAP_ERROR_MEMORY;
1203                 goto free_set;
1204         }
1205   
1206         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1207         if (fetch_att == NULL) {
1208                 mailimap_section_free(section);
1209                 res = MAILIMAP_ERROR_MEMORY;
1210                 goto free_set;
1211         }
1212   
1213         fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1214         if (fetch_type == NULL) {
1215                 res = MAILIMAP_ERROR_MEMORY;
1216                 goto free_fetch_att;
1217         }
1218
1219         r = mailimap_uid_fetch(imap, set,
1220                                fetch_type, &fetch_result);
1221   
1222         mailimap_fetch_type_free(fetch_type);
1223         mailimap_set_free(set);
1224   
1225         switch (r) {
1226         case MAILIMAP_NO_ERROR:
1227                 break;
1228         default:
1229                 return r;
1230         }
1231   
1232         if (clist_begin(fetch_result) == NULL) {
1233                 mailimap_fetch_list_free(fetch_result);
1234                 return MAILIMAP_ERROR_FETCH;
1235         }
1236
1237         msg_att = clist_begin(fetch_result)->data;
1238
1239         text = NULL;
1240         text_length = 0;
1241
1242         for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1243             cur = clist_next(cur)) {
1244                 msg_att_item = clist_content(cur);
1245
1246                 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1247                         if (msg_att_item->att_data.att_static->att_type ==
1248                             MAILIMAP_MSG_ATT_BODY_SECTION) {
1249                                 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1250                                 /* detach */
1251                                 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1252                                 text_length =
1253                                         msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1254                         }
1255                 }
1256         }
1257
1258         mailimap_fetch_list_free(fetch_result);
1259
1260         if (text == NULL)
1261                 return MAILIMAP_ERROR_FETCH;
1262
1263         * result = text;
1264         * result_len = text_length;
1265   
1266         return MAILIMAP_NO_ERROR;
1267
1268  free_fetch_att:
1269         mailimap_fetch_att_free(fetch_att);
1270  free_set:
1271         mailimap_set_free(set);
1272  err:
1273         return res;
1274 }
1275
1276 static int imap_fetch_header(mailimap * imap,
1277                              uint32_t msg_index,
1278                              char ** result,
1279                              size_t * result_len)
1280 {
1281   int r;
1282   struct mailimap_set * set;
1283   struct mailimap_fetch_att * fetch_att;
1284   struct mailimap_fetch_type * fetch_type;
1285   clist * fetch_result;
1286   struct mailimap_msg_att * msg_att;
1287   struct mailimap_msg_att_item * msg_att_item;
1288   char * text;
1289   size_t text_length;
1290   int res;
1291   clistiter * cur;
1292   struct mailimap_section * section;
1293   
1294   set = mailimap_set_new_single(msg_index);
1295   if (set == NULL) {
1296     res = MAILIMAP_ERROR_MEMORY;
1297     goto err;
1298   }
1299
1300   section = mailimap_section_new_header();
1301   if (section == NULL) {
1302     res = MAILIMAP_ERROR_MEMORY;
1303     goto free_set;
1304   }
1305   
1306   fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1307   if (fetch_att == NULL) {
1308     mailimap_section_free(section);
1309     res = MAILIMAP_ERROR_MEMORY;
1310     goto free_set;
1311   }
1312   
1313   fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1314   if (fetch_type == NULL) {
1315     res = MAILIMAP_ERROR_MEMORY;
1316     goto free_fetch_att;
1317   }
1318
1319   r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1320   
1321   mailimap_fetch_type_free(fetch_type);
1322   mailimap_set_free(set);
1323
1324   switch (r) {
1325   case MAILIMAP_NO_ERROR:
1326     break;
1327   default:
1328     return r;
1329   }
1330
1331   if (clist_begin(fetch_result) == NULL) {
1332     mailimap_fetch_list_free(fetch_result);
1333     return MAILIMAP_ERROR_FETCH;
1334   }
1335
1336   msg_att = clist_begin(fetch_result)->data;
1337
1338   text = NULL;
1339   text_length = 0;
1340
1341   for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1342       cur = clist_next(cur)) {
1343     msg_att_item = clist_content(cur);
1344
1345     if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1346       if (msg_att_item->att_data.att_static->att_type ==
1347           MAILIMAP_MSG_ATT_BODY_SECTION) {
1348         text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1349         msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1350         text_length =
1351           msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1352       }
1353     }
1354   }
1355
1356   mailimap_fetch_list_free(fetch_result);
1357
1358   if (text == NULL)
1359     return MAILIMAP_ERROR_FETCH;
1360
1361   * result = text;
1362   * result_len = text_length;
1363
1364   return MAILIMAP_NO_ERROR;
1365
1366  free_fetch_att:
1367   mailimap_fetch_att_free(fetch_att);
1368  free_set:
1369   mailimap_set_free(set);
1370  err:
1371   return res;
1372 }
1373
1374
1375
1376 struct fetch_content_param {
1377         mailimap * imap;
1378         uint32_t msg_index;
1379         const char * filename;
1380         int with_body;
1381 };
1382
1383 struct fetch_content_result {
1384         int error;
1385 };
1386
1387 static void fetch_content_run(struct etpan_thread_op * op)
1388 {
1389         struct fetch_content_param * param;
1390         struct fetch_content_result * result;
1391         char * content;
1392         size_t content_size;
1393         int r;
1394         int fd;
1395         FILE * f;
1396         
1397         param = op->param;
1398         
1399         content = NULL;
1400         content_size = 0;
1401         if (param->with_body)
1402                 r = imap_fetch(param->imap, param->msg_index,
1403                                &content, &content_size);
1404         else
1405                 r = imap_fetch_header(param->imap, param->msg_index,
1406                                       &content, &content_size);
1407         
1408         result = op->result;
1409         result->error = r;
1410         
1411         if (r == MAILIMAP_NO_ERROR) {
1412                 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
1413                 if (fd < 0) {
1414                         result->error = MAILIMAP_ERROR_FETCH;
1415                         goto free;
1416                 }
1417                 
1418                 f = fdopen(fd, "wb");
1419                 if (f == NULL) {
1420                         result->error = MAILIMAP_ERROR_FETCH;
1421                         goto close;
1422                 }
1423                 
1424                 r = fwrite(content, 1, content_size, f);
1425                 if (r == 0) {
1426                         goto fclose;
1427                 }
1428                 
1429                 r = fclose(f);
1430                 if (r == EOF) {
1431                         unlink(param->filename);
1432                         goto close;
1433                 }
1434                 goto free;
1435                 
1436         fclose:
1437                 fclose(f);
1438                 goto unlink;
1439         close:
1440                 close(fd);
1441         unlink:
1442                 unlink(param->filename);
1443         
1444         free:
1445                 if (mmap_string_unref(content) != 0)
1446                         free(content);
1447         }
1448         
1449         debug_print("imap fetch_content run - end %i\n", r);
1450 }
1451
1452 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
1453                                 int with_body,
1454                                 const char * filename)
1455 {
1456         struct fetch_content_param param;
1457         struct fetch_content_result result;
1458         mailimap * imap;
1459         
1460         debug_print("imap fetch_content - begin\n");
1461         
1462         imap = get_imap(folder);
1463         param.imap = imap;
1464         param.msg_index = msg_index;
1465         param.filename = filename;
1466         param.with_body = with_body;
1467         
1468         threaded_run(folder, &param, &result, fetch_content_run);
1469         
1470         if (result.error != MAILIMAP_NO_ERROR)
1471                 return result.error;
1472         
1473         debug_print("imap fetch_content - end\n");
1474         
1475         return result.error;
1476 }
1477
1478
1479
1480 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
1481 {
1482         int flags;
1483         clist * flag_list;
1484         clistiter * cur;
1485         
1486         flags = MSG_UNREAD;
1487         
1488         flag_list = att_dyn->att_list;
1489         if (flag_list == NULL)
1490                 return flags;
1491         
1492         for(cur = clist_begin(flag_list) ; cur != NULL ;
1493             cur = clist_next(cur)) {
1494                 struct mailimap_flag_fetch * flag_fetch;
1495                         
1496                 flag_fetch = clist_content(cur);
1497                 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
1498                         flags |= MSG_NEW;
1499                 else {
1500                         switch (flag_fetch->fl_flag->fl_type) {
1501                         case MAILIMAP_FLAG_ANSWERED:
1502                                 flags |= MSG_REPLIED;
1503                                 break;
1504                         case MAILIMAP_FLAG_FLAGGED:
1505                                 flags |= MSG_MARKED;
1506                                 break;
1507                         case MAILIMAP_FLAG_DELETED:
1508                                 flags |= MSG_DELETED;
1509                                 break;
1510                         case MAILIMAP_FLAG_SEEN:
1511                                 flags &= ~MSG_UNREAD;
1512                                 flags &= ~MSG_NEW;
1513                                 break;
1514                         }
1515                 }
1516         }
1517         
1518         return flags;
1519 }
1520
1521 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1522                                  uint32_t * puid,
1523                                  char ** pheaders,
1524                                  size_t * pref_size,
1525                                  struct mailimap_msg_att_dynamic ** patt_dyn)
1526 {
1527   clistiter * item_cur;
1528   uint32_t uid;
1529   char * headers;
1530   size_t ref_size;
1531   struct mailimap_msg_att_dynamic * att_dyn;
1532
1533   uid = 0;
1534   headers = NULL;
1535   ref_size = 0;
1536   att_dyn = NULL;
1537
1538   for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
1539       item_cur = clist_next(item_cur)) {
1540     struct mailimap_msg_att_item * item;
1541
1542     item = clist_content(item_cur);
1543       
1544     switch (item->att_type) {
1545     case MAILIMAP_MSG_ATT_ITEM_STATIC:
1546       switch (item->att_data.att_static->att_type) {
1547       case MAILIMAP_MSG_ATT_UID:
1548         uid = item->att_data.att_static->att_data.att_uid;
1549         break;
1550
1551       case MAILIMAP_MSG_ATT_BODY_SECTION:
1552         if (headers == NULL) {
1553           headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
1554         }
1555         break;
1556       case MAILIMAP_MSG_ATT_RFC822_SIZE:
1557               ref_size = item->att_data.att_static->att_data.att_rfc822_size;
1558               break;
1559       }
1560       break;
1561       
1562     case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
1563       if (att_dyn == NULL) {
1564         att_dyn = item->att_data.att_dyn;
1565       }
1566       break;
1567     }
1568   }
1569
1570   if (puid != NULL)
1571     * puid = uid;
1572   if (pheaders != NULL)
1573     * pheaders = headers;
1574   if (pref_size != NULL)
1575     * pref_size = ref_size;
1576   if (patt_dyn != NULL)
1577     * patt_dyn = att_dyn;
1578
1579   return MAIL_NO_ERROR;
1580 }
1581
1582 static struct imap_fetch_env_info *
1583 fetch_to_env_info(struct mailimap_msg_att * msg_att)
1584 {
1585         struct imap_fetch_env_info * info;
1586         uint32_t uid;
1587         char * headers;
1588         size_t size;
1589         struct mailimap_msg_att_dynamic * att_dyn;
1590         
1591         imap_get_msg_att_info(msg_att, &uid, &headers, &size,
1592                               &att_dyn);
1593         
1594         info = malloc(sizeof(* info));
1595         info->uid = uid;
1596         info->headers = strdup(headers);
1597         info->size = size;
1598         info->flags = imap_flags_to_flags(att_dyn);
1599         
1600         return info;
1601 }
1602
1603 static int
1604 imap_fetch_result_to_envelop_list(clist * fetch_result,
1605                                   carray ** p_env_list)
1606 {
1607         clistiter * cur;
1608         unsigned int i;
1609         carray * env_list;
1610   
1611         i = 0;
1612   
1613         env_list = carray_new(16);
1614   
1615         for(cur = clist_begin(fetch_result) ; cur != NULL ;
1616             cur = clist_next(cur)) {
1617                 struct mailimap_msg_att * msg_att;
1618                 struct imap_fetch_env_info * env_info;
1619     
1620                 msg_att = clist_content(cur);
1621
1622                 env_info = fetch_to_env_info(msg_att);
1623                 carray_add(env_list, env_info, NULL);
1624         }
1625   
1626         * p_env_list = env_list;
1627   
1628         return MAIL_NO_ERROR;
1629 }
1630
1631 int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
1632 {
1633         struct mailimap_fetch_att * fetch_att;
1634         int r;
1635         char * header;
1636         clist * hdrlist;
1637         struct mailimap_header_list * imap_hdrlist;
1638         struct mailimap_section * section;
1639
1640         hdrlist = clist_new();
1641   
1642         header = strdup("Date");
1643         r = clist_append(hdrlist, header);
1644         header = strdup("From");
1645         r = clist_append(hdrlist, header);
1646         header = strdup("To");
1647         r = clist_append(hdrlist, header);
1648         header = strdup("Cc");
1649         r = clist_append(hdrlist, header);
1650         header = strdup("Subject");
1651         r = clist_append(hdrlist, header);
1652         header = strdup("Message-ID");
1653         r = clist_append(hdrlist, header);
1654         header = strdup("References");
1655         r = clist_append(hdrlist, header);
1656         header = strdup("In-Reply-To");
1657         r = clist_append(hdrlist, header);
1658   
1659         imap_hdrlist = mailimap_header_list_new(hdrlist);
1660         section = mailimap_section_new_header_fields(imap_hdrlist);
1661         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1662         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1663   
1664         return MAIL_NO_ERROR;
1665 }
1666
1667 int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
1668 {
1669         struct mailimap_fetch_att * fetch_att;
1670         struct mailimap_section * section;
1671         
1672         section = mailimap_section_new_header();
1673         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1674         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1675         
1676         return MAIL_NO_ERROR;
1677 }
1678
1679 static int
1680 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
1681                         carray ** p_env_list)
1682 {
1683         struct mailimap_fetch_att * fetch_att;
1684         struct mailimap_fetch_type * fetch_type;
1685         int res;
1686         clist * fetch_result;
1687         int r;
1688         carray * env_list;
1689         chashdatum key;
1690         chashdatum value;
1691         
1692         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1693   
1694         /* uid */
1695         fetch_att = mailimap_fetch_att_new_uid();
1696         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1697   
1698         /* flags */
1699         fetch_att = mailimap_fetch_att_new_flags();
1700         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1701   
1702         /* rfc822 size */
1703         fetch_att = mailimap_fetch_att_new_rfc822_size();
1704         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1705   
1706         /* headers */
1707         key.data = &imap;
1708         key.len = sizeof(imap);
1709         r = chash_get(courier_workaround_hash, &key, &value);
1710         if (r < 0)
1711                 r = imap_add_envelope_fetch_att(fetch_type);
1712         else
1713                 r = imap_add_header_fetch_att(fetch_type);
1714         
1715         r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1716         
1717         switch (r) {
1718         case MAILIMAP_NO_ERROR:
1719                 break;
1720         default:
1721                 mailimap_fetch_type_free(fetch_type);
1722                 return r;
1723         }
1724         
1725         if (clist_begin(fetch_result) == NULL) {
1726                 res = MAILIMAP_ERROR_FETCH;
1727                 goto err;
1728         }
1729         
1730         r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
1731         mailimap_fetch_list_free(fetch_result);
1732         
1733         if (r != MAILIMAP_NO_ERROR) {
1734                 mailimap_fetch_type_free(fetch_type);
1735                 res = MAILIMAP_ERROR_MEMORY;
1736                 goto err;
1737         }
1738         
1739         mailimap_fetch_type_free(fetch_type);
1740         
1741         * p_env_list = env_list;
1742         
1743         return MAILIMAP_NO_ERROR;
1744   
1745  err:
1746         return res;
1747 }
1748
1749 struct fetch_env_param {
1750         mailimap * imap;
1751         struct mailimap_set * set;
1752 };
1753
1754 struct fetch_env_result {
1755         carray * fetch_env_result;
1756         int error;
1757 };
1758
1759 static void fetch_env_run(struct etpan_thread_op * op)
1760 {
1761         struct fetch_env_param * param;
1762         struct fetch_env_result * result;
1763         carray * env_list;
1764         int r;
1765         
1766         param = op->param;
1767         
1768         env_list = NULL;
1769         r = imap_get_envelopes_list(param->imap, param->set,
1770                                     &env_list);
1771         
1772         result = op->result;
1773         result->error = r;
1774         result->fetch_env_result = env_list;
1775         
1776         debug_print("imap fetch_env run - end %i\n", r);
1777 }
1778
1779 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
1780                             carray ** p_env_list)
1781 {
1782         struct fetch_env_param param;
1783         struct fetch_env_result result;
1784         mailimap * imap;
1785         
1786         debug_print("imap fetch_env - begin\n");
1787         
1788         imap = get_imap(folder);
1789         param.imap = imap;
1790         param.set = set;
1791         
1792         threaded_run(folder, &param, &result, fetch_env_run);
1793         
1794         if (result.error != MAILIMAP_NO_ERROR) {
1795                 chashdatum key;
1796                 chashdatum value;
1797                 int r;
1798                 
1799                 key.data = &imap;
1800                 key.len = sizeof(imap);
1801                 r = chash_get(courier_workaround_hash, &key, &value);
1802                 if (r < 0) {
1803                         value.data = NULL;
1804                         value.len = 0;
1805                         chash_set(courier_workaround_hash, &key, &value, NULL);
1806                         
1807                         threaded_run(folder, &param, &result, fetch_env_run);
1808                 }
1809         }
1810         
1811         if (result.error != MAILIMAP_NO_ERROR)
1812                 return result.error;
1813         
1814         debug_print("imap fetch_env - end\n");
1815         
1816         * p_env_list = result.fetch_env_result;
1817         
1818         return result.error;
1819 }
1820
1821 void imap_fetch_env_free(carray * env_list)
1822 {
1823         unsigned int i;
1824         
1825         for(i = 0 ; i < carray_count(env_list) ; i ++) {
1826                 struct imap_fetch_env_info * env_info;
1827                 
1828                 env_info = carray_get(env_list, i);
1829                 free(env_info->headers);
1830                 free(env_info);
1831         }
1832         carray_free(env_list);
1833 }
1834
1835
1836
1837
1838
1839 struct append_param {
1840         mailimap * imap;
1841         const char * mailbox;
1842         const char * filename;
1843         struct mailimap_flag_list * flag_list;
1844 };
1845
1846 struct append_result {
1847         int error;
1848 };
1849
1850 static void append_run(struct etpan_thread_op * op)
1851 {
1852         struct append_param * param;
1853         struct append_result * result;
1854         int r;
1855         char * data;
1856         size_t size;
1857         struct stat stat_buf;
1858         int fd;
1859         
1860         param = op->param;
1861         result = op->result;
1862         
1863         r = stat(param->filename, &stat_buf);
1864         if (r < 0) {
1865                 result->error = MAILIMAP_ERROR_APPEND;
1866                 return;
1867         }
1868         size = stat_buf.st_size;
1869         
1870         fd = open(param->filename, O_RDONLY);
1871         if (fd < 0) {
1872                 result->error = MAILIMAP_ERROR_APPEND;
1873                 return;
1874         }
1875         
1876         data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
1877         if (data == (void *) MAP_FAILED) {
1878                 close(fd);
1879                 result->error = MAILIMAP_ERROR_APPEND;
1880                 return;
1881         }
1882         
1883         r = mailimap_append(param->imap, param->mailbox,
1884                             param->flag_list, NULL,
1885                             data, size);
1886         
1887         munmap(data, size);
1888         close(fd);
1889         
1890         result->error = r;
1891         
1892         debug_print("imap append run - end %i\n", r);
1893 }
1894
1895 int imap_threaded_append(Folder * folder, const char * mailbox,
1896                          const char * filename,
1897                          struct mailimap_flag_list * flag_list)
1898 {
1899         struct append_param param;
1900         struct append_result result;
1901         mailimap * imap;
1902         
1903         debug_print("imap append - begin\n");
1904         
1905         imap = get_imap(folder);
1906         param.imap = imap;
1907         param.mailbox = mailbox;
1908         param.filename = filename;
1909         param.flag_list = flag_list;
1910         
1911         threaded_run(folder, &param, &result, append_run);
1912         
1913         if (result.error != MAILIMAP_NO_ERROR)
1914                 return result.error;
1915         
1916         debug_print("imap append - end\n");
1917         
1918         return result.error;
1919 }
1920
1921
1922
1923
1924 struct expunge_param {
1925         mailimap * imap;
1926 };
1927
1928 struct expunge_result {
1929         int error;
1930 };
1931
1932 static void expunge_run(struct etpan_thread_op * op)
1933 {
1934         struct expunge_param * param;
1935         struct expunge_result * result;
1936         int r;
1937         
1938         param = op->param;
1939         r = mailimap_expunge(param->imap);
1940         
1941         result = op->result;
1942         result->error = r;
1943         debug_print("imap expunge run - end %i\n", r);
1944 }
1945
1946 int imap_threaded_expunge(Folder * folder)
1947 {
1948         struct expunge_param param;
1949         struct expunge_result result;
1950         
1951         debug_print("imap expunge - begin\n");
1952         
1953         param.imap = get_imap(folder);
1954         
1955         threaded_run(folder, &param, &result, expunge_run);
1956         
1957         debug_print("imap expunge - end\n");
1958         
1959         return result.error;
1960 }
1961
1962
1963 struct copy_param {
1964         mailimap * imap;
1965         struct mailimap_set * set;
1966         const char * mb;
1967 };
1968
1969 struct copy_result {
1970         int error;
1971 };
1972
1973 static void copy_run(struct etpan_thread_op * op)
1974 {
1975         struct copy_param * param;
1976         struct copy_result * result;
1977         int r;
1978         
1979         param = op->param;
1980         
1981         r = mailimap_uid_copy(param->imap, param->set, param->mb);
1982         
1983         result = op->result;
1984         result->error = r;
1985         
1986         debug_print("imap copy run - end %i\n", r);
1987 }
1988
1989 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
1990                        const char * mb)
1991 {
1992         struct copy_param param;
1993         struct copy_result result;
1994         mailimap * imap;
1995         
1996         debug_print("imap copy - begin\n");
1997         
1998         imap = get_imap(folder);
1999         param.imap = imap;
2000         param.set = set;
2001         param.mb = mb;
2002         
2003         threaded_run(folder, &param, &result, copy_run);
2004         
2005         if (result.error != MAILIMAP_NO_ERROR)
2006                 return result.error;
2007         
2008         debug_print("imap copy - end\n");
2009         
2010         return result.error;
2011 }
2012
2013
2014
2015 struct store_param {
2016         mailimap * imap;
2017         struct mailimap_set * set;
2018         struct mailimap_store_att_flags * store_att_flags;
2019 };
2020
2021 struct store_result {
2022         int error;
2023 };
2024
2025 static void store_run(struct etpan_thread_op * op)
2026 {
2027         struct store_param * param;
2028         struct store_result * result;
2029         int r;
2030         
2031         param = op->param;
2032         
2033         r = mailimap_uid_store(param->imap, param->set,
2034                                param->store_att_flags);
2035         
2036         result = op->result;
2037         result->error = r;
2038         
2039         debug_print("imap store run - end %i\n", r);
2040 }
2041
2042 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
2043                         struct mailimap_store_att_flags * store_att_flags)
2044 {
2045         struct store_param param;
2046         struct store_result result;
2047         mailimap * imap;
2048         
2049         debug_print("imap store - begin\n");
2050         
2051         imap = get_imap(folder);
2052         param.imap = imap;
2053         param.set = set;
2054         param.store_att_flags = store_att_flags;
2055         
2056         threaded_run(folder, &param, &result, store_run);
2057         
2058         if (result.error != MAILIMAP_NO_ERROR)
2059                 return result.error;
2060         
2061         debug_print("imap store - end\n");
2062         
2063         return result.error;
2064 }
2065
2066
2067
2068 static void do_exec_command(int fd, const char * command,
2069                             const char * servername, uint16_t port)
2070 {
2071         int i, maxopen;
2072   
2073         if (fork() > 0) {
2074                 /* Fork again to become a child of init rather than
2075                    the etpan client. */
2076                 exit(0);
2077         }
2078   
2079         if (servername)
2080                 setenv("ETPANSERVER", servername, 1);
2081         else
2082                 unsetenv("ETPANSERVER");
2083   
2084         if (port) {
2085                 char porttext[20];
2086     
2087                 snprintf(porttext, sizeof(porttext), "%d", port);
2088                 setenv("ETPANPORT", porttext, 1);
2089         }
2090         else {
2091                 unsetenv("ETPANPORT");
2092         }
2093   
2094         /* Not a lot we can do if there's an error other than bail. */
2095         if (dup2(fd, 0) == -1)
2096                 exit(1);
2097         if (dup2(fd, 1) == -1)
2098                 exit(1);
2099   
2100         /* Should we close stderr and reopen /dev/null? */
2101   
2102         maxopen = sysconf(_SC_OPEN_MAX);
2103         for (i=3; i < maxopen; i++)
2104                 close(i);
2105   
2106 #ifdef TIOCNOTTY
2107         /* Detach from the controlling tty if we have one. Otherwise,
2108            SSH might do something stupid like trying to use it instead
2109            of running $SSH_ASKPASS. Doh. */
2110         fd = open("/dev/tty", O_RDONLY);
2111         if (fd != -1) {
2112                 ioctl(fd, TIOCNOTTY, NULL);
2113                 close(fd);
2114         }
2115 #endif /* TIOCNOTTY */
2116
2117         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
2118   
2119         /* Eep. Shouldn't reach this */
2120         exit(1);
2121 }
2122
2123 static int subcommand_connect(const char *command,
2124                               const char *servername, uint16_t port)
2125 {
2126         /* SEB unsupported on Windows */
2127         int sockfds[2];
2128         pid_t childpid;
2129   
2130         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
2131                 return -1;
2132   
2133         childpid = fork();
2134         if (!childpid) {
2135                 do_exec_command(sockfds[1], command, servername, port);
2136         }
2137         else if (childpid == -1) {
2138                 close(sockfds[0]);
2139                 close(sockfds[1]);
2140                 return -1;
2141         }
2142   
2143         close(sockfds[1]);
2144   
2145         /* Reap child, leaving grandchild process to run */
2146         waitpid(childpid, NULL, 0);
2147   
2148         return sockfds[0];
2149 }
2150
2151 int socket_connect_cmd(mailimap * imap, const char * command,
2152                        const char * server, int port)
2153 {
2154         int fd;
2155         mailstream * s;
2156         int r;
2157         
2158         fd = subcommand_connect(command, server, port);
2159         if (fd < 0)
2160                 return MAILIMAP_ERROR_STREAM;
2161         
2162         s = mailstream_socket_open(fd);
2163         if (s == NULL) {
2164                 close(fd);
2165                 return MAILIMAP_ERROR_STREAM;
2166         }
2167         
2168         r = mailimap_connect(imap, s);
2169         if (r != MAILIMAP_NO_ERROR) {
2170                 mailstream_close(s);
2171                 return r;
2172         }
2173         
2174         return MAILIMAP_NO_ERROR;
2175 }
2176
2177 /* connect cmd */
2178
2179 struct connect_cmd_param {
2180         mailimap * imap;
2181         const char * command;
2182         const char * server;
2183         int port;
2184 };
2185
2186 struct connect_cmd_result {
2187         int error;
2188 };
2189
2190 static void connect_cmd_run(struct etpan_thread_op * op)
2191 {
2192         int r;
2193         struct connect_cmd_param * param;
2194         struct connect_cmd_result * result;
2195         
2196         param = op->param;
2197         result = op->result;
2198         
2199         r = socket_connect_cmd(param->imap, param->command,
2200                                param->server, param->port);
2201         
2202         result->error = r;
2203 }
2204
2205
2206 int imap_threaded_connect_cmd(Folder * folder, const char * command,
2207                               const char * server, int port)
2208 {
2209         struct connect_cmd_param param;
2210         struct connect_cmd_result result;
2211         chashdatum key;
2212         chashdatum value;
2213         mailimap * imap;
2214         
2215         imap = mailimap_new(0, NULL);
2216         
2217         key.data = &folder;
2218         key.len = sizeof(folder);
2219         value.data = imap;
2220         value.len = 0;
2221         chash_set(session_hash, &key, &value, NULL);
2222         
2223         param.imap = imap;
2224         param.command = command;
2225         param.server = server;
2226         param.port = port;
2227         
2228         threaded_run(folder, &param, &result, connect_cmd_run);
2229         
2230         debug_print("connect_cmd ok %i\n", result.error);
2231         
2232         return result.error;
2233 }
2234 #else
2235
2236 void imap_main_init(void)
2237 {
2238 }
2239 void imap_main_done(void)
2240 {
2241 }
2242 void imap_main_set_timeout(int sec)
2243 {
2244 }
2245
2246 #endif