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