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