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