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