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