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