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