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