2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2005-2007 DINH Viet Hoa and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "imap-thread.h"
28 #include <sys/types.h>
30 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__))
31 #include <sys/socket.h>
39 #include "etpan-thread-manager.h"
41 #include "mainwindow.h"
42 #include "ssl_certificate.h"
44 #include "remotefolder.h"
46 #define DISABLE_LOG_DURING_LOGIN
48 static struct etpan_thread_manager * thread_manager = NULL;
49 static chash * courier_workaround_hash = NULL;
50 static chash * imap_hash = NULL;
51 static chash * session_hash = NULL;
52 static guint thread_manager_signal = 0;
53 static GIOChannel * io_channel = NULL;
55 static void delete_imap(Folder *folder, mailimap *imap)
61 key.len = sizeof(folder);
64 chash_delete(session_hash, &key, NULL);
67 key.len = sizeof(imap);
68 chash_delete(courier_workaround_hash, &key, NULL);
69 if (imap && imap->imap_stream) {
70 /* we don't want libetpan to logout */
71 mailstream_close(imap->imap_stream);
72 imap->imap_stream = NULL;
74 debug_print("removing mailimap %p\n", imap);
78 static gboolean thread_manager_event(GIOChannel * source,
79 GIOCondition condition,
82 etpan_thread_manager_loop(thread_manager);
87 static void imap_logger_noop(int direction, const char * str, size_t size)
92 static void imap_logger_cmd(int direction, const char * str, size_t size)
99 log_print(LOG_PROTOCOL, "IMAP4%c [CMD data - %zd bytes]\n", direction?'>':'<', size);
102 buf = malloc(size+1);
103 memset(buf, 0, size+1);
104 strncpy(buf, str, size);
107 if (!strncmp(buf, "<<<<<<<", 7)
108 || !strncmp(buf, ">>>>>>>", 7)) {
112 while (strstr(buf, "\r"))
113 *strstr(buf, "\r") = ' ';
114 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
115 buf[strlen(buf)-1] = '\0';
117 lines = g_strsplit(buf, "\n", -1);
119 while (lines[i] && *lines[i]) {
120 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
127 static void imap_logger_fetch(int direction, const char * str, size_t size)
133 if (size > 128 && !direction) {
134 log_print(LOG_PROTOCOL, "IMAP4%c [FETCH data - %zd bytes]\n", direction?'>':'<', size);
138 buf = malloc(size+1);
139 memset(buf, 0, size+1);
140 strncpy(buf, str, size);
142 if (!strncmp(buf, "<<<<<<<", 7)
143 || !strncmp(buf, ">>>>>>>", 7)) {
147 while (strstr(buf, "\r"))
148 *strstr(buf, "\r") = ' ';
149 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
150 buf[strlen(buf)-1] = '\0';
152 lines = g_strsplit(buf, "\n", -1);
154 if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) {
155 while (lines[i] && *lines[i]) {
156 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
160 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
166 static void imap_logger_uid(int direction, const char * str, size_t size)
173 log_print(LOG_PROTOCOL, "IMAP4%c [UID data - %zd bytes]\n", direction?'>':'<', size);
176 buf = malloc(size+1);
177 memset(buf, 0, size+1);
178 strncpy(buf, str, size);
180 if (!strncmp(buf, "<<<<<<<", 7)
181 || !strncmp(buf, ">>>>>>>", 7)) {
185 while (strstr(buf, "\r"))
186 *strstr(buf, "\r") = ' ';
187 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
188 buf[strlen(buf)-1] = '\0';
190 lines = g_strsplit(buf, "\n", -1);
192 while (lines[i] && *lines[i]) {
193 int llen = strlen(lines[i]);
195 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
198 strncpy2(tmp, lines[i], 63);
199 log_print(LOG_PROTOCOL, "IMAP4%c %s[... - %zd bytes more]\n", direction?'>':'<', tmp,
208 static void imap_logger_append(int direction, const char * str, size_t size)
215 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
217 } else if (direction == 0 && size > 64) {
218 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
221 buf = malloc(size+1);
222 memset(buf, 0, size+1);
223 strncpy(buf, str, size);
225 if (!strncmp(buf, "<<<<<<<", 7)
226 || !strncmp(buf, ">>>>>>>", 7)) {
230 while (strstr(buf, "\r"))
231 *strstr(buf, "\r") = ' ';
232 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
233 buf[strlen(buf)-1] = '\0';
235 lines = g_strsplit(buf, "\n", -1);
237 if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
238 while (lines[i] && *lines[i]) {
239 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
243 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
249 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
250 static gboolean etpan_skip_ssl_cert_check = FALSE;
251 extern void mailsasl_ref(void);
253 void imap_main_init(gboolean skip_ssl_cert_check)
255 int fd_thread_manager;
257 etpan_skip_ssl_cert_check = skip_ssl_cert_check;
258 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
259 mailstream_network_delay.tv_usec = 0;
261 mailstream_debug = 1;
262 mailstream_logger = imap_logger_cmd;
265 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
266 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
267 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
269 thread_manager = etpan_thread_manager_new();
271 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
273 io_channel = g_io_channel_unix_new(fd_thread_manager);
275 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
276 thread_manager_event,
281 void imap_main_set_timeout(int sec)
283 mailstream_network_delay.tv_sec = sec;
284 mailstream_network_delay.tv_usec = 0;
287 void imap_main_done(void)
289 etpan_thread_manager_stop(thread_manager);
290 etpan_thread_manager_join(thread_manager);
292 g_source_remove(thread_manager_signal);
293 g_io_channel_unref(io_channel);
295 etpan_thread_manager_free(thread_manager);
297 chash_free(courier_workaround_hash);
298 chash_free(session_hash);
299 chash_free(imap_hash);
302 void imap_init(Folder * folder)
304 struct etpan_thread * thread;
308 thread = etpan_thread_manager_get_thread(thread_manager);
311 key.len = sizeof(folder);
315 chash_set(imap_hash, &key, &value, NULL);
318 void imap_done(Folder * folder)
320 struct etpan_thread * thread;
326 key.len = sizeof(folder);
328 r = chash_get(imap_hash, &key, &value);
334 etpan_thread_unbind(thread);
336 chash_delete(imap_hash, &key, NULL);
338 debug_print("remove thread");
341 static struct etpan_thread * get_thread(Folder * folder)
343 struct etpan_thread * thread;
348 key.len = sizeof(folder);
350 chash_get(imap_hash, &key, &value);
356 static mailimap * get_imap(Folder * folder)
364 key.len = sizeof(folder);
366 r = chash_get(session_hash, &key, &value);
371 debug_print("found imap %p\n", imap);
376 static void generic_cb(int cancelled, void * result, void * callback_data)
378 struct etpan_thread_op * op;
380 op = (struct etpan_thread_op *) callback_data;
382 debug_print("generic_cb\n");
383 if (op->imap && op->imap->imap_response_info &&
384 op->imap->imap_response_info->rsp_alert) {
385 log_error(LOG_PROTOCOL, "IMAP4< Alert: %s\n",
386 op->imap->imap_response_info->rsp_alert);
387 mainwindow_show_error();
392 static void threaded_run(Folder * folder, void * param, void * result,
393 void (* func)(struct etpan_thread_op * ))
395 struct etpan_thread_op * op;
396 struct etpan_thread * thread;
398 imap_folder_ref(folder);
400 op = etpan_thread_op_new();
402 op->imap = get_imap(folder);
408 op->callback = generic_cb;
409 op->callback_data = op;
414 thread = get_thread(folder);
415 etpan_thread_op_schedule(thread, op);
417 while (!op->finished) {
418 gtk_main_iteration();
421 etpan_thread_op_free(op);
423 imap_folder_unref(folder);
429 struct connect_param {
435 struct connect_result {
439 #define CHECK_IMAP() { \
440 if (!param->imap) { \
441 result->error = MAILIMAP_ERROR_BAD_STATE; \
446 static void connect_run(struct etpan_thread_op * op)
449 struct connect_param * param;
450 struct connect_result * result;
457 r = mailimap_socket_connect(param->imap,
458 param->server, param->port);
464 int imap_threaded_connect(Folder * folder, const char * server, int port)
466 struct connect_param param;
467 struct connect_result result;
470 mailimap * imap, * oldimap;
472 oldimap = get_imap(folder);
474 imap = mailimap_new(0, NULL);
477 debug_print("deleting old imap %p\n", oldimap);
478 delete_imap(folder, oldimap);
482 key.len = sizeof(folder);
485 chash_set(session_hash, &key, &value, NULL);
488 param.server = server;
492 threaded_run(folder, ¶m, &result, connect_run);
494 debug_print("connect ok %i with imap %p\n", result.error, imap);
499 static int etpan_certificate_check(const unsigned char *certificate, int len, void *data)
502 struct connect_param *param = (struct connect_param *)data;
505 if (certificate == NULL || len < 0) {
506 g_warning("no cert presented.\n");
509 cert = d2i_X509(NULL, &certificate, len);
511 g_warning("can't get cert\n");
513 } else if (ssl_certificate_check(cert, NULL,
514 (gchar *)param->server, (gushort)param->port) == TRUE) {
526 static void connect_ssl_run(struct etpan_thread_op * op)
529 struct connect_param * param;
530 struct connect_result * result;
537 r = mailimap_ssl_connect(param->imap,
538 param->server, param->port);
542 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
544 struct connect_param param;
545 struct connect_result result;
548 mailimap * imap, * oldimap;
549 unsigned char *certificate = NULL;
552 oldimap = get_imap(folder);
554 imap = mailimap_new(0, NULL);
557 debug_print("deleting old imap %p\n", oldimap);
558 delete_imap(folder, oldimap);
562 key.len = sizeof(folder);
565 chash_set(session_hash, &key, &value, NULL);
568 param.server = server;
572 threaded_run(folder, ¶m, &result, connect_ssl_run);
574 if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
575 result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
576 cert_len = (int)mailstream_ssl_get_certificate(imap->imap_stream, &certificate);
577 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
582 debug_print("connect %d with imap %p\n", result.error, imap);
593 struct mailimap_capability_data *caps;
596 static void capability_run(struct etpan_thread_op * op)
599 struct capa_param * param;
600 struct capa_result * result;
601 struct mailimap_capability_data *caps;
608 r = mailimap_capability(param->imap, &caps);
611 result->caps = (r == 0 ? caps : NULL);
615 struct mailimap_capability_data * imap_threaded_capability(Folder *folder, int *ok)
617 struct capa_param param;
618 struct capa_result result;
621 imap = get_imap(folder);
625 threaded_run(folder, ¶m, &result, capability_run);
627 debug_print("capa %d\n", result.error);
636 struct disconnect_param {
640 struct disconnect_result {
644 static void disconnect_run(struct etpan_thread_op * op)
647 struct disconnect_param * param;
648 struct disconnect_result * result;
655 r = mailimap_logout(param->imap);
660 void imap_threaded_disconnect(Folder * folder)
662 struct connect_param param;
663 struct connect_result result;
666 imap = get_imap(folder);
668 debug_print("was disconnected\n");
674 threaded_run(folder, ¶m, &result, disconnect_run);
676 if (imap == get_imap(folder)) {
677 debug_print("deleting old imap %p\n", imap);
678 delete_imap(folder, imap);
680 debug_print("imap already deleted %p\n", imap);
683 debug_print("disconnect ok\n");
690 const char * wildcard;
699 static void list_run(struct etpan_thread_op * op)
701 struct list_param * param;
702 struct list_result * result;
713 if (param->base == NULL || param->wildcard == NULL) {
716 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
720 r = mailimap_lsub(param->imap, param->base,
721 param->wildcard, &list);
723 r = mailimap_list(param->imap, param->base,
724 param->wildcard, &list);
727 debug_print("imap list run - end\n");
730 int imap_threaded_list(Folder * folder, const char * base,
731 const char * wildcard,
734 struct list_param param;
735 struct list_result result;
737 debug_print("imap list - begin\n");
739 param.imap = get_imap(folder);
741 param.wildcard = wildcard;
742 param.sub_only = FALSE;
744 threaded_run(folder, ¶m, &result, list_run);
746 * p_result = result.list;
748 debug_print("imap list - end %p\n", result.list);
753 int imap_threaded_lsub(Folder * folder, const char * base,
754 const char * wildcard,
757 struct list_param param;
758 struct list_result result;
760 debug_print("imap lsub - begin\n");
762 param.imap = get_imap(folder);
764 param.wildcard = wildcard;
765 param.sub_only = TRUE;
767 threaded_run(folder, ¶m, &result, list_run);
769 * p_result = result.list;
771 debug_print("imap lsub - end %p\n", result.list);
776 struct subscribe_param {
782 struct subscribe_result {
786 static void subscribe_run(struct etpan_thread_op * op)
788 struct subscribe_param * param;
789 struct subscribe_result * result;
797 if (param->mb == NULL) {
799 debug_print("no mb\n");
802 if (param->subscribe)
803 r = mailimap_subscribe(param->imap, param->mb);
805 r = mailimap_unsubscribe(param->imap, param->mb);
807 debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
810 int imap_threaded_subscribe(Folder * folder, const char * mb,
813 struct subscribe_param param;
814 struct subscribe_result result;
816 debug_print("imap list - begin\n");
818 param.imap = get_imap(folder);
820 param.subscribe = subscribe;
822 threaded_run(folder, ¶m, &result, subscribe_run);
830 const char * password;
835 struct login_result {
839 static void login_run(struct etpan_thread_op * op)
841 struct login_param * param;
842 struct login_result * result;
844 #ifdef DISABLE_LOG_DURING_LOGIN
853 #ifdef DISABLE_LOG_DURING_LOGIN
854 old_debug = mailstream_debug;
855 mailstream_debug = 0;
857 if (!strcmp(param->type, "LOGIN"))
858 r = mailimap_login(param->imap,
859 param->login, param->password);
860 else if (!strcmp(param->type, "GSSAPI"))
861 r = mailimap_authenticate(param->imap,
862 param->type, param->server, NULL, NULL,
863 param->login, param->login,
864 param->password, NULL);
866 r = mailimap_authenticate(param->imap,
867 param->type, NULL, NULL, NULL,
868 param->login, param->login,
869 param->password, NULL);
870 #ifdef DISABLE_LOG_DURING_LOGIN
871 mailstream_debug = old_debug;
875 debug_print("imap login run - end %i\n", r);
878 int imap_threaded_login(Folder * folder,
879 const char * login, const char * password,
882 struct login_param param;
883 struct login_result result;
885 debug_print("imap login - begin\n");
887 param.imap = get_imap(folder);
889 param.password = password;
891 if (folder && folder->account)
892 param.server = folder->account->recv_server;
896 threaded_run(folder, ¶m, &result, login_run);
898 debug_print("imap login - end\n");
904 struct status_param {
907 struct mailimap_status_att_list * status_att_list;
910 struct status_result {
912 struct mailimap_mailbox_data_status * data_status;
915 static void status_run(struct etpan_thread_op * op)
917 struct status_param * param;
918 struct status_result * result;
926 r = mailimap_status(param->imap, param->mb,
927 param->status_att_list,
928 &result->data_status);
931 debug_print("imap status run - end %i\n", r);
934 int imap_threaded_status(Folder * folder, const char * mb,
935 struct mailimap_mailbox_data_status ** data_status,
938 struct status_param param;
939 struct status_result result;
940 struct mailimap_status_att_list * status_att_list;
942 debug_print("imap status - begin\n");
944 status_att_list = mailimap_status_att_list_new_empty();
946 mailimap_status_att_list_add(status_att_list,
947 MAILIMAP_STATUS_ATT_MESSAGES);
950 mailimap_status_att_list_add(status_att_list,
951 MAILIMAP_STATUS_ATT_RECENT);
954 mailimap_status_att_list_add(status_att_list,
955 MAILIMAP_STATUS_ATT_UIDNEXT);
958 mailimap_status_att_list_add(status_att_list,
959 MAILIMAP_STATUS_ATT_UIDVALIDITY);
962 mailimap_status_att_list_add(status_att_list,
963 MAILIMAP_STATUS_ATT_UNSEEN);
965 param.imap = get_imap(folder);
967 param.status_att_list = status_att_list;
969 threaded_run(folder, ¶m, &result, status_run);
971 debug_print("imap status - end\n");
973 * data_status = result.data_status;
975 mailimap_status_att_list_free(status_att_list);
990 static void noop_run(struct etpan_thread_op * op)
992 struct noop_param * param;
993 struct noop_result * result;
1001 r = mailimap_noop(param->imap);
1004 debug_print("imap noop run - end %i\n", r);
1007 int imap_threaded_noop(Folder * folder, unsigned int * p_exists,
1008 unsigned int *p_recent,
1009 unsigned int *p_expunge,
1010 unsigned int *p_unseen,
1011 unsigned int *p_uidnext,
1012 unsigned int *p_uidval)
1014 struct noop_param param;
1015 struct noop_result result;
1018 debug_print("imap noop - begin\n");
1020 imap = get_imap(folder);
1023 threaded_run(folder, ¶m, &result, noop_run);
1025 if (result.error == 0 && imap && imap->imap_selection_info != NULL) {
1026 * p_exists = imap->imap_selection_info->sel_exists;
1027 * p_recent = imap->imap_selection_info->sel_recent;
1028 * p_unseen = imap->imap_selection_info->sel_unseen;
1029 * p_uidnext = imap->imap_selection_info->sel_uidnext;
1030 * p_uidval = imap->imap_selection_info->sel_uidvalidity;
1038 if (result.error == 0 && imap && imap->imap_response_info != NULL &&
1039 imap->imap_response_info->rsp_expunged != NULL) {
1040 * p_expunge = clist_count(imap->imap_response_info->rsp_expunged);
1044 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1045 *p_exists, *p_recent, *p_expunge, *p_unseen,
1046 *p_uidnext, *p_uidval);
1048 return result.error;
1052 struct starttls_result {
1056 static void starttls_run(struct etpan_thread_op * op)
1058 struct connect_param * param;
1059 struct starttls_result * result;
1063 result = op->result;
1067 r = mailimap_starttls(param->imap);
1070 debug_print("imap starttls run - end %i\n", r);
1073 mailimap *imap = param->imap;
1074 mailstream_low *plain_low = NULL;
1075 mailstream_low *tls_low = NULL;
1078 plain_low = mailstream_get_low(imap->imap_stream);
1079 fd = mailstream_low_get_fd(plain_low);
1081 debug_print("imap starttls run - can't get fd\n");
1082 result->error = MAILIMAP_ERROR_STREAM;
1086 tls_low = mailstream_low_tls_open(fd);
1087 if (tls_low == NULL) {
1088 debug_print("imap starttls run - can't tls_open\n");
1089 result->error = MAILIMAP_ERROR_STREAM;
1092 mailstream_low_free(plain_low);
1093 mailstream_set_low(imap->imap_stream, tls_low);
1097 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1099 struct connect_param param;
1100 struct starttls_result result;
1102 unsigned char *certificate;
1104 debug_print("imap starttls - begin\n");
1106 param.imap = get_imap(folder);
1107 param.server = host;
1110 threaded_run(folder, ¶m, &result, starttls_run);
1112 debug_print("imap starttls - end\n");
1114 if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
1115 cert_len = (int)mailstream_ssl_get_certificate(param.imap->imap_stream, &certificate);
1116 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
1117 result.error = MAILIMAP_ERROR_STREAM;
1121 return result.error;
1126 struct create_param {
1131 struct create_result {
1135 static void create_run(struct etpan_thread_op * op)
1137 struct create_param * param;
1138 struct create_result * result;
1142 result = op->result;
1146 r = mailimap_create(param->imap, param->mb);
1149 debug_print("imap create run - end %i\n", r);
1152 int imap_threaded_create(Folder * folder, const char * mb)
1154 struct create_param param;
1155 struct create_result result;
1157 debug_print("imap create - begin\n");
1159 param.imap = get_imap(folder);
1162 threaded_run(folder, ¶m, &result, create_run);
1164 debug_print("imap create - end\n");
1166 return result.error;
1172 struct rename_param {
1175 const char * new_name;
1178 struct rename_result {
1182 static void rename_run(struct etpan_thread_op * op)
1184 struct rename_param * param;
1185 struct rename_result * result;
1189 result = op->result;
1193 r = mailimap_rename(param->imap, param->mb, param->new_name);
1196 debug_print("imap rename run - end %i\n", r);
1199 int imap_threaded_rename(Folder * folder,
1200 const char * mb, const char * new_name)
1202 struct rename_param param;
1203 struct rename_result result;
1205 debug_print("imap rename - begin\n");
1207 param.imap = get_imap(folder);
1209 param.new_name = new_name;
1211 threaded_run(folder, ¶m, &result, rename_run);
1213 debug_print("imap rename - end\n");
1215 return result.error;
1221 struct delete_param {
1226 struct delete_result {
1230 static void delete_run(struct etpan_thread_op * op)
1232 struct delete_param * param;
1233 struct delete_result * result;
1237 result = op->result;
1241 r = mailimap_delete(param->imap, param->mb);
1244 debug_print("imap delete run - end %i\n", r);
1247 int imap_threaded_delete(Folder * folder, const char * mb)
1249 struct delete_param param;
1250 struct delete_result result;
1252 debug_print("imap delete - begin\n");
1254 param.imap = get_imap(folder);
1257 threaded_run(folder, ¶m, &result, delete_run);
1259 debug_print("imap delete - end\n");
1261 return result.error;
1266 struct select_param {
1271 struct select_result {
1275 static void select_run(struct etpan_thread_op * op)
1277 struct select_param * param;
1278 struct select_result * result;
1282 result = op->result;
1286 r = mailimap_select(param->imap, param->mb);
1289 debug_print("imap select run - end %i\n", r);
1292 int imap_threaded_select(Folder * folder, const char * mb,
1293 gint * exists, gint * recent, gint * unseen,
1294 guint32 * uid_validity)
1296 struct select_param param;
1297 struct select_result result;
1300 debug_print("imap select - begin\n");
1302 imap = get_imap(folder);
1306 threaded_run(folder, ¶m, &result, select_run);
1308 if (result.error != MAILIMAP_NO_ERROR)
1309 return result.error;
1311 if (!imap || imap->imap_selection_info == NULL)
1312 return MAILIMAP_ERROR_PARSE;
1314 * exists = imap->imap_selection_info->sel_exists;
1315 * recent = imap->imap_selection_info->sel_recent;
1316 * unseen = imap->imap_selection_info->sel_unseen;
1317 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1319 debug_print("imap select - end\n");
1321 return result.error;
1324 static void close_run(struct etpan_thread_op * op)
1326 struct select_param * param;
1327 struct select_result * result;
1331 result = op->result;
1335 r = mailimap_close(param->imap);
1338 debug_print("imap close run - end %i\n", r);
1341 int imap_threaded_close(Folder * folder)
1343 struct select_param param;
1344 struct select_result result;
1347 debug_print("imap close - begin\n");
1349 imap = get_imap(folder);
1352 threaded_run(folder, ¶m, &result, close_run);
1354 if (result.error != MAILIMAP_NO_ERROR)
1355 return result.error;
1357 debug_print("imap close - end\n");
1359 return result.error;
1362 struct examine_param {
1367 struct examine_result {
1371 static void examine_run(struct etpan_thread_op * op)
1373 struct examine_param * param;
1374 struct examine_result * result;
1378 result = op->result;
1382 r = mailimap_examine(param->imap, param->mb);
1385 debug_print("imap examine run - end %i\n", r);
1388 int imap_threaded_examine(Folder * folder, const char * mb,
1389 gint * exists, gint * recent, gint * unseen,
1390 guint32 * uid_validity)
1392 struct examine_param param;
1393 struct examine_result result;
1396 debug_print("imap examine - begin\n");
1398 imap = get_imap(folder);
1402 threaded_run(folder, ¶m, &result, examine_run);
1404 if (result.error != MAILIMAP_NO_ERROR)
1405 return result.error;
1407 if (!imap || imap->imap_selection_info == NULL)
1408 return MAILIMAP_ERROR_PARSE;
1410 * exists = imap->imap_selection_info->sel_exists;
1411 * recent = imap->imap_selection_info->sel_recent;
1412 * unseen = imap->imap_selection_info->sel_unseen;
1413 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1415 debug_print("imap examine - end\n");
1417 return result.error;
1423 struct search_param {
1426 struct mailimap_set * set;
1429 struct search_result {
1431 clist * search_result;
1434 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1436 return mailimap_set_item_new(orig->set_first, orig->set_last);
1439 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1441 clist *list = orig ? orig->set_list : NULL;
1442 clist *newlist = clist_new();
1447 for (cur = clist_begin(list); cur; cur = clist_next(cur))
1448 clist_append(newlist,
1449 sc_mailimap_set_item_copy(
1450 (struct mailimap_set_item *)clist_content(cur)));
1451 return mailimap_set_new(newlist);
1454 static void search_run(struct etpan_thread_op * op)
1456 struct search_param * param;
1457 struct search_result * result;
1459 struct mailimap_search_key * key = NULL;
1460 struct mailimap_search_key * uid_key = NULL;
1461 struct mailimap_search_key * search_type_key;
1462 clist * search_result;
1465 result = op->result;
1469 /* we copy the mailimap_set because freeing the key is recursive */
1470 if (param->set != NULL) {
1471 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1472 } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1473 uid_key = mailimap_search_key_new_all();
1475 search_type_key = NULL;
1476 switch (param->type) {
1477 case IMAP_SEARCH_TYPE_SIMPLE:
1478 search_type_key = NULL;
1481 case IMAP_SEARCH_TYPE_SEEN:
1482 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
1483 NULL, NULL, NULL, NULL, NULL,
1484 NULL, NULL, NULL, NULL, NULL,
1485 NULL, NULL, NULL, NULL, 0,
1486 NULL, NULL, NULL, NULL, NULL,
1487 NULL, 0, NULL, NULL, NULL);
1490 case IMAP_SEARCH_TYPE_UNSEEN:
1491 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
1492 NULL, NULL, NULL, NULL, NULL,
1493 NULL, NULL, NULL, NULL, NULL,
1494 NULL, NULL, NULL, NULL, 0,
1495 NULL, NULL, NULL, NULL, NULL,
1496 NULL, 0, NULL, NULL, NULL);
1499 case IMAP_SEARCH_TYPE_ANSWERED:
1500 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
1501 NULL, NULL, NULL, NULL, NULL,
1502 NULL, NULL, NULL, NULL, NULL,
1503 NULL, NULL, NULL, NULL, 0,
1504 NULL, NULL, NULL, NULL, NULL,
1505 NULL, 0, NULL, NULL, NULL);
1508 case IMAP_SEARCH_TYPE_FLAGGED:
1509 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
1510 NULL, NULL, NULL, NULL, NULL,
1511 NULL, NULL, NULL, NULL, NULL,
1512 NULL, NULL, NULL, NULL, 0,
1513 NULL, NULL, NULL, NULL, NULL,
1514 NULL, 0, NULL, NULL, NULL);
1516 case IMAP_SEARCH_TYPE_DELETED:
1517 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_DELETED,
1518 NULL, NULL, NULL, NULL, NULL,
1519 NULL, NULL, NULL, NULL, NULL,
1520 NULL, NULL, NULL, NULL, 0,
1521 NULL, NULL, NULL, NULL, NULL,
1522 NULL, 0, NULL, NULL, NULL);
1526 if (search_type_key != NULL) {
1527 if (param->set != NULL) {
1528 key = mailimap_search_key_new_multiple_empty();
1529 mailimap_search_key_multiple_add(key, search_type_key);
1530 mailimap_search_key_multiple_add(key, uid_key);
1532 key = search_type_key;
1534 } else if (uid_key != NULL) {
1539 g_warning("no key!");
1540 result = op->result;
1542 result->search_result = NULL;
1544 mailstream_logger = imap_logger_uid;
1546 r = mailimap_uid_search(param->imap, NULL, key, &search_result);
1548 mailstream_logger = imap_logger_cmd;
1550 /* free the key (with the imapset) */
1551 mailimap_search_key_free(key);
1554 result->search_result = search_result;
1556 debug_print("imap search run - end %i\n", result->error);
1559 int imap_threaded_search(Folder * folder, int search_type,
1560 struct mailimap_set * set, clist ** search_result)
1562 struct search_param param;
1563 struct search_result result;
1566 debug_print("imap search - begin\n");
1568 imap = get_imap(folder);
1571 param.type = search_type;
1573 threaded_run(folder, ¶m, &result, search_run);
1575 if (result.error != MAILIMAP_NO_ERROR)
1576 return result.error;
1578 debug_print("imap search - end\n");
1580 * search_result = result.search_result;
1582 return result.error;
1587 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1591 struct mailimap_msg_att_dynamic ** patt_dyn);
1594 result_to_uid_list(clist * fetch_result, carray ** result)
1601 tab = carray_new(128);
1603 res = MAILIMAP_ERROR_MEMORY;
1607 for(cur = clist_begin(fetch_result) ; cur != NULL ;
1608 cur = clist_next(cur)) {
1609 struct mailimap_msg_att * msg_att;
1613 msg_att = clist_content(cur);
1616 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL);
1618 puid = malloc(sizeof(* puid));
1620 res = MAILIMAP_ERROR_MEMORY;
1625 r = carray_add(tab, puid, NULL);
1628 res = MAILIMAP_ERROR_MEMORY;
1635 return MAILIMAP_NO_ERROR;
1638 imap_fetch_uid_list_free(tab);
1643 static int imap_get_messages_list(mailimap * imap,
1644 uint32_t first_index,
1649 struct mailimap_fetch_att * fetch_att;
1650 struct mailimap_fetch_type * fetch_type;
1651 struct mailimap_set * set;
1652 clist * fetch_result;
1655 set = mailimap_set_new_interval(first_index, 0);
1657 res = MAILIMAP_ERROR_MEMORY;
1661 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1662 if (fetch_type == NULL) {
1663 res = MAILIMAP_ERROR_MEMORY;
1667 fetch_att = mailimap_fetch_att_new_uid();
1668 if (fetch_att == NULL) {
1669 res = MAILIMAP_ERROR_MEMORY;
1670 goto free_fetch_type;
1673 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1674 if (r != MAILIMAP_NO_ERROR) {
1675 mailimap_fetch_att_free(fetch_att);
1676 res = MAILIMAP_ERROR_MEMORY;
1677 goto free_fetch_type;
1680 mailstream_logger = imap_logger_fetch;
1682 r = mailimap_uid_fetch(imap, set,
1683 fetch_type, &fetch_result);
1685 mailstream_logger = imap_logger_cmd;
1686 mailimap_fetch_type_free(fetch_type);
1687 mailimap_set_free(set);
1689 if (r != MAILIMAP_NO_ERROR) {
1695 r = result_to_uid_list(fetch_result, &env_list);
1696 mailimap_fetch_list_free(fetch_result);
1698 * result = env_list;
1700 return MAILIMAP_NO_ERROR;
1703 mailimap_fetch_type_free(fetch_type);
1705 mailimap_set_free(set);
1713 struct fetch_uid_param {
1715 uint32_t first_index;
1718 struct fetch_uid_result {
1720 carray * fetch_result;
1723 static void fetch_uid_run(struct etpan_thread_op * op)
1725 struct fetch_uid_param * param;
1726 struct fetch_uid_result * result;
1727 carray * fetch_result;
1731 result = op->result;
1735 fetch_result = NULL;
1736 mailstream_logger = imap_logger_noop;
1737 log_print(LOG_PROTOCOL, "IMAP4- [fetching UIDs...]\n");
1739 r = imap_get_messages_list(param->imap, param->first_index,
1742 mailstream_logger = imap_logger_cmd;
1745 result->fetch_result = fetch_result;
1746 debug_print("imap fetch_uid run - end %i\n", r);
1749 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1750 carray ** fetch_result)
1752 struct fetch_uid_param param;
1753 struct fetch_uid_result result;
1756 debug_print("imap fetch_uid - begin\n");
1758 imap = get_imap(folder);
1760 param.first_index = first_index;
1762 threaded_run(folder, ¶m, &result, fetch_uid_run);
1764 if (result.error != MAILIMAP_NO_ERROR)
1765 return result.error;
1767 debug_print("imap fetch_uid - end\n");
1769 * fetch_result = result.fetch_result;
1771 return result.error;
1775 void imap_fetch_uid_list_free(carray * uid_list)
1779 for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1782 puid = carray_get(uid_list, i);
1785 carray_free(uid_list);
1791 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn);
1794 result_to_uid_flags_list(clist * fetch_result, carray ** result)
1801 tab = carray_new(128);
1803 res = MAILIMAP_ERROR_MEMORY;
1807 for(cur = clist_begin(fetch_result) ; cur != NULL ;
1808 cur = clist_next(cur)) {
1809 struct mailimap_msg_att * msg_att;
1812 struct mailimap_msg_att_dynamic * att_dyn;
1816 msg_att = clist_content(cur);
1820 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn);
1823 if (att_dyn == NULL)
1826 flags = imap_flags_to_flags(att_dyn);
1828 puid = malloc(sizeof(* puid));
1830 res = MAILIMAP_ERROR_MEMORY;
1835 r = carray_add(tab, puid, NULL);
1838 res = MAILIMAP_ERROR_MEMORY;
1841 pflags = malloc(sizeof(* pflags));
1842 if (pflags == NULL) {
1843 res = MAILIMAP_ERROR_MEMORY;
1847 r = carray_add(tab, pflags, NULL);
1850 res = MAILIMAP_ERROR_MEMORY;
1857 return MAILIMAP_NO_ERROR;
1860 imap_fetch_uid_flags_list_free(tab);
1865 static int imap_get_messages_flags_list(mailimap * imap,
1866 uint32_t first_index,
1871 struct mailimap_fetch_att * fetch_att;
1872 struct mailimap_fetch_type * fetch_type;
1873 struct mailimap_set * set;
1874 clist * fetch_result;
1877 set = mailimap_set_new_interval(first_index, 0);
1879 res = MAILIMAP_ERROR_MEMORY;
1883 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1884 if (fetch_type == NULL) {
1885 res = MAILIMAP_ERROR_MEMORY;
1889 fetch_att = mailimap_fetch_att_new_flags();
1890 if (fetch_att == NULL) {
1891 res = MAILIMAP_ERROR_MEMORY;
1892 goto free_fetch_type;
1895 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1896 if (r != MAILIMAP_NO_ERROR) {
1897 mailimap_fetch_att_free(fetch_att);
1898 res = MAILIMAP_ERROR_MEMORY;
1899 goto free_fetch_type;
1902 fetch_att = mailimap_fetch_att_new_uid();
1903 if (fetch_att == NULL) {
1904 res = MAILIMAP_ERROR_MEMORY;
1905 goto free_fetch_type;
1908 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1909 if (r != MAILIMAP_NO_ERROR) {
1910 mailimap_fetch_att_free(fetch_att);
1911 res = MAILIMAP_ERROR_MEMORY;
1912 goto free_fetch_type;
1915 mailstream_logger = imap_logger_fetch;
1917 r = mailimap_uid_fetch(imap, set,
1918 fetch_type, &fetch_result);
1920 mailstream_logger = imap_logger_cmd;
1921 mailimap_fetch_type_free(fetch_type);
1922 mailimap_set_free(set);
1924 if (r != MAILIMAP_NO_ERROR) {
1930 r = result_to_uid_flags_list(fetch_result, &env_list);
1931 mailimap_fetch_list_free(fetch_result);
1933 * result = env_list;
1935 return MAILIMAP_NO_ERROR;
1938 mailimap_fetch_type_free(fetch_type);
1940 mailimap_set_free(set);
1947 static void fetch_uid_flags_run(struct etpan_thread_op * op)
1949 struct fetch_uid_param * param;
1950 struct fetch_uid_result * result;
1951 carray * fetch_result;
1955 result = op->result;
1959 fetch_result = NULL;
1960 r = imap_get_messages_flags_list(param->imap, param->first_index,
1964 result->fetch_result = fetch_result;
1965 debug_print("imap fetch_uid run - end %i\n", r);
1968 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index,
1969 carray ** fetch_result)
1971 struct fetch_uid_param param;
1972 struct fetch_uid_result result;
1975 debug_print("imap fetch_uid - begin\n");
1977 imap = get_imap(folder);
1979 param.first_index = first_index;
1981 mailstream_logger = imap_logger_noop;
1982 log_print(LOG_PROTOCOL, "IMAP4- [fetching flags...]\n");
1984 threaded_run(folder, ¶m, &result, fetch_uid_flags_run);
1986 mailstream_logger = imap_logger_cmd;
1989 if (result.error != MAILIMAP_NO_ERROR)
1990 return result.error;
1992 debug_print("imap fetch_uid - end\n");
1994 * fetch_result = result.fetch_result;
1996 return result.error;
2000 void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
2004 for(i = 0 ; i < carray_count(uid_flags_list) ; i ++) {
2007 data = carray_get(uid_flags_list, i);
2010 carray_free(uid_flags_list);
2015 static int imap_fetch(mailimap * imap,
2018 size_t * result_len)
2021 struct mailimap_set * set;
2022 struct mailimap_fetch_att * fetch_att;
2023 struct mailimap_fetch_type * fetch_type;
2024 clist * fetch_result;
2025 struct mailimap_msg_att * msg_att;
2026 struct mailimap_msg_att_item * msg_att_item;
2031 struct mailimap_section * section;
2033 set = mailimap_set_new_single(msg_index);
2035 res = MAILIMAP_ERROR_MEMORY;
2039 section = mailimap_section_new(NULL);
2040 if (section == NULL) {
2041 res = MAILIMAP_ERROR_MEMORY;
2045 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2046 if (fetch_att == NULL) {
2047 mailimap_section_free(section);
2048 res = MAILIMAP_ERROR_MEMORY;
2052 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2053 if (fetch_type == NULL) {
2054 res = MAILIMAP_ERROR_MEMORY;
2055 goto free_fetch_att;
2058 mailstream_logger = imap_logger_fetch;
2060 r = mailimap_uid_fetch(imap, set,
2061 fetch_type, &fetch_result);
2063 mailstream_logger = imap_logger_cmd;
2065 mailimap_fetch_type_free(fetch_type);
2066 mailimap_set_free(set);
2069 case MAILIMAP_NO_ERROR:
2075 if (clist_begin(fetch_result) == NULL) {
2076 mailimap_fetch_list_free(fetch_result);
2077 return MAILIMAP_ERROR_FETCH;
2080 msg_att = clist_begin(fetch_result)->data;
2085 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
2086 cur = clist_next(cur)) {
2087 msg_att_item = clist_content(cur);
2089 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2090 if (msg_att_item->att_data.att_static->att_type ==
2091 MAILIMAP_MSG_ATT_BODY_SECTION) {
2092 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2094 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2096 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2101 mailimap_fetch_list_free(fetch_result);
2104 return MAILIMAP_ERROR_FETCH;
2107 * result_len = text_length;
2109 return MAILIMAP_NO_ERROR;
2112 mailimap_fetch_att_free(fetch_att);
2114 mailimap_set_free(set);
2119 static int imap_fetch_header(mailimap * imap,
2122 size_t * result_len)
2125 struct mailimap_set * set;
2126 struct mailimap_fetch_att * fetch_att;
2127 struct mailimap_fetch_type * fetch_type;
2128 clist * fetch_result;
2129 struct mailimap_msg_att * msg_att;
2130 struct mailimap_msg_att_item * msg_att_item;
2135 struct mailimap_section * section;
2137 set = mailimap_set_new_single(msg_index);
2139 res = MAILIMAP_ERROR_MEMORY;
2143 section = mailimap_section_new_header();
2144 if (section == NULL) {
2145 res = MAILIMAP_ERROR_MEMORY;
2149 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2150 if (fetch_att == NULL) {
2151 mailimap_section_free(section);
2152 res = MAILIMAP_ERROR_MEMORY;
2156 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2157 if (fetch_type == NULL) {
2158 res = MAILIMAP_ERROR_MEMORY;
2159 goto free_fetch_att;
2162 mailstream_logger = imap_logger_fetch;
2164 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2166 mailstream_logger = imap_logger_cmd;
2167 mailimap_fetch_type_free(fetch_type);
2168 mailimap_set_free(set);
2171 case MAILIMAP_NO_ERROR:
2177 if (clist_begin(fetch_result) == NULL) {
2178 mailimap_fetch_list_free(fetch_result);
2179 return MAILIMAP_ERROR_FETCH;
2182 msg_att = clist_begin(fetch_result)->data;
2187 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
2188 cur = clist_next(cur)) {
2189 msg_att_item = clist_content(cur);
2191 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2192 if (msg_att_item->att_data.att_static->att_type ==
2193 MAILIMAP_MSG_ATT_BODY_SECTION) {
2194 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2195 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2197 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2202 mailimap_fetch_list_free(fetch_result);
2205 return MAILIMAP_ERROR_FETCH;
2208 * result_len = text_length;
2210 return MAILIMAP_NO_ERROR;
2213 mailimap_fetch_att_free(fetch_att);
2215 mailimap_set_free(set);
2222 struct fetch_content_param {
2225 const char * filename;
2229 struct fetch_content_result {
2233 static void fetch_content_run(struct etpan_thread_op * op)
2235 struct fetch_content_param * param;
2236 struct fetch_content_result * result;
2238 size_t content_size;
2244 result = op->result;
2250 if (param->with_body)
2251 r = imap_fetch(param->imap, param->msg_index,
2252 &content, &content_size);
2254 r = imap_fetch_header(param->imap, param->msg_index,
2255 &content, &content_size);
2259 if (r == MAILIMAP_NO_ERROR) {
2260 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
2262 result->error = MAILIMAP_ERROR_FETCH;
2266 f = fdopen(fd, "wb");
2268 result->error = MAILIMAP_ERROR_FETCH;
2272 r = fwrite(content, 1, content_size, f);
2279 g_unlink(param->filename);
2290 g_unlink(param->filename);
2293 if (mmap_string_unref(content) != 0)
2297 debug_print("imap fetch_content run - end %i\n", r);
2300 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2302 const char * filename)
2304 struct fetch_content_param param;
2305 struct fetch_content_result result;
2308 debug_print("imap fetch_content - begin\n");
2310 imap = get_imap(folder);
2312 param.msg_index = msg_index;
2313 param.filename = filename;
2314 param.with_body = with_body;
2316 threaded_run(folder, ¶m, &result, fetch_content_run);
2318 if (result.error != MAILIMAP_NO_ERROR)
2319 return result.error;
2321 debug_print("imap fetch_content - end\n");
2323 return result.error;
2328 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
2336 flag_list = att_dyn->att_list;
2337 if (flag_list == NULL)
2340 for(cur = clist_begin(flag_list) ; cur != NULL ;
2341 cur = clist_next(cur)) {
2342 struct mailimap_flag_fetch * flag_fetch;
2344 flag_fetch = clist_content(cur);
2345 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2348 switch (flag_fetch->fl_flag->fl_type) {
2349 case MAILIMAP_FLAG_ANSWERED:
2350 flags |= MSG_REPLIED;
2352 case MAILIMAP_FLAG_FLAGGED:
2353 flags |= MSG_MARKED;
2355 case MAILIMAP_FLAG_DELETED:
2356 flags |= MSG_DELETED;
2358 case MAILIMAP_FLAG_SEEN:
2359 flags &= ~MSG_UNREAD;
2369 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2373 struct mailimap_msg_att_dynamic ** patt_dyn)
2375 clistiter * item_cur;
2379 struct mailimap_msg_att_dynamic * att_dyn;
2386 for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
2387 item_cur = clist_next(item_cur)) {
2388 struct mailimap_msg_att_item * item;
2390 item = clist_content(item_cur);
2392 switch (item->att_type) {
2393 case MAILIMAP_MSG_ATT_ITEM_STATIC:
2394 switch (item->att_data.att_static->att_type) {
2395 case MAILIMAP_MSG_ATT_UID:
2396 uid = item->att_data.att_static->att_data.att_uid;
2399 case MAILIMAP_MSG_ATT_BODY_SECTION:
2400 if (headers == NULL) {
2401 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2404 case MAILIMAP_MSG_ATT_RFC822_SIZE:
2405 ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2410 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2411 if (att_dyn == NULL) {
2412 att_dyn = item->att_data.att_dyn;
2420 if (pheaders != NULL)
2421 * pheaders = headers;
2422 if (pref_size != NULL)
2423 * pref_size = ref_size;
2424 if (patt_dyn != NULL)
2425 * patt_dyn = att_dyn;
2427 return MAIL_NO_ERROR;
2430 static struct imap_fetch_env_info *
2431 fetch_to_env_info(struct mailimap_msg_att * msg_att)
2433 struct imap_fetch_env_info * info;
2437 struct mailimap_msg_att_dynamic * att_dyn;
2439 imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2444 info = malloc(sizeof(* info));
2446 info->headers = strdup(headers);
2448 info->flags = imap_flags_to_flags(att_dyn);
2454 imap_fetch_result_to_envelop_list(clist * fetch_result,
2455 carray ** p_env_list)
2462 env_list = carray_new(16);
2464 for(cur = clist_begin(fetch_result) ; cur != NULL ;
2465 cur = clist_next(cur)) {
2466 struct mailimap_msg_att * msg_att;
2467 struct imap_fetch_env_info * env_info;
2469 msg_att = clist_content(cur);
2471 env_info = fetch_to_env_info(msg_att);
2473 return MAILIMAP_ERROR_MEMORY;
2474 carray_add(env_list, env_info, NULL);
2477 * p_env_list = env_list;
2479 return MAIL_NO_ERROR;
2482 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2484 struct mailimap_fetch_att * fetch_att;
2488 struct mailimap_header_list * imap_hdrlist;
2489 struct mailimap_section * section;
2491 hdrlist = clist_new();
2493 header = strdup("Date");
2494 r = clist_append(hdrlist, header);
2495 header = strdup("From");
2496 r = clist_append(hdrlist, header);
2497 header = strdup("To");
2498 r = clist_append(hdrlist, header);
2499 header = strdup("Cc");
2500 r = clist_append(hdrlist, header);
2501 header = strdup("Subject");
2502 r = clist_append(hdrlist, header);
2503 header = strdup("Message-ID");
2504 r = clist_append(hdrlist, header);
2505 header = strdup("References");
2506 r = clist_append(hdrlist, header);
2507 header = strdup("In-Reply-To");
2508 r = clist_append(hdrlist, header);
2510 imap_hdrlist = mailimap_header_list_new(hdrlist);
2511 section = mailimap_section_new_header_fields(imap_hdrlist);
2512 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2513 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2515 return MAIL_NO_ERROR;
2518 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2520 struct mailimap_fetch_att * fetch_att;
2521 struct mailimap_section * section;
2523 section = mailimap_section_new_header();
2524 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2525 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2527 return MAIL_NO_ERROR;
2531 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2532 carray ** p_env_list)
2534 struct mailimap_fetch_att * fetch_att;
2535 struct mailimap_fetch_type * fetch_type;
2537 clist * fetch_result;
2539 carray * env_list = NULL;
2543 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2546 fetch_att = mailimap_fetch_att_new_uid();
2547 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2550 fetch_att = mailimap_fetch_att_new_flags();
2551 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2554 fetch_att = mailimap_fetch_att_new_rfc822_size();
2555 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2559 key.len = sizeof(imap);
2560 r = chash_get(courier_workaround_hash, &key, &value);
2562 r = imap_add_envelope_fetch_att(fetch_type);
2564 r = imap_add_header_fetch_att(fetch_type);
2566 mailstream_logger = imap_logger_fetch;
2568 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2570 mailstream_logger = imap_logger_cmd;
2572 case MAILIMAP_NO_ERROR:
2575 mailimap_fetch_type_free(fetch_type);
2576 debug_print("uid_fetch: %d\n", r);
2580 if (clist_begin(fetch_result) == NULL) {
2581 res = MAILIMAP_ERROR_FETCH;
2582 debug_print("clist_begin = NULL\n");
2586 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2587 mailimap_fetch_list_free(fetch_result);
2589 if (r != MAILIMAP_NO_ERROR) {
2590 mailimap_fetch_type_free(fetch_type);
2591 res = MAILIMAP_ERROR_MEMORY;
2592 debug_print("fetch_result_to_envelop_list: %d\n", res);
2596 mailimap_fetch_type_free(fetch_type);
2598 * p_env_list = env_list;
2600 return MAILIMAP_NO_ERROR;
2606 struct fetch_env_param {
2608 struct mailimap_set * set;
2611 struct fetch_env_result {
2612 carray * fetch_env_result;
2616 static void fetch_env_run(struct etpan_thread_op * op)
2618 struct fetch_env_param * param;
2619 struct fetch_env_result * result;
2624 result = op->result;
2629 r = imap_get_envelopes_list(param->imap, param->set,
2633 result->fetch_env_result = env_list;
2635 debug_print("imap fetch_env run - end %i\n", r);
2638 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
2639 carray ** p_env_list)
2641 struct fetch_env_param param;
2642 struct fetch_env_result result;
2645 debug_print("imap fetch_env - begin\n");
2647 imap = get_imap(folder);
2651 threaded_run(folder, ¶m, &result, fetch_env_run);
2653 if (result.error != MAILIMAP_NO_ERROR) {
2659 key.len = sizeof(imap);
2660 r = chash_get(courier_workaround_hash, &key, &value);
2664 chash_set(courier_workaround_hash, &key, &value, NULL);
2666 threaded_run(folder, ¶m, &result, fetch_env_run);
2670 if (result.error != MAILIMAP_NO_ERROR)
2671 return result.error;
2673 debug_print("imap fetch_env - end\n");
2675 * p_env_list = result.fetch_env_result;
2677 return result.error;
2680 void imap_fetch_env_free(carray * env_list)
2684 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2685 struct imap_fetch_env_info * env_info;
2687 env_info = carray_get(env_list, i);
2688 free(env_info->headers);
2691 carray_free(env_list);
2698 struct append_param {
2700 const char * mailbox;
2701 const char * filename;
2702 struct mailimap_flag_list * flag_list;
2705 struct append_result {
2710 static void append_run(struct etpan_thread_op * op)
2712 struct append_param * param;
2713 struct append_result * result;
2717 struct stat stat_buf;
2719 guint32 uid = 0, val = 0;
2722 result = op->result;
2726 r = stat(param->filename, &stat_buf);
2728 result->error = MAILIMAP_ERROR_APPEND;
2731 size = stat_buf.st_size;
2733 fd = open(param->filename, O_RDONLY);
2735 result->error = MAILIMAP_ERROR_APPEND;
2739 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2740 if (data == (void *) MAP_FAILED) {
2742 result->error = MAILIMAP_ERROR_APPEND;
2746 mailstream_logger = imap_logger_append;
2748 r = mailimap_uidplus_append(param->imap, param->mailbox,
2749 param->flag_list, NULL,
2750 data, size, &val, &uid);
2752 mailstream_logger = imap_logger_cmd;
2759 debug_print("imap append run - end %i uid %d\n", r, uid);
2762 int imap_threaded_append(Folder * folder, const char * mailbox,
2763 const char * filename,
2764 struct mailimap_flag_list * flag_list,
2767 struct append_param param;
2768 struct append_result result;
2771 debug_print("imap append - begin\n");
2773 imap = get_imap(folder);
2775 param.mailbox = mailbox;
2776 param.filename = filename;
2777 param.flag_list = flag_list;
2779 threaded_run(folder, ¶m, &result, append_run);
2781 if (result.error != MAILIMAP_NO_ERROR)
2782 return result.error;
2784 debug_print("imap append - end\n");
2788 return result.error;
2794 struct expunge_param {
2798 struct expunge_result {
2802 static void expunge_run(struct etpan_thread_op * op)
2804 struct expunge_param * param;
2805 struct expunge_result * result;
2809 result = op->result;
2813 r = mailimap_expunge(param->imap);
2816 debug_print("imap expunge run - end %i\n", r);
2819 int imap_threaded_expunge(Folder * folder)
2821 struct expunge_param param;
2822 struct expunge_result result;
2824 debug_print("imap expunge - begin\n");
2826 param.imap = get_imap(folder);
2828 threaded_run(folder, ¶m, &result, expunge_run);
2830 debug_print("imap expunge - end\n");
2832 return result.error;
2838 struct mailimap_set * set;
2842 struct copy_result {
2844 struct mailimap_set *source;
2845 struct mailimap_set *dest;
2848 static void copy_run(struct etpan_thread_op * op)
2850 struct copy_param * param;
2851 struct copy_result * result;
2854 struct mailimap_set *source = NULL, *dest = NULL;
2857 result = op->result;
2861 r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
2862 &val, &source, &dest);
2866 result->source = source;
2867 result->dest = dest;
2869 result->source = NULL;
2870 result->dest = NULL;
2872 debug_print("imap copy run - end %i\n", r);
2875 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
2876 const char * mb, struct mailimap_set **source,
2877 struct mailimap_set **dest)
2879 struct copy_param param;
2880 struct copy_result result;
2883 debug_print("imap copy - begin\n");
2885 imap = get_imap(folder);
2890 threaded_run(folder, ¶m, &result, copy_run);
2894 if (result.error != MAILIMAP_NO_ERROR)
2895 return result.error;
2897 *source = result.source;
2898 *dest = result.dest;
2900 debug_print("imap copy - end\n");
2902 return result.error;
2907 struct store_param {
2909 struct mailimap_set * set;
2910 struct mailimap_store_att_flags * store_att_flags;
2913 struct store_result {
2917 static void store_run(struct etpan_thread_op * op)
2919 struct store_param * param;
2920 struct store_result * result;
2924 result = op->result;
2928 r = mailimap_uid_store(param->imap, param->set,
2929 param->store_att_flags);
2933 debug_print("imap store run - end %i\n", r);
2936 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
2937 struct mailimap_store_att_flags * store_att_flags)
2939 struct store_param param;
2940 struct store_result result;
2943 debug_print("imap store - begin\n");
2945 imap = get_imap(folder);
2948 param.store_att_flags = store_att_flags;
2950 threaded_run(folder, ¶m, &result, store_run);
2952 if (result.error != MAILIMAP_NO_ERROR)
2953 return result.error;
2955 debug_print("imap store - end\n");
2957 return result.error;
2961 #define ENV_BUFFER_SIZE 512
2963 static void do_exec_command(int fd, const char * command,
2964 const char * servername, uint16_t port)
2968 char env_buffer[ENV_BUFFER_SIZE];
2972 /* Fork again to become a child of init rather than
2973 the etpan client. */
2979 snprintf(env_buffer, ENV_BUFFER_SIZE,
2980 "ETPANSERVER=%s", servername);
2982 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANSERVER=");
2986 setenv("ETPANSERVER", servername, 1);
2988 unsetenv("ETPANSERVER");
2993 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=%d", port);
2995 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=");
3001 snprintf(porttext, sizeof(porttext), "%d", port);
3002 setenv("ETPANPORT", porttext, 1);
3005 unsetenv("ETPANPORT");
3009 /* Not a lot we can do if there's an error other than bail. */
3010 if (dup2(fd, 0) == -1)
3012 if (dup2(fd, 1) == -1)
3015 /* Should we close stderr and reopen /dev/null? */
3017 maxopen = sysconf(_SC_OPEN_MAX);
3018 for (i=3; i < maxopen; i++)
3022 /* Detach from the controlling tty if we have one. Otherwise,
3023 SSH might do something stupid like trying to use it instead
3024 of running $SSH_ASKPASS. Doh. */
3025 fd = open("/dev/tty", O_RDONLY);
3027 ioctl(fd, TIOCNOTTY, NULL);
3030 #endif /* TIOCNOTTY */
3032 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
3034 /* Eep. Shouldn't reach this */
3038 static int subcommand_connect(const char *command,
3039 const char *servername, uint16_t port)
3041 /* SEB unsupported on Windows */
3045 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
3050 do_exec_command(sockfds[1], command, servername, port);
3052 else if (childpid == -1) {
3060 /* Reap child, leaving grandchild process to run */
3061 waitpid(childpid, NULL, 0);
3066 static int socket_connect_cmd(mailimap * imap, const char * command,
3067 const char * server, int port)
3073 fd = subcommand_connect(command, server, port);
3075 return MAILIMAP_ERROR_STREAM;
3077 s = mailstream_socket_open(fd);
3080 return MAILIMAP_ERROR_STREAM;
3083 r = mailimap_connect(imap, s);
3084 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
3085 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
3086 mailstream_close(s);
3088 imap->imap_stream = NULL;
3097 struct connect_cmd_param {
3099 const char * command;
3100 const char * server;
3104 struct connect_cmd_result {
3108 static void connect_cmd_run(struct etpan_thread_op * op)
3111 struct connect_cmd_param * param;
3112 struct connect_cmd_result * result;
3115 result = op->result;
3119 r = socket_connect_cmd(param->imap, param->command,
3120 param->server, param->port);
3126 int imap_threaded_connect_cmd(Folder * folder, const char * command,
3127 const char * server, int port)
3129 struct connect_cmd_param param;
3130 struct connect_cmd_result result;
3133 mailimap * imap, * oldimap;
3135 oldimap = get_imap(folder);
3137 imap = mailimap_new(0, NULL);
3140 debug_print("deleting old imap %p\n", oldimap);
3141 delete_imap(folder, oldimap);
3145 key.len = sizeof(folder);
3148 chash_set(session_hash, &key, &value, NULL);
3151 param.command = command;
3152 param.server = server;
3155 threaded_run(folder, ¶m, &result, connect_cmd_run);
3157 debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
3159 return result.error;
3162 void imap_threaded_cancel(Folder * folder)
3166 imap = get_imap(folder);
3167 if (imap->imap_stream != NULL)
3168 mailstream_cancel(imap->imap_stream);
3173 void imap_main_init(void)
3176 void imap_main_done(void)
3179 void imap_main_set_timeout(int sec)
3183 void imap_threaded_cancel(Folder * folder);