20b0e2a99ca2b63ff1441816c17c9cb55d4035d2
[claws.git] / src / etpan / imap-thread.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2005-2007 DINH Viet Hoa and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #ifdef HAVE_LIBETPAN
25
26 #include "imap-thread.h"
27 #include <imap.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__))
31 #include <sys/socket.h>
32 #endif
33 #include <fcntl.h>
34 #include <sys/mman.h>
35 #include <sys/wait.h>
36
37 #include <gtk/gtk.h>
38 #include <log.h>
39 #include "etpan-thread-manager.h"
40 #include "utils.h"
41 #include "mainwindow.h"
42 #include "ssl_certificate.h"
43 #include "socket.h"
44 #include "remotefolder.h"
45
46 #define DISABLE_LOG_DURING_LOGIN
47
48 static struct etpan_thread_manager * thread_manager = NULL;
49 static chash * courier_workaround_hash = NULL;
50 static chash * imap_hash = NULL;
51 static chash * session_hash = NULL;
52 static guint thread_manager_signal = 0;
53 static GIOChannel * io_channel = NULL;
54
55 static void delete_imap(Folder *folder, mailimap *imap)
56 {
57         chashdatum key;
58         chashdatum value;
59
60         key.data = &folder;
61         key.len = sizeof(folder);
62         value.data = imap;
63         value.len = 0;
64         chash_delete(session_hash, &key, NULL);
65         
66         key.data = &imap;
67         key.len = sizeof(imap);
68         chash_delete(courier_workaround_hash, &key, NULL);
69         if (imap && imap->imap_stream) {
70                 /* we don't want libetpan to logout */
71                 mailstream_close(imap->imap_stream);
72                 imap->imap_stream = NULL;
73         }
74         debug_print("removing mailimap %p\n", imap);
75         mailimap_free(imap);    
76 }
77
78 static gboolean thread_manager_event(GIOChannel * source,
79     GIOCondition condition,
80     gpointer data)
81 {
82         etpan_thread_manager_loop(thread_manager);
83         
84         return TRUE;
85 }
86
87 static void imap_logger_noop(int direction, const char * str, size_t size) 
88 {
89         /* inhibit logging */
90 }
91
92 static void imap_logger_cmd(int direction, const char * str, size_t size) 
93 {
94         gchar *buf;
95         gchar **lines;
96         int i = 0;
97
98         if (size > 8192) {
99                 log_print(LOG_PROTOCOL, "IMAP4%c [CMD data - %zd bytes]\n", direction?'>':'<', size);
100                 return;
101         }
102         buf = malloc(size+1);
103         memset(buf, 0, size+1);
104         strncpy(buf, str, size);
105         buf[size] = '\0';
106
107         if (!strncmp(buf, "<<<<<<<", 7) 
108         ||  !strncmp(buf, ">>>>>>>", 7)) {
109                 free(buf);
110                 return;
111         }
112         while (strstr(buf, "\r"))
113                 *strstr(buf, "\r") = ' ';
114         while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
115                 buf[strlen(buf)-1] = '\0';
116
117         lines = g_strsplit(buf, "\n", -1);
118
119         while (lines[i] && *lines[i]) {
120                 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
121                 i++;
122         }
123         g_strfreev(lines);
124         free(buf);
125 }
126
127 static void imap_logger_fetch(int direction, const char * str, size_t size) 
128 {
129         gchar *buf;
130         gchar **lines;
131         int i = 0;
132
133         if (size > 128 && !direction) {
134                 log_print(LOG_PROTOCOL, "IMAP4%c [FETCH data - %zd bytes]\n", direction?'>':'<', size);
135                 return;
136         }
137         
138         buf = malloc(size+1);
139         memset(buf, 0, size+1);
140         strncpy(buf, str, size);
141         buf[size] = '\0';
142         if (!strncmp(buf, "<<<<<<<", 7) 
143         ||  !strncmp(buf, ">>>>>>>", 7)) {
144                 free(buf);
145                 return;
146         }
147         while (strstr(buf, "\r"))
148                 *strstr(buf, "\r") = ' ';
149         while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
150                 buf[strlen(buf)-1] = '\0';
151
152         lines = g_strsplit(buf, "\n", -1);
153
154         if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) {
155                 while (lines[i] && *lines[i]) {
156                         log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
157                         i++;
158                 }
159         } else {
160                 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
161         }
162         g_strfreev(lines);
163         free(buf);
164 }
165
166 static void imap_logger_uid(int direction, const char * str, size_t size) 
167 {
168         gchar *buf;
169         gchar **lines;
170         int i = 0;
171
172         if (size > 8192) {
173                 log_print(LOG_PROTOCOL, "IMAP4%c [UID data - %zd bytes]\n", direction?'>':'<', size);
174                 return;
175         }
176         buf = malloc(size+1);
177         memset(buf, 0, size+1);
178         strncpy(buf, str, size);
179         buf[size] = '\0';
180         if (!strncmp(buf, "<<<<<<<", 7) 
181         ||  !strncmp(buf, ">>>>>>>", 7)) {
182                 free(buf);
183                 return;
184         }
185         while (strstr(buf, "\r"))
186                 *strstr(buf, "\r") = ' ';
187         while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
188                 buf[strlen(buf)-1] = '\0';
189
190         lines = g_strsplit(buf, "\n", -1);
191
192         while (lines[i] && *lines[i]) {
193                 int llen = strlen(lines[i]);
194                 if (llen < 64)
195                         log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
196                 else {
197                         gchar tmp[64];
198                         strncpy2(tmp, lines[i], 63);
199                         log_print(LOG_PROTOCOL, "IMAP4%c %s[... - %d bytes more]\n", direction?'>':'<', tmp,
200                                   llen-64);
201                 }
202                 i++;
203         }
204         g_strfreev(lines);
205         free(buf);
206 }
207
208 static void imap_logger_append(int direction, const char * str, size_t size) 
209 {
210         gchar *buf;
211         gchar **lines;
212         int i = 0;
213
214         if (size > 8192) {
215                 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
216                 return;
217         } else if (direction == 0 && size > 64) {
218                 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
219                 return;
220         } 
221         buf = malloc(size+1);
222         memset(buf, 0, size+1);
223         strncpy(buf, str, size);
224         buf[size] = '\0';
225         if (!strncmp(buf, "<<<<<<<", 7) 
226         ||  !strncmp(buf, ">>>>>>>", 7)) {
227                 free(buf);
228                 return;
229         }
230         while (strstr(buf, "\r"))
231                 *strstr(buf, "\r") = ' ';
232         while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
233                 buf[strlen(buf)-1] = '\0';
234
235         lines = g_strsplit(buf, "\n", -1);
236
237         if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
238                 while (lines[i] && *lines[i]) {
239                         log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
240                         i++;
241                 }
242         } else {
243                 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
244         }
245         g_strfreev(lines);
246         free(buf);
247 }
248
249 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
250 gboolean etpan_skip_ssl_cert_check = FALSE;
251 extern void mailsasl_ref(void);
252
253 void imap_main_init(gboolean skip_ssl_cert_check)
254 {
255         int fd_thread_manager;
256         
257         etpan_skip_ssl_cert_check = skip_ssl_cert_check;
258         mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
259         mailstream_network_delay.tv_usec = 0;
260         
261         mailstream_debug = 1;
262         mailstream_logger = imap_logger_cmd;
263         mailsasl_ref();
264         
265         imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
266         session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
267         courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
268         
269         thread_manager = etpan_thread_manager_new();
270         
271         fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
272         
273         io_channel = g_io_channel_unix_new(fd_thread_manager);
274         
275         thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
276                                                     thread_manager_event,
277                                                     (gpointer) NULL,
278                                                     NULL);
279 }
280
281 void imap_main_set_timeout(int sec)
282 {
283         mailstream_network_delay.tv_sec = sec;
284         mailstream_network_delay.tv_usec = 0;
285 }
286
287 void imap_main_done(void)
288 {
289         etpan_thread_manager_stop(thread_manager);
290         etpan_thread_manager_join(thread_manager);
291         
292         g_source_remove(thread_manager_signal);
293         g_io_channel_unref(io_channel);
294         
295         etpan_thread_manager_free(thread_manager);
296         
297         chash_free(courier_workaround_hash);
298         chash_free(session_hash);
299         chash_free(imap_hash);
300 }
301
302 void imap_init(Folder * folder)
303 {
304         struct etpan_thread * thread;
305         chashdatum key;
306         chashdatum value;
307         
308         thread = etpan_thread_manager_get_thread(thread_manager);
309         
310         key.data = &folder;
311         key.len = sizeof(folder);
312         value.data = thread;
313         value.len = 0;
314         
315         chash_set(imap_hash, &key, &value, NULL);
316 }
317
318 void imap_done(Folder * folder)
319 {
320         struct etpan_thread * thread;
321         chashdatum key;
322         chashdatum value;
323         int r;
324         
325         key.data = &folder;
326         key.len = sizeof(folder);
327         
328         r = chash_get(imap_hash, &key, &value);
329         if (r < 0)
330                 return;
331         
332         thread = value.data;
333         
334         etpan_thread_unbind(thread);
335         
336         chash_delete(imap_hash, &key, NULL);
337         
338         debug_print("remove thread");
339 }
340
341 static struct etpan_thread * get_thread(Folder * folder)
342 {
343         struct etpan_thread * thread;
344         chashdatum key;
345         chashdatum value;
346         
347         key.data = &folder;
348         key.len = sizeof(folder);
349         
350         chash_get(imap_hash, &key, &value);
351         thread = value.data;
352         
353         return thread;
354 }
355
356 static mailimap * get_imap(Folder * folder)
357 {
358         mailimap * imap;
359         chashdatum key;
360         chashdatum value;
361         int r;
362         
363         key.data = &folder;
364         key.len = sizeof(folder);
365         
366         r = chash_get(session_hash, &key, &value);
367         if (r < 0)
368                 return NULL;
369         
370         imap = value.data;
371         debug_print("found imap %p\n", imap);
372         return imap;
373 }
374
375 static gboolean cb_show_error(gpointer data)
376 {
377         mainwindow_show_error();
378         return FALSE;
379 }
380
381 static void generic_cb(int cancelled, void * result, void * callback_data)
382 {
383         struct etpan_thread_op * op;
384         
385         op = (struct etpan_thread_op *) callback_data;
386
387         debug_print("generic_cb\n");
388         if (op->imap && op->imap->imap_response_info &&
389             op->imap->imap_response_info->rsp_alert) {
390                 log_error(LOG_PROTOCOL, "IMAP4< Alert: %s\n", 
391                         op->imap->imap_response_info->rsp_alert);
392                 g_timeout_add(10, cb_show_error, NULL);
393         } 
394         op->finished = 1;
395 }
396
397 static void threaded_run(Folder * folder, void * param, void * result,
398                          void (* func)(struct etpan_thread_op * ))
399 {
400         struct etpan_thread_op * op;
401         struct etpan_thread * thread;
402         
403         imap_folder_ref(folder);
404
405         op = etpan_thread_op_new();
406         
407         op->imap = get_imap(folder);
408         op->param = param;
409         op->result = result;
410         
411         op->cancellable = 0;
412         op->run = func;
413         op->callback = generic_cb;
414         op->callback_data = op;
415         op->cleanup = NULL;
416         
417         op->finished = 0;
418         
419         thread = get_thread(folder);
420         etpan_thread_op_schedule(thread, op);
421         
422         while (!op->finished) {
423                 gtk_main_iteration();
424         }
425         
426         etpan_thread_op_free(op);
427
428         imap_folder_unref(folder);
429 }
430
431
432 /* connect */
433
434 struct connect_param {
435         mailimap * imap;
436         const char * server;
437         int port;
438 };
439
440 struct connect_result {
441         int error;
442 };
443
444 #define CHECK_IMAP() {                                          \
445         if (!param->imap) {                                     \
446                 result->error = MAILIMAP_ERROR_BAD_STATE;       \
447                 return;                                         \
448         }                                                       \
449 }
450
451 static void connect_run(struct etpan_thread_op * op)
452 {
453         int r;
454         struct connect_param * param;
455         struct connect_result * result;
456         
457         param = op->param;
458         result = op->result;
459         
460         CHECK_IMAP();
461
462         r = mailimap_socket_connect(param->imap,
463                                     param->server, param->port);
464         
465         result->error = r;
466 }
467
468
469 int imap_threaded_connect(Folder * folder, const char * server, int port)
470 {
471         struct connect_param param;
472         struct connect_result result;
473         chashdatum key;
474         chashdatum value;
475         mailimap * imap, * oldimap;
476         
477         oldimap = get_imap(folder);
478
479         imap = mailimap_new(0, NULL);
480         
481         if (oldimap) {
482                 debug_print("deleting old imap %p\n", oldimap);
483                 delete_imap(folder, oldimap);
484         }
485         
486         key.data = &folder;
487         key.len = sizeof(folder);
488         value.data = imap;
489         value.len = 0;
490         chash_set(session_hash, &key, &value, NULL);
491         
492         param.imap = imap;
493         param.server = server;
494         param.port = port;
495         
496         refresh_resolvers();
497         threaded_run(folder, &param, &result, connect_run);
498         
499         debug_print("connect ok %i with imap %p\n", result.error, imap);
500         
501         return result.error;
502 }
503
504 static int etpan_certificate_check(const unsigned char *certificate, int len, void *data)
505 {
506 #ifdef USE_OPENSSL
507         struct connect_param *param = (struct connect_param *)data;
508         X509 *cert = NULL;
509         
510         if (certificate == NULL || len < 0) {
511                 g_warning("no cert presented.\n");
512                 return 0;
513         }
514         cert = d2i_X509(NULL, (const unsigned char **)&certificate, len);
515         if (cert == NULL) {
516                 g_warning("IMAP: can't get cert\n");
517                 return 0;
518         } else if (ssl_certificate_check(cert, NULL,
519                 (gchar *)param->server, (gushort)param->port) == TRUE) {
520                 X509_free(cert);
521                 return 0;
522         } else {
523                 X509_free(cert);
524                 return -1;
525         }
526 #elif USE_GNUTLS
527         struct connect_param *param = (struct connect_param *)data;
528         gnutls_x509_crt cert = NULL;
529         gnutls_datum tmp;
530         
531         if (certificate == NULL || len < 0) {
532                 g_warning("no cert presented.\n");
533                 return 0;
534         }
535         
536         tmp.data = malloc(len);
537         memcpy(tmp.data, certificate, len);
538         tmp.size = len;
539         gnutls_x509_crt_init(&cert);
540         if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) {
541                 g_warning("IMAP: can't get cert\n");
542                 return 0;
543         } else if (ssl_certificate_check(cert, (guint)-1, NULL,
544                 (gchar *)param->server, (gushort)param->port) == TRUE) {
545                 gnutls_x509_crt_deinit(cert);
546                 return 0;
547         } else {
548                 gnutls_x509_crt_deinit(cert);
549                 return -1;
550         }
551 #endif
552         return 0;
553 }
554
555 static void connect_ssl_run(struct etpan_thread_op * op)
556 {
557         int r;
558         struct connect_param * param;
559         struct connect_result * result;
560         
561         param = op->param;
562         result = op->result;
563         
564         CHECK_IMAP();
565
566         r = mailimap_ssl_connect(param->imap,
567                                  param->server, param->port);
568         result->error = r;
569 }
570
571 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
572 {
573         struct connect_param param;
574         struct connect_result result;
575         chashdatum key;
576         chashdatum value;
577         mailimap * imap, * oldimap;
578         unsigned char *certificate = NULL;
579         int cert_len;
580         
581         oldimap = get_imap(folder);
582
583         imap = mailimap_new(0, NULL);
584         
585         if (oldimap) {
586                 debug_print("deleting old imap %p\n", oldimap);
587                 delete_imap(folder, oldimap);
588         }
589
590         key.data = &folder;
591         key.len = sizeof(folder);
592         value.data = imap;
593         value.len = 0;
594         chash_set(session_hash, &key, &value, NULL);
595         
596         param.imap = imap;
597         param.server = server;
598         param.port = port;
599         
600         refresh_resolvers();
601         threaded_run(folder, &param, &result, connect_ssl_run);
602
603         if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
604              result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
605                 cert_len = (int)mailstream_ssl_get_certificate(imap->imap_stream, &certificate);
606                 if (etpan_certificate_check(certificate, cert_len, &param) < 0)
607                         return -1;
608                 if (certificate) 
609                         free(certificate); 
610         }
611         debug_print("connect %d with imap %p\n", result.error, imap);
612         
613         return result.error;
614 }
615
616 struct capa_param {
617         mailimap * imap;
618 };
619
620 struct capa_result {
621         int error;
622         struct mailimap_capability_data *caps;
623 };
624
625 static void capability_run(struct etpan_thread_op * op)
626 {
627         int r;
628         struct capa_param * param;
629         struct capa_result * result;
630         struct mailimap_capability_data *caps;
631
632         param = op->param;
633         result = op->result;
634         
635         CHECK_IMAP();
636
637         r = mailimap_capability(param->imap, &caps);
638         
639         result->error = r;
640         result->caps = (r == 0 ? caps : NULL);
641 }
642
643
644 struct mailimap_capability_data * imap_threaded_capability(Folder *folder, int *ok)
645 {
646         struct capa_param param;
647         struct capa_result result;
648         mailimap *imap;
649         
650         imap = get_imap(folder);
651         
652         param.imap = imap;
653         
654         threaded_run(folder, &param, &result, capability_run);
655         
656         debug_print("capa %d\n", result.error);
657         
658         if (ok)
659                 *ok = result.error;
660
661         return result.caps;
662         
663 }
664         
665 struct disconnect_param {
666         mailimap * imap;
667 };
668
669 struct disconnect_result {
670         int error;
671 };
672
673 static void disconnect_run(struct etpan_thread_op * op)
674 {
675         int r;
676         struct disconnect_param * param;
677         struct disconnect_result * result;
678         
679         param = op->param;
680         result = op->result;
681         
682         CHECK_IMAP();
683
684         r = mailimap_logout(param->imap);
685         
686         result->error = r;
687 }
688
689 void imap_threaded_disconnect(Folder * folder)
690 {
691         struct connect_param param;
692         struct connect_result result;
693         mailimap * imap;
694         
695         imap = get_imap(folder);
696         if (imap == NULL) {
697                 debug_print("was disconnected\n");
698                 return;
699         }
700         
701         param.imap = imap;
702         
703         threaded_run(folder, &param, &result, disconnect_run);
704         
705         if (imap == get_imap(folder)) {
706                 debug_print("deleting old imap %p\n", imap);
707                 delete_imap(folder, imap);
708         } else {
709                 debug_print("imap already deleted %p\n", imap);
710         }
711         
712         debug_print("disconnect ok\n");
713 }
714
715
716 struct list_param {
717         mailimap * imap;
718         const char * base;
719         const char * wildcard;
720         gboolean sub_only;
721 };
722
723 struct list_result {
724         int error;
725         clist * list;
726 };
727
728 static void list_run(struct etpan_thread_op * op)
729 {
730         struct list_param * param;
731         struct list_result * result;
732         int r;
733         clist * list;
734         
735         param = op->param;
736         result = op->result;
737
738         CHECK_IMAP();
739
740         list = NULL;
741         
742         if (param->base == NULL || param->wildcard == NULL) {
743                 result->list = list;
744                 result->error = -1;
745                 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
746                 return;
747         }
748         if (param->sub_only)
749                 r = mailimap_lsub(param->imap, param->base,
750                           param->wildcard, &list);
751         else
752                 r = mailimap_list(param->imap, param->base,
753                           param->wildcard, &list);
754         result->error = r;
755         result->list = list;
756         debug_print("imap list run - end\n");
757 }
758
759 int imap_threaded_list(Folder * folder, const char * base,
760                        const char * wildcard,
761                        clist ** p_result)
762 {
763         struct list_param param;
764         struct list_result result;
765         
766         debug_print("imap list - begin\n");
767         
768         param.imap = get_imap(folder);
769         param.base = base;
770         param.wildcard = wildcard;
771         param.sub_only = FALSE;
772
773         threaded_run(folder, &param, &result, list_run);
774         
775         * p_result = result.list;
776         
777         debug_print("imap list - end %p\n", result.list);
778         
779         return result.error;
780 }
781
782 int imap_threaded_lsub(Folder * folder, const char * base,
783                        const char * wildcard,
784                        clist ** p_result)
785 {
786         struct list_param param;
787         struct list_result result;
788         
789         debug_print("imap lsub - begin\n");
790         
791         param.imap = get_imap(folder);
792         param.base = base;
793         param.wildcard = wildcard;
794         param.sub_only = TRUE;
795         
796         threaded_run(folder, &param, &result, list_run);
797         
798         * p_result = result.list;
799         
800         debug_print("imap lsub - end %p\n", result.list);
801         
802         return result.error;
803 }
804
805 struct subscribe_param {
806         mailimap * imap;
807         const char * mb;
808         gboolean subscribe;
809 };
810
811 struct subscribe_result {
812         int error;
813 };
814
815 static void subscribe_run(struct etpan_thread_op * op)
816 {
817         struct subscribe_param * param;
818         struct subscribe_result * result;
819         int r;
820         
821         param = op->param;
822         result = op->result;
823
824         CHECK_IMAP();
825
826         if (param->mb == NULL) {
827                 result->error = -1;
828                 debug_print("no mb\n");
829                 return;
830         }
831         if (param->subscribe)
832                 r = mailimap_subscribe(param->imap, param->mb);
833         else
834                 r = mailimap_unsubscribe(param->imap, param->mb);
835         result->error = r;
836         debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
837 }
838
839 int imap_threaded_subscribe(Folder * folder, const char * mb,
840                        gboolean subscribe)
841 {
842         struct subscribe_param param;
843         struct subscribe_result result;
844         
845         debug_print("imap list - begin\n");
846         
847         param.imap = get_imap(folder);
848         param.mb = mb;
849         param.subscribe = subscribe;
850
851         threaded_run(folder, &param, &result, subscribe_run);
852         
853         return result.error;
854 }
855
856 struct login_param {
857         mailimap * imap;
858         const char * login;
859         const char * password;
860         const char * type;
861         const char * server;
862 };
863
864 struct login_result {
865         int error;
866 };
867
868 static void login_run(struct etpan_thread_op * op)
869 {
870         struct login_param * param;
871         struct login_result * result;
872         int r;
873 #ifdef DISABLE_LOG_DURING_LOGIN
874         int old_debug;
875 #endif
876         
877         param = op->param;
878         result = op->result;
879
880         CHECK_IMAP();
881
882 #ifdef DISABLE_LOG_DURING_LOGIN
883         old_debug = mailstream_debug;
884         mailstream_debug = 0;
885 #endif
886         if (!strcmp(param->type, "LOGIN"))
887                 r = mailimap_login(param->imap,
888                            param->login, param->password);
889         else if (!strcmp(param->type, "GSSAPI"))
890                 r = mailimap_authenticate(param->imap,
891                         param->type, param->server, NULL, NULL,
892                         param->login, param->login,
893                         param->password, NULL);
894         else 
895                 r = mailimap_authenticate(param->imap,
896                         param->type, NULL, NULL, NULL,
897                         param->login, param->login,
898                         param->password, NULL);
899 #ifdef DISABLE_LOG_DURING_LOGIN
900         mailstream_debug = old_debug;
901 #endif
902         
903         result->error = r;
904         if (param->imap->imap_response)
905                 imap_logger_cmd(0, param->imap->imap_response, strlen(param->imap->imap_response));
906         debug_print("imap login run - end %i\n", r);
907 }
908
909 int imap_threaded_login(Folder * folder,
910                         const char * login, const char * password,
911                         const char * type)
912 {
913         struct login_param param;
914         struct login_result result;
915         
916         debug_print("imap login - begin\n");
917         
918         param.imap = get_imap(folder);
919         param.login = login;
920         param.password = password;
921         param.type = type;
922         if (folder && folder->account)
923                 param.server = folder->account->recv_server;
924         else
925                 param.server = NULL;
926
927         threaded_run(folder, &param, &result, login_run);
928         
929         debug_print("imap login - end\n");
930         
931         return result.error;
932 }
933
934
935 struct status_param {
936         mailimap * imap;
937         const char * mb;
938         struct mailimap_status_att_list * status_att_list;
939 };
940
941 struct status_result {
942         int error;
943         struct mailimap_mailbox_data_status * data_status;
944 };
945
946 static void status_run(struct etpan_thread_op * op)
947 {
948         struct status_param * param;
949         struct status_result * result;
950         int r;
951         
952         param = op->param;
953         result = op->result;
954         
955         CHECK_IMAP();
956
957         r = mailimap_status(param->imap, param->mb,
958                             param->status_att_list,
959                             &result->data_status);
960         
961         result->error = r;
962         debug_print("imap status run - end %i\n", r);
963 }
964
965 int imap_threaded_status(Folder * folder, const char * mb,
966                          struct mailimap_mailbox_data_status ** data_status,
967                          guint mask)
968 {
969         struct status_param param;
970         struct status_result result;
971         struct mailimap_status_att_list * status_att_list;
972         
973         debug_print("imap status - begin\n");
974         
975         status_att_list = mailimap_status_att_list_new_empty();
976         if (mask & 1 << 0) {
977                 mailimap_status_att_list_add(status_att_list,
978                                      MAILIMAP_STATUS_ATT_MESSAGES);
979         }
980         if (mask & 1 << 1) {
981                 mailimap_status_att_list_add(status_att_list,
982                                      MAILIMAP_STATUS_ATT_RECENT);
983         }
984         if (mask & 1 << 2) {
985                 mailimap_status_att_list_add(status_att_list,
986                                      MAILIMAP_STATUS_ATT_UIDNEXT);
987         }
988         if (mask & 1 << 3) {
989                 mailimap_status_att_list_add(status_att_list,
990                                      MAILIMAP_STATUS_ATT_UIDVALIDITY);
991         }
992         if (mask & 1 << 4) {
993                 mailimap_status_att_list_add(status_att_list,
994                                      MAILIMAP_STATUS_ATT_UNSEEN);
995         }
996         param.imap = get_imap(folder);
997         param.mb = mb;
998         param.status_att_list = status_att_list;
999         
1000         threaded_run(folder, &param, &result, status_run);
1001         
1002         debug_print("imap status - end\n");
1003         
1004         * data_status = result.data_status;
1005         
1006         mailimap_status_att_list_free(status_att_list);
1007         
1008         return result.error;
1009 }
1010
1011
1012
1013 struct noop_param {
1014         mailimap * imap;
1015 };
1016
1017 struct noop_result {
1018         int error;
1019 };
1020
1021 static void noop_run(struct etpan_thread_op * op)
1022 {
1023         struct noop_param * param;
1024         struct noop_result * result;
1025         int r;
1026         
1027         param = op->param;
1028         result = op->result;
1029
1030         CHECK_IMAP();
1031
1032         r = mailimap_noop(param->imap);
1033         
1034         result->error = r;
1035         debug_print("imap noop run - end %i\n", r);
1036 }
1037
1038 int imap_threaded_noop(Folder * folder, unsigned int * p_exists, 
1039                        unsigned int *p_recent, 
1040                        unsigned int *p_expunge,
1041                        unsigned int *p_unseen,
1042                        unsigned int *p_uidnext,
1043                        unsigned int *p_uidval)
1044 {
1045         struct noop_param param;
1046         struct noop_result result;
1047         mailimap * imap;
1048         
1049         debug_print("imap noop - begin\n");
1050         
1051         imap = get_imap(folder);
1052         param.imap = imap;
1053
1054         threaded_run(folder, &param, &result, noop_run);
1055         
1056         if (result.error == 0 && imap && imap->imap_selection_info != NULL) {
1057                 * p_exists = imap->imap_selection_info->sel_exists;
1058                 * p_recent = imap->imap_selection_info->sel_recent;
1059                 * p_unseen = imap->imap_selection_info->sel_unseen;
1060                 * p_uidnext = imap->imap_selection_info->sel_uidnext;
1061                 * p_uidval = imap->imap_selection_info->sel_uidvalidity;
1062         } else {
1063                 * p_exists = 0;
1064                 * p_recent = 0;
1065                 * p_unseen = 0;
1066                 * p_uidnext = 0;
1067                 * p_uidval = 0;
1068         }
1069         if (result.error == 0 && imap && imap->imap_response_info != NULL &&
1070             imap->imap_response_info->rsp_expunged != NULL) {
1071                 * p_expunge = clist_count(imap->imap_response_info->rsp_expunged);
1072         } else {
1073                 * p_expunge = 0;
1074         }       
1075         debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1076                 *p_exists, *p_recent, *p_expunge, *p_unseen,
1077                 *p_uidnext, *p_uidval);
1078         
1079         return result.error;
1080 }
1081
1082
1083 struct starttls_result {
1084         int error;
1085 };
1086
1087 static void starttls_run(struct etpan_thread_op * op)
1088 {
1089         struct connect_param * param;
1090         struct starttls_result * result;
1091         int r;
1092
1093         param = op->param;
1094         result = op->result;
1095
1096         CHECK_IMAP();
1097
1098         r = mailimap_starttls(param->imap);
1099         
1100         result->error = r;
1101         debug_print("imap starttls run - end %i\n", r);
1102         
1103         if (r == 0) {
1104                 mailimap *imap = param->imap;
1105                 mailstream_low *plain_low = NULL;
1106                 mailstream_low *tls_low = NULL;
1107                 int fd = -1;
1108                 
1109                 plain_low = mailstream_get_low(imap->imap_stream);
1110                 fd = mailstream_low_get_fd(plain_low);
1111                 if (fd == -1) {
1112                         debug_print("imap starttls run - can't get fd\n");
1113                         result->error = MAILIMAP_ERROR_STREAM;
1114                         return;
1115                 }
1116
1117                 tls_low = mailstream_low_tls_open(fd);
1118                 if (tls_low == NULL) {
1119                         debug_print("imap starttls run - can't tls_open\n");
1120                         result->error = MAILIMAP_ERROR_STREAM;
1121                         return;
1122                 }
1123                 mailstream_low_free(plain_low);
1124                 mailstream_set_low(imap->imap_stream, tls_low);
1125         }
1126 }
1127
1128 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1129 {
1130         struct connect_param param;
1131         struct starttls_result result;
1132         int cert_len;
1133         unsigned char *certificate;
1134         
1135         debug_print("imap starttls - begin\n");
1136         
1137         param.imap = get_imap(folder);
1138         param.server = host;
1139         param.port = port;
1140         
1141         threaded_run(folder, &param, &result, starttls_run);
1142         
1143         debug_print("imap starttls - end\n");
1144
1145         if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
1146                 cert_len = (int)mailstream_ssl_get_certificate(param.imap->imap_stream, &certificate);
1147                 if (etpan_certificate_check(certificate, cert_len, &param) < 0)
1148                         result.error = MAILIMAP_ERROR_STREAM;
1149                 if (certificate) 
1150                         free(certificate); 
1151         }       
1152         return result.error;
1153 }
1154
1155
1156
1157 struct create_param {
1158         mailimap * imap;
1159         const char * mb;
1160 };
1161
1162 struct create_result {
1163         int error;
1164 };
1165
1166 static void create_run(struct etpan_thread_op * op)
1167 {
1168         struct create_param * param;
1169         struct create_result * result;
1170         int r;
1171         
1172         param = op->param;
1173         result = op->result;
1174
1175         CHECK_IMAP();
1176
1177         r = mailimap_create(param->imap, param->mb);
1178         
1179         result->error = r;
1180         debug_print("imap create run - end %i\n", r);
1181 }
1182
1183 int imap_threaded_create(Folder * folder, const char * mb)
1184 {
1185         struct create_param param;
1186         struct create_result result;
1187         
1188         debug_print("imap create - begin\n");
1189         
1190         param.imap = get_imap(folder);
1191         param.mb = mb;
1192         
1193         threaded_run(folder, &param, &result, create_run);
1194         
1195         debug_print("imap create - end\n");
1196         
1197         return result.error;
1198 }
1199
1200
1201
1202
1203 struct rename_param {
1204         mailimap * imap;
1205         const char * mb;
1206         const char * new_name;
1207 };
1208
1209 struct rename_result {
1210         int error;
1211 };
1212
1213 static void rename_run(struct etpan_thread_op * op)
1214 {
1215         struct rename_param * param;
1216         struct rename_result * result;
1217         int r;
1218         
1219         param = op->param;
1220         result = op->result;
1221
1222         CHECK_IMAP();
1223
1224         r = mailimap_rename(param->imap, param->mb, param->new_name);
1225         
1226         result->error = r;
1227         debug_print("imap rename run - end %i\n", r);
1228 }
1229
1230 int imap_threaded_rename(Folder * folder,
1231                          const char * mb, const char * new_name)
1232 {
1233         struct rename_param param;
1234         struct rename_result result;
1235         
1236         debug_print("imap rename - begin\n");
1237         
1238         param.imap = get_imap(folder);
1239         param.mb = mb;
1240         param.new_name = new_name;
1241         
1242         threaded_run(folder, &param, &result, rename_run);
1243         
1244         debug_print("imap rename - end\n");
1245         
1246         return result.error;
1247 }
1248
1249
1250
1251
1252 struct delete_param {
1253         mailimap * imap;
1254         const char * mb;
1255 };
1256
1257 struct delete_result {
1258         int error;
1259 };
1260
1261 static void delete_run(struct etpan_thread_op * op)
1262 {
1263         struct delete_param * param;
1264         struct delete_result * result;
1265         int r;
1266         
1267         param = op->param;
1268         result = op->result;
1269
1270         CHECK_IMAP();
1271
1272         r = mailimap_delete(param->imap, param->mb);
1273         
1274         result->error = r;
1275         debug_print("imap delete run - end %i\n", r);
1276 }
1277
1278 int imap_threaded_delete(Folder * folder, const char * mb)
1279 {
1280         struct delete_param param;
1281         struct delete_result result;
1282         
1283         debug_print("imap delete - begin\n");
1284         
1285         param.imap = get_imap(folder);
1286         param.mb = mb;
1287         
1288         threaded_run(folder, &param, &result, delete_run);
1289         
1290         debug_print("imap delete - end\n");
1291         
1292         return result.error;
1293 }
1294
1295
1296
1297 struct select_param {
1298         mailimap * imap;
1299         const char * mb;
1300 };
1301
1302 struct select_result {
1303         int error;
1304 };
1305
1306 static void select_run(struct etpan_thread_op * op)
1307 {
1308         struct select_param * param;
1309         struct select_result * result;
1310         int r;
1311         
1312         param = op->param;
1313         result = op->result;
1314
1315         CHECK_IMAP();
1316
1317         r = mailimap_select(param->imap, param->mb);
1318         
1319         result->error = r;
1320         debug_print("imap select run - end %i\n", r);
1321 }
1322
1323 int imap_threaded_select(Folder * folder, const char * mb,
1324                          gint * exists, gint * recent, gint * unseen,
1325                          guint32 * uid_validity,gint *can_create_flags)
1326 {
1327         struct select_param param;
1328         struct select_result result;
1329         mailimap * imap;
1330
1331         debug_print("imap select - begin\n");
1332         
1333         imap = get_imap(folder);
1334         param.imap = imap;
1335         param.mb = mb;
1336         
1337         threaded_run(folder, &param, &result, select_run);
1338         
1339         if (result.error != MAILIMAP_NO_ERROR)
1340                 return result.error;
1341         
1342         if (!imap || imap->imap_selection_info == NULL)
1343                 return MAILIMAP_ERROR_PARSE;
1344         
1345         * exists = imap->imap_selection_info->sel_exists;
1346         * recent = imap->imap_selection_info->sel_recent;
1347         * unseen = imap->imap_selection_info->sel_unseen;
1348         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1349         * can_create_flags = FALSE;
1350
1351         if (imap->imap_selection_info->sel_perm_flags) {
1352                 clistiter *cur =
1353                         clist_begin(imap->imap_selection_info->sel_perm_flags);
1354                 for (; cur && !(*can_create_flags); cur = clist_next(cur)) {
1355                         struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur);
1356                         if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL)
1357                                 *can_create_flags = TRUE;
1358                         else if (flag->fl_flag && 
1359                                         flag->fl_flag->fl_type == 6 &&
1360                                         !strcmp(flag->fl_flag->fl_data.fl_extension, "*"))
1361                                 *can_create_flags = TRUE; 
1362                         
1363                 }
1364         }
1365         debug_print("imap select - end\n");
1366         
1367         return result.error;
1368 }
1369
1370 static void close_run(struct etpan_thread_op * op)
1371 {
1372         struct select_param * param;
1373         struct select_result * result;
1374         int r;
1375         
1376         param = op->param;
1377         result = op->result;
1378
1379         CHECK_IMAP();
1380
1381         r = mailimap_close(param->imap);
1382         
1383         result->error = r;
1384         debug_print("imap close run - end %i\n", r);
1385 }
1386
1387 int imap_threaded_close(Folder * folder)
1388 {
1389         struct select_param param;
1390         struct select_result result;
1391         mailimap * imap;
1392         
1393         debug_print("imap close - begin\n");
1394         
1395         imap = get_imap(folder);
1396         param.imap = imap;
1397         
1398         threaded_run(folder, &param, &result, close_run);
1399         
1400         if (result.error != MAILIMAP_NO_ERROR)
1401                 return result.error;
1402         
1403         debug_print("imap close - end\n");
1404         
1405         return result.error;
1406 }
1407
1408 struct examine_param {
1409         mailimap * imap;
1410         const char * mb;
1411 };
1412
1413 struct examine_result {
1414         int error;
1415 };
1416
1417 static void examine_run(struct etpan_thread_op * op)
1418 {
1419         struct examine_param * param;
1420         struct examine_result * result;
1421         int r;
1422         
1423         param = op->param;
1424         result = op->result;
1425
1426         CHECK_IMAP();
1427
1428         r = mailimap_examine(param->imap, param->mb);
1429         
1430         result->error = r;
1431         debug_print("imap examine run - end %i\n", r);
1432 }
1433
1434 int imap_threaded_examine(Folder * folder, const char * mb,
1435                           gint * exists, gint * recent, gint * unseen,
1436                           guint32 * uid_validity)
1437 {
1438         struct examine_param param;
1439         struct examine_result result;
1440         mailimap * imap;
1441         
1442         debug_print("imap examine - begin\n");
1443         
1444         imap = get_imap(folder);
1445         param.imap = imap;
1446         param.mb = mb;
1447         
1448         threaded_run(folder, &param, &result, examine_run);
1449         
1450         if (result.error != MAILIMAP_NO_ERROR)
1451                 return result.error;
1452         
1453         if (!imap || imap->imap_selection_info == NULL)
1454                 return MAILIMAP_ERROR_PARSE;
1455         
1456         * exists = imap->imap_selection_info->sel_exists;
1457         * recent = imap->imap_selection_info->sel_recent;
1458         * unseen = imap->imap_selection_info->sel_unseen;
1459         * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1460         
1461         debug_print("imap examine - end\n");
1462         
1463         return result.error;
1464 }
1465
1466
1467
1468
1469 struct search_param {
1470         mailimap * imap;
1471         int type;
1472         struct mailimap_set * set;
1473 };
1474
1475 struct search_result {
1476         int error;
1477         clist * search_result;
1478 };
1479
1480 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1481 {
1482         return mailimap_set_item_new(orig->set_first, orig->set_last);
1483 }
1484
1485 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1486 {
1487         clist *list = orig ? orig->set_list : NULL;
1488         clist *newlist = clist_new();
1489         clistiter *cur;
1490         
1491         if (!orig)
1492                 return NULL;
1493         for (cur = clist_begin(list); cur; cur = clist_next(cur))
1494                 clist_append(newlist, 
1495                         sc_mailimap_set_item_copy(
1496                         (struct mailimap_set_item *)clist_content(cur)));
1497         return mailimap_set_new(newlist);
1498 }
1499
1500 static void search_run(struct etpan_thread_op * op)
1501 {
1502         struct search_param * param;
1503         struct search_result * result;
1504         int r;
1505         struct mailimap_search_key * key = NULL;
1506         struct mailimap_search_key * uid_key = NULL;
1507         struct mailimap_search_key * search_type_key;
1508         clist * search_result;
1509         
1510         param = op->param;
1511         result = op->result;
1512
1513         CHECK_IMAP();
1514
1515         /* we copy the mailimap_set because freeing the key is recursive */
1516         if (param->set != NULL) {
1517                 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1518         } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1519                 uid_key = mailimap_search_key_new_all();
1520         }
1521         search_type_key = NULL;
1522         switch (param->type) {
1523         case IMAP_SEARCH_TYPE_SIMPLE:
1524                 search_type_key = NULL;
1525                 break;
1526                 
1527         case IMAP_SEARCH_TYPE_SEEN:
1528                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
1529                                                           NULL, NULL, NULL, NULL, NULL,
1530                                                           NULL, NULL, NULL, NULL, NULL,
1531                                                           NULL, NULL, NULL, NULL, 0,
1532                                                           NULL, NULL, NULL, NULL, NULL,
1533                                                           NULL, 0, NULL, NULL, NULL);
1534                 break;
1535                 
1536         case IMAP_SEARCH_TYPE_UNSEEN:
1537                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
1538                                                           NULL, NULL, NULL, NULL, NULL,
1539                                                           NULL, NULL, NULL, NULL, NULL,
1540                                                           NULL, NULL, NULL, NULL, 0,
1541                                                           NULL, NULL, NULL, NULL, NULL,
1542                                                           NULL, 0, NULL, NULL, NULL);
1543                 break;
1544                 
1545         case IMAP_SEARCH_TYPE_ANSWERED:
1546                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
1547                                                           NULL, NULL, NULL, NULL, NULL,
1548                                                           NULL, NULL, NULL, NULL, NULL,
1549                                                           NULL, NULL, NULL, NULL, 0,
1550                                                           NULL, NULL, NULL, NULL, NULL,
1551                                                           NULL, 0, NULL, NULL, NULL);
1552                 break;
1553                 
1554         case IMAP_SEARCH_TYPE_FLAGGED:
1555                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
1556                                                           NULL, NULL, NULL, NULL, NULL,
1557                                                           NULL, NULL, NULL, NULL, NULL,
1558                                                           NULL, NULL, NULL, NULL, 0,
1559                                                           NULL, NULL, NULL, NULL, NULL,
1560                                                           NULL, 0, NULL, NULL, NULL);
1561                 break;
1562         case IMAP_SEARCH_TYPE_DELETED:
1563                 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_DELETED,
1564                                                           NULL, NULL, NULL, NULL, NULL,
1565                                                           NULL, NULL, NULL, NULL, NULL,
1566                                                           NULL, NULL, NULL, NULL, 0,
1567                                                           NULL, NULL, NULL, NULL, NULL,
1568                                                           NULL, 0, NULL, NULL, NULL);
1569                 break;
1570         }
1571         
1572         if (search_type_key != NULL) {
1573                 if (param->set != NULL) {
1574                         key = mailimap_search_key_new_multiple_empty();
1575                         mailimap_search_key_multiple_add(key, search_type_key);
1576                         mailimap_search_key_multiple_add(key, uid_key);
1577                 } else {
1578                         key = search_type_key;
1579                 }
1580         } else if (uid_key != NULL) {
1581                 key = uid_key;
1582         }
1583         
1584         if (key == NULL) {
1585                 g_warning("no key!");
1586                 result = op->result;
1587                 result->error = -1;
1588                 result->search_result = NULL;
1589         } else {
1590                 mailstream_logger = imap_logger_uid;
1591
1592                 r = mailimap_uid_search(param->imap, NULL, key, &search_result);
1593
1594                 mailstream_logger = imap_logger_cmd;
1595
1596                 /* free the key (with the imapset) */
1597                 mailimap_search_key_free(key);
1598
1599                 result->error = r;
1600                 result->search_result = search_result;
1601         }
1602         debug_print("imap search run - end %i\n", result->error);
1603 }
1604
1605 int imap_threaded_search(Folder * folder, int search_type,
1606                          struct mailimap_set * set, clist ** search_result)
1607 {
1608         struct search_param param;
1609         struct search_result result;
1610         mailimap * imap;
1611         
1612         debug_print("imap search - begin\n");
1613
1614         imap = get_imap(folder);
1615         param.imap = imap;
1616         param.set = set;
1617         param.type = search_type;
1618         
1619         threaded_run(folder, &param, &result, search_run);
1620         
1621         if (result.error != MAILIMAP_NO_ERROR)
1622                 return result.error;
1623         
1624         debug_print("imap search - end\n");
1625         
1626         * search_result = result.search_result;
1627         
1628         return result.error;
1629 }
1630
1631
1632
1633 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1634                                  uint32_t * puid,
1635                                  char ** pheaders,
1636                                  size_t * pref_size,
1637                                  struct mailimap_msg_att_dynamic ** patt_dyn);
1638
1639 static int
1640 result_to_uid_list(clist * fetch_result, carray ** result)
1641 {
1642         clistiter * cur;
1643         int r;
1644         int res;
1645         carray * tab;
1646         
1647         tab = carray_new(128);
1648         if (tab == NULL) {
1649                 res = MAILIMAP_ERROR_MEMORY;
1650                 goto err;
1651         }
1652         
1653         for(cur = clist_begin(fetch_result) ; cur != NULL ;
1654             cur = clist_next(cur)) {
1655                 struct mailimap_msg_att * msg_att;
1656                 uint32_t uid;
1657                 uint32_t * puid;
1658                 
1659                 msg_att = clist_content(cur);
1660                 
1661                 uid = 0;
1662                 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL);
1663                 
1664                 puid = malloc(sizeof(* puid));
1665                 if (puid == NULL) {
1666                         res = MAILIMAP_ERROR_MEMORY;
1667                         goto free_list;
1668                 }
1669                 * puid = uid;
1670                         
1671                 r = carray_add(tab, puid, NULL);
1672                 if (r < 0) {
1673                         free(puid);
1674                         res = MAILIMAP_ERROR_MEMORY;
1675                         goto free_list;
1676                 }
1677         }
1678                 
1679         * result = tab;
1680
1681         return MAILIMAP_NO_ERROR;
1682   
1683  free_list:
1684         imap_fetch_uid_list_free(tab);
1685  err:
1686         return res;
1687 }
1688
1689 static int imap_get_messages_list(mailimap * imap,
1690                                   uint32_t first_index,
1691                                   carray ** result)
1692 {
1693         carray * env_list;
1694         int r;
1695         struct mailimap_fetch_att * fetch_att;
1696         struct mailimap_fetch_type * fetch_type;
1697         struct mailimap_set * set;
1698         clist * fetch_result;
1699         int res;
1700         
1701         set = mailimap_set_new_interval(first_index, 0);
1702         if (set == NULL) {
1703                 res = MAILIMAP_ERROR_MEMORY;
1704                 goto err;
1705         }
1706
1707         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1708         if (fetch_type == NULL) {
1709                 res = MAILIMAP_ERROR_MEMORY;
1710                 goto free_set;
1711         }
1712
1713         fetch_att = mailimap_fetch_att_new_uid();
1714         if (fetch_att == NULL) {
1715                 res = MAILIMAP_ERROR_MEMORY;
1716                 goto free_fetch_type;
1717         }
1718
1719         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1720         if (r != MAILIMAP_NO_ERROR) {
1721                 mailimap_fetch_att_free(fetch_att);
1722                 res = MAILIMAP_ERROR_MEMORY;
1723                 goto free_fetch_type;
1724         }
1725
1726         mailstream_logger = imap_logger_fetch;
1727         
1728         r = mailimap_uid_fetch(imap, set,
1729                                fetch_type, &fetch_result);
1730
1731         mailstream_logger = imap_logger_cmd;
1732         mailimap_fetch_type_free(fetch_type);
1733         mailimap_set_free(set);
1734
1735         if (r != MAILIMAP_NO_ERROR) {
1736                 res = r;
1737                 goto err;
1738         }
1739
1740         env_list = NULL;
1741         r = result_to_uid_list(fetch_result, &env_list);
1742         mailimap_fetch_list_free(fetch_result);
1743         
1744         * result = env_list;
1745
1746         return MAILIMAP_NO_ERROR;
1747
1748  free_fetch_type:
1749         mailimap_fetch_type_free(fetch_type);
1750  free_set:
1751         mailimap_set_free(set);
1752  err:
1753         return res;
1754 }
1755
1756
1757
1758
1759 struct fetch_uid_param {
1760         mailimap * imap;
1761         uint32_t first_index;
1762 };
1763
1764 struct fetch_uid_result {
1765         int error;
1766         carray * fetch_result;
1767 };
1768
1769 static void fetch_uid_run(struct etpan_thread_op * op)
1770 {
1771         struct fetch_uid_param * param;
1772         struct fetch_uid_result * result;
1773         carray * fetch_result;
1774         int r;
1775         
1776         param = op->param;
1777         result = op->result;
1778
1779         CHECK_IMAP();
1780
1781         fetch_result = NULL;
1782         mailstream_logger = imap_logger_noop;
1783         log_print(LOG_PROTOCOL, "IMAP4- [fetching UIDs...]\n");
1784
1785         r = imap_get_messages_list(param->imap, param->first_index,
1786                                    &fetch_result);
1787         
1788         mailstream_logger = imap_logger_cmd;
1789
1790         result->error = r;
1791         result->fetch_result = fetch_result;
1792         debug_print("imap fetch_uid run - end %i\n", r);
1793 }
1794
1795 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1796                             carray ** fetch_result)
1797 {
1798         struct fetch_uid_param param;
1799         struct fetch_uid_result result;
1800         mailimap * imap;
1801         
1802         debug_print("imap fetch_uid - begin\n");
1803         
1804         imap = get_imap(folder);
1805         param.imap = imap;
1806         param.first_index = first_index;
1807         
1808         threaded_run(folder, &param, &result, fetch_uid_run);
1809         
1810         if (result.error != MAILIMAP_NO_ERROR)
1811                 return result.error;
1812         
1813         debug_print("imap fetch_uid - end\n");
1814         
1815         * fetch_result = result.fetch_result;
1816         
1817         return result.error;
1818 }
1819
1820
1821 void imap_fetch_uid_list_free(carray * uid_list)
1822 {
1823         unsigned int i;
1824         
1825         for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1826                 uint32_t * puid;
1827                 
1828                 puid = carray_get(uid_list, i);
1829                 free(puid);
1830         }
1831         carray_free(uid_list);
1832 }
1833
1834
1835
1836
1837 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags);
1838
1839 static int
1840 result_to_uid_flags_list(clist * fetch_result, carray ** result)
1841 {
1842         clistiter * cur;
1843         int r;
1844         int res;
1845         carray * tab;
1846         GSList *tags = NULL;
1847
1848         tab = carray_new(128);
1849         if (tab == NULL) {
1850                 res = MAILIMAP_ERROR_MEMORY;
1851                 goto err;
1852         }
1853         
1854         for(cur = clist_begin(fetch_result) ; cur != NULL ;
1855             cur = clist_next(cur)) {
1856                 struct mailimap_msg_att * msg_att;
1857                 uint32_t uid;
1858                 uint32_t * puid;
1859                 struct mailimap_msg_att_dynamic * att_dyn;
1860                 int flags;
1861                 int * pflags;
1862                 
1863                 tags = NULL;
1864
1865                 msg_att = clist_content(cur);
1866                 
1867                 uid = 0;
1868                 att_dyn = NULL;
1869                 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn);
1870                 if (uid == 0)
1871                         continue;
1872                 if (att_dyn == NULL)
1873                         continue;
1874                 
1875                 flags = imap_flags_to_flags(att_dyn, &tags);
1876                 
1877                 puid = malloc(sizeof(* puid));
1878                 if (puid == NULL) {
1879                         res = MAILIMAP_ERROR_MEMORY;
1880                         goto free_list;
1881                 }
1882                 * puid = uid;
1883                 
1884                 r = carray_add(tab, puid, NULL);
1885                 if (r < 0) {
1886                         free(puid);
1887                         res = MAILIMAP_ERROR_MEMORY;
1888                         goto free_list;
1889                 }
1890                 pflags = malloc(sizeof(* pflags));
1891                 if (pflags == NULL) {
1892                         res = MAILIMAP_ERROR_MEMORY;
1893                         goto free_list;
1894                 }
1895                 * pflags = flags;
1896                 r = carray_add(tab, pflags, NULL);
1897                 if (r < 0) {
1898                         free(pflags);
1899                         res = MAILIMAP_ERROR_MEMORY;
1900                         goto free_list;
1901                 }
1902                 r = carray_add(tab, tags, NULL);
1903                 if (r < 0) {
1904                         free(pflags);
1905                         res = MAILIMAP_ERROR_MEMORY;
1906                         goto free_list;
1907                 }
1908         }
1909                 
1910         * result = tab;
1911
1912         return MAILIMAP_NO_ERROR;
1913   
1914  free_list:
1915         imap_fetch_uid_flags_list_free(tab);
1916         slist_free_strings(tags);
1917         g_slist_free(tags);
1918  err:
1919         return res;
1920 }
1921
1922 static int imap_get_messages_flags_list(mailimap * imap,
1923                                         uint32_t first_index,
1924                                         carray ** result)
1925 {
1926         carray * env_list;
1927         int r;
1928         struct mailimap_fetch_att * fetch_att;
1929         struct mailimap_fetch_type * fetch_type;
1930         struct mailimap_set * set;
1931         clist * fetch_result;
1932         int res;
1933         
1934         set = mailimap_set_new_interval(first_index, 0);
1935         if (set == NULL) {
1936                 res = MAILIMAP_ERROR_MEMORY;
1937                 goto err;
1938         }
1939
1940         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1941         if (fetch_type == NULL) {
1942                 res = MAILIMAP_ERROR_MEMORY;
1943                 goto free_set;
1944         }
1945
1946         fetch_att = mailimap_fetch_att_new_flags();
1947         if (fetch_att == NULL) {
1948                 res = MAILIMAP_ERROR_MEMORY;
1949                 goto free_fetch_type;
1950         }
1951         
1952         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1953         if (r != MAILIMAP_NO_ERROR) {
1954                 mailimap_fetch_att_free(fetch_att);
1955                 res = MAILIMAP_ERROR_MEMORY;
1956                 goto free_fetch_type;
1957         }
1958         
1959         fetch_att = mailimap_fetch_att_new_uid();
1960         if (fetch_att == NULL) {
1961                 res = MAILIMAP_ERROR_MEMORY;
1962                 goto free_fetch_type;
1963         }
1964
1965         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1966         if (r != MAILIMAP_NO_ERROR) {
1967                 mailimap_fetch_att_free(fetch_att);
1968                 res = MAILIMAP_ERROR_MEMORY;
1969                 goto free_fetch_type;
1970         }
1971
1972         mailstream_logger = imap_logger_fetch;
1973         
1974         r = mailimap_uid_fetch(imap, set,
1975                                fetch_type, &fetch_result);
1976
1977         mailstream_logger = imap_logger_cmd;
1978         mailimap_fetch_type_free(fetch_type);
1979         mailimap_set_free(set);
1980
1981         if (r != MAILIMAP_NO_ERROR) {
1982                 res = r;
1983                 goto err;
1984         }
1985
1986         env_list = NULL;
1987         r = result_to_uid_flags_list(fetch_result, &env_list);
1988         mailimap_fetch_list_free(fetch_result);
1989         
1990         * result = env_list;
1991
1992         return MAILIMAP_NO_ERROR;
1993
1994  free_fetch_type:
1995         mailimap_fetch_type_free(fetch_type);
1996  free_set:
1997         mailimap_set_free(set);
1998  err:
1999         return res;
2000 }
2001
2002
2003
2004 static void fetch_uid_flags_run(struct etpan_thread_op * op)
2005 {
2006         struct fetch_uid_param * param;
2007         struct fetch_uid_result * result;
2008         carray * fetch_result;
2009         int r;
2010         
2011         param = op->param;
2012         result = op->result;
2013
2014         CHECK_IMAP();
2015
2016         fetch_result = NULL;
2017         r = imap_get_messages_flags_list(param->imap, param->first_index,
2018                                          &fetch_result);
2019         
2020         result->error = r;
2021         result->fetch_result = fetch_result;
2022         debug_print("imap fetch_uid run - end %i\n", r);
2023 }
2024
2025 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index,
2026                                   carray ** fetch_result)
2027 {
2028         struct fetch_uid_param param;
2029         struct fetch_uid_result result;
2030         mailimap * imap;
2031         
2032         debug_print("imap fetch_uid - begin\n");
2033         
2034         imap = get_imap(folder);
2035         param.imap = imap;
2036         param.first_index = first_index;
2037         
2038         mailstream_logger = imap_logger_noop;
2039         log_print(LOG_PROTOCOL, "IMAP4- [fetching flags...]\n");
2040
2041         threaded_run(folder, &param, &result, fetch_uid_flags_run);
2042
2043         mailstream_logger = imap_logger_cmd;
2044
2045         
2046         if (result.error != MAILIMAP_NO_ERROR)
2047                 return result.error;
2048         
2049         debug_print("imap fetch_uid - end\n");
2050         
2051         * fetch_result = result.fetch_result;
2052         
2053         return result.error;
2054 }
2055
2056
2057 void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
2058 {
2059         unsigned int i;
2060         
2061         for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) {
2062                 void * data;
2063                 
2064                 data = carray_get(uid_flags_list, i);
2065                 free(data);
2066                 data = carray_get(uid_flags_list, i + 1);
2067                 free(data);
2068         }
2069         carray_free(uid_flags_list);
2070 }
2071
2072
2073
2074 static int imap_fetch(mailimap * imap,
2075                       uint32_t msg_index,
2076                       char ** result,
2077                       size_t * result_len)
2078 {
2079         int r;
2080         struct mailimap_set * set;
2081         struct mailimap_fetch_att * fetch_att;
2082         struct mailimap_fetch_type * fetch_type;
2083         clist * fetch_result;
2084         struct mailimap_msg_att * msg_att;
2085         struct mailimap_msg_att_item * msg_att_item;
2086         char * text;
2087         size_t text_length;
2088         int res;
2089         clistiter * cur;
2090         struct mailimap_section * section;
2091
2092         set = mailimap_set_new_single(msg_index);
2093         if (set == NULL) {
2094                 res = MAILIMAP_ERROR_MEMORY;
2095                 goto err;
2096         }
2097
2098         section = mailimap_section_new(NULL);
2099         if (section == NULL) {
2100                 res = MAILIMAP_ERROR_MEMORY;
2101                 goto free_set;
2102         }
2103   
2104         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2105         if (fetch_att == NULL) {
2106                 mailimap_section_free(section);
2107                 res = MAILIMAP_ERROR_MEMORY;
2108                 goto free_set;
2109         }
2110   
2111         fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2112         if (fetch_type == NULL) {
2113                 res = MAILIMAP_ERROR_MEMORY;
2114                 goto free_fetch_att;
2115         }
2116
2117         mailstream_logger = imap_logger_fetch;
2118         
2119         r = mailimap_uid_fetch(imap, set,
2120                                fetch_type, &fetch_result);
2121   
2122         mailstream_logger = imap_logger_cmd;
2123         
2124         mailimap_fetch_type_free(fetch_type);
2125         mailimap_set_free(set);
2126   
2127         switch (r) {
2128         case MAILIMAP_NO_ERROR:
2129                 break;
2130         default:
2131                 return r;
2132         }
2133   
2134         if (clist_begin(fetch_result) == NULL) {
2135                 mailimap_fetch_list_free(fetch_result);
2136                 return MAILIMAP_ERROR_FETCH;
2137         }
2138
2139         msg_att = clist_begin(fetch_result)->data;
2140
2141         text = NULL;
2142         text_length = 0;
2143
2144         for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
2145             cur = clist_next(cur)) {
2146                 msg_att_item = clist_content(cur);
2147
2148                 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2149                         if (msg_att_item->att_data.att_static->att_type ==
2150                             MAILIMAP_MSG_ATT_BODY_SECTION) {
2151                                 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2152                                 /* detach */
2153                                 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2154                                 text_length =
2155                                         msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2156                         }
2157                 }
2158         }
2159
2160         mailimap_fetch_list_free(fetch_result);
2161
2162         if (text == NULL)
2163                 return MAILIMAP_ERROR_FETCH;
2164
2165         * result = text;
2166         * result_len = text_length;
2167   
2168         return MAILIMAP_NO_ERROR;
2169
2170  free_fetch_att:
2171         mailimap_fetch_att_free(fetch_att);
2172  free_set:
2173         mailimap_set_free(set);
2174  err:
2175         return res;
2176 }
2177
2178 static int imap_fetch_header(mailimap * imap,
2179                              uint32_t msg_index,
2180                              char ** result,
2181                              size_t * result_len)
2182 {
2183   int r;
2184   struct mailimap_set * set;
2185   struct mailimap_fetch_att * fetch_att;
2186   struct mailimap_fetch_type * fetch_type;
2187   clist * fetch_result;
2188   struct mailimap_msg_att * msg_att;
2189   struct mailimap_msg_att_item * msg_att_item;
2190   char * text;
2191   size_t text_length;
2192   int res;
2193   clistiter * cur;
2194   struct mailimap_section * section;
2195   
2196   set = mailimap_set_new_single(msg_index);
2197   if (set == NULL) {
2198     res = MAILIMAP_ERROR_MEMORY;
2199     goto err;
2200   }
2201
2202   section = mailimap_section_new_header();
2203   if (section == NULL) {
2204     res = MAILIMAP_ERROR_MEMORY;
2205     goto free_set;
2206   }
2207   
2208   fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2209   if (fetch_att == NULL) {
2210     mailimap_section_free(section);
2211     res = MAILIMAP_ERROR_MEMORY;
2212     goto free_set;
2213   }
2214   
2215   fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2216   if (fetch_type == NULL) {
2217     res = MAILIMAP_ERROR_MEMORY;
2218     goto free_fetch_att;
2219   }
2220
2221   mailstream_logger = imap_logger_fetch;
2222   
2223   r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2224   
2225   mailstream_logger = imap_logger_cmd;
2226   mailimap_fetch_type_free(fetch_type);
2227   mailimap_set_free(set);
2228
2229   switch (r) {
2230   case MAILIMAP_NO_ERROR:
2231     break;
2232   default:
2233     return r;
2234   }
2235
2236   if (clist_begin(fetch_result) == NULL) {
2237     mailimap_fetch_list_free(fetch_result);
2238     return MAILIMAP_ERROR_FETCH;
2239   }
2240
2241   msg_att = clist_begin(fetch_result)->data;
2242
2243   text = NULL;
2244   text_length = 0;
2245
2246   for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
2247       cur = clist_next(cur)) {
2248     msg_att_item = clist_content(cur);
2249
2250     if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2251       if (msg_att_item->att_data.att_static->att_type ==
2252           MAILIMAP_MSG_ATT_BODY_SECTION) {
2253         text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2254         msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2255         text_length =
2256           msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2257       }
2258     }
2259   }
2260
2261   mailimap_fetch_list_free(fetch_result);
2262
2263   if (text == NULL)
2264     return MAILIMAP_ERROR_FETCH;
2265
2266   * result = text;
2267   * result_len = text_length;
2268
2269   return MAILIMAP_NO_ERROR;
2270
2271  free_fetch_att:
2272   mailimap_fetch_att_free(fetch_att);
2273  free_set:
2274   mailimap_set_free(set);
2275  err:
2276   return res;
2277 }
2278
2279
2280
2281 struct fetch_content_param {
2282         mailimap * imap;
2283         uint32_t msg_index;
2284         const char * filename;
2285         int with_body;
2286 };
2287
2288 struct fetch_content_result {
2289         int error;
2290 };
2291
2292 static void fetch_content_run(struct etpan_thread_op * op)
2293 {
2294         struct fetch_content_param * param;
2295         struct fetch_content_result * result;
2296         char * content;
2297         size_t content_size;
2298         int r;
2299         int fd;
2300         FILE * f;
2301         
2302         param = op->param;
2303         result = op->result;
2304
2305         CHECK_IMAP();
2306
2307         content = NULL;
2308         content_size = 0;
2309         if (param->with_body)
2310                 r = imap_fetch(param->imap, param->msg_index,
2311                                &content, &content_size);
2312         else
2313                 r = imap_fetch_header(param->imap, param->msg_index,
2314                                       &content, &content_size);
2315         
2316         result->error = r;
2317         
2318         if (r == MAILIMAP_NO_ERROR) {
2319                 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
2320                 if (fd < 0) {
2321                         result->error = MAILIMAP_ERROR_FETCH;
2322                         goto free;
2323                 }
2324                 
2325                 f = fdopen(fd, "wb");
2326                 if (f == NULL) {
2327                         result->error = MAILIMAP_ERROR_FETCH;
2328                         goto close;
2329                 }
2330                 
2331                 r = fwrite(content, 1, content_size, f);
2332                 if (r < content_size) {
2333                         goto fclose;
2334                 }
2335                 
2336                 r = fclose(f);
2337                 if (r == EOF) {
2338                         goto unlink;
2339                 }
2340                 goto free;
2341                 
2342         fclose:
2343                 fclose(f);
2344                 goto unlink;
2345         close:
2346                 close(fd);
2347         unlink:
2348                 g_unlink(param->filename);
2349         
2350         free:
2351                 /* mmap_string_unref is a simple free in libetpan
2352                  * when it has MMAP_UNAVAILABLE defined */
2353                 if (mmap_string_unref(content) != 0)
2354                         free(content);
2355         }
2356         
2357         debug_print("imap fetch_content run - end %i\n", r);
2358 }
2359
2360 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2361                                 int with_body,
2362                                 const char * filename)
2363 {
2364         struct fetch_content_param param;
2365         struct fetch_content_result result;
2366         mailimap * imap;
2367         
2368         debug_print("imap fetch_content - begin\n");
2369         
2370         imap = get_imap(folder);
2371         param.imap = imap;
2372         param.msg_index = msg_index;
2373         param.filename = filename;
2374         param.with_body = with_body;
2375         
2376         threaded_run(folder, &param, &result, fetch_content_run);
2377         
2378         if (result.error != MAILIMAP_NO_ERROR)
2379                 return result.error;
2380         
2381         debug_print("imap fetch_content - end\n");
2382         
2383         return result.error;
2384 }
2385
2386
2387
2388 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags)
2389 {
2390         int flags;
2391         clist * flag_list;
2392         clistiter * cur;
2393         GSList *tags = NULL;
2394
2395         flags = MSG_UNREAD;
2396         
2397         flag_list = att_dyn->att_list;
2398         if (flag_list == NULL)
2399                 return flags;
2400         
2401         for(cur = clist_begin(flag_list) ; cur != NULL ;
2402             cur = clist_next(cur)) {
2403                 struct mailimap_flag_fetch * flag_fetch;
2404                         
2405                 flag_fetch = clist_content(cur);
2406                 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2407                         flags |= MSG_NEW;
2408                 else {
2409                         switch (flag_fetch->fl_flag->fl_type) {
2410                         case MAILIMAP_FLAG_ANSWERED:
2411                                 flags |= MSG_REPLIED;
2412                                 break;
2413                         case MAILIMAP_FLAG_FLAGGED:
2414                                 flags |= MSG_MARKED;
2415                                 break;
2416                         case MAILIMAP_FLAG_DELETED:
2417                                 flags |= MSG_DELETED;
2418                                 break;
2419                         case MAILIMAP_FLAG_SEEN:
2420                                 flags &= ~MSG_UNREAD;
2421                                 flags &= ~MSG_NEW;
2422                                 break;
2423                         case MAILIMAP_FLAG_KEYWORD:
2424                                 if (s_tags)
2425                                         tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword));
2426                                 break;
2427                         }
2428                 }
2429         }
2430         if (s_tags)
2431                 *s_tags = tags;
2432         return flags;
2433 }
2434
2435 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2436                                  uint32_t * puid,
2437                                  char ** pheaders,
2438                                  size_t * pref_size,
2439                                  struct mailimap_msg_att_dynamic ** patt_dyn)
2440 {
2441   clistiter * item_cur;
2442   uint32_t uid;
2443   char * headers;
2444   size_t ref_size;
2445   struct mailimap_msg_att_dynamic * att_dyn;
2446
2447   uid = 0;
2448   headers = NULL;
2449   ref_size = 0;
2450   att_dyn = NULL;
2451
2452   for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
2453       item_cur = clist_next(item_cur)) {
2454     struct mailimap_msg_att_item * item;
2455
2456     item = clist_content(item_cur);
2457       
2458     switch (item->att_type) {
2459     case MAILIMAP_MSG_ATT_ITEM_STATIC:
2460       switch (item->att_data.att_static->att_type) {
2461       case MAILIMAP_MSG_ATT_UID:
2462         uid = item->att_data.att_static->att_data.att_uid;
2463         break;
2464
2465       case MAILIMAP_MSG_ATT_BODY_SECTION:
2466         if (headers == NULL) {
2467           headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2468         }
2469         break;
2470       case MAILIMAP_MSG_ATT_RFC822_SIZE:
2471               ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2472               break;
2473       }
2474       break;
2475       
2476     case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2477       if (att_dyn == NULL) {
2478         att_dyn = item->att_data.att_dyn;
2479       }
2480       break;
2481     }
2482   }
2483
2484   if (puid != NULL)
2485     * puid = uid;
2486   if (pheaders != NULL)
2487     * pheaders = headers;
2488   if (pref_size != NULL)
2489     * pref_size = ref_size;
2490   if (patt_dyn != NULL)
2491     * patt_dyn = att_dyn;
2492
2493   return MAIL_NO_ERROR;
2494 }
2495
2496 static struct imap_fetch_env_info *
2497 fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags)
2498 {
2499         struct imap_fetch_env_info * info;
2500         uint32_t uid;
2501         char * headers;
2502         size_t size;
2503         struct mailimap_msg_att_dynamic * att_dyn;
2504
2505         imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2506                               &att_dyn);
2507         
2508         if (!headers)
2509                 return NULL;
2510         info = malloc(sizeof(* info));
2511         info->uid = uid;
2512         info->headers = strdup(headers);
2513         info->size = size;
2514         info->flags = imap_flags_to_flags(att_dyn, tags);
2515         
2516         return info;
2517 }
2518
2519 static int
2520 imap_fetch_result_to_envelop_list(clist * fetch_result,
2521                                   carray ** p_env_list)
2522 {
2523         clistiter * cur;
2524         unsigned int i;
2525         carray * env_list;
2526
2527         i = 0;
2528         env_list = carray_new(16);
2529   
2530         for(cur = clist_begin(fetch_result) ; cur != NULL ;
2531             cur = clist_next(cur)) {
2532                 struct mailimap_msg_att * msg_att;
2533                 struct imap_fetch_env_info * env_info;
2534                 GSList *tags = NULL;
2535
2536                 msg_att = clist_content(cur);
2537
2538                 env_info = fetch_to_env_info(msg_att, &tags);
2539                 if (!env_info)
2540                         return MAILIMAP_ERROR_MEMORY;
2541                 carray_add(env_list, env_info, NULL);
2542                 carray_add(env_list, tags, NULL);
2543         }
2544   
2545         * p_env_list = env_list;
2546   
2547         return MAIL_NO_ERROR;
2548 }
2549
2550 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2551 {
2552         struct mailimap_fetch_att * fetch_att;
2553         int r;
2554         char * header;
2555         clist * hdrlist;
2556         struct mailimap_header_list * imap_hdrlist;
2557         struct mailimap_section * section;
2558
2559         hdrlist = clist_new();
2560   
2561         header = strdup("Date");
2562         r = clist_append(hdrlist, header);
2563         header = strdup("From");
2564         r = clist_append(hdrlist, header);
2565         header = strdup("To");
2566         r = clist_append(hdrlist, header);
2567         header = strdup("Cc");
2568         r = clist_append(hdrlist, header);
2569         header = strdup("Subject");
2570         r = clist_append(hdrlist, header);
2571         header = strdup("Message-ID");
2572         r = clist_append(hdrlist, header);
2573         header = strdup("References");
2574         r = clist_append(hdrlist, header);
2575         header = strdup("In-Reply-To");
2576         r = clist_append(hdrlist, header);
2577   
2578         imap_hdrlist = mailimap_header_list_new(hdrlist);
2579         section = mailimap_section_new_header_fields(imap_hdrlist);
2580         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2581         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2582   
2583         return MAIL_NO_ERROR;
2584 }
2585
2586 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2587 {
2588         struct mailimap_fetch_att * fetch_att;
2589         struct mailimap_section * section;
2590         
2591         section = mailimap_section_new_header();
2592         fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2593         mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2594         
2595         return MAIL_NO_ERROR;
2596 }
2597
2598 static int
2599 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2600                         carray ** p_env_list)
2601 {
2602         struct mailimap_fetch_att * fetch_att;
2603         struct mailimap_fetch_type * fetch_type;
2604         int res;
2605         clist * fetch_result;
2606         int r;
2607         carray * env_list = NULL;
2608         chashdatum key;
2609         chashdatum value;
2610         
2611         fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2612   
2613         /* uid */
2614         fetch_att = mailimap_fetch_att_new_uid();
2615         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2616   
2617         /* flags */
2618         fetch_att = mailimap_fetch_att_new_flags();
2619         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2620   
2621         /* rfc822 size */
2622         fetch_att = mailimap_fetch_att_new_rfc822_size();
2623         r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2624   
2625         /* headers */
2626         key.data = &imap;
2627         key.len = sizeof(imap);
2628         r = chash_get(courier_workaround_hash, &key, &value);
2629         if (r < 0)
2630                 r = imap_add_envelope_fetch_att(fetch_type);
2631         else
2632                 r = imap_add_header_fetch_att(fetch_type);
2633         
2634         mailstream_logger = imap_logger_fetch;
2635         
2636         r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2637         
2638         mailstream_logger = imap_logger_cmd;
2639         switch (r) {
2640         case MAILIMAP_NO_ERROR:
2641                 break;
2642         default:
2643                 mailimap_fetch_type_free(fetch_type);
2644                 debug_print("uid_fetch: %d\n", r);
2645                 return r;
2646         }
2647         
2648         if (clist_begin(fetch_result) == NULL) {
2649                 res = MAILIMAP_ERROR_FETCH;
2650                 debug_print("clist_begin = NULL\n");
2651                 goto err;
2652         }
2653         
2654         r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2655         mailimap_fetch_list_free(fetch_result);
2656         
2657         if (r != MAILIMAP_NO_ERROR) {
2658                 mailimap_fetch_type_free(fetch_type);
2659                 res = MAILIMAP_ERROR_MEMORY;
2660                 debug_print("fetch_result_to_envelop_list: %d\n", res);
2661                 goto err;
2662         }
2663         
2664         mailimap_fetch_type_free(fetch_type);
2665         
2666         * p_env_list = env_list;
2667         
2668         return MAILIMAP_NO_ERROR;
2669   
2670  err:
2671         return res;
2672 }
2673
2674 struct fetch_env_param {
2675         mailimap * imap;
2676         struct mailimap_set * set;
2677 };
2678
2679 struct fetch_env_result {
2680         carray * fetch_env_result;
2681         int error;
2682 };
2683
2684 static void fetch_env_run(struct etpan_thread_op * op)
2685 {
2686         struct fetch_env_param * param;
2687         struct fetch_env_result * result;
2688         carray * env_list;
2689         int r;
2690         
2691         param = op->param;
2692         result = op->result;
2693
2694         CHECK_IMAP();
2695
2696         env_list = NULL;
2697         r = imap_get_envelopes_list(param->imap, param->set,
2698                                     &env_list);
2699         
2700         result->error = r;
2701         result->fetch_env_result = env_list;
2702         
2703         debug_print("imap fetch_env run - end %i\n", r);
2704 }
2705
2706 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
2707                             carray ** p_env_list)
2708 {
2709         struct fetch_env_param param;
2710         struct fetch_env_result result;
2711         mailimap * imap;
2712         
2713         debug_print("imap fetch_env - begin\n");
2714         
2715         imap = get_imap(folder);
2716         param.imap = imap;
2717         param.set = set;
2718         
2719         threaded_run(folder, &param, &result, fetch_env_run);
2720         
2721         if (result.error != MAILIMAP_NO_ERROR) {
2722                 chashdatum key;
2723                 chashdatum value;
2724                 int r;
2725                 
2726                 key.data = &imap;
2727                 key.len = sizeof(imap);
2728                 r = chash_get(courier_workaround_hash, &key, &value);
2729                 if (r < 0) {
2730                         value.data = NULL;
2731                         value.len = 0;
2732                         chash_set(courier_workaround_hash, &key, &value, NULL);
2733                         
2734                         threaded_run(folder, &param, &result, fetch_env_run);
2735                 }
2736         }
2737         
2738         if (result.error != MAILIMAP_NO_ERROR)
2739                 return result.error;
2740         
2741         debug_print("imap fetch_env - end\n");
2742         
2743         * p_env_list = result.fetch_env_result;
2744         
2745         return result.error;
2746 }
2747
2748 void imap_fetch_env_free(carray * env_list)
2749 {
2750         unsigned int i;
2751         
2752         for(i = 0 ; i < carray_count(env_list) ; i += 2) {
2753                 struct imap_fetch_env_info * env_info;
2754                 
2755                 env_info = carray_get(env_list, i);
2756                 free(env_info->headers);
2757                 free(env_info);
2758         }
2759         carray_free(env_list);
2760 }
2761
2762
2763
2764
2765
2766 struct append_param {
2767         mailimap * imap;
2768         const char * mailbox;
2769         const char * filename;
2770         struct mailimap_flag_list * flag_list;
2771 };
2772
2773 struct append_result {
2774         int error;
2775         int uid;
2776 };
2777
2778 static void append_run(struct etpan_thread_op * op)
2779 {
2780         struct append_param * param;
2781         struct append_result * result;
2782         int r;
2783         char * data;
2784         size_t size;
2785 #ifndef G_OS_WIN32
2786         struct stat stat_buf;
2787         int fd;
2788 #endif
2789         guint32 uid = 0, val = 0;
2790         
2791         param = op->param;
2792         result = op->result;
2793         
2794         CHECK_IMAP();
2795
2796 #ifndef G_OS_WIN32
2797         r = stat(param->filename, &stat_buf);
2798         if (r < 0) {
2799                 result->error = MAILIMAP_ERROR_APPEND;
2800                 return;
2801         }
2802         size = stat_buf.st_size;
2803         
2804         fd = open(param->filename, O_RDONLY);
2805         if (fd < 0) {
2806                 result->error = MAILIMAP_ERROR_APPEND;
2807                 return;
2808         }
2809         
2810         data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2811         if (data == (void *) MAP_FAILED) {
2812                 close(fd);
2813                 result->error = MAILIMAP_ERROR_APPEND;
2814                 return;
2815         }
2816 #else
2817         data = file_read_to_str_no_recode(param->filename);
2818         if (data == NULL) {
2819                 result->error = MAILIMAP_ERROR_APPEND;
2820                 return;
2821         }
2822         size = strlen(data);
2823 #endif
2824         mailstream_logger = imap_logger_append;
2825         
2826         r = mailimap_uidplus_append(param->imap, param->mailbox,
2827                             param->flag_list, NULL,
2828                             data, size, &val, &uid);
2829
2830         mailstream_logger = imap_logger_cmd;
2831         
2832 #ifndef G_OS_WIN32
2833         munmap(data, size);
2834         close(fd);
2835 #else
2836         g_free(data);
2837 #endif
2838         
2839         result->error = r;
2840         result->uid = uid;
2841         debug_print("imap append run - end %i uid %d\n", r, uid);
2842 }
2843
2844 int imap_threaded_append(Folder * folder, const char * mailbox,
2845                          const char * filename,
2846                          struct mailimap_flag_list * flag_list,
2847                          int *uid)
2848 {
2849         struct append_param param;
2850         struct append_result result;
2851         mailimap * imap;
2852         
2853         debug_print("imap append - begin\n");
2854         
2855         imap = get_imap(folder);
2856         param.imap = imap;
2857         param.mailbox = mailbox;
2858         param.filename = filename;
2859         param.flag_list = flag_list;
2860         
2861         threaded_run(folder, &param, &result, append_run);
2862         
2863         if (result.error != MAILIMAP_NO_ERROR)
2864                 return result.error;
2865         
2866         debug_print("imap append - end\n");
2867         if (uid != NULL)
2868                 *uid = result.uid;
2869
2870         return result.error;
2871 }
2872
2873
2874
2875
2876 struct expunge_param {
2877         mailimap * imap;
2878 };
2879
2880 struct expunge_result {
2881         int error;
2882 };
2883
2884 static void expunge_run(struct etpan_thread_op * op)
2885 {
2886         struct expunge_param * param;
2887         struct expunge_result * result;
2888         int r;
2889         
2890         param = op->param;
2891         result = op->result;
2892
2893         CHECK_IMAP();
2894
2895         r = mailimap_expunge(param->imap);
2896         
2897         result->error = r;
2898         debug_print("imap expunge run - end %i\n", r);
2899 }
2900
2901 int imap_threaded_expunge(Folder * folder)
2902 {
2903         struct expunge_param param;
2904         struct expunge_result result;
2905         
2906         debug_print("imap expunge - begin\n");
2907         
2908         param.imap = get_imap(folder);
2909         
2910         threaded_run(folder, &param, &result, expunge_run);
2911         
2912         debug_print("imap expunge - end\n");
2913         
2914         return result.error;
2915 }
2916
2917
2918 struct copy_param {
2919         mailimap * imap;
2920         struct mailimap_set * set;
2921         const char * mb;
2922 };
2923
2924 struct copy_result {
2925         int error;
2926         struct mailimap_set *source;
2927         struct mailimap_set *dest;
2928 };
2929
2930 static void copy_run(struct etpan_thread_op * op)
2931 {
2932         struct copy_param * param;
2933         struct copy_result * result;
2934         int r;
2935         guint32 val;
2936         struct mailimap_set *source = NULL, *dest = NULL;
2937
2938         param = op->param;
2939         result = op->result;
2940
2941         CHECK_IMAP();
2942
2943         r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
2944                 &val, &source, &dest);
2945         
2946         result->error = r;
2947         if (r == 0) {
2948                 result->source = source;
2949                 result->dest = dest;
2950         } else {
2951                 result->source = NULL;
2952                 result->dest = NULL;
2953         }
2954         debug_print("imap copy run - end %i\n", r);
2955 }
2956
2957 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
2958                        const char * mb, struct mailimap_set **source,
2959                        struct mailimap_set **dest)
2960 {
2961         struct copy_param param;
2962         struct copy_result result;
2963         mailimap * imap;
2964         
2965         debug_print("imap copy - begin\n");
2966         
2967         imap = get_imap(folder);
2968         param.imap = imap;
2969         param.set = set;
2970         param.mb = mb;
2971         
2972         threaded_run(folder, &param, &result, copy_run);
2973         *source = NULL;
2974         *dest = NULL;
2975         
2976         if (result.error != MAILIMAP_NO_ERROR)
2977                 return result.error;
2978         
2979         *source = result.source;
2980         *dest = result.dest;
2981
2982         debug_print("imap copy - end\n");
2983         
2984         return result.error;
2985 }
2986
2987
2988
2989 struct store_param {
2990         mailimap * imap;
2991         struct mailimap_set * set;
2992         struct mailimap_store_att_flags * store_att_flags;
2993 };
2994
2995 struct store_result {
2996         int error;
2997 };
2998
2999 static void store_run(struct etpan_thread_op * op)
3000 {
3001         struct store_param * param;
3002         struct store_result * result;
3003         int r;
3004         
3005         param = op->param;
3006         result = op->result;
3007
3008         CHECK_IMAP();
3009
3010         r = mailimap_uid_store(param->imap, param->set,
3011                                param->store_att_flags);
3012         
3013         result->error = r;
3014         
3015         debug_print("imap store run - end %i\n", r);
3016 }
3017
3018 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
3019                         struct mailimap_store_att_flags * store_att_flags)
3020 {
3021         struct store_param param;
3022         struct store_result result;
3023         mailimap * imap;
3024         
3025         debug_print("imap store - begin\n");
3026         
3027         imap = get_imap(folder);
3028         param.imap = imap;
3029         param.set = set;
3030         param.store_att_flags = store_att_flags;
3031         
3032         threaded_run(folder, &param, &result, store_run);
3033         
3034         if (result.error != MAILIMAP_NO_ERROR)
3035                 return result.error;
3036         
3037         debug_print("imap store - end\n");
3038         
3039         return result.error;
3040 }
3041
3042
3043 #define ENV_BUFFER_SIZE 512
3044 #ifndef G_OS_WIN32
3045 static void do_exec_command(int fd, const char * command,
3046                             const char * servername, uint16_t port)
3047 {
3048         int i, maxopen;
3049 #ifdef SOLARIS
3050         char env_buffer[ENV_BUFFER_SIZE];
3051 #endif
3052         
3053         if (fork() > 0) {
3054                 /* Fork again to become a child of init rather than
3055                    the etpan client. */
3056                 exit(0);
3057         }
3058   
3059 #ifdef SOLARIS
3060         if (servername)
3061                 snprintf(env_buffer, ENV_BUFFER_SIZE,
3062                          "ETPANSERVER=%s", servername);
3063         else
3064                 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANSERVER=");
3065         putenv(env_buffer);
3066 #else
3067         if (servername)
3068                 setenv("ETPANSERVER", servername, 1);
3069         else
3070                 unsetenv("ETPANSERVER");
3071 #endif
3072   
3073 #ifdef SOLARIS
3074         if (port)
3075                 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=%d", port);
3076         else
3077                 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=");
3078         putenv(env_buffer);
3079 #else
3080         if (port) {
3081                 char porttext[20];
3082                 
3083                 snprintf(porttext, sizeof(porttext), "%d", port);
3084                 setenv("ETPANPORT", porttext, 1);
3085         }
3086         else {
3087                 unsetenv("ETPANPORT");
3088         }
3089 #endif
3090                 
3091         /* Not a lot we can do if there's an error other than bail. */
3092         if (dup2(fd, 0) == -1)
3093                 exit(1);
3094         if (dup2(fd, 1) == -1)
3095                 exit(1);
3096   
3097         /* Should we close stderr and reopen /dev/null? */
3098   
3099         maxopen = sysconf(_SC_OPEN_MAX);
3100         for (i=3; i < maxopen; i++)
3101                 close(i);
3102   
3103 #ifdef TIOCNOTTY
3104         /* Detach from the controlling tty if we have one. Otherwise,
3105            SSH might do something stupid like trying to use it instead
3106            of running $SSH_ASKPASS. Doh. */
3107         fd = open("/dev/tty", O_RDONLY);
3108         if (fd != -1) {
3109                 ioctl(fd, TIOCNOTTY, NULL);
3110                 close(fd);
3111         }
3112 #endif /* TIOCNOTTY */
3113
3114         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
3115   
3116         /* Eep. Shouldn't reach this */
3117         exit(1);
3118 }
3119
3120 static int subcommand_connect(const char *command,
3121                               const char *servername, uint16_t port)
3122 {
3123         /* SEB unsupported on Windows */
3124         int sockfds[2];
3125         pid_t childpid;
3126   
3127         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
3128                 return -1;
3129   
3130         childpid = fork();
3131         if (!childpid) {
3132                 do_exec_command(sockfds[1], command, servername, port);
3133         }
3134         else if (childpid == -1) {
3135                 close(sockfds[0]);
3136                 close(sockfds[1]);
3137                 return -1;
3138         }
3139   
3140         close(sockfds[1]);
3141   
3142         /* Reap child, leaving grandchild process to run */
3143         waitpid(childpid, NULL, 0);
3144   
3145         return sockfds[0];
3146 }
3147
3148 static int socket_connect_cmd(mailimap * imap, const char * command,
3149                        const char * server, int port)
3150 {
3151         int fd;
3152         mailstream * s;
3153         int r;
3154         
3155         fd = subcommand_connect(command, server, port);
3156         if (fd < 0)
3157                 return MAILIMAP_ERROR_STREAM;
3158         
3159         s = mailstream_socket_open(fd);
3160         if (s == NULL) {
3161                 close(fd);
3162                 return MAILIMAP_ERROR_STREAM;
3163         }
3164         
3165         r = mailimap_connect(imap, s);
3166         if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
3167         &&  r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
3168                 mailstream_close(s);
3169                 if (imap)
3170                         imap->imap_stream = NULL;
3171                 return r;
3172         }
3173         
3174         return r;
3175 }
3176
3177 /* connect cmd */
3178
3179 struct connect_cmd_param {
3180         mailimap * imap;
3181         const char * command;
3182         const char * server;
3183         int port;
3184 };
3185
3186 struct connect_cmd_result {
3187         int error;
3188 };
3189
3190 static void connect_cmd_run(struct etpan_thread_op * op)
3191 {
3192         int r;
3193         struct connect_cmd_param * param;
3194         struct connect_cmd_result * result;
3195         
3196         param = op->param;
3197         result = op->result;
3198         
3199         CHECK_IMAP();
3200
3201         r = socket_connect_cmd(param->imap, param->command,
3202                                param->server, param->port);
3203         
3204         result->error = r;
3205 }
3206
3207
3208 int imap_threaded_connect_cmd(Folder * folder, const char * command,
3209                               const char * server, int port)
3210 {
3211         struct connect_cmd_param param;
3212         struct connect_cmd_result result;
3213         chashdatum key;
3214         chashdatum value;
3215         mailimap * imap, * oldimap;
3216         
3217         oldimap = get_imap(folder);
3218
3219         imap = mailimap_new(0, NULL);
3220         
3221         if (oldimap) {
3222                 debug_print("deleting old imap %p\n", oldimap);
3223                 delete_imap(folder, oldimap);
3224         }
3225
3226         key.data = &folder;
3227         key.len = sizeof(folder);
3228         value.data = imap;
3229         value.len = 0;
3230         chash_set(session_hash, &key, &value, NULL);
3231         
3232         param.imap = imap;
3233         param.command = command;
3234         param.server = server;
3235         param.port = port;
3236         
3237         threaded_run(folder, &param, &result, connect_cmd_run);
3238         
3239         debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
3240         
3241         return result.error;
3242 }
3243 #endif /* G_OS_WIN32 */
3244
3245 void imap_threaded_cancel(Folder * folder)
3246 {
3247         mailimap * imap;
3248         
3249         imap = get_imap(folder);
3250         if (imap->imap_stream != NULL)
3251                 mailstream_cancel(imap->imap_stream);
3252 }
3253
3254 #else
3255
3256 void imap_main_init(void)
3257 {
3258 }
3259 void imap_main_done(void)
3260 {
3261 }
3262 void imap_main_set_timeout(int sec)
3263 {
3264 }
3265
3266 void imap_threaded_cancel(Folder * folder);
3267 {
3268 }
3269
3270 #endif