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