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