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