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