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