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