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