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