7 #include "imap-thread.h"
11 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__CYGWIN__))
12 #include <sys/socket.h>
20 #include "etpan-thread-manager.h"
22 #include "ssl_certificate.h"
24 #define DISABLE_LOG_DURING_LOGIN
26 static struct etpan_thread_manager * thread_manager = NULL;
27 static chash * courier_workaround_hash = NULL;
28 static chash * imap_hash = NULL;
29 static chash * session_hash = NULL;
30 static guint thread_manager_signal = 0;
31 static GIOChannel * io_channel = NULL;
34 static gboolean thread_manager_event(GIOChannel * source,
35 GIOCondition condition,
38 etpan_thread_manager_loop(thread_manager);
43 void imap_logger(int direction, const char * str, size_t size)
48 strncpy(buf, str, size > 510 ? 510:size);
52 if (!strncmp(buf, "<<<<<<<", 7)
53 || !strncmp(buf, ">>>>>>>", 7)
54 || buf[0] == '\r' || buf[0] == '\n')
57 while (strstr(buf, "\r"))
58 *strstr(buf, "\r") = ' ';
59 while (strstr(buf, "\n"))
60 *strstr(buf, "\n") = ' ';
62 log_print("IMAP4%c %s\n", direction?'>':'<', buf);
65 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
67 void imap_main_init(void)
69 int fd_thread_manager;
71 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
72 mailstream_network_delay.tv_usec = 0;
75 mailstream_logger = imap_logger;
77 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
78 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
79 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
81 thread_manager = etpan_thread_manager_new();
83 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
85 io_channel = g_io_channel_unix_new(fd_thread_manager);
87 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
93 void imap_main_set_timeout(int sec)
95 mailstream_network_delay.tv_sec = sec;
96 mailstream_network_delay.tv_usec = 0;
99 void imap_main_done(void)
101 etpan_thread_manager_stop(thread_manager);
102 etpan_thread_manager_join(thread_manager);
104 g_source_remove(thread_manager_signal);
105 g_io_channel_unref(io_channel);
107 etpan_thread_manager_free(thread_manager);
109 chash_free(courier_workaround_hash);
110 chash_free(session_hash);
111 chash_free(imap_hash);
114 void imap_init(Folder * folder)
116 struct etpan_thread * thread;
120 thread = etpan_thread_manager_get_thread(thread_manager);
123 key.len = sizeof(folder);
127 chash_set(imap_hash, &key, &value, NULL);
130 void imap_done(Folder * folder)
132 struct etpan_thread * thread;
138 key.len = sizeof(folder);
140 r = chash_get(imap_hash, &key, &value);
146 etpan_thread_unbind(thread);
148 chash_delete(imap_hash, &key, NULL);
150 debug_print("remove thread");
153 static struct etpan_thread * get_thread(Folder * folder)
155 struct etpan_thread * thread;
160 key.len = sizeof(folder);
162 chash_get(imap_hash, &key, &value);
168 static mailimap * get_imap(Folder * folder)
176 key.len = sizeof(folder);
178 r = chash_get(session_hash, &key, &value);
188 static void generic_cb(int cancelled, void * result, void * callback_data)
192 p_finished = callback_data;
194 debug_print("generic_cb\n");
199 static void threaded_run(Folder * folder, void * param, void * result,
200 void (* func)(struct etpan_thread_op * ))
202 struct etpan_thread_op * op;
203 struct etpan_thread * thread;
206 imap_folder_ref(folder);
208 op = etpan_thread_op_new();
214 op->callback = generic_cb;
215 op->callback_data = &finished;
220 thread = get_thread(folder);
221 etpan_thread_op_schedule(thread, op);
224 gtk_main_iteration();
227 etpan_thread_op_free(op);
229 imap_folder_unref(folder);
235 struct connect_param {
241 struct connect_result {
245 static void connect_run(struct etpan_thread_op * op)
248 struct connect_param * param;
249 struct connect_result * result;
254 r = mailimap_socket_connect(param->imap,
255 param->server, param->port);
261 int imap_threaded_connect(Folder * folder, const char * server, int port)
263 struct connect_param param;
264 struct connect_result result;
269 imap = mailimap_new(0, NULL);
272 key.len = sizeof(folder);
275 chash_set(session_hash, &key, &value, NULL);
278 param.server = server;
281 threaded_run(folder, ¶m, &result, connect_run);
283 debug_print("connect ok %i\n", result.error);
288 static int etpan_certificate_check(unsigned char *certificate, int len, void *data)
291 struct connect_param *param = (struct connect_param *)data;
294 if (certificate == NULL || len < 0) {
295 g_warning("no cert presented.\n");
298 cert = d2i_X509(NULL, &certificate, len);
300 g_warning("can't get cert\n");
302 } else if (ssl_certificate_check(cert,
303 (gchar *)param->server, param->port) == TRUE) {
313 static void connect_ssl_run(struct etpan_thread_op * op)
316 struct connect_param * param;
317 struct connect_result * result;
322 r = mailimap_ssl_connect(param->imap,
323 param->server, param->port);
327 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
329 struct connect_param param;
330 struct connect_result result;
334 unsigned char *certificate = NULL;
337 imap = mailimap_new(0, NULL);
340 key.len = sizeof(folder);
343 chash_set(session_hash, &key, &value, NULL);
346 param.server = server;
349 threaded_run(folder, ¶m, &result, connect_ssl_run);
351 if (result.error >= 0) {
352 cert_len = mailstream_ssl_get_certificate(imap->imap_stream, &certificate);
353 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
358 debug_print("connect %d\n", result.error);
369 struct mailimap_capability_data *caps;
372 static void capability_run(struct etpan_thread_op * op)
375 struct capa_param * param;
376 struct capa_result * result;
377 struct mailimap_capability_data *caps;
382 r = mailimap_capability(param->imap, &caps);
385 result->caps = (r == 0 ? caps : NULL);
389 struct mailimap_capability_data * imap_threaded_capability(Folder *folder)
391 struct capa_param param;
392 struct capa_result result;
395 imap = get_imap(folder);
399 threaded_run(folder, ¶m, &result, capability_run);
401 debug_print("capa ok\n");
407 struct disconnect_param {
411 struct disconnect_result {
415 static void disconnect_run(struct etpan_thread_op * op)
418 struct disconnect_param * param;
419 struct disconnect_result * result;
424 r = mailimap_logout(param->imap);
429 void imap_threaded_disconnect(Folder * folder)
431 struct connect_param param;
432 struct connect_result result;
437 imap = get_imap(folder);
439 debug_print("was disconnected\n");
445 threaded_run(folder, ¶m, &result, disconnect_run);
448 key.len = sizeof(folder);
451 chash_delete(session_hash, &key, NULL);
454 key.len = sizeof(imap);
455 chash_delete(courier_workaround_hash, &key, NULL);
459 debug_print("disconnect ok\n");
466 const char * wildcard;
474 static void list_run(struct etpan_thread_op * op)
476 struct list_param * param;
477 struct list_result * result;
483 r = mailimap_list(param->imap, param->base,
484 param->wildcard, &list);
489 debug_print("imap list run - end\n");
492 int imap_threaded_list(Folder * folder, const char * base,
493 const char * wildcard,
496 struct list_param param;
497 struct list_result result;
499 debug_print("imap list - begin\n");
501 param.imap = get_imap(folder);
503 param.wildcard = wildcard;
505 threaded_run(folder, ¶m, &result, list_run);
507 * p_result = result.list;
509 debug_print("imap list - end %p\n", result.list);
519 const char * password;
523 struct login_result {
527 static void login_run(struct etpan_thread_op * op)
529 struct login_param * param;
530 struct login_result * result;
532 #ifdef DISABLE_LOG_DURING_LOGIN
538 #ifdef DISABLE_LOG_DURING_LOGIN
539 old_debug = mailstream_debug;
540 mailstream_debug = 0;
542 if (!strcmp(param->type, "LOGIN"))
543 r = mailimap_login(param->imap,
544 param->login, param->password);
546 r = mailimap_authenticate(param->imap,
547 param->type, NULL, NULL, NULL,
548 param->login, param->login,
549 param->password, NULL);
550 #ifdef DISABLE_LOG_DURING_LOGIN
551 mailstream_debug = old_debug;
556 debug_print("imap login run - end %i\n", r);
559 int imap_threaded_login(Folder * folder,
560 const char * login, const char * password,
563 struct login_param param;
564 struct login_result result;
566 debug_print("imap login - begin\n");
568 param.imap = get_imap(folder);
570 param.password = password;
573 threaded_run(folder, ¶m, &result, login_run);
575 debug_print("imap login - end\n");
581 struct status_param {
584 struct mailimap_status_att_list * status_att_list;
587 struct status_result {
589 struct mailimap_mailbox_data_status * data_status;
592 static void status_run(struct etpan_thread_op * op)
594 struct status_param * param;
595 struct status_result * result;
601 r = mailimap_status(param->imap, param->mb,
602 param->status_att_list,
603 &result->data_status);
606 debug_print("imap status run - end %i\n", r);
609 int imap_threaded_status(Folder * folder, const char * mb,
610 struct mailimap_mailbox_data_status ** data_status,
613 struct status_param param;
614 struct status_result result;
615 struct mailimap_status_att_list * status_att_list;
617 debug_print("imap status - begin\n");
619 status_att_list = mailimap_status_att_list_new_empty();
621 mailimap_status_att_list_add(status_att_list,
622 MAILIMAP_STATUS_ATT_MESSAGES);
625 mailimap_status_att_list_add(status_att_list,
626 MAILIMAP_STATUS_ATT_RECENT);
629 mailimap_status_att_list_add(status_att_list,
630 MAILIMAP_STATUS_ATT_UIDNEXT);
633 mailimap_status_att_list_add(status_att_list,
634 MAILIMAP_STATUS_ATT_UIDVALIDITY);
637 mailimap_status_att_list_add(status_att_list,
638 MAILIMAP_STATUS_ATT_UNSEEN);
640 param.imap = get_imap(folder);
642 param.status_att_list = status_att_list;
644 threaded_run(folder, ¶m, &result, status_run);
646 debug_print("imap status - end\n");
648 * data_status = result.data_status;
650 mailimap_status_att_list_free(status_att_list);
665 static void noop_run(struct etpan_thread_op * op)
667 struct noop_param * param;
668 struct noop_result * result;
672 r = mailimap_noop(param->imap);
676 debug_print("imap noop run - end %i\n", r);
679 int imap_threaded_noop(Folder * folder, unsigned int * p_exists)
681 struct noop_param param;
682 struct noop_result result;
685 debug_print("imap noop - begin\n");
687 imap = get_imap(folder);
690 threaded_run(folder, ¶m, &result, noop_run);
692 if (imap->imap_selection_info != NULL) {
693 * p_exists = imap->imap_selection_info->sel_exists;
699 debug_print("imap noop - end\n");
705 struct starttls_result {
709 static void starttls_run(struct etpan_thread_op * op)
711 struct connect_param * param;
712 struct starttls_result * result;
716 r = mailimap_starttls(param->imap);
720 debug_print("imap starttls run - end %i\n", r);
723 mailimap *imap = param->imap;
724 mailstream_low *plain_low = NULL;
725 mailstream_low *tls_low = NULL;
728 plain_low = mailstream_get_low(imap->imap_stream);
729 fd = mailstream_low_get_fd(plain_low);
731 debug_print("imap starttls run - can't get fd\n");
732 result->error = MAILIMAP_ERROR_STREAM;
736 tls_low = mailstream_low_tls_open(fd);
737 if (tls_low == NULL) {
738 debug_print("imap starttls run - can't tls_open\n");
739 result->error = MAILIMAP_ERROR_STREAM;
742 mailstream_low_free(plain_low);
743 mailstream_set_low(imap->imap_stream, tls_low);
747 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
749 struct connect_param param;
750 struct starttls_result result;
752 unsigned char *certificate;
754 debug_print("imap starttls - begin\n");
756 param.imap = get_imap(folder);
760 threaded_run(folder, ¶m, &result, starttls_run);
762 debug_print("imap starttls - end\n");
764 if (result.error == 0) {
765 cert_len = mailstream_ssl_get_certificate(param.imap->imap_stream, &certificate);
766 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
767 result.error = MAILIMAP_ERROR_STREAM;
776 struct create_param {
781 struct create_result {
785 static void create_run(struct etpan_thread_op * op)
787 struct create_param * param;
788 struct create_result * result;
792 r = mailimap_create(param->imap, param->mb);
796 debug_print("imap create run - end %i\n", r);
799 int imap_threaded_create(Folder * folder, const char * mb)
801 struct create_param param;
802 struct create_result result;
804 debug_print("imap create - begin\n");
806 param.imap = get_imap(folder);
809 threaded_run(folder, ¶m, &result, create_run);
811 debug_print("imap create - end\n");
819 struct rename_param {
822 const char * new_name;
825 struct rename_result {
829 static void rename_run(struct etpan_thread_op * op)
831 struct rename_param * param;
832 struct rename_result * result;
836 r = mailimap_rename(param->imap, param->mb, param->new_name);
840 debug_print("imap rename run - end %i\n", r);
843 int imap_threaded_rename(Folder * folder,
844 const char * mb, const char * new_name)
846 struct rename_param param;
847 struct rename_result result;
849 debug_print("imap rename - begin\n");
851 param.imap = get_imap(folder);
853 param.new_name = new_name;
855 threaded_run(folder, ¶m, &result, rename_run);
857 debug_print("imap rename - end\n");
865 struct delete_param {
870 struct delete_result {
874 static void delete_run(struct etpan_thread_op * op)
876 struct delete_param * param;
877 struct delete_result * result;
881 r = mailimap_delete(param->imap, param->mb);
885 debug_print("imap delete run - end %i\n", r);
888 int imap_threaded_delete(Folder * folder, const char * mb)
890 struct delete_param param;
891 struct delete_result result;
893 debug_print("imap delete - begin\n");
895 param.imap = get_imap(folder);
898 threaded_run(folder, ¶m, &result, delete_run);
900 debug_print("imap delete - end\n");
907 struct select_param {
912 struct select_result {
916 static void select_run(struct etpan_thread_op * op)
918 struct select_param * param;
919 struct select_result * result;
923 r = mailimap_select(param->imap, param->mb);
927 debug_print("imap select run - end %i\n", r);
930 int imap_threaded_select(Folder * folder, const char * mb,
931 gint * exists, gint * recent, gint * unseen,
932 guint32 * uid_validity)
934 struct select_param param;
935 struct select_result result;
938 debug_print("imap select - begin\n");
940 imap = get_imap(folder);
944 threaded_run(folder, ¶m, &result, select_run);
946 if (result.error != MAILIMAP_NO_ERROR)
949 if (imap->imap_selection_info == NULL)
950 return MAILIMAP_ERROR_PARSE;
952 * exists = imap->imap_selection_info->sel_exists;
953 * recent = imap->imap_selection_info->sel_recent;
954 * unseen = imap->imap_selection_info->sel_unseen;
955 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
957 debug_print("imap select - end\n");
964 struct examine_param {
969 struct examine_result {
973 static void examine_run(struct etpan_thread_op * op)
975 struct examine_param * param;
976 struct examine_result * result;
980 r = mailimap_examine(param->imap, param->mb);
984 debug_print("imap examine run - end %i\n", r);
987 int imap_threaded_examine(Folder * folder, const char * mb,
988 gint * exists, gint * recent, gint * unseen,
989 guint32 * uid_validity)
991 struct examine_param param;
992 struct examine_result result;
995 debug_print("imap examine - begin\n");
997 imap = get_imap(folder);
1001 threaded_run(folder, ¶m, &result, examine_run);
1003 if (result.error != MAILIMAP_NO_ERROR)
1004 return result.error;
1006 if (imap->imap_selection_info == NULL)
1007 return MAILIMAP_ERROR_PARSE;
1009 * exists = imap->imap_selection_info->sel_exists;
1010 * recent = imap->imap_selection_info->sel_recent;
1011 * unseen = imap->imap_selection_info->sel_unseen;
1012 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1014 debug_print("imap examine - end\n");
1016 return result.error;
1022 struct search_param {
1025 struct mailimap_set * set;
1028 struct search_result {
1030 clist * search_result;
1033 static void search_run(struct etpan_thread_op * op)
1035 struct search_param * param;
1036 struct search_result * result;
1038 struct mailimap_search_key * key;
1039 struct mailimap_search_key * uid_key;
1040 struct mailimap_search_key * search_type_key;
1041 clist * search_result;
1045 uid_key = mailimap_search_key_new_uid(param->set);
1047 search_type_key = NULL;
1048 switch (param->type) {
1049 case IMAP_SEARCH_TYPE_SIMPLE:
1050 search_type_key = NULL;
1053 case IMAP_SEARCH_TYPE_SEEN:
1054 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
1055 NULL, NULL, NULL, NULL, NULL,
1056 NULL, NULL, NULL, NULL, NULL,
1057 NULL, NULL, NULL, NULL, 0,
1058 NULL, NULL, NULL, NULL, NULL,
1059 NULL, 0, NULL, NULL, NULL);
1062 case IMAP_SEARCH_TYPE_UNSEEN:
1063 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
1064 NULL, NULL, NULL, NULL, NULL,
1065 NULL, NULL, NULL, NULL, NULL,
1066 NULL, NULL, NULL, NULL, 0,
1067 NULL, NULL, NULL, NULL, NULL,
1068 NULL, 0, NULL, NULL, NULL);
1071 case IMAP_SEARCH_TYPE_ANSWERED:
1072 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
1073 NULL, NULL, NULL, NULL, NULL,
1074 NULL, NULL, NULL, NULL, NULL,
1075 NULL, NULL, NULL, NULL, 0,
1076 NULL, NULL, NULL, NULL, NULL,
1077 NULL, 0, NULL, NULL, NULL);
1080 case IMAP_SEARCH_TYPE_FLAGGED:
1081 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
1082 NULL, NULL, NULL, NULL, NULL,
1083 NULL, NULL, NULL, NULL, NULL,
1084 NULL, NULL, NULL, NULL, 0,
1085 NULL, NULL, NULL, NULL, NULL,
1086 NULL, 0, NULL, NULL, NULL);
1088 case IMAP_SEARCH_TYPE_DELETED:
1089 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_DELETED,
1090 NULL, NULL, NULL, NULL, NULL,
1091 NULL, NULL, NULL, NULL, NULL,
1092 NULL, NULL, NULL, NULL, 0,
1093 NULL, NULL, NULL, NULL, NULL,
1094 NULL, 0, NULL, NULL, NULL);
1098 if (search_type_key != NULL) {
1099 key = mailimap_search_key_new_multiple_empty();
1100 mailimap_search_key_multiple_add(key, search_type_key);
1101 mailimap_search_key_multiple_add(key, uid_key);
1107 r = mailimap_uid_search(param->imap, NULL, key, &search_result);
1109 result = op->result;
1111 result->search_result = search_result;
1112 debug_print("imap search run - end %i\n", r);
1115 int imap_threaded_search(Folder * folder, int search_type,
1116 struct mailimap_set * set, clist ** search_result)
1118 struct search_param param;
1119 struct search_result result;
1122 debug_print("imap search - begin\n");
1124 imap = get_imap(folder);
1127 param.type = search_type;
1129 threaded_run(folder, ¶m, &result, search_run);
1131 if (result.error != MAILIMAP_NO_ERROR)
1132 return result.error;
1134 debug_print("imap search - end\n");
1136 * search_result = result.search_result;
1138 return result.error;
1145 uid_list_to_env_list(clist * fetch_result, carray ** result)
1153 tab = carray_new(128);
1155 res = MAILIMAP_ERROR_MEMORY;
1159 for(cur = clist_begin(fetch_result) ; cur != NULL ;
1160 cur = clist_next(cur)) {
1161 struct mailimap_msg_att * msg_att;
1162 clistiter * item_cur;
1167 msg_att = clist_content(cur);
1171 for(item_cur = clist_begin(msg_att->att_list) ;
1173 item_cur = clist_next(item_cur)) {
1174 struct mailimap_msg_att_item * item;
1176 item = clist_content(item_cur);
1178 switch (item->att_type) {
1179 case MAILIMAP_MSG_ATT_ITEM_STATIC:
1180 switch (item->att_data.att_static->att_type) {
1181 case MAILIMAP_MSG_ATT_UID:
1182 uid = item->att_data.att_static->att_data.att_uid;
1188 puid = malloc(sizeof(* puid));
1190 res = MAILIMAP_ERROR_MEMORY;
1195 r = carray_add(tab, puid, NULL);
1198 res = MAILIMAP_ERROR_MEMORY;
1205 return MAILIMAP_NO_ERROR;
1208 for(i = 0 ; i < carray_count(tab) ; i++)
1209 mailmessage_free(carray_get(tab, i));
1214 static int imap_get_messages_list(mailimap * imap,
1215 uint32_t first_index,
1220 struct mailimap_fetch_att * fetch_att;
1221 struct mailimap_fetch_type * fetch_type;
1222 struct mailimap_set * set;
1223 clist * fetch_result;
1226 set = mailimap_set_new_interval(first_index, 0);
1228 res = MAILIMAP_ERROR_MEMORY;
1232 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1233 if (fetch_type == NULL) {
1234 res = MAILIMAP_ERROR_MEMORY;
1238 fetch_att = mailimap_fetch_att_new_uid();
1239 if (fetch_att == NULL) {
1240 res = MAILIMAP_ERROR_MEMORY;
1241 goto free_fetch_type;
1244 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1245 if (r != MAILIMAP_NO_ERROR) {
1246 mailimap_fetch_att_free(fetch_att);
1247 res = MAILIMAP_ERROR_MEMORY;
1248 goto free_fetch_type;
1251 r = mailimap_uid_fetch(imap, set,
1252 fetch_type, &fetch_result);
1254 mailimap_fetch_type_free(fetch_type);
1255 mailimap_set_free(set);
1257 if (r != MAILIMAP_NO_ERROR) {
1263 r = uid_list_to_env_list(fetch_result, &env_list);
1264 mailimap_fetch_list_free(fetch_result);
1266 * result = env_list;
1268 return MAILIMAP_NO_ERROR;
1271 mailimap_fetch_type_free(fetch_type);
1273 mailimap_set_free(set);
1281 struct fetch_uid_param {
1283 uint32_t first_index;
1286 struct fetch_uid_result {
1288 carray * fetch_result;
1291 static void fetch_uid_run(struct etpan_thread_op * op)
1293 struct fetch_uid_param * param;
1294 struct fetch_uid_result * result;
1295 carray * fetch_result;
1300 fetch_result = NULL;
1301 r = imap_get_messages_list(param->imap, param->first_index,
1304 result = op->result;
1306 result->fetch_result = fetch_result;
1307 debug_print("imap fetch_uid run - end %i\n", r);
1310 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1311 carray ** fetch_result)
1313 struct fetch_uid_param param;
1314 struct fetch_uid_result result;
1317 debug_print("imap fetch_uid - begin\n");
1319 imap = get_imap(folder);
1321 param.first_index = first_index;
1323 threaded_run(folder, ¶m, &result, fetch_uid_run);
1325 if (result.error != MAILIMAP_NO_ERROR)
1326 return result.error;
1328 debug_print("imap fetch_uid - end\n");
1330 * fetch_result = result.fetch_result;
1332 return result.error;
1336 void imap_fetch_uid_list_free(carray * uid_list)
1340 for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1343 puid = carray_get(uid_list, i);
1346 carray_free(uid_list);
1351 static int imap_fetch(mailimap * imap,
1354 size_t * result_len)
1357 struct mailimap_set * set;
1358 struct mailimap_fetch_att * fetch_att;
1359 struct mailimap_fetch_type * fetch_type;
1360 clist * fetch_result;
1361 struct mailimap_msg_att * msg_att;
1362 struct mailimap_msg_att_item * msg_att_item;
1367 struct mailimap_section * section;
1369 set = mailimap_set_new_single(msg_index);
1371 res = MAILIMAP_ERROR_MEMORY;
1375 section = mailimap_section_new(NULL);
1376 if (section == NULL) {
1377 res = MAILIMAP_ERROR_MEMORY;
1381 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1382 if (fetch_att == NULL) {
1383 mailimap_section_free(section);
1384 res = MAILIMAP_ERROR_MEMORY;
1388 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1389 if (fetch_type == NULL) {
1390 res = MAILIMAP_ERROR_MEMORY;
1391 goto free_fetch_att;
1394 r = mailimap_uid_fetch(imap, set,
1395 fetch_type, &fetch_result);
1397 mailimap_fetch_type_free(fetch_type);
1398 mailimap_set_free(set);
1401 case MAILIMAP_NO_ERROR:
1407 if (clist_begin(fetch_result) == NULL) {
1408 mailimap_fetch_list_free(fetch_result);
1409 return MAILIMAP_ERROR_FETCH;
1412 msg_att = clist_begin(fetch_result)->data;
1417 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1418 cur = clist_next(cur)) {
1419 msg_att_item = clist_content(cur);
1421 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1422 if (msg_att_item->att_data.att_static->att_type ==
1423 MAILIMAP_MSG_ATT_BODY_SECTION) {
1424 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1426 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1428 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1433 mailimap_fetch_list_free(fetch_result);
1436 return MAILIMAP_ERROR_FETCH;
1439 * result_len = text_length;
1441 return MAILIMAP_NO_ERROR;
1444 mailimap_fetch_att_free(fetch_att);
1446 mailimap_set_free(set);
1451 static int imap_fetch_header(mailimap * imap,
1454 size_t * result_len)
1457 struct mailimap_set * set;
1458 struct mailimap_fetch_att * fetch_att;
1459 struct mailimap_fetch_type * fetch_type;
1460 clist * fetch_result;
1461 struct mailimap_msg_att * msg_att;
1462 struct mailimap_msg_att_item * msg_att_item;
1467 struct mailimap_section * section;
1469 set = mailimap_set_new_single(msg_index);
1471 res = MAILIMAP_ERROR_MEMORY;
1475 section = mailimap_section_new_header();
1476 if (section == NULL) {
1477 res = MAILIMAP_ERROR_MEMORY;
1481 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1482 if (fetch_att == NULL) {
1483 mailimap_section_free(section);
1484 res = MAILIMAP_ERROR_MEMORY;
1488 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1489 if (fetch_type == NULL) {
1490 res = MAILIMAP_ERROR_MEMORY;
1491 goto free_fetch_att;
1494 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1496 mailimap_fetch_type_free(fetch_type);
1497 mailimap_set_free(set);
1500 case MAILIMAP_NO_ERROR:
1506 if (clist_begin(fetch_result) == NULL) {
1507 mailimap_fetch_list_free(fetch_result);
1508 return MAILIMAP_ERROR_FETCH;
1511 msg_att = clist_begin(fetch_result)->data;
1516 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1517 cur = clist_next(cur)) {
1518 msg_att_item = clist_content(cur);
1520 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1521 if (msg_att_item->att_data.att_static->att_type ==
1522 MAILIMAP_MSG_ATT_BODY_SECTION) {
1523 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1524 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1526 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1531 mailimap_fetch_list_free(fetch_result);
1534 return MAILIMAP_ERROR_FETCH;
1537 * result_len = text_length;
1539 return MAILIMAP_NO_ERROR;
1542 mailimap_fetch_att_free(fetch_att);
1544 mailimap_set_free(set);
1551 struct fetch_content_param {
1554 const char * filename;
1558 struct fetch_content_result {
1562 static void fetch_content_run(struct etpan_thread_op * op)
1564 struct fetch_content_param * param;
1565 struct fetch_content_result * result;
1567 size_t content_size;
1576 if (param->with_body)
1577 r = imap_fetch(param->imap, param->msg_index,
1578 &content, &content_size);
1580 r = imap_fetch_header(param->imap, param->msg_index,
1581 &content, &content_size);
1583 result = op->result;
1586 if (r == MAILIMAP_NO_ERROR) {
1587 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
1589 result->error = MAILIMAP_ERROR_FETCH;
1593 f = fdopen(fd, "wb");
1595 result->error = MAILIMAP_ERROR_FETCH;
1599 r = fwrite(content, 1, content_size, f);
1606 g_unlink(param->filename);
1617 g_unlink(param->filename);
1620 if (mmap_string_unref(content) != 0)
1624 debug_print("imap fetch_content run - end %i\n", r);
1627 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
1629 const char * filename)
1631 struct fetch_content_param param;
1632 struct fetch_content_result result;
1635 debug_print("imap fetch_content - begin\n");
1637 imap = get_imap(folder);
1639 param.msg_index = msg_index;
1640 param.filename = filename;
1641 param.with_body = with_body;
1643 threaded_run(folder, ¶m, &result, fetch_content_run);
1645 if (result.error != MAILIMAP_NO_ERROR)
1646 return result.error;
1648 debug_print("imap fetch_content - end\n");
1650 return result.error;
1655 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
1663 flag_list = att_dyn->att_list;
1664 if (flag_list == NULL)
1667 for(cur = clist_begin(flag_list) ; cur != NULL ;
1668 cur = clist_next(cur)) {
1669 struct mailimap_flag_fetch * flag_fetch;
1671 flag_fetch = clist_content(cur);
1672 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
1675 switch (flag_fetch->fl_flag->fl_type) {
1676 case MAILIMAP_FLAG_ANSWERED:
1677 flags |= MSG_REPLIED;
1679 case MAILIMAP_FLAG_FLAGGED:
1680 flags |= MSG_MARKED;
1682 case MAILIMAP_FLAG_DELETED:
1683 flags |= MSG_DELETED;
1685 case MAILIMAP_FLAG_SEEN:
1686 flags &= ~MSG_UNREAD;
1696 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1700 struct mailimap_msg_att_dynamic ** patt_dyn)
1702 clistiter * item_cur;
1706 struct mailimap_msg_att_dynamic * att_dyn;
1713 for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
1714 item_cur = clist_next(item_cur)) {
1715 struct mailimap_msg_att_item * item;
1717 item = clist_content(item_cur);
1719 switch (item->att_type) {
1720 case MAILIMAP_MSG_ATT_ITEM_STATIC:
1721 switch (item->att_data.att_static->att_type) {
1722 case MAILIMAP_MSG_ATT_UID:
1723 uid = item->att_data.att_static->att_data.att_uid;
1726 case MAILIMAP_MSG_ATT_BODY_SECTION:
1727 if (headers == NULL) {
1728 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
1731 case MAILIMAP_MSG_ATT_RFC822_SIZE:
1732 ref_size = item->att_data.att_static->att_data.att_rfc822_size;
1737 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
1738 if (att_dyn == NULL) {
1739 att_dyn = item->att_data.att_dyn;
1747 if (pheaders != NULL)
1748 * pheaders = headers;
1749 if (pref_size != NULL)
1750 * pref_size = ref_size;
1751 if (patt_dyn != NULL)
1752 * patt_dyn = att_dyn;
1754 return MAIL_NO_ERROR;
1757 static struct imap_fetch_env_info *
1758 fetch_to_env_info(struct mailimap_msg_att * msg_att)
1760 struct imap_fetch_env_info * info;
1764 struct mailimap_msg_att_dynamic * att_dyn;
1766 imap_get_msg_att_info(msg_att, &uid, &headers, &size,
1771 info = malloc(sizeof(* info));
1773 info->headers = strdup(headers);
1775 info->flags = imap_flags_to_flags(att_dyn);
1781 imap_fetch_result_to_envelop_list(clist * fetch_result,
1782 carray ** p_env_list)
1789 env_list = carray_new(16);
1791 for(cur = clist_begin(fetch_result) ; cur != NULL ;
1792 cur = clist_next(cur)) {
1793 struct mailimap_msg_att * msg_att;
1794 struct imap_fetch_env_info * env_info;
1796 msg_att = clist_content(cur);
1798 env_info = fetch_to_env_info(msg_att);
1800 return MAILIMAP_ERROR_MEMORY;
1801 carray_add(env_list, env_info, NULL);
1804 * p_env_list = env_list;
1806 return MAIL_NO_ERROR;
1809 int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
1811 struct mailimap_fetch_att * fetch_att;
1815 struct mailimap_header_list * imap_hdrlist;
1816 struct mailimap_section * section;
1818 hdrlist = clist_new();
1820 header = strdup("Date");
1821 r = clist_append(hdrlist, header);
1822 header = strdup("From");
1823 r = clist_append(hdrlist, header);
1824 header = strdup("To");
1825 r = clist_append(hdrlist, header);
1826 header = strdup("Cc");
1827 r = clist_append(hdrlist, header);
1828 header = strdup("Subject");
1829 r = clist_append(hdrlist, header);
1830 header = strdup("Message-ID");
1831 r = clist_append(hdrlist, header);
1832 header = strdup("References");
1833 r = clist_append(hdrlist, header);
1834 header = strdup("In-Reply-To");
1835 r = clist_append(hdrlist, header);
1837 imap_hdrlist = mailimap_header_list_new(hdrlist);
1838 section = mailimap_section_new_header_fields(imap_hdrlist);
1839 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1840 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1842 return MAIL_NO_ERROR;
1845 int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
1847 struct mailimap_fetch_att * fetch_att;
1848 struct mailimap_section * section;
1850 section = mailimap_section_new_header();
1851 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1852 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1854 return MAIL_NO_ERROR;
1858 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
1859 carray ** p_env_list)
1861 struct mailimap_fetch_att * fetch_att;
1862 struct mailimap_fetch_type * fetch_type;
1864 clist * fetch_result;
1866 carray * env_list = NULL;
1870 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1873 fetch_att = mailimap_fetch_att_new_uid();
1874 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1877 fetch_att = mailimap_fetch_att_new_flags();
1878 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1881 fetch_att = mailimap_fetch_att_new_rfc822_size();
1882 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1886 key.len = sizeof(imap);
1887 r = chash_get(courier_workaround_hash, &key, &value);
1889 r = imap_add_envelope_fetch_att(fetch_type);
1891 r = imap_add_header_fetch_att(fetch_type);
1893 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1896 case MAILIMAP_NO_ERROR:
1899 mailimap_fetch_type_free(fetch_type);
1900 debug_print("uid_fetch: %d\n", r);
1904 if (clist_begin(fetch_result) == NULL) {
1905 res = MAILIMAP_ERROR_FETCH;
1906 debug_print("clist_begin = NULL\n");
1910 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
1911 mailimap_fetch_list_free(fetch_result);
1913 if (r != MAILIMAP_NO_ERROR) {
1914 mailimap_fetch_type_free(fetch_type);
1915 res = MAILIMAP_ERROR_MEMORY;
1916 debug_print("fetch_result_to_envelop_list: %d\n", res);
1920 mailimap_fetch_type_free(fetch_type);
1922 * p_env_list = env_list;
1924 return MAILIMAP_NO_ERROR;
1930 struct fetch_env_param {
1932 struct mailimap_set * set;
1935 struct fetch_env_result {
1936 carray * fetch_env_result;
1940 static void fetch_env_run(struct etpan_thread_op * op)
1942 struct fetch_env_param * param;
1943 struct fetch_env_result * result;
1950 r = imap_get_envelopes_list(param->imap, param->set,
1953 result = op->result;
1955 result->fetch_env_result = env_list;
1957 debug_print("imap fetch_env run - end %i\n", r);
1960 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
1961 carray ** p_env_list)
1963 struct fetch_env_param param;
1964 struct fetch_env_result result;
1967 debug_print("imap fetch_env - begin\n");
1969 imap = get_imap(folder);
1973 threaded_run(folder, ¶m, &result, fetch_env_run);
1975 if (result.error != MAILIMAP_NO_ERROR) {
1981 key.len = sizeof(imap);
1982 r = chash_get(courier_workaround_hash, &key, &value);
1986 chash_set(courier_workaround_hash, &key, &value, NULL);
1988 threaded_run(folder, ¶m, &result, fetch_env_run);
1992 if (result.error != MAILIMAP_NO_ERROR)
1993 return result.error;
1995 debug_print("imap fetch_env - end\n");
1997 * p_env_list = result.fetch_env_result;
1999 return result.error;
2002 void imap_fetch_env_free(carray * env_list)
2006 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2007 struct imap_fetch_env_info * env_info;
2009 env_info = carray_get(env_list, i);
2010 free(env_info->headers);
2013 carray_free(env_list);
2020 struct append_param {
2022 const char * mailbox;
2023 const char * filename;
2024 struct mailimap_flag_list * flag_list;
2027 struct append_result {
2032 static void append_run(struct etpan_thread_op * op)
2034 struct append_param * param;
2035 struct append_result * result;
2039 struct stat stat_buf;
2043 result = op->result;
2045 r = stat(param->filename, &stat_buf);
2047 result->error = MAILIMAP_ERROR_APPEND;
2050 size = stat_buf.st_size;
2052 fd = open(param->filename, O_RDONLY);
2054 result->error = MAILIMAP_ERROR_APPEND;
2058 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2059 if (data == (void *) MAP_FAILED) {
2061 result->error = MAILIMAP_ERROR_APPEND;
2065 r = mailimap_append(param->imap, param->mailbox,
2066 param->flag_list, NULL,
2067 data, size/*, &uid */);
2074 debug_print("imap append run - end %i uid %d\n", r, uid);
2077 int imap_threaded_append(Folder * folder, const char * mailbox,
2078 const char * filename,
2079 struct mailimap_flag_list * flag_list,
2082 struct append_param param;
2083 struct append_result result;
2086 debug_print("imap append - begin\n");
2088 imap = get_imap(folder);
2090 param.mailbox = mailbox;
2091 param.filename = filename;
2092 param.flag_list = flag_list;
2094 threaded_run(folder, ¶m, &result, append_run);
2096 if (result.error != MAILIMAP_NO_ERROR)
2097 return result.error;
2099 debug_print("imap append - end\n");
2103 return result.error;
2109 struct expunge_param {
2113 struct expunge_result {
2117 static void expunge_run(struct etpan_thread_op * op)
2119 struct expunge_param * param;
2120 struct expunge_result * result;
2124 r = mailimap_expunge(param->imap);
2126 result = op->result;
2128 debug_print("imap expunge run - end %i\n", r);
2131 int imap_threaded_expunge(Folder * folder)
2133 struct expunge_param param;
2134 struct expunge_result result;
2136 debug_print("imap expunge - begin\n");
2138 param.imap = get_imap(folder);
2140 threaded_run(folder, ¶m, &result, expunge_run);
2142 debug_print("imap expunge - end\n");
2144 return result.error;
2150 struct mailimap_set * set;
2154 struct copy_result {
2158 static void copy_run(struct etpan_thread_op * op)
2160 struct copy_param * param;
2161 struct copy_result * result;
2166 r = mailimap_uid_copy(param->imap, param->set, param->mb);
2168 result = op->result;
2171 debug_print("imap copy run - end %i\n", r);
2174 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
2177 struct copy_param param;
2178 struct copy_result result;
2181 debug_print("imap copy - begin\n");
2183 imap = get_imap(folder);
2188 threaded_run(folder, ¶m, &result, copy_run);
2190 if (result.error != MAILIMAP_NO_ERROR)
2191 return result.error;
2193 debug_print("imap copy - end\n");
2195 return result.error;
2200 struct store_param {
2202 struct mailimap_set * set;
2203 struct mailimap_store_att_flags * store_att_flags;
2206 struct store_result {
2210 static void store_run(struct etpan_thread_op * op)
2212 struct store_param * param;
2213 struct store_result * result;
2218 r = mailimap_uid_store(param->imap, param->set,
2219 param->store_att_flags);
2221 result = op->result;
2224 debug_print("imap store run - end %i\n", r);
2227 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
2228 struct mailimap_store_att_flags * store_att_flags)
2230 struct store_param param;
2231 struct store_result result;
2234 debug_print("imap store - begin\n");
2236 imap = get_imap(folder);
2239 param.store_att_flags = store_att_flags;
2241 threaded_run(folder, ¶m, &result, store_run);
2243 if (result.error != MAILIMAP_NO_ERROR)
2244 return result.error;
2246 debug_print("imap store - end\n");
2248 return result.error;
2252 #define ENV_BUFFER_SIZE 512
2254 static void do_exec_command(int fd, const char * command,
2255 const char * servername, uint16_t port)
2259 char env_buffer[ENV_BUFFER_SIZE];
2263 /* Fork again to become a child of init rather than
2264 the etpan client. */
2270 snprintf(env_buffer, ENV_BUFFER_SIZE,
2271 "ETPANSERVER=%s", servername);
2273 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANSERVER=");
2277 setenv("ETPANSERVER", servername, 1);
2279 unsetenv("ETPANSERVER");
2284 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=%d", port);
2286 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=");
2292 snprintf(porttext, sizeof(porttext), "%d", port);
2293 setenv("ETPANPORT", porttext, 1);
2296 unsetenv("ETPANPORT");
2300 /* Not a lot we can do if there's an error other than bail. */
2301 if (dup2(fd, 0) == -1)
2303 if (dup2(fd, 1) == -1)
2306 /* Should we close stderr and reopen /dev/null? */
2308 maxopen = sysconf(_SC_OPEN_MAX);
2309 for (i=3; i < maxopen; i++)
2313 /* Detach from the controlling tty if we have one. Otherwise,
2314 SSH might do something stupid like trying to use it instead
2315 of running $SSH_ASKPASS. Doh. */
2316 fd = open("/dev/tty", O_RDONLY);
2318 ioctl(fd, TIOCNOTTY, NULL);
2321 #endif /* TIOCNOTTY */
2323 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
2325 /* Eep. Shouldn't reach this */
2329 static int subcommand_connect(const char *command,
2330 const char *servername, uint16_t port)
2332 /* SEB unsupported on Windows */
2336 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
2341 do_exec_command(sockfds[1], command, servername, port);
2343 else if (childpid == -1) {
2351 /* Reap child, leaving grandchild process to run */
2352 waitpid(childpid, NULL, 0);
2357 int socket_connect_cmd(mailimap * imap, const char * command,
2358 const char * server, int port)
2364 fd = subcommand_connect(command, server, port);
2366 return MAILIMAP_ERROR_STREAM;
2368 s = mailstream_socket_open(fd);
2371 return MAILIMAP_ERROR_STREAM;
2374 r = mailimap_connect(imap, s);
2375 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
2376 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
2377 mailstream_close(s);
2386 struct connect_cmd_param {
2388 const char * command;
2389 const char * server;
2393 struct connect_cmd_result {
2397 static void connect_cmd_run(struct etpan_thread_op * op)
2400 struct connect_cmd_param * param;
2401 struct connect_cmd_result * result;
2404 result = op->result;
2406 r = socket_connect_cmd(param->imap, param->command,
2407 param->server, param->port);
2413 int imap_threaded_connect_cmd(Folder * folder, const char * command,
2414 const char * server, int port)
2416 struct connect_cmd_param param;
2417 struct connect_cmd_result result;
2422 imap = mailimap_new(0, NULL);
2425 key.len = sizeof(folder);
2428 chash_set(session_hash, &key, &value, NULL);
2431 param.command = command;
2432 param.server = server;
2435 threaded_run(folder, ¶m, &result, connect_cmd_run);
2437 debug_print("connect_cmd ok %i\n", result.error);
2439 return result.error;
2443 void imap_main_init(void)
2446 void imap_main_done(void)
2449 void imap_main_set_timeout(int sec)