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