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