933c1445a2ab821179e0ae882cd06e6b68b2a790
[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         if (r == 0) {
626                 mailimap *imap = param->imap;
627                 mailstream_low *plain_low = NULL;
628                 mailstream_low *tls_low = NULL;
629                 int fd = -1;
630                 
631                 plain_low = mailstream_get_low(imap->imap_stream);
632                 fd = mailstream_low_get_fd(plain_low);
633                 if (fd == -1) {
634                         debug_print("imap starttls run - can't get fd\n");
635                         result->error = MAILIMAP_ERROR_STREAM;
636                         return;
637                 }
638                 tls_low = mailstream_low_ssl_open(fd);
639                 if (tls_low == NULL) {
640                         debug_print("imap starttls run - can't ssl_open\n");
641                         result->error = MAILIMAP_ERROR_STREAM;
642                         return;
643                 }
644                 mailstream_low_free(plain_low);
645                 mailstream_set_low(imap->imap_stream, tls_low);
646         }
647 }
648
649 int imap_threaded_starttls(Folder * folder)
650 {
651         struct starttls_param param;
652         struct starttls_result result;
653         
654         debug_print("imap starttls - begin\n");
655         
656         param.imap = get_imap(folder);
657         
658         threaded_run(folder, &param, &result, starttls_run);
659         
660         debug_print("imap starttls - end\n");
661         
662         return result.error;
663 }
664
665
666
667 struct create_param {
668         mailimap * imap;
669         const char * mb;
670 };
671
672 struct create_result {
673         int error;
674 };
675
676 static void create_run(struct etpan_thread_op * op)
677 {
678         struct create_param * param;
679         struct create_result * result;
680         int r;
681         
682         param = op->param;
683         r = mailimap_create(param->imap, param->mb);
684         
685         result = op->result;
686         result->error = r;
687         debug_print("imap create run - end %i\n", r);
688 }
689
690 int imap_threaded_create(Folder * folder, const char * mb)
691 {
692         struct create_param param;
693         struct create_result result;
694         
695         debug_print("imap create - begin\n");
696         
697         param.imap = get_imap(folder);
698         param.mb = mb;
699         
700         threaded_run(folder, &param, &result, create_run);
701         
702         debug_print("imap create - end\n");
703         
704         return result.error;
705 }
706
707
708
709
710 struct rename_param {
711         mailimap * imap;
712         const char * mb;
713         const char * new_name;
714 };
715
716 struct rename_result {
717         int error;
718 };
719
720 static void rename_run(struct etpan_thread_op * op)
721 {
722         struct rename_param * param;
723         struct rename_result * result;
724         int r;
725         
726         param = op->param;
727         r = mailimap_rename(param->imap, param->mb, param->new_name);
728         
729         result = op->result;
730         result->error = r;
731         debug_print("imap rename run - end %i\n", r);
732 }
733
734 int imap_threaded_rename(Folder * folder,
735                          const char * mb, const char * new_name)
736 {
737         struct rename_param param;
738         struct rename_result result;
739         
740         debug_print("imap rename - begin\n");
741         
742         param.imap = get_imap(folder);
743         param.mb = mb;
744         param.new_name = new_name;
745         
746         threaded_run(folder, &param, &result, rename_run);
747         
748         debug_print("imap rename - end\n");
749         
750         return result.error;
751 }
752
753
754
755
756 struct delete_param {
757         mailimap * imap;
758         const char * mb;
759 };
760
761 struct delete_result {
762         int error;
763 };
764
765 static void delete_run(struct etpan_thread_op * op)
766 {
767         struct delete_param * param;
768         struct delete_result * result;
769         int r;
770         
771         param = op->param;
772         r = mailimap_delete(param->imap, param->mb);
773         
774         result = op->result;
775         result->error = r;
776         debug_print("imap delete run - end %i\n", r);
777 }
778
779 int imap_threaded_delete(Folder * folder, const char * mb)
780 {
781         struct delete_param param;
782         struct delete_result result;
783         
784         debug_print("imap delete - begin\n");
785         
786         param.imap = get_imap(folder);
787         param.mb = mb;
788         
789         threaded_run(folder, &param, &result, delete_run);
790         
791         debug_print("imap delete - end\n");
792         
793         return result.error;
794 }
795
796
797
798 struct select_param {
799         mailimap * imap;
800         const char * mb;
801 };
802
803 struct select_result {
804         int error;
805 };
806
807 static void select_run(struct etpan_thread_op * op)
808 {
809         struct select_param * param;
810         struct select_result * result;
811         int r;
812         
813         param = op->param;
814         r = mailimap_select(param->imap, param->mb);
815         
816         result = op->result;
817         result->error = r;
818         debug_print("imap select run - end %i\n", r);
819 }
820
821 int imap_threaded_select(Folder * folder, const char * mb,
822                          gint * exists, gint * recent, gint * unseen,
823                          guint32 * uid_validity)
824 {
825         struct select_param param;
826         struct select_result result;
827         mailimap * imap;
828         
829         debug_print("imap select - begin\n");
830         
831         imap = get_imap(folder);
832         param.imap = imap;
833         param.mb = mb;
834         
835         threaded_run(folder, &param, &result, select_run);
836         
837         if (result.error != MAILIMAP_NO_ERROR)
838                 return result.error;
839         
840         if (imap->imap_selection_info == NULL)
841                 return MAILIMAP_ERROR_PARSE;
842         
843         * exists = imap->imap_selection_info->sel_exists;
844         * recent = imap->imap_selection_info->sel_recent;
845         * unseen = imap->imap_selection_info->sel_unseen;
846         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
847         
848         debug_print("imap select - end\n");
849         
850         return result.error;
851 }
852
853
854
855 struct examine_param {
856         mailimap * imap;
857         const char * mb;
858 };
859
860 struct examine_result {
861         int error;
862 };
863
864 static void examine_run(struct etpan_thread_op * op)
865 {
866         struct examine_param * param;
867         struct examine_result * result;
868         int r;
869         
870         param = op->param;
871         r = mailimap_examine(param->imap, param->mb);
872         
873         result = op->result;
874         result->error = r;
875         debug_print("imap examine run - end %i\n", r);
876 }
877
878 int imap_threaded_examine(Folder * folder, const char * mb,
879                           gint * exists, gint * recent, gint * unseen,
880                           guint32 * uid_validity)
881 {
882         struct examine_param param;
883         struct examine_result result;
884         mailimap * imap;
885         
886         debug_print("imap examine - begin\n");
887         
888         imap = get_imap(folder);
889         param.imap = imap;
890         param.mb = mb;
891         
892         threaded_run(folder, &param, &result, examine_run);
893         
894         if (result.error != MAILIMAP_NO_ERROR)
895                 return result.error;
896         
897         if (imap->imap_selection_info == NULL)
898                 return MAILIMAP_ERROR_PARSE;
899         
900         * exists = imap->imap_selection_info->sel_exists;
901         * recent = imap->imap_selection_info->sel_recent;
902         * unseen = imap->imap_selection_info->sel_unseen;
903         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
904         
905         debug_print("imap examine - end\n");
906         
907         return result.error;
908 }
909
910
911
912
913 struct search_param {
914         mailimap * imap;
915         int type;
916         struct mailimap_set * set;
917 };
918
919 struct search_result {
920         int error;
921         clist * search_result;
922 };
923
924 static void search_run(struct etpan_thread_op * op)
925 {
926         struct search_param * param;
927         struct search_result * result;
928         int r;
929         struct mailimap_search_key * key;
930         struct mailimap_search_key * uid_key;
931         struct mailimap_search_key * search_type_key;
932         clist * search_result;
933         
934         param = op->param;
935         
936         uid_key = mailimap_search_key_new_uid(param->set);
937         
938         search_type_key = NULL;
939         switch (param->type) {
940         case IMAP_SEARCH_TYPE_SIMPLE:
941                 search_type_key = NULL;
942                 break;
943                 
944         case IMAP_SEARCH_TYPE_SEEN:
945                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
946                                                           NULL, NULL, NULL, NULL, NULL,
947                                                           NULL, NULL, NULL, NULL, NULL,
948                                                           NULL, NULL, NULL, NULL, 0,
949                                                           NULL, NULL, NULL, NULL, NULL,
950                                                           NULL, 0, NULL, NULL, NULL);
951                 break;
952                 
953         case IMAP_SEARCH_TYPE_UNSEEN:
954                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
955                                                           NULL, NULL, NULL, NULL, NULL,
956                                                           NULL, NULL, NULL, NULL, NULL,
957                                                           NULL, NULL, NULL, NULL, 0,
958                                                           NULL, NULL, NULL, NULL, NULL,
959                                                           NULL, 0, NULL, NULL, NULL);
960                 break;
961                 
962         case IMAP_SEARCH_TYPE_ANSWERED:
963                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
964                                                           NULL, NULL, NULL, NULL, NULL,
965                                                           NULL, NULL, NULL, NULL, NULL,
966                                                           NULL, NULL, NULL, NULL, 0,
967                                                           NULL, NULL, NULL, NULL, NULL,
968                                                           NULL, 0, NULL, NULL, NULL);
969                 break;
970                 
971         case IMAP_SEARCH_TYPE_FLAGGED:
972                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
973                                                           NULL, NULL, NULL, NULL, NULL,
974                                                           NULL, NULL, NULL, NULL, NULL,
975                                                           NULL, NULL, NULL, NULL, 0,
976                                                           NULL, NULL, NULL, NULL, NULL,
977                                                           NULL, 0, NULL, NULL, NULL);
978                 break;
979         }
980         
981         if (search_type_key != NULL) {
982                 key = mailimap_search_key_new_multiple_empty();
983                 mailimap_search_key_multiple_add(key, search_type_key);
984                 mailimap_search_key_multiple_add(key, uid_key);
985         }
986         else {
987                 key = uid_key;
988         }
989         
990         r = mailimap_uid_search(param->imap, NULL, key, &search_result);
991         
992         result = op->result;
993         result->error = r;
994         result->search_result = search_result;
995         debug_print("imap search run - end %i\n", r);
996 }
997
998 int imap_threaded_search(Folder * folder, int search_type,
999                          struct mailimap_set * set, clist ** search_result)
1000 {
1001         struct search_param param;
1002         struct search_result result;
1003         mailimap * imap;
1004         
1005         debug_print("imap search - begin\n");
1006         
1007         imap = get_imap(folder);
1008         param.imap = imap;
1009         param.set = set;
1010         param.type = search_type;
1011         
1012         threaded_run(folder, &param, &result, search_run);
1013         
1014         if (result.error != MAILIMAP_NO_ERROR)
1015                 return result.error;
1016         
1017         debug_print("imap search - end\n");
1018         
1019         * search_result = result.search_result;
1020         
1021         return result.error;
1022 }
1023
1024
1025
1026
1027 static int
1028 uid_list_to_env_list(clist * fetch_result, carray ** result)
1029 {
1030         clistiter * cur;
1031         int r;
1032         int res;
1033         carray * tab;
1034         unsigned int i;
1035         
1036         tab = carray_new(128);
1037         if (tab == NULL) {
1038                 res = MAILIMAP_ERROR_MEMORY;
1039                 goto err;
1040         }
1041         
1042         for(cur = clist_begin(fetch_result) ; cur != NULL ;
1043             cur = clist_next(cur)) {
1044                 struct mailimap_msg_att * msg_att;
1045                 clistiter * item_cur;
1046                 uint32_t uid;
1047                 size_t size;
1048                 uint32_t * puid;
1049                 
1050                 msg_att = clist_content(cur);
1051                 
1052                 uid = 0;
1053                 size = 0;
1054                 for(item_cur = clist_begin(msg_att->att_list) ;
1055                     item_cur != NULL ;
1056                     item_cur = clist_next(item_cur)) {
1057                         struct mailimap_msg_att_item * item;
1058                         
1059                         item = clist_content(item_cur);
1060                         
1061                         switch (item->att_type) {
1062                         case MAILIMAP_MSG_ATT_ITEM_STATIC:
1063                                 switch (item->att_data.att_static->att_type) {
1064                                 case MAILIMAP_MSG_ATT_UID:
1065                                         uid = item->att_data.att_static->att_data.att_uid;
1066                                         break;
1067                                 }
1068                         }
1069                 }
1070                 
1071                 puid = malloc(sizeof(* puid));
1072                 if (puid == NULL) {
1073                         res = MAILIMAP_ERROR_MEMORY;
1074                         goto free_list;
1075                 }
1076                 * puid = uid;
1077                         
1078                 r = carray_add(tab, puid, NULL);
1079                 if (r < 0) {
1080                         free(puid);
1081                         res = MAILIMAP_ERROR_MEMORY;
1082                         goto free_list;
1083                 }
1084         }
1085                 
1086         * result = tab;
1087
1088         return MAILIMAP_NO_ERROR;
1089   
1090  free_list:
1091         for(i = 0 ; i < carray_count(tab) ; i++)
1092                 mailmessage_free(carray_get(tab, i));
1093  err:
1094         return res;
1095 }
1096
1097 static int imap_get_messages_list(mailimap * imap,
1098                                   uint32_t first_index,
1099                                   carray ** result)
1100 {
1101         carray * env_list;
1102         int r;
1103         struct mailimap_fetch_att * fetch_att;
1104         struct mailimap_fetch_type * fetch_type;
1105         struct mailimap_set * set;
1106         clist * fetch_result;
1107         int res;
1108         
1109         set = mailimap_set_new_interval(first_index, 0);
1110         if (set == NULL) {
1111                 res = MAILIMAP_ERROR_MEMORY;
1112                 goto err;
1113         }
1114
1115         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1116         if (fetch_type == NULL) {
1117                 res = MAILIMAP_ERROR_MEMORY;
1118                 goto free_set;
1119         }
1120
1121         fetch_att = mailimap_fetch_att_new_uid();
1122         if (fetch_att == NULL) {
1123                 res = MAILIMAP_ERROR_MEMORY;
1124                 goto free_fetch_type;
1125         }
1126
1127         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1128         if (r != MAILIMAP_NO_ERROR) {
1129                 mailimap_fetch_att_free(fetch_att);
1130                 res = MAILIMAP_ERROR_MEMORY;
1131                 goto free_fetch_type;
1132         }
1133
1134         r = mailimap_uid_fetch(imap, set,
1135                                fetch_type, &fetch_result);
1136
1137         mailimap_fetch_type_free(fetch_type);
1138         mailimap_set_free(set);
1139
1140         if (r != MAILIMAP_NO_ERROR) {
1141                 res = r;
1142                 goto err;
1143         }
1144
1145         env_list = NULL;
1146         r = uid_list_to_env_list(fetch_result, &env_list);
1147         mailimap_fetch_list_free(fetch_result);
1148         
1149         * result = env_list;
1150
1151         return MAILIMAP_NO_ERROR;
1152
1153  free_fetch_type:
1154         mailimap_fetch_type_free(fetch_type);
1155  free_set:
1156         mailimap_set_free(set);
1157  err:
1158         return res;
1159 }
1160
1161
1162
1163
1164 struct fetch_uid_param {
1165         mailimap * imap;
1166         uint32_t first_index;
1167 };
1168
1169 struct fetch_uid_result {
1170         int error;
1171         carray * fetch_result;
1172 };
1173
1174 static void fetch_uid_run(struct etpan_thread_op * op)
1175 {
1176         struct fetch_uid_param * param;
1177         struct fetch_uid_result * result;
1178         carray * fetch_result;
1179         int r;
1180         
1181         param = op->param;
1182         
1183         fetch_result = NULL;
1184         r = imap_get_messages_list(param->imap, param->first_index,
1185                                    &fetch_result);
1186         
1187         result = op->result;
1188         result->error = r;
1189         result->fetch_result = fetch_result;
1190         debug_print("imap fetch_uid run - end %i\n", r);
1191 }
1192
1193 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1194                             carray ** fetch_result)
1195 {
1196         struct fetch_uid_param param;
1197         struct fetch_uid_result result;
1198         mailimap * imap;
1199         
1200         debug_print("imap fetch_uid - begin\n");
1201         
1202         imap = get_imap(folder);
1203         param.imap = imap;
1204         param.first_index = first_index;
1205         
1206         threaded_run(folder, &param, &result, fetch_uid_run);
1207         
1208         if (result.error != MAILIMAP_NO_ERROR)
1209                 return result.error;
1210         
1211         debug_print("imap fetch_uid - end\n");
1212         
1213         * fetch_result = result.fetch_result;
1214         
1215         return result.error;
1216 }
1217
1218
1219 void imap_fetch_uid_list_free(carray * uid_list)
1220 {
1221         unsigned int i;
1222         
1223         for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1224                 uint32_t * puid;
1225                 
1226                 puid = carray_get(uid_list, i);
1227                 free(puid);
1228         }
1229         carray_free(uid_list);
1230 }
1231
1232
1233
1234 static int imap_fetch(mailimap * imap,
1235                       uint32_t msg_index,
1236                       char ** result,
1237                       size_t * result_len)
1238 {
1239         int r;
1240         struct mailimap_set * set;
1241         struct mailimap_fetch_att * fetch_att;
1242         struct mailimap_fetch_type * fetch_type;
1243         clist * fetch_result;
1244         struct mailimap_msg_att * msg_att;
1245         struct mailimap_msg_att_item * msg_att_item;
1246         char * text;
1247         size_t text_length;
1248         int res;
1249         clistiter * cur;
1250         struct mailimap_section * section;
1251
1252         set = mailimap_set_new_single(msg_index);
1253         if (set == NULL) {
1254                 res = MAILIMAP_ERROR_MEMORY;
1255                 goto err;
1256         }
1257
1258         section = mailimap_section_new(NULL);
1259         if (section == NULL) {
1260                 res = MAILIMAP_ERROR_MEMORY;
1261                 goto free_set;
1262         }
1263   
1264         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1265         if (fetch_att == NULL) {
1266                 mailimap_section_free(section);
1267                 res = MAILIMAP_ERROR_MEMORY;
1268                 goto free_set;
1269         }
1270   
1271         fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1272         if (fetch_type == NULL) {
1273                 res = MAILIMAP_ERROR_MEMORY;
1274                 goto free_fetch_att;
1275         }
1276
1277         r = mailimap_uid_fetch(imap, set,
1278                                fetch_type, &fetch_result);
1279   
1280         mailimap_fetch_type_free(fetch_type);
1281         mailimap_set_free(set);
1282   
1283         switch (r) {
1284         case MAILIMAP_NO_ERROR:
1285                 break;
1286         default:
1287                 return r;
1288         }
1289   
1290         if (clist_begin(fetch_result) == NULL) {
1291                 mailimap_fetch_list_free(fetch_result);
1292                 return MAILIMAP_ERROR_FETCH;
1293         }
1294
1295         msg_att = clist_begin(fetch_result)->data;
1296
1297         text = NULL;
1298         text_length = 0;
1299
1300         for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1301             cur = clist_next(cur)) {
1302                 msg_att_item = clist_content(cur);
1303
1304                 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1305                         if (msg_att_item->att_data.att_static->att_type ==
1306                             MAILIMAP_MSG_ATT_BODY_SECTION) {
1307                                 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1308                                 /* detach */
1309                                 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1310                                 text_length =
1311                                         msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1312                         }
1313                 }
1314         }
1315
1316         mailimap_fetch_list_free(fetch_result);
1317
1318         if (text == NULL)
1319                 return MAILIMAP_ERROR_FETCH;
1320
1321         * result = text;
1322         * result_len = text_length;
1323   
1324         return MAILIMAP_NO_ERROR;
1325
1326  free_fetch_att:
1327         mailimap_fetch_att_free(fetch_att);
1328  free_set:
1329         mailimap_set_free(set);
1330  err:
1331         return res;
1332 }
1333
1334 static int imap_fetch_header(mailimap * imap,
1335                              uint32_t msg_index,
1336                              char ** result,
1337                              size_t * result_len)
1338 {
1339   int r;
1340   struct mailimap_set * set;
1341   struct mailimap_fetch_att * fetch_att;
1342   struct mailimap_fetch_type * fetch_type;
1343   clist * fetch_result;
1344   struct mailimap_msg_att * msg_att;
1345   struct mailimap_msg_att_item * msg_att_item;
1346   char * text;
1347   size_t text_length;
1348   int res;
1349   clistiter * cur;
1350   struct mailimap_section * section;
1351   
1352   set = mailimap_set_new_single(msg_index);
1353   if (set == NULL) {
1354     res = MAILIMAP_ERROR_MEMORY;
1355     goto err;
1356   }
1357
1358   section = mailimap_section_new_header();
1359   if (section == NULL) {
1360     res = MAILIMAP_ERROR_MEMORY;
1361     goto free_set;
1362   }
1363   
1364   fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1365   if (fetch_att == NULL) {
1366     mailimap_section_free(section);
1367     res = MAILIMAP_ERROR_MEMORY;
1368     goto free_set;
1369   }
1370   
1371   fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1372   if (fetch_type == NULL) {
1373     res = MAILIMAP_ERROR_MEMORY;
1374     goto free_fetch_att;
1375   }
1376
1377   r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1378   
1379   mailimap_fetch_type_free(fetch_type);
1380   mailimap_set_free(set);
1381
1382   switch (r) {
1383   case MAILIMAP_NO_ERROR:
1384     break;
1385   default:
1386     return r;
1387   }
1388
1389   if (clist_begin(fetch_result) == NULL) {
1390     mailimap_fetch_list_free(fetch_result);
1391     return MAILIMAP_ERROR_FETCH;
1392   }
1393
1394   msg_att = clist_begin(fetch_result)->data;
1395
1396   text = NULL;
1397   text_length = 0;
1398
1399   for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1400       cur = clist_next(cur)) {
1401     msg_att_item = clist_content(cur);
1402
1403     if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1404       if (msg_att_item->att_data.att_static->att_type ==
1405           MAILIMAP_MSG_ATT_BODY_SECTION) {
1406         text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1407         msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1408         text_length =
1409           msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1410       }
1411     }
1412   }
1413
1414   mailimap_fetch_list_free(fetch_result);
1415
1416   if (text == NULL)
1417     return MAILIMAP_ERROR_FETCH;
1418
1419   * result = text;
1420   * result_len = text_length;
1421
1422   return MAILIMAP_NO_ERROR;
1423
1424  free_fetch_att:
1425   mailimap_fetch_att_free(fetch_att);
1426  free_set:
1427   mailimap_set_free(set);
1428  err:
1429   return res;
1430 }
1431
1432
1433
1434 struct fetch_content_param {
1435         mailimap * imap;
1436         uint32_t msg_index;
1437         const char * filename;
1438         int with_body;
1439 };
1440
1441 struct fetch_content_result {
1442         int error;
1443 };
1444
1445 static void fetch_content_run(struct etpan_thread_op * op)
1446 {
1447         struct fetch_content_param * param;
1448         struct fetch_content_result * result;
1449         char * content;
1450         size_t content_size;
1451         int r;
1452         int fd;
1453         FILE * f;
1454         
1455         param = op->param;
1456         
1457         content = NULL;
1458         content_size = 0;
1459         if (param->with_body)
1460                 r = imap_fetch(param->imap, param->msg_index,
1461                                &content, &content_size);
1462         else
1463                 r = imap_fetch_header(param->imap, param->msg_index,
1464                                       &content, &content_size);
1465         
1466         result = op->result;
1467         result->error = r;
1468         
1469         if (r == MAILIMAP_NO_ERROR) {
1470                 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
1471                 if (fd < 0) {
1472                         result->error = MAILIMAP_ERROR_FETCH;
1473                         goto free;
1474                 }
1475                 
1476                 f = fdopen(fd, "wb");
1477                 if (f == NULL) {
1478                         result->error = MAILIMAP_ERROR_FETCH;
1479                         goto close;
1480                 }
1481                 
1482                 r = fwrite(content, 1, content_size, f);
1483                 if (r == 0) {
1484                         goto fclose;
1485                 }
1486                 
1487                 r = fclose(f);
1488                 if (r == EOF) {
1489                         unlink(param->filename);
1490                         goto close;
1491                 }
1492                 goto free;
1493                 
1494         fclose:
1495                 fclose(f);
1496                 goto unlink;
1497         close:
1498                 close(fd);
1499         unlink:
1500                 unlink(param->filename);
1501         
1502         free:
1503                 if (mmap_string_unref(content) != 0)
1504                         free(content);
1505         }
1506         
1507         debug_print("imap fetch_content run - end %i\n", r);
1508 }
1509
1510 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
1511                                 int with_body,
1512                                 const char * filename)
1513 {
1514         struct fetch_content_param param;
1515         struct fetch_content_result result;
1516         mailimap * imap;
1517         
1518         debug_print("imap fetch_content - begin\n");
1519         
1520         imap = get_imap(folder);
1521         param.imap = imap;
1522         param.msg_index = msg_index;
1523         param.filename = filename;
1524         param.with_body = with_body;
1525         
1526         threaded_run(folder, &param, &result, fetch_content_run);
1527         
1528         if (result.error != MAILIMAP_NO_ERROR)
1529                 return result.error;
1530         
1531         debug_print("imap fetch_content - end\n");
1532         
1533         return result.error;
1534 }
1535
1536
1537
1538 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
1539 {
1540         int flags;
1541         clist * flag_list;
1542         clistiter * cur;
1543         
1544         flags = MSG_UNREAD;
1545         
1546         flag_list = att_dyn->att_list;
1547         if (flag_list == NULL)
1548                 return flags;
1549         
1550         for(cur = clist_begin(flag_list) ; cur != NULL ;
1551             cur = clist_next(cur)) {
1552                 struct mailimap_flag_fetch * flag_fetch;
1553                         
1554                 flag_fetch = clist_content(cur);
1555                 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
1556                         flags |= MSG_NEW;
1557                 else {
1558                         switch (flag_fetch->fl_flag->fl_type) {
1559                         case MAILIMAP_FLAG_ANSWERED:
1560                                 flags |= MSG_REPLIED;
1561                                 break;
1562                         case MAILIMAP_FLAG_FLAGGED:
1563                                 flags |= MSG_MARKED;
1564                                 break;
1565                         case MAILIMAP_FLAG_DELETED:
1566                                 flags |= MSG_DELETED;
1567                                 break;
1568                         case MAILIMAP_FLAG_SEEN:
1569                                 flags &= ~MSG_UNREAD;
1570                                 flags &= ~MSG_NEW;
1571                                 break;
1572                         }
1573                 }
1574         }
1575         
1576         return flags;
1577 }
1578
1579 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1580                                  uint32_t * puid,
1581                                  char ** pheaders,
1582                                  size_t * pref_size,
1583                                  struct mailimap_msg_att_dynamic ** patt_dyn)
1584 {
1585   clistiter * item_cur;
1586   uint32_t uid;
1587   char * headers;
1588   size_t ref_size;
1589   struct mailimap_msg_att_dynamic * att_dyn;
1590
1591   uid = 0;
1592   headers = NULL;
1593   ref_size = 0;
1594   att_dyn = NULL;
1595
1596   for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
1597       item_cur = clist_next(item_cur)) {
1598     struct mailimap_msg_att_item * item;
1599
1600     item = clist_content(item_cur);
1601       
1602     switch (item->att_type) {
1603     case MAILIMAP_MSG_ATT_ITEM_STATIC:
1604       switch (item->att_data.att_static->att_type) {
1605       case MAILIMAP_MSG_ATT_UID:
1606         uid = item->att_data.att_static->att_data.att_uid;
1607         break;
1608
1609       case MAILIMAP_MSG_ATT_BODY_SECTION:
1610         if (headers == NULL) {
1611           headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
1612         }
1613         break;
1614       case MAILIMAP_MSG_ATT_RFC822_SIZE:
1615               ref_size = item->att_data.att_static->att_data.att_rfc822_size;
1616               break;
1617       }
1618       break;
1619       
1620     case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
1621       if (att_dyn == NULL) {
1622         att_dyn = item->att_data.att_dyn;
1623       }
1624       break;
1625     }
1626   }
1627
1628   if (puid != NULL)
1629     * puid = uid;
1630   if (pheaders != NULL)
1631     * pheaders = headers;
1632   if (pref_size != NULL)
1633     * pref_size = ref_size;
1634   if (patt_dyn != NULL)
1635     * patt_dyn = att_dyn;
1636
1637   return MAIL_NO_ERROR;
1638 }
1639
1640 static struct imap_fetch_env_info *
1641 fetch_to_env_info(struct mailimap_msg_att * msg_att)
1642 {
1643         struct imap_fetch_env_info * info;
1644         uint32_t uid;
1645         char * headers;
1646         size_t size;
1647         struct mailimap_msg_att_dynamic * att_dyn;
1648         
1649         imap_get_msg_att_info(msg_att, &uid, &headers, &size,
1650                               &att_dyn);
1651         
1652         info = malloc(sizeof(* info));
1653         info->uid = uid;
1654         info->headers = strdup(headers);
1655         info->size = size;
1656         info->flags = imap_flags_to_flags(att_dyn);
1657         
1658         return info;
1659 }
1660
1661 static int
1662 imap_fetch_result_to_envelop_list(clist * fetch_result,
1663                                   carray ** p_env_list)
1664 {
1665         clistiter * cur;
1666         unsigned int i;
1667         carray * env_list;
1668   
1669         i = 0;
1670   
1671         env_list = carray_new(16);
1672   
1673         for(cur = clist_begin(fetch_result) ; cur != NULL ;
1674             cur = clist_next(cur)) {
1675                 struct mailimap_msg_att * msg_att;
1676                 struct imap_fetch_env_info * env_info;
1677     
1678                 msg_att = clist_content(cur);
1679
1680                 env_info = fetch_to_env_info(msg_att);
1681                 carray_add(env_list, env_info, NULL);
1682         }
1683   
1684         * p_env_list = env_list;
1685   
1686         return MAIL_NO_ERROR;
1687 }
1688
1689 int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
1690 {
1691         struct mailimap_fetch_att * fetch_att;
1692         int r;
1693         char * header;
1694         clist * hdrlist;
1695         struct mailimap_header_list * imap_hdrlist;
1696         struct mailimap_section * section;
1697
1698         hdrlist = clist_new();
1699   
1700         header = strdup("Date");
1701         r = clist_append(hdrlist, header);
1702         header = strdup("From");
1703         r = clist_append(hdrlist, header);
1704         header = strdup("To");
1705         r = clist_append(hdrlist, header);
1706         header = strdup("Cc");
1707         r = clist_append(hdrlist, header);
1708         header = strdup("Subject");
1709         r = clist_append(hdrlist, header);
1710         header = strdup("Message-ID");
1711         r = clist_append(hdrlist, header);
1712         header = strdup("References");
1713         r = clist_append(hdrlist, header);
1714         header = strdup("In-Reply-To");
1715         r = clist_append(hdrlist, header);
1716   
1717         imap_hdrlist = mailimap_header_list_new(hdrlist);
1718         section = mailimap_section_new_header_fields(imap_hdrlist);
1719         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1720         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1721   
1722         return MAIL_NO_ERROR;
1723 }
1724
1725 int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
1726 {
1727         struct mailimap_fetch_att * fetch_att;
1728         struct mailimap_section * section;
1729         
1730         section = mailimap_section_new_header();
1731         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1732         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1733         
1734         return MAIL_NO_ERROR;
1735 }
1736
1737 static int
1738 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
1739                         carray ** p_env_list)
1740 {
1741         struct mailimap_fetch_att * fetch_att;
1742         struct mailimap_fetch_type * fetch_type;
1743         int res;
1744         clist * fetch_result;
1745         int r;
1746         carray * env_list;
1747         chashdatum key;
1748         chashdatum value;
1749         
1750         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1751   
1752         /* uid */
1753         fetch_att = mailimap_fetch_att_new_uid();
1754         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1755   
1756         /* flags */
1757         fetch_att = mailimap_fetch_att_new_flags();
1758         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1759   
1760         /* rfc822 size */
1761         fetch_att = mailimap_fetch_att_new_rfc822_size();
1762         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1763   
1764         /* headers */
1765         key.data = &imap;
1766         key.len = sizeof(imap);
1767         r = chash_get(courier_workaround_hash, &key, &value);
1768         if (r < 0)
1769                 r = imap_add_envelope_fetch_att(fetch_type);
1770         else
1771                 r = imap_add_header_fetch_att(fetch_type);
1772         
1773         r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1774         
1775         switch (r) {
1776         case MAILIMAP_NO_ERROR:
1777                 break;
1778         default:
1779                 mailimap_fetch_type_free(fetch_type);
1780                 return r;
1781         }
1782         
1783         if (clist_begin(fetch_result) == NULL) {
1784                 res = MAILIMAP_ERROR_FETCH;
1785                 goto err;
1786         }
1787         
1788         r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
1789         mailimap_fetch_list_free(fetch_result);
1790         
1791         if (r != MAILIMAP_NO_ERROR) {
1792                 mailimap_fetch_type_free(fetch_type);
1793                 res = MAILIMAP_ERROR_MEMORY;
1794                 goto err;
1795         }
1796         
1797         mailimap_fetch_type_free(fetch_type);
1798         
1799         * p_env_list = env_list;
1800         
1801         return MAILIMAP_NO_ERROR;
1802   
1803  err:
1804         return res;
1805 }
1806
1807 struct fetch_env_param {
1808         mailimap * imap;
1809         struct mailimap_set * set;
1810 };
1811
1812 struct fetch_env_result {
1813         carray * fetch_env_result;
1814         int error;
1815 };
1816
1817 static void fetch_env_run(struct etpan_thread_op * op)
1818 {
1819         struct fetch_env_param * param;
1820         struct fetch_env_result * result;
1821         carray * env_list;
1822         int r;
1823         
1824         param = op->param;
1825         
1826         env_list = NULL;
1827         r = imap_get_envelopes_list(param->imap, param->set,
1828                                     &env_list);
1829         
1830         result = op->result;
1831         result->error = r;
1832         result->fetch_env_result = env_list;
1833         
1834         debug_print("imap fetch_env run - end %i\n", r);
1835 }
1836
1837 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
1838                             carray ** p_env_list)
1839 {
1840         struct fetch_env_param param;
1841         struct fetch_env_result result;
1842         mailimap * imap;
1843         
1844         debug_print("imap fetch_env - begin\n");
1845         
1846         imap = get_imap(folder);
1847         param.imap = imap;
1848         param.set = set;
1849         
1850         threaded_run(folder, &param, &result, fetch_env_run);
1851         
1852         if (result.error != MAILIMAP_NO_ERROR) {
1853                 chashdatum key;
1854                 chashdatum value;
1855                 int r;
1856                 
1857                 key.data = &imap;
1858                 key.len = sizeof(imap);
1859                 r = chash_get(courier_workaround_hash, &key, &value);
1860                 if (r < 0) {
1861                         value.data = NULL;
1862                         value.len = 0;
1863                         chash_set(courier_workaround_hash, &key, &value, NULL);
1864                         
1865                         threaded_run(folder, &param, &result, fetch_env_run);
1866                 }
1867         }
1868         
1869         if (result.error != MAILIMAP_NO_ERROR)
1870                 return result.error;
1871         
1872         debug_print("imap fetch_env - end\n");
1873         
1874         * p_env_list = result.fetch_env_result;
1875         
1876         return result.error;
1877 }
1878
1879 void imap_fetch_env_free(carray * env_list)
1880 {
1881         unsigned int i;
1882         
1883         for(i = 0 ; i < carray_count(env_list) ; i ++) {
1884                 struct imap_fetch_env_info * env_info;
1885                 
1886                 env_info = carray_get(env_list, i);
1887                 free(env_info->headers);
1888                 free(env_info);
1889         }
1890         carray_free(env_list);
1891 }
1892
1893
1894
1895
1896
1897 struct append_param {
1898         mailimap * imap;
1899         const char * mailbox;
1900         const char * filename;
1901         struct mailimap_flag_list * flag_list;
1902 };
1903
1904 struct append_result {
1905         int error;
1906 };
1907
1908 static void append_run(struct etpan_thread_op * op)
1909 {
1910         struct append_param * param;
1911         struct append_result * result;
1912         int r;
1913         char * data;
1914         size_t size;
1915         struct stat stat_buf;
1916         int fd;
1917         
1918         param = op->param;
1919         result = op->result;
1920         
1921         r = stat(param->filename, &stat_buf);
1922         if (r < 0) {
1923                 result->error = MAILIMAP_ERROR_APPEND;
1924                 return;
1925         }
1926         size = stat_buf.st_size;
1927         
1928         fd = open(param->filename, O_RDONLY);
1929         if (fd < 0) {
1930                 result->error = MAILIMAP_ERROR_APPEND;
1931                 return;
1932         }
1933         
1934         data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
1935         if (data == (void *) MAP_FAILED) {
1936                 close(fd);
1937                 result->error = MAILIMAP_ERROR_APPEND;
1938                 return;
1939         }
1940         
1941         r = mailimap_append(param->imap, param->mailbox,
1942                             param->flag_list, NULL,
1943                             data, size);
1944         
1945         munmap(data, size);
1946         close(fd);
1947         
1948         result->error = r;
1949         
1950         debug_print("imap append run - end %i\n", r);
1951 }
1952
1953 int imap_threaded_append(Folder * folder, const char * mailbox,
1954                          const char * filename,
1955                          struct mailimap_flag_list * flag_list)
1956 {
1957         struct append_param param;
1958         struct append_result result;
1959         mailimap * imap;
1960         
1961         debug_print("imap append - begin\n");
1962         
1963         imap = get_imap(folder);
1964         param.imap = imap;
1965         param.mailbox = mailbox;
1966         param.filename = filename;
1967         param.flag_list = flag_list;
1968         
1969         threaded_run(folder, &param, &result, append_run);
1970         
1971         if (result.error != MAILIMAP_NO_ERROR)
1972                 return result.error;
1973         
1974         debug_print("imap append - end\n");
1975         
1976         return result.error;
1977 }
1978
1979
1980
1981
1982 struct expunge_param {
1983         mailimap * imap;
1984 };
1985
1986 struct expunge_result {
1987         int error;
1988 };
1989
1990 static void expunge_run(struct etpan_thread_op * op)
1991 {
1992         struct expunge_param * param;
1993         struct expunge_result * result;
1994         int r;
1995         
1996         param = op->param;
1997         r = mailimap_expunge(param->imap);
1998         
1999         result = op->result;
2000         result->error = r;
2001         debug_print("imap expunge run - end %i\n", r);
2002 }
2003
2004 int imap_threaded_expunge(Folder * folder)
2005 {
2006         struct expunge_param param;
2007         struct expunge_result result;
2008         
2009         debug_print("imap expunge - begin\n");
2010         
2011         param.imap = get_imap(folder);
2012         
2013         threaded_run(folder, &param, &result, expunge_run);
2014         
2015         debug_print("imap expunge - end\n");
2016         
2017         return result.error;
2018 }
2019
2020
2021 struct copy_param {
2022         mailimap * imap;
2023         struct mailimap_set * set;
2024         const char * mb;
2025 };
2026
2027 struct copy_result {
2028         int error;
2029 };
2030
2031 static void copy_run(struct etpan_thread_op * op)
2032 {
2033         struct copy_param * param;
2034         struct copy_result * result;
2035         int r;
2036         
2037         param = op->param;
2038         
2039         r = mailimap_uid_copy(param->imap, param->set, param->mb);
2040         
2041         result = op->result;
2042         result->error = r;
2043         
2044         debug_print("imap copy run - end %i\n", r);
2045 }
2046
2047 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
2048                        const char * mb)
2049 {
2050         struct copy_param param;
2051         struct copy_result result;
2052         mailimap * imap;
2053         
2054         debug_print("imap copy - begin\n");
2055         
2056         imap = get_imap(folder);
2057         param.imap = imap;
2058         param.set = set;
2059         param.mb = mb;
2060         
2061         threaded_run(folder, &param, &result, copy_run);
2062         
2063         if (result.error != MAILIMAP_NO_ERROR)
2064                 return result.error;
2065         
2066         debug_print("imap copy - end\n");
2067         
2068         return result.error;
2069 }
2070
2071
2072
2073 struct store_param {
2074         mailimap * imap;
2075         struct mailimap_set * set;
2076         struct mailimap_store_att_flags * store_att_flags;
2077 };
2078
2079 struct store_result {
2080         int error;
2081 };
2082
2083 static void store_run(struct etpan_thread_op * op)
2084 {
2085         struct store_param * param;
2086         struct store_result * result;
2087         int r;
2088         
2089         param = op->param;
2090         
2091         r = mailimap_uid_store(param->imap, param->set,
2092                                param->store_att_flags);
2093         
2094         result = op->result;
2095         result->error = r;
2096         
2097         debug_print("imap store run - end %i\n", r);
2098 }
2099
2100 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
2101                         struct mailimap_store_att_flags * store_att_flags)
2102 {
2103         struct store_param param;
2104         struct store_result result;
2105         mailimap * imap;
2106         
2107         debug_print("imap store - begin\n");
2108         
2109         imap = get_imap(folder);
2110         param.imap = imap;
2111         param.set = set;
2112         param.store_att_flags = store_att_flags;
2113         
2114         threaded_run(folder, &param, &result, store_run);
2115         
2116         if (result.error != MAILIMAP_NO_ERROR)
2117                 return result.error;
2118         
2119         debug_print("imap store - end\n");
2120         
2121         return result.error;
2122 }
2123
2124
2125
2126 static void do_exec_command(int fd, const char * command,
2127                             const char * servername, uint16_t port)
2128 {
2129         int i, maxopen;
2130   
2131         if (fork() > 0) {
2132                 /* Fork again to become a child of init rather than
2133                    the etpan client. */
2134                 exit(0);
2135         }
2136   
2137         if (servername)
2138                 setenv("ETPANSERVER", servername, 1);
2139         else
2140                 unsetenv("ETPANSERVER");
2141   
2142         if (port) {
2143                 char porttext[20];
2144     
2145                 snprintf(porttext, sizeof(porttext), "%d", port);
2146                 setenv("ETPANPORT", porttext, 1);
2147         }
2148         else {
2149                 unsetenv("ETPANPORT");
2150         }
2151   
2152         /* Not a lot we can do if there's an error other than bail. */
2153         if (dup2(fd, 0) == -1)
2154                 exit(1);
2155         if (dup2(fd, 1) == -1)
2156                 exit(1);
2157   
2158         /* Should we close stderr and reopen /dev/null? */
2159   
2160         maxopen = sysconf(_SC_OPEN_MAX);
2161         for (i=3; i < maxopen; i++)
2162                 close(i);
2163   
2164 #ifdef TIOCNOTTY
2165         /* Detach from the controlling tty if we have one. Otherwise,
2166            SSH might do something stupid like trying to use it instead
2167            of running $SSH_ASKPASS. Doh. */
2168         fd = open("/dev/tty", O_RDONLY);
2169         if (fd != -1) {
2170                 ioctl(fd, TIOCNOTTY, NULL);
2171                 close(fd);
2172         }
2173 #endif /* TIOCNOTTY */
2174
2175         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
2176   
2177         /* Eep. Shouldn't reach this */
2178         exit(1);
2179 }
2180
2181 static int subcommand_connect(const char *command,
2182                               const char *servername, uint16_t port)
2183 {
2184         /* SEB unsupported on Windows */
2185         int sockfds[2];
2186         pid_t childpid;
2187   
2188         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
2189                 return -1;
2190   
2191         childpid = fork();
2192         if (!childpid) {
2193                 do_exec_command(sockfds[1], command, servername, port);
2194         }
2195         else if (childpid == -1) {
2196                 close(sockfds[0]);
2197                 close(sockfds[1]);
2198                 return -1;
2199         }
2200   
2201         close(sockfds[1]);
2202   
2203         /* Reap child, leaving grandchild process to run */
2204         waitpid(childpid, NULL, 0);
2205   
2206         return sockfds[0];
2207 }
2208
2209 int socket_connect_cmd(mailimap * imap, const char * command,
2210                        const char * server, int port)
2211 {
2212         int fd;
2213         mailstream * s;
2214         int r;
2215         
2216         fd = subcommand_connect(command, server, port);
2217         if (fd < 0)
2218                 return MAILIMAP_ERROR_STREAM;
2219         
2220         s = mailstream_socket_open(fd);
2221         if (s == NULL) {
2222                 close(fd);
2223                 return MAILIMAP_ERROR_STREAM;
2224         }
2225         
2226         r = mailimap_connect(imap, s);
2227         if (r != MAILIMAP_NO_ERROR) {
2228                 mailstream_close(s);
2229                 return r;
2230         }
2231         
2232         return MAILIMAP_NO_ERROR;
2233 }
2234
2235 /* connect cmd */
2236
2237 struct connect_cmd_param {
2238         mailimap * imap;
2239         const char * command;
2240         const char * server;
2241         int port;
2242 };
2243
2244 struct connect_cmd_result {
2245         int error;
2246 };
2247
2248 static void connect_cmd_run(struct etpan_thread_op * op)
2249 {
2250         int r;
2251         struct connect_cmd_param * param;
2252         struct connect_cmd_result * result;
2253         
2254         param = op->param;
2255         result = op->result;
2256         
2257         r = socket_connect_cmd(param->imap, param->command,
2258                                param->server, param->port);
2259         
2260         result->error = r;
2261 }
2262
2263
2264 int imap_threaded_connect_cmd(Folder * folder, const char * command,
2265                               const char * server, int port)
2266 {
2267         struct connect_cmd_param param;
2268         struct connect_cmd_result result;
2269         chashdatum key;
2270         chashdatum value;
2271         mailimap * imap;
2272         
2273         imap = mailimap_new(0, NULL);
2274         
2275         key.data = &folder;
2276         key.len = sizeof(folder);
2277         value.data = imap;
2278         value.len = 0;
2279         chash_set(session_hash, &key, &value, NULL);
2280         
2281         param.imap = imap;
2282         param.command = command;
2283         param.server = server;
2284         param.port = port;
2285         
2286         threaded_run(folder, &param, &result, connect_cmd_run);
2287         
2288         debug_print("connect_cmd ok %i\n", result.error);
2289         
2290         return result.error;
2291 }
2292 #else
2293
2294 void imap_main_init(void)
2295 {
2296 }
2297 void imap_main_done(void)
2298 {
2299 }
2300 void imap_main_set_timeout(int sec)
2301 {
2302 }
2303
2304 #endif