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