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