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