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