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