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 2 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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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"
45 #define DISABLE_LOG_DURING_LOGIN
47 static struct etpan_thread_manager * thread_manager = NULL;
48 static chash * courier_workaround_hash = NULL;
49 static chash * imap_hash = NULL;
50 static chash * session_hash = NULL;
51 static guint thread_manager_signal = 0;
52 static GIOChannel * io_channel = NULL;
54 static void delete_imap(Folder *folder, mailimap *imap)
60 key.len = sizeof(folder);
63 chash_delete(session_hash, &key, NULL);
66 key.len = sizeof(imap);
67 chash_delete(courier_workaround_hash, &key, NULL);
68 if (imap->imap_stream) {
69 /* we don't want libetpan to logout */
70 mailstream_close(imap->imap_stream);
71 imap->imap_stream = NULL;
73 debug_print("removing mailimap %p\n", imap);
77 static gboolean thread_manager_event(GIOChannel * source,
78 GIOCondition condition,
81 etpan_thread_manager_loop(thread_manager);
86 static void imap_logger_cmd(int direction, const char * str, size_t size)
93 log_print(LOG_PROTOCOL, "IMAP4%c [CMD data - %zd bytes]\n", direction?'>':'<', size);
97 memset(buf, 0, size+1);
98 strncpy(buf, str, size);
101 if (!strncmp(buf, "<<<<<<<", 7)
102 || !strncmp(buf, ">>>>>>>", 7)) {
106 while (strstr(buf, "\r"))
107 *strstr(buf, "\r") = ' ';
108 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
109 buf[strlen(buf)-1] = '\0';
111 lines = g_strsplit(buf, "\n", -1);
113 while (lines[i] && *lines[i]) {
114 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
121 static void imap_logger_fetch(int direction, const char * str, size_t size)
128 log_print(LOG_PROTOCOL, "IMAP4%c [FETCH data - %zd bytes]\n", direction?'>':'<', size);
132 buf = malloc(size+1);
133 memset(buf, 0, size+1);
134 strncpy(buf, str, size);
136 if (!strncmp(buf, "<<<<<<<", 7)
137 || !strncmp(buf, ">>>>>>>", 7)) {
141 while (strstr(buf, "\r"))
142 *strstr(buf, "\r") = ' ';
143 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
144 buf[strlen(buf)-1] = '\0';
146 lines = g_strsplit(buf, "\n", -1);
148 if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) {
149 while (lines[i] && *lines[i]) {
150 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
154 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
160 static void imap_logger_uid(int direction, const char * str, size_t size)
167 log_print(LOG_PROTOCOL, "IMAP4%c [UID data - %zd bytes]\n", direction?'>':'<', size);
170 buf = malloc(size+1);
171 memset(buf, 0, size+1);
172 strncpy(buf, str, size);
174 if (!strncmp(buf, "<<<<<<<", 7)
175 || !strncmp(buf, ">>>>>>>", 7)) {
179 while (strstr(buf, "\r"))
180 *strstr(buf, "\r") = ' ';
181 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
182 buf[strlen(buf)-1] = '\0';
184 lines = g_strsplit(buf, "\n", -1);
186 while (lines[i] && *lines[i]) {
187 int llen = strlen(lines[i]);
189 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
192 strncpy2(tmp, lines[i], 63);
193 log_print(LOG_PROTOCOL, "IMAP4%c %s[... - %zd bytes more]\n", direction?'>':'<', tmp,
202 static void imap_logger_append(int direction, const char * str, size_t size)
209 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
211 } else if (direction == 0 && size > 64) {
212 log_print(LOG_PROTOCOL, "IMAP4%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
215 buf = malloc(size+1);
216 memset(buf, 0, size+1);
217 strncpy(buf, str, size);
219 if (!strncmp(buf, "<<<<<<<", 7)
220 || !strncmp(buf, ">>>>>>>", 7)) {
224 while (strstr(buf, "\r"))
225 *strstr(buf, "\r") = ' ';
226 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
227 buf[strlen(buf)-1] = '\0';
229 lines = g_strsplit(buf, "\n", -1);
231 if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
232 while (lines[i] && *lines[i]) {
233 log_print(LOG_PROTOCOL, "IMAP4%c %s\n", direction?'>':'<', lines[i]);
237 log_print(LOG_PROTOCOL, "IMAP4%c [data - %zd bytes]\n", direction?'>':'<', size);
243 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
244 static gboolean etpan_skip_ssl_cert_check = FALSE;
245 extern void mailsasl_ref(void);
247 void imap_main_init(gboolean skip_ssl_cert_check)
249 int fd_thread_manager;
251 etpan_skip_ssl_cert_check = skip_ssl_cert_check;
252 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
253 mailstream_network_delay.tv_usec = 0;
255 mailstream_debug = 1;
256 mailstream_logger = imap_logger_cmd;
259 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
260 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
261 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
263 thread_manager = etpan_thread_manager_new();
265 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
267 io_channel = g_io_channel_unix_new(fd_thread_manager);
269 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
270 thread_manager_event,
275 void imap_main_set_timeout(int sec)
277 mailstream_network_delay.tv_sec = sec;
278 mailstream_network_delay.tv_usec = 0;
281 void imap_main_done(void)
283 etpan_thread_manager_stop(thread_manager);
284 etpan_thread_manager_join(thread_manager);
286 g_source_remove(thread_manager_signal);
287 g_io_channel_unref(io_channel);
289 etpan_thread_manager_free(thread_manager);
291 chash_free(courier_workaround_hash);
292 chash_free(session_hash);
293 chash_free(imap_hash);
296 void imap_init(Folder * folder)
298 struct etpan_thread * thread;
302 thread = etpan_thread_manager_get_thread(thread_manager);
305 key.len = sizeof(folder);
309 chash_set(imap_hash, &key, &value, NULL);
312 void imap_done(Folder * folder)
314 struct etpan_thread * thread;
320 key.len = sizeof(folder);
322 r = chash_get(imap_hash, &key, &value);
328 etpan_thread_unbind(thread);
330 chash_delete(imap_hash, &key, NULL);
332 debug_print("remove thread");
335 static struct etpan_thread * get_thread(Folder * folder)
337 struct etpan_thread * thread;
342 key.len = sizeof(folder);
344 chash_get(imap_hash, &key, &value);
350 static mailimap * get_imap(Folder * folder)
358 key.len = sizeof(folder);
360 r = chash_get(session_hash, &key, &value);
365 debug_print("found imap %p\n", imap);
370 static void generic_cb(int cancelled, void * result, void * callback_data)
372 struct etpan_thread_op * op;
374 op = (struct etpan_thread_op *) callback_data;
376 debug_print("generic_cb\n");
377 if (op->imap && op->imap->imap_response_info &&
378 op->imap->imap_response_info->rsp_alert) {
379 log_error(LOG_PROTOCOL, "IMAP4< Alert: %s\n",
380 op->imap->imap_response_info->rsp_alert);
381 mainwindow_show_error();
386 static void threaded_run(Folder * folder, void * param, void * result,
387 void (* func)(struct etpan_thread_op * ))
389 struct etpan_thread_op * op;
390 struct etpan_thread * thread;
392 imap_folder_ref(folder);
394 op = etpan_thread_op_new();
396 op->imap = get_imap(folder);
402 op->callback = generic_cb;
403 op->callback_data = op;
408 thread = get_thread(folder);
409 etpan_thread_op_schedule(thread, op);
411 while (!op->finished) {
412 gtk_main_iteration();
415 etpan_thread_op_free(op);
417 imap_folder_unref(folder);
423 struct connect_param {
429 struct connect_result {
433 #define CHECK_IMAP() { \
434 if (!param->imap) { \
435 result->error = MAILIMAP_ERROR_BAD_STATE; \
440 static void connect_run(struct etpan_thread_op * op)
443 struct connect_param * param;
444 struct connect_result * result;
451 r = mailimap_socket_connect(param->imap,
452 param->server, param->port);
458 int imap_threaded_connect(Folder * folder, const char * server, int port)
460 struct connect_param param;
461 struct connect_result result;
464 mailimap * imap, * oldimap;
466 oldimap = get_imap(folder);
468 imap = mailimap_new(0, NULL);
471 debug_print("deleting old imap %p\n", oldimap);
472 delete_imap(folder, oldimap);
476 key.len = sizeof(folder);
479 chash_set(session_hash, &key, &value, NULL);
482 param.server = server;
486 threaded_run(folder, ¶m, &result, connect_run);
488 debug_print("connect ok %i with imap %p\n", result.error, imap);
493 static int etpan_certificate_check(const unsigned char *certificate, int len, void *data)
496 struct connect_param *param = (struct connect_param *)data;
499 if (certificate == NULL || len < 0) {
500 g_warning("no cert presented.\n");
503 cert = d2i_X509(NULL, &certificate, len);
505 g_warning("can't get cert\n");
507 } else if (ssl_certificate_check(cert, NULL,
508 (gchar *)param->server, (gushort)param->port) == TRUE) {
520 static void connect_ssl_run(struct etpan_thread_op * op)
523 struct connect_param * param;
524 struct connect_result * result;
531 r = mailimap_ssl_connect(param->imap,
532 param->server, param->port);
536 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
538 struct connect_param param;
539 struct connect_result result;
542 mailimap * imap, * oldimap;
543 unsigned char *certificate = NULL;
546 oldimap = get_imap(folder);
548 imap = mailimap_new(0, NULL);
551 debug_print("deleting old imap %p\n", oldimap);
552 delete_imap(folder, oldimap);
556 key.len = sizeof(folder);
559 chash_set(session_hash, &key, &value, NULL);
562 param.server = server;
566 threaded_run(folder, ¶m, &result, connect_ssl_run);
568 if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
569 result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
570 cert_len = (int)mailstream_ssl_get_certificate(imap->imap_stream, &certificate);
571 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
576 debug_print("connect %d with imap %p\n", result.error, imap);
587 struct mailimap_capability_data *caps;
590 static void capability_run(struct etpan_thread_op * op)
593 struct capa_param * param;
594 struct capa_result * result;
595 struct mailimap_capability_data *caps;
602 r = mailimap_capability(param->imap, &caps);
605 result->caps = (r == 0 ? caps : NULL);
609 struct mailimap_capability_data * imap_threaded_capability(Folder *folder, int *ok)
611 struct capa_param param;
612 struct capa_result result;
615 imap = get_imap(folder);
619 threaded_run(folder, ¶m, &result, capability_run);
621 debug_print("capa %d\n", result.error);
630 struct disconnect_param {
634 struct disconnect_result {
638 static void disconnect_run(struct etpan_thread_op * op)
641 struct disconnect_param * param;
642 struct disconnect_result * result;
649 r = mailimap_logout(param->imap);
654 void imap_threaded_disconnect(Folder * folder)
656 struct connect_param param;
657 struct connect_result result;
660 imap = get_imap(folder);
662 debug_print("was disconnected\n");
668 threaded_run(folder, ¶m, &result, disconnect_run);
670 if (imap == get_imap(folder)) {
671 debug_print("deleting old imap %p\n", imap);
672 delete_imap(folder, imap);
674 debug_print("imap already deleted %p\n", imap);
677 debug_print("disconnect ok\n");
684 const char * wildcard;
693 static void list_run(struct etpan_thread_op * op)
695 struct list_param * param;
696 struct list_result * result;
707 if (param->base == NULL || param->wildcard == NULL) {
710 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
714 r = mailimap_lsub(param->imap, param->base,
715 param->wildcard, &list);
717 r = mailimap_list(param->imap, param->base,
718 param->wildcard, &list);
721 debug_print("imap list run - end\n");
724 int imap_threaded_list(Folder * folder, const char * base,
725 const char * wildcard,
728 struct list_param param;
729 struct list_result result;
731 debug_print("imap list - begin\n");
733 param.imap = get_imap(folder);
735 param.wildcard = wildcard;
736 param.sub_only = FALSE;
738 threaded_run(folder, ¶m, &result, list_run);
740 * p_result = result.list;
742 debug_print("imap list - end %p\n", result.list);
747 int imap_threaded_lsub(Folder * folder, const char * base,
748 const char * wildcard,
751 struct list_param param;
752 struct list_result result;
754 debug_print("imap lsub - begin\n");
756 param.imap = get_imap(folder);
758 param.wildcard = wildcard;
759 param.sub_only = TRUE;
761 threaded_run(folder, ¶m, &result, list_run);
763 * p_result = result.list;
765 debug_print("imap lsub - end %p\n", result.list);
770 struct subscribe_param {
776 struct subscribe_result {
780 static void subscribe_run(struct etpan_thread_op * op)
782 struct subscribe_param * param;
783 struct subscribe_result * result;
791 if (param->mb == NULL) {
793 debug_print("no mb\n");
796 if (param->subscribe)
797 r = mailimap_subscribe(param->imap, param->mb);
799 r = mailimap_unsubscribe(param->imap, param->mb);
801 debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
804 int imap_threaded_subscribe(Folder * folder, const char * mb,
807 struct subscribe_param param;
808 struct subscribe_result result;
810 debug_print("imap list - begin\n");
812 param.imap = get_imap(folder);
814 param.subscribe = subscribe;
816 threaded_run(folder, ¶m, &result, subscribe_run);
824 const char * password;
829 struct login_result {
833 static void login_run(struct etpan_thread_op * op)
835 struct login_param * param;
836 struct login_result * result;
838 #ifdef DISABLE_LOG_DURING_LOGIN
847 #ifdef DISABLE_LOG_DURING_LOGIN
848 old_debug = mailstream_debug;
849 mailstream_debug = 0;
851 if (!strcmp(param->type, "LOGIN"))
852 r = mailimap_login(param->imap,
853 param->login, param->password);
854 else if (!strcmp(param->type, "GSSAPI"))
855 r = mailimap_authenticate(param->imap,
856 param->type, param->server, NULL, NULL,
857 param->login, param->login,
858 param->password, NULL);
860 r = mailimap_authenticate(param->imap,
861 param->type, NULL, NULL, NULL,
862 param->login, param->login,
863 param->password, NULL);
864 #ifdef DISABLE_LOG_DURING_LOGIN
865 mailstream_debug = old_debug;
869 debug_print("imap login run - end %i\n", r);
872 int imap_threaded_login(Folder * folder,
873 const char * login, const char * password,
876 struct login_param param;
877 struct login_result result;
879 debug_print("imap login - begin\n");
881 param.imap = get_imap(folder);
883 param.password = password;
885 if (folder && folder->account)
886 param.server = folder->account->recv_server;
890 threaded_run(folder, ¶m, &result, login_run);
892 debug_print("imap login - end\n");
898 struct status_param {
901 struct mailimap_status_att_list * status_att_list;
904 struct status_result {
906 struct mailimap_mailbox_data_status * data_status;
909 static void status_run(struct etpan_thread_op * op)
911 struct status_param * param;
912 struct status_result * result;
920 r = mailimap_status(param->imap, param->mb,
921 param->status_att_list,
922 &result->data_status);
925 debug_print("imap status run - end %i\n", r);
928 int imap_threaded_status(Folder * folder, const char * mb,
929 struct mailimap_mailbox_data_status ** data_status,
932 struct status_param param;
933 struct status_result result;
934 struct mailimap_status_att_list * status_att_list;
936 debug_print("imap status - begin\n");
938 status_att_list = mailimap_status_att_list_new_empty();
940 mailimap_status_att_list_add(status_att_list,
941 MAILIMAP_STATUS_ATT_MESSAGES);
944 mailimap_status_att_list_add(status_att_list,
945 MAILIMAP_STATUS_ATT_RECENT);
948 mailimap_status_att_list_add(status_att_list,
949 MAILIMAP_STATUS_ATT_UIDNEXT);
952 mailimap_status_att_list_add(status_att_list,
953 MAILIMAP_STATUS_ATT_UIDVALIDITY);
956 mailimap_status_att_list_add(status_att_list,
957 MAILIMAP_STATUS_ATT_UNSEEN);
959 param.imap = get_imap(folder);
961 param.status_att_list = status_att_list;
963 threaded_run(folder, ¶m, &result, status_run);
965 debug_print("imap status - end\n");
967 * data_status = result.data_status;
969 mailimap_status_att_list_free(status_att_list);
984 static void noop_run(struct etpan_thread_op * op)
986 struct noop_param * param;
987 struct noop_result * result;
995 r = mailimap_noop(param->imap);
998 debug_print("imap noop run - end %i\n", r);
1001 int imap_threaded_noop(Folder * folder, unsigned int * p_exists)
1003 struct noop_param param;
1004 struct noop_result result;
1007 debug_print("imap noop - begin\n");
1009 imap = get_imap(folder);
1012 threaded_run(folder, ¶m, &result, noop_run);
1014 if (imap->imap_selection_info != NULL) {
1015 * p_exists = imap->imap_selection_info->sel_exists;
1021 debug_print("imap noop - end\n");
1023 return result.error;
1027 struct starttls_result {
1031 static void starttls_run(struct etpan_thread_op * op)
1033 struct connect_param * param;
1034 struct starttls_result * result;
1038 result = op->result;
1042 r = mailimap_starttls(param->imap);
1045 debug_print("imap starttls run - end %i\n", r);
1048 mailimap *imap = param->imap;
1049 mailstream_low *plain_low = NULL;
1050 mailstream_low *tls_low = NULL;
1053 plain_low = mailstream_get_low(imap->imap_stream);
1054 fd = mailstream_low_get_fd(plain_low);
1056 debug_print("imap starttls run - can't get fd\n");
1057 result->error = MAILIMAP_ERROR_STREAM;
1061 tls_low = mailstream_low_tls_open(fd);
1062 if (tls_low == NULL) {
1063 debug_print("imap starttls run - can't tls_open\n");
1064 result->error = MAILIMAP_ERROR_STREAM;
1067 mailstream_low_free(plain_low);
1068 mailstream_set_low(imap->imap_stream, tls_low);
1072 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1074 struct connect_param param;
1075 struct starttls_result result;
1077 unsigned char *certificate;
1079 debug_print("imap starttls - begin\n");
1081 param.imap = get_imap(folder);
1082 param.server = host;
1085 threaded_run(folder, ¶m, &result, starttls_run);
1087 debug_print("imap starttls - end\n");
1089 if (result.error == 0 && !etpan_skip_ssl_cert_check) {
1090 cert_len = (int)mailstream_ssl_get_certificate(param.imap->imap_stream, &certificate);
1091 if (etpan_certificate_check(certificate, cert_len, ¶m) < 0)
1092 result.error = MAILIMAP_ERROR_STREAM;
1096 return result.error;
1101 struct create_param {
1106 struct create_result {
1110 static void create_run(struct etpan_thread_op * op)
1112 struct create_param * param;
1113 struct create_result * result;
1117 result = op->result;
1121 r = mailimap_create(param->imap, param->mb);
1124 debug_print("imap create run - end %i\n", r);
1127 int imap_threaded_create(Folder * folder, const char * mb)
1129 struct create_param param;
1130 struct create_result result;
1132 debug_print("imap create - begin\n");
1134 param.imap = get_imap(folder);
1137 threaded_run(folder, ¶m, &result, create_run);
1139 debug_print("imap create - end\n");
1141 return result.error;
1147 struct rename_param {
1150 const char * new_name;
1153 struct rename_result {
1157 static void rename_run(struct etpan_thread_op * op)
1159 struct rename_param * param;
1160 struct rename_result * result;
1164 result = op->result;
1168 r = mailimap_rename(param->imap, param->mb, param->new_name);
1171 debug_print("imap rename run - end %i\n", r);
1174 int imap_threaded_rename(Folder * folder,
1175 const char * mb, const char * new_name)
1177 struct rename_param param;
1178 struct rename_result result;
1180 debug_print("imap rename - begin\n");
1182 param.imap = get_imap(folder);
1184 param.new_name = new_name;
1186 threaded_run(folder, ¶m, &result, rename_run);
1188 debug_print("imap rename - end\n");
1190 return result.error;
1196 struct delete_param {
1201 struct delete_result {
1205 static void delete_run(struct etpan_thread_op * op)
1207 struct delete_param * param;
1208 struct delete_result * result;
1212 result = op->result;
1216 r = mailimap_delete(param->imap, param->mb);
1219 debug_print("imap delete run - end %i\n", r);
1222 int imap_threaded_delete(Folder * folder, const char * mb)
1224 struct delete_param param;
1225 struct delete_result result;
1227 debug_print("imap delete - begin\n");
1229 param.imap = get_imap(folder);
1232 threaded_run(folder, ¶m, &result, delete_run);
1234 debug_print("imap delete - end\n");
1236 return result.error;
1241 struct select_param {
1246 struct select_result {
1250 static void select_run(struct etpan_thread_op * op)
1252 struct select_param * param;
1253 struct select_result * result;
1257 result = op->result;
1261 r = mailimap_select(param->imap, param->mb);
1264 debug_print("imap select run - end %i\n", r);
1267 int imap_threaded_select(Folder * folder, const char * mb,
1268 gint * exists, gint * recent, gint * unseen,
1269 guint32 * uid_validity)
1271 struct select_param param;
1272 struct select_result result;
1275 debug_print("imap select - begin\n");
1277 imap = get_imap(folder);
1281 threaded_run(folder, ¶m, &result, select_run);
1283 if (result.error != MAILIMAP_NO_ERROR)
1284 return result.error;
1286 if (imap->imap_selection_info == NULL)
1287 return MAILIMAP_ERROR_PARSE;
1289 * exists = imap->imap_selection_info->sel_exists;
1290 * recent = imap->imap_selection_info->sel_recent;
1291 * unseen = imap->imap_selection_info->sel_unseen;
1292 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1294 debug_print("imap select - end\n");
1296 return result.error;
1301 struct examine_param {
1306 struct examine_result {
1310 static void examine_run(struct etpan_thread_op * op)
1312 struct examine_param * param;
1313 struct examine_result * result;
1317 result = op->result;
1321 r = mailimap_examine(param->imap, param->mb);
1324 debug_print("imap examine run - end %i\n", r);
1327 int imap_threaded_examine(Folder * folder, const char * mb,
1328 gint * exists, gint * recent, gint * unseen,
1329 guint32 * uid_validity)
1331 struct examine_param param;
1332 struct examine_result result;
1335 debug_print("imap examine - begin\n");
1337 imap = get_imap(folder);
1341 threaded_run(folder, ¶m, &result, examine_run);
1343 if (result.error != MAILIMAP_NO_ERROR)
1344 return result.error;
1346 if (imap->imap_selection_info == NULL)
1347 return MAILIMAP_ERROR_PARSE;
1349 * exists = imap->imap_selection_info->sel_exists;
1350 * recent = imap->imap_selection_info->sel_recent;
1351 * unseen = imap->imap_selection_info->sel_unseen;
1352 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1354 debug_print("imap examine - end\n");
1356 return result.error;
1362 struct search_param {
1365 struct mailimap_set * set;
1368 struct search_result {
1370 clist * search_result;
1373 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1375 return mailimap_set_item_new(orig->set_first, orig->set_last);
1378 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1380 clist *list = orig ? orig->set_list : NULL;
1381 clist *newlist = clist_new();
1386 for (cur = clist_begin(list); cur; cur = clist_next(cur))
1387 clist_append(newlist,
1388 sc_mailimap_set_item_copy(
1389 (struct mailimap_set_item *)clist_content(cur)));
1390 return mailimap_set_new(newlist);
1393 static void search_run(struct etpan_thread_op * op)
1395 struct search_param * param;
1396 struct search_result * result;
1398 struct mailimap_search_key * key = NULL;
1399 struct mailimap_search_key * uid_key = NULL;
1400 struct mailimap_search_key * search_type_key;
1401 clist * search_result;
1404 result = op->result;
1408 /* we copy the mailimap_set because freeing the key is recursive */
1409 if (param->set != NULL) {
1410 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1411 } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1412 uid_key = mailimap_search_key_new_all();
1414 search_type_key = NULL;
1415 switch (param->type) {
1416 case IMAP_SEARCH_TYPE_SIMPLE:
1417 search_type_key = NULL;
1420 case IMAP_SEARCH_TYPE_SEEN:
1421 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN,
1422 NULL, NULL, NULL, NULL, NULL,
1423 NULL, NULL, NULL, NULL, NULL,
1424 NULL, NULL, NULL, NULL, 0,
1425 NULL, NULL, NULL, NULL, NULL,
1426 NULL, 0, NULL, NULL, NULL);
1429 case IMAP_SEARCH_TYPE_UNSEEN:
1430 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
1431 NULL, NULL, NULL, NULL, NULL,
1432 NULL, NULL, NULL, NULL, NULL,
1433 NULL, NULL, NULL, NULL, 0,
1434 NULL, NULL, NULL, NULL, NULL,
1435 NULL, 0, NULL, NULL, NULL);
1438 case IMAP_SEARCH_TYPE_ANSWERED:
1439 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED,
1440 NULL, NULL, NULL, NULL, NULL,
1441 NULL, NULL, NULL, NULL, NULL,
1442 NULL, NULL, NULL, NULL, 0,
1443 NULL, NULL, NULL, NULL, NULL,
1444 NULL, 0, NULL, NULL, NULL);
1447 case IMAP_SEARCH_TYPE_FLAGGED:
1448 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED,
1449 NULL, NULL, NULL, NULL, NULL,
1450 NULL, NULL, NULL, NULL, NULL,
1451 NULL, NULL, NULL, NULL, 0,
1452 NULL, NULL, NULL, NULL, NULL,
1453 NULL, 0, NULL, NULL, NULL);
1455 case IMAP_SEARCH_TYPE_DELETED:
1456 search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_DELETED,
1457 NULL, NULL, NULL, NULL, NULL,
1458 NULL, NULL, NULL, NULL, NULL,
1459 NULL, NULL, NULL, NULL, 0,
1460 NULL, NULL, NULL, NULL, NULL,
1461 NULL, 0, NULL, NULL, NULL);
1465 if (search_type_key != NULL) {
1466 if (param->set != NULL) {
1467 key = mailimap_search_key_new_multiple_empty();
1468 mailimap_search_key_multiple_add(key, search_type_key);
1469 mailimap_search_key_multiple_add(key, uid_key);
1471 key = search_type_key;
1473 } else if (uid_key != NULL) {
1478 g_warning("no key!");
1479 result = op->result;
1481 result->search_result = NULL;
1483 mailstream_logger = imap_logger_uid;
1485 r = mailimap_uid_search(param->imap, NULL, key, &search_result);
1487 mailstream_logger = imap_logger_cmd;
1489 /* free the key (with the imapset) */
1490 mailimap_search_key_free(key);
1493 result->search_result = search_result;
1495 debug_print("imap search run - end %i\n", result->error);
1498 int imap_threaded_search(Folder * folder, int search_type,
1499 struct mailimap_set * set, clist ** search_result)
1501 struct search_param param;
1502 struct search_result result;
1505 debug_print("imap search - begin\n");
1507 imap = get_imap(folder);
1510 param.type = search_type;
1512 threaded_run(folder, ¶m, &result, search_run);
1514 if (result.error != MAILIMAP_NO_ERROR)
1515 return result.error;
1517 debug_print("imap search - end\n");
1519 * search_result = result.search_result;
1521 return result.error;
1528 uid_list_to_env_list(clist * fetch_result, carray ** result)
1536 tab = carray_new(128);
1538 res = MAILIMAP_ERROR_MEMORY;
1542 for(cur = clist_begin(fetch_result) ; cur != NULL ;
1543 cur = clist_next(cur)) {
1544 struct mailimap_msg_att * msg_att;
1545 clistiter * item_cur;
1550 msg_att = clist_content(cur);
1554 for(item_cur = clist_begin(msg_att->att_list) ;
1556 item_cur = clist_next(item_cur)) {
1557 struct mailimap_msg_att_item * item;
1559 item = clist_content(item_cur);
1561 switch (item->att_type) {
1562 case MAILIMAP_MSG_ATT_ITEM_STATIC:
1563 switch (item->att_data.att_static->att_type) {
1564 case MAILIMAP_MSG_ATT_UID:
1565 uid = item->att_data.att_static->att_data.att_uid;
1571 puid = malloc(sizeof(* puid));
1573 res = MAILIMAP_ERROR_MEMORY;
1578 r = carray_add(tab, puid, NULL);
1581 res = MAILIMAP_ERROR_MEMORY;
1588 return MAILIMAP_NO_ERROR;
1591 for(i = 0 ; i < carray_count(tab) ; i++)
1592 mailmessage_free(carray_get(tab, i));
1597 static int imap_get_messages_list(mailimap * imap,
1598 uint32_t first_index,
1603 struct mailimap_fetch_att * fetch_att;
1604 struct mailimap_fetch_type * fetch_type;
1605 struct mailimap_set * set;
1606 clist * fetch_result;
1609 set = mailimap_set_new_interval(first_index, 0);
1611 res = MAILIMAP_ERROR_MEMORY;
1615 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1616 if (fetch_type == NULL) {
1617 res = MAILIMAP_ERROR_MEMORY;
1621 fetch_att = mailimap_fetch_att_new_uid();
1622 if (fetch_att == NULL) {
1623 res = MAILIMAP_ERROR_MEMORY;
1624 goto free_fetch_type;
1627 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1628 if (r != MAILIMAP_NO_ERROR) {
1629 mailimap_fetch_att_free(fetch_att);
1630 res = MAILIMAP_ERROR_MEMORY;
1631 goto free_fetch_type;
1634 r = mailimap_uid_fetch(imap, set,
1635 fetch_type, &fetch_result);
1637 mailimap_fetch_type_free(fetch_type);
1638 mailimap_set_free(set);
1640 if (r != MAILIMAP_NO_ERROR) {
1646 r = uid_list_to_env_list(fetch_result, &env_list);
1647 mailimap_fetch_list_free(fetch_result);
1649 * result = env_list;
1651 return MAILIMAP_NO_ERROR;
1654 mailimap_fetch_type_free(fetch_type);
1656 mailimap_set_free(set);
1664 struct fetch_uid_param {
1666 uint32_t first_index;
1669 struct fetch_uid_result {
1671 carray * fetch_result;
1674 static void fetch_uid_run(struct etpan_thread_op * op)
1676 struct fetch_uid_param * param;
1677 struct fetch_uid_result * result;
1678 carray * fetch_result;
1682 result = op->result;
1686 fetch_result = NULL;
1687 r = imap_get_messages_list(param->imap, param->first_index,
1691 result->fetch_result = fetch_result;
1692 debug_print("imap fetch_uid run - end %i\n", r);
1695 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
1696 carray ** fetch_result)
1698 struct fetch_uid_param param;
1699 struct fetch_uid_result result;
1702 debug_print("imap fetch_uid - begin\n");
1704 imap = get_imap(folder);
1706 param.first_index = first_index;
1708 threaded_run(folder, ¶m, &result, fetch_uid_run);
1710 if (result.error != MAILIMAP_NO_ERROR)
1711 return result.error;
1713 debug_print("imap fetch_uid - end\n");
1715 * fetch_result = result.fetch_result;
1717 return result.error;
1721 void imap_fetch_uid_list_free(carray * uid_list)
1725 for(i = 0 ; i < carray_count(uid_list) ; i ++) {
1728 puid = carray_get(uid_list, i);
1731 carray_free(uid_list);
1736 static int imap_fetch(mailimap * imap,
1739 size_t * result_len)
1742 struct mailimap_set * set;
1743 struct mailimap_fetch_att * fetch_att;
1744 struct mailimap_fetch_type * fetch_type;
1745 clist * fetch_result;
1746 struct mailimap_msg_att * msg_att;
1747 struct mailimap_msg_att_item * msg_att_item;
1752 struct mailimap_section * section;
1754 set = mailimap_set_new_single(msg_index);
1756 res = MAILIMAP_ERROR_MEMORY;
1760 section = mailimap_section_new(NULL);
1761 if (section == NULL) {
1762 res = MAILIMAP_ERROR_MEMORY;
1766 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1767 if (fetch_att == NULL) {
1768 mailimap_section_free(section);
1769 res = MAILIMAP_ERROR_MEMORY;
1773 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1774 if (fetch_type == NULL) {
1775 res = MAILIMAP_ERROR_MEMORY;
1776 goto free_fetch_att;
1779 mailstream_logger = imap_logger_fetch;
1781 r = mailimap_uid_fetch(imap, set,
1782 fetch_type, &fetch_result);
1784 mailstream_logger = imap_logger_cmd;
1786 mailimap_fetch_type_free(fetch_type);
1787 mailimap_set_free(set);
1790 case MAILIMAP_NO_ERROR:
1796 if (clist_begin(fetch_result) == NULL) {
1797 mailimap_fetch_list_free(fetch_result);
1798 return MAILIMAP_ERROR_FETCH;
1801 msg_att = clist_begin(fetch_result)->data;
1806 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1807 cur = clist_next(cur)) {
1808 msg_att_item = clist_content(cur);
1810 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1811 if (msg_att_item->att_data.att_static->att_type ==
1812 MAILIMAP_MSG_ATT_BODY_SECTION) {
1813 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1815 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1817 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1822 mailimap_fetch_list_free(fetch_result);
1825 return MAILIMAP_ERROR_FETCH;
1828 * result_len = text_length;
1830 return MAILIMAP_NO_ERROR;
1833 mailimap_fetch_att_free(fetch_att);
1835 mailimap_set_free(set);
1840 static int imap_fetch_header(mailimap * imap,
1843 size_t * result_len)
1846 struct mailimap_set * set;
1847 struct mailimap_fetch_att * fetch_att;
1848 struct mailimap_fetch_type * fetch_type;
1849 clist * fetch_result;
1850 struct mailimap_msg_att * msg_att;
1851 struct mailimap_msg_att_item * msg_att_item;
1856 struct mailimap_section * section;
1858 set = mailimap_set_new_single(msg_index);
1860 res = MAILIMAP_ERROR_MEMORY;
1864 section = mailimap_section_new_header();
1865 if (section == NULL) {
1866 res = MAILIMAP_ERROR_MEMORY;
1870 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
1871 if (fetch_att == NULL) {
1872 mailimap_section_free(section);
1873 res = MAILIMAP_ERROR_MEMORY;
1877 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
1878 if (fetch_type == NULL) {
1879 res = MAILIMAP_ERROR_MEMORY;
1880 goto free_fetch_att;
1883 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
1885 mailimap_fetch_type_free(fetch_type);
1886 mailimap_set_free(set);
1889 case MAILIMAP_NO_ERROR:
1895 if (clist_begin(fetch_result) == NULL) {
1896 mailimap_fetch_list_free(fetch_result);
1897 return MAILIMAP_ERROR_FETCH;
1900 msg_att = clist_begin(fetch_result)->data;
1905 for(cur = clist_begin(msg_att->att_list) ; cur != NULL ;
1906 cur = clist_next(cur)) {
1907 msg_att_item = clist_content(cur);
1909 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
1910 if (msg_att_item->att_data.att_static->att_type ==
1911 MAILIMAP_MSG_ATT_BODY_SECTION) {
1912 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
1913 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
1915 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
1920 mailimap_fetch_list_free(fetch_result);
1923 return MAILIMAP_ERROR_FETCH;
1926 * result_len = text_length;
1928 return MAILIMAP_NO_ERROR;
1931 mailimap_fetch_att_free(fetch_att);
1933 mailimap_set_free(set);
1940 struct fetch_content_param {
1943 const char * filename;
1947 struct fetch_content_result {
1951 static void fetch_content_run(struct etpan_thread_op * op)
1953 struct fetch_content_param * param;
1954 struct fetch_content_result * result;
1956 size_t content_size;
1962 result = op->result;
1968 if (param->with_body)
1969 r = imap_fetch(param->imap, param->msg_index,
1970 &content, &content_size);
1972 r = imap_fetch_header(param->imap, param->msg_index,
1973 &content, &content_size);
1977 if (r == MAILIMAP_NO_ERROR) {
1978 fd = open(param->filename, O_RDWR | O_CREAT, 0600);
1980 result->error = MAILIMAP_ERROR_FETCH;
1984 f = fdopen(fd, "wb");
1986 result->error = MAILIMAP_ERROR_FETCH;
1990 r = fwrite(content, 1, content_size, f);
1997 g_unlink(param->filename);
2008 g_unlink(param->filename);
2011 if (mmap_string_unref(content) != 0)
2015 debug_print("imap fetch_content run - end %i\n", r);
2018 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2020 const char * filename)
2022 struct fetch_content_param param;
2023 struct fetch_content_result result;
2026 debug_print("imap fetch_content - begin\n");
2028 imap = get_imap(folder);
2030 param.msg_index = msg_index;
2031 param.filename = filename;
2032 param.with_body = with_body;
2034 threaded_run(folder, ¶m, &result, fetch_content_run);
2036 if (result.error != MAILIMAP_NO_ERROR)
2037 return result.error;
2039 debug_print("imap fetch_content - end\n");
2041 return result.error;
2046 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
2054 flag_list = att_dyn->att_list;
2055 if (flag_list == NULL)
2058 for(cur = clist_begin(flag_list) ; cur != NULL ;
2059 cur = clist_next(cur)) {
2060 struct mailimap_flag_fetch * flag_fetch;
2062 flag_fetch = clist_content(cur);
2063 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2066 switch (flag_fetch->fl_flag->fl_type) {
2067 case MAILIMAP_FLAG_ANSWERED:
2068 flags |= MSG_REPLIED;
2070 case MAILIMAP_FLAG_FLAGGED:
2071 flags |= MSG_MARKED;
2073 case MAILIMAP_FLAG_DELETED:
2074 flags |= MSG_DELETED;
2076 case MAILIMAP_FLAG_SEEN:
2077 flags &= ~MSG_UNREAD;
2087 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2091 struct mailimap_msg_att_dynamic ** patt_dyn)
2093 clistiter * item_cur;
2097 struct mailimap_msg_att_dynamic * att_dyn;
2104 for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ;
2105 item_cur = clist_next(item_cur)) {
2106 struct mailimap_msg_att_item * item;
2108 item = clist_content(item_cur);
2110 switch (item->att_type) {
2111 case MAILIMAP_MSG_ATT_ITEM_STATIC:
2112 switch (item->att_data.att_static->att_type) {
2113 case MAILIMAP_MSG_ATT_UID:
2114 uid = item->att_data.att_static->att_data.att_uid;
2117 case MAILIMAP_MSG_ATT_BODY_SECTION:
2118 if (headers == NULL) {
2119 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2122 case MAILIMAP_MSG_ATT_RFC822_SIZE:
2123 ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2128 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2129 if (att_dyn == NULL) {
2130 att_dyn = item->att_data.att_dyn;
2138 if (pheaders != NULL)
2139 * pheaders = headers;
2140 if (pref_size != NULL)
2141 * pref_size = ref_size;
2142 if (patt_dyn != NULL)
2143 * patt_dyn = att_dyn;
2145 return MAIL_NO_ERROR;
2148 static struct imap_fetch_env_info *
2149 fetch_to_env_info(struct mailimap_msg_att * msg_att)
2151 struct imap_fetch_env_info * info;
2155 struct mailimap_msg_att_dynamic * att_dyn;
2157 imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2162 info = malloc(sizeof(* info));
2164 info->headers = strdup(headers);
2166 info->flags = imap_flags_to_flags(att_dyn);
2172 imap_fetch_result_to_envelop_list(clist * fetch_result,
2173 carray ** p_env_list)
2180 env_list = carray_new(16);
2182 for(cur = clist_begin(fetch_result) ; cur != NULL ;
2183 cur = clist_next(cur)) {
2184 struct mailimap_msg_att * msg_att;
2185 struct imap_fetch_env_info * env_info;
2187 msg_att = clist_content(cur);
2189 env_info = fetch_to_env_info(msg_att);
2191 return MAILIMAP_ERROR_MEMORY;
2192 carray_add(env_list, env_info, NULL);
2195 * p_env_list = env_list;
2197 return MAIL_NO_ERROR;
2200 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2202 struct mailimap_fetch_att * fetch_att;
2206 struct mailimap_header_list * imap_hdrlist;
2207 struct mailimap_section * section;
2209 hdrlist = clist_new();
2211 header = strdup("Date");
2212 r = clist_append(hdrlist, header);
2213 header = strdup("From");
2214 r = clist_append(hdrlist, header);
2215 header = strdup("To");
2216 r = clist_append(hdrlist, header);
2217 header = strdup("Cc");
2218 r = clist_append(hdrlist, header);
2219 header = strdup("Subject");
2220 r = clist_append(hdrlist, header);
2221 header = strdup("Message-ID");
2222 r = clist_append(hdrlist, header);
2223 header = strdup("References");
2224 r = clist_append(hdrlist, header);
2225 header = strdup("In-Reply-To");
2226 r = clist_append(hdrlist, header);
2228 imap_hdrlist = mailimap_header_list_new(hdrlist);
2229 section = mailimap_section_new_header_fields(imap_hdrlist);
2230 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2231 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2233 return MAIL_NO_ERROR;
2236 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2238 struct mailimap_fetch_att * fetch_att;
2239 struct mailimap_section * section;
2241 section = mailimap_section_new_header();
2242 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2243 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2245 return MAIL_NO_ERROR;
2249 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2250 carray ** p_env_list)
2252 struct mailimap_fetch_att * fetch_att;
2253 struct mailimap_fetch_type * fetch_type;
2255 clist * fetch_result;
2257 carray * env_list = NULL;
2261 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2264 fetch_att = mailimap_fetch_att_new_uid();
2265 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2268 fetch_att = mailimap_fetch_att_new_flags();
2269 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2272 fetch_att = mailimap_fetch_att_new_rfc822_size();
2273 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2277 key.len = sizeof(imap);
2278 r = chash_get(courier_workaround_hash, &key, &value);
2280 r = imap_add_envelope_fetch_att(fetch_type);
2282 r = imap_add_header_fetch_att(fetch_type);
2284 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2287 case MAILIMAP_NO_ERROR:
2290 mailimap_fetch_type_free(fetch_type);
2291 debug_print("uid_fetch: %d\n", r);
2295 if (clist_begin(fetch_result) == NULL) {
2296 res = MAILIMAP_ERROR_FETCH;
2297 debug_print("clist_begin = NULL\n");
2301 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2302 mailimap_fetch_list_free(fetch_result);
2304 if (r != MAILIMAP_NO_ERROR) {
2305 mailimap_fetch_type_free(fetch_type);
2306 res = MAILIMAP_ERROR_MEMORY;
2307 debug_print("fetch_result_to_envelop_list: %d\n", res);
2311 mailimap_fetch_type_free(fetch_type);
2313 * p_env_list = env_list;
2315 return MAILIMAP_NO_ERROR;
2321 struct fetch_env_param {
2323 struct mailimap_set * set;
2326 struct fetch_env_result {
2327 carray * fetch_env_result;
2331 static void fetch_env_run(struct etpan_thread_op * op)
2333 struct fetch_env_param * param;
2334 struct fetch_env_result * result;
2339 result = op->result;
2344 r = imap_get_envelopes_list(param->imap, param->set,
2348 result->fetch_env_result = env_list;
2350 debug_print("imap fetch_env run - end %i\n", r);
2353 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
2354 carray ** p_env_list)
2356 struct fetch_env_param param;
2357 struct fetch_env_result result;
2360 debug_print("imap fetch_env - begin\n");
2362 imap = get_imap(folder);
2366 threaded_run(folder, ¶m, &result, fetch_env_run);
2368 if (result.error != MAILIMAP_NO_ERROR) {
2374 key.len = sizeof(imap);
2375 r = chash_get(courier_workaround_hash, &key, &value);
2379 chash_set(courier_workaround_hash, &key, &value, NULL);
2381 threaded_run(folder, ¶m, &result, fetch_env_run);
2385 if (result.error != MAILIMAP_NO_ERROR)
2386 return result.error;
2388 debug_print("imap fetch_env - end\n");
2390 * p_env_list = result.fetch_env_result;
2392 return result.error;
2395 void imap_fetch_env_free(carray * env_list)
2399 for(i = 0 ; i < carray_count(env_list) ; i ++) {
2400 struct imap_fetch_env_info * env_info;
2402 env_info = carray_get(env_list, i);
2403 free(env_info->headers);
2406 carray_free(env_list);
2413 struct append_param {
2415 const char * mailbox;
2416 const char * filename;
2417 struct mailimap_flag_list * flag_list;
2420 struct append_result {
2425 static void append_run(struct etpan_thread_op * op)
2427 struct append_param * param;
2428 struct append_result * result;
2432 struct stat stat_buf;
2434 guint32 uid = 0, val = 0;
2437 result = op->result;
2441 r = stat(param->filename, &stat_buf);
2443 result->error = MAILIMAP_ERROR_APPEND;
2446 size = stat_buf.st_size;
2448 fd = open(param->filename, O_RDONLY);
2450 result->error = MAILIMAP_ERROR_APPEND;
2454 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2455 if (data == (void *) MAP_FAILED) {
2457 result->error = MAILIMAP_ERROR_APPEND;
2461 mailstream_logger = imap_logger_append;
2463 r = mailimap_uidplus_append(param->imap, param->mailbox,
2464 param->flag_list, NULL,
2465 data, size, &val, &uid);
2467 mailstream_logger = imap_logger_cmd;
2474 debug_print("imap append run - end %i uid %d\n", r, uid);
2477 int imap_threaded_append(Folder * folder, const char * mailbox,
2478 const char * filename,
2479 struct mailimap_flag_list * flag_list,
2482 struct append_param param;
2483 struct append_result result;
2486 debug_print("imap append - begin\n");
2488 imap = get_imap(folder);
2490 param.mailbox = mailbox;
2491 param.filename = filename;
2492 param.flag_list = flag_list;
2494 threaded_run(folder, ¶m, &result, append_run);
2496 if (result.error != MAILIMAP_NO_ERROR)
2497 return result.error;
2499 debug_print("imap append - end\n");
2503 return result.error;
2509 struct expunge_param {
2513 struct expunge_result {
2517 static void expunge_run(struct etpan_thread_op * op)
2519 struct expunge_param * param;
2520 struct expunge_result * result;
2524 result = op->result;
2528 r = mailimap_expunge(param->imap);
2531 debug_print("imap expunge run - end %i\n", r);
2534 int imap_threaded_expunge(Folder * folder)
2536 struct expunge_param param;
2537 struct expunge_result result;
2539 debug_print("imap expunge - begin\n");
2541 param.imap = get_imap(folder);
2543 threaded_run(folder, ¶m, &result, expunge_run);
2545 debug_print("imap expunge - end\n");
2547 return result.error;
2553 struct mailimap_set * set;
2557 struct copy_result {
2559 struct mailimap_set *source;
2560 struct mailimap_set *dest;
2563 static void copy_run(struct etpan_thread_op * op)
2565 struct copy_param * param;
2566 struct copy_result * result;
2569 struct mailimap_set *source = NULL, *dest = NULL;
2572 result = op->result;
2576 r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
2577 &val, &source, &dest);
2581 result->source = source;
2582 result->dest = dest;
2584 result->source = NULL;
2585 result->dest = NULL;
2587 debug_print("imap copy run - end %i\n", r);
2590 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
2591 const char * mb, struct mailimap_set **source,
2592 struct mailimap_set **dest)
2594 struct copy_param param;
2595 struct copy_result result;
2598 debug_print("imap copy - begin\n");
2600 imap = get_imap(folder);
2605 threaded_run(folder, ¶m, &result, copy_run);
2609 if (result.error != MAILIMAP_NO_ERROR)
2610 return result.error;
2612 *source = result.source;
2613 *dest = result.dest;
2615 debug_print("imap copy - end\n");
2617 return result.error;
2622 struct store_param {
2624 struct mailimap_set * set;
2625 struct mailimap_store_att_flags * store_att_flags;
2628 struct store_result {
2632 static void store_run(struct etpan_thread_op * op)
2634 struct store_param * param;
2635 struct store_result * result;
2639 result = op->result;
2643 r = mailimap_uid_store(param->imap, param->set,
2644 param->store_att_flags);
2648 debug_print("imap store run - end %i\n", r);
2651 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
2652 struct mailimap_store_att_flags * store_att_flags)
2654 struct store_param param;
2655 struct store_result result;
2658 debug_print("imap store - begin\n");
2660 imap = get_imap(folder);
2663 param.store_att_flags = store_att_flags;
2665 threaded_run(folder, ¶m, &result, store_run);
2667 if (result.error != MAILIMAP_NO_ERROR)
2668 return result.error;
2670 debug_print("imap store - end\n");
2672 return result.error;
2676 #define ENV_BUFFER_SIZE 512
2678 static void do_exec_command(int fd, const char * command,
2679 const char * servername, uint16_t port)
2683 char env_buffer[ENV_BUFFER_SIZE];
2687 /* Fork again to become a child of init rather than
2688 the etpan client. */
2694 snprintf(env_buffer, ENV_BUFFER_SIZE,
2695 "ETPANSERVER=%s", servername);
2697 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANSERVER=");
2701 setenv("ETPANSERVER", servername, 1);
2703 unsetenv("ETPANSERVER");
2708 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=%d", port);
2710 snprintf(env_buffer, ENV_BUFFER_SIZE, "ETPANPORT=");
2716 snprintf(porttext, sizeof(porttext), "%d", port);
2717 setenv("ETPANPORT", porttext, 1);
2720 unsetenv("ETPANPORT");
2724 /* Not a lot we can do if there's an error other than bail. */
2725 if (dup2(fd, 0) == -1)
2727 if (dup2(fd, 1) == -1)
2730 /* Should we close stderr and reopen /dev/null? */
2732 maxopen = sysconf(_SC_OPEN_MAX);
2733 for (i=3; i < maxopen; i++)
2737 /* Detach from the controlling tty if we have one. Otherwise,
2738 SSH might do something stupid like trying to use it instead
2739 of running $SSH_ASKPASS. Doh. */
2740 fd = open("/dev/tty", O_RDONLY);
2742 ioctl(fd, TIOCNOTTY, NULL);
2745 #endif /* TIOCNOTTY */
2747 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
2749 /* Eep. Shouldn't reach this */
2753 static int subcommand_connect(const char *command,
2754 const char *servername, uint16_t port)
2756 /* SEB unsupported on Windows */
2760 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
2765 do_exec_command(sockfds[1], command, servername, port);
2767 else if (childpid == -1) {
2775 /* Reap child, leaving grandchild process to run */
2776 waitpid(childpid, NULL, 0);
2781 static int socket_connect_cmd(mailimap * imap, const char * command,
2782 const char * server, int port)
2788 fd = subcommand_connect(command, server, port);
2790 return MAILIMAP_ERROR_STREAM;
2792 s = mailstream_socket_open(fd);
2795 return MAILIMAP_ERROR_STREAM;
2798 r = mailimap_connect(imap, s);
2799 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
2800 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
2801 mailstream_close(s);
2802 imap->imap_stream = NULL;
2811 struct connect_cmd_param {
2813 const char * command;
2814 const char * server;
2818 struct connect_cmd_result {
2822 static void connect_cmd_run(struct etpan_thread_op * op)
2825 struct connect_cmd_param * param;
2826 struct connect_cmd_result * result;
2829 result = op->result;
2833 r = socket_connect_cmd(param->imap, param->command,
2834 param->server, param->port);
2840 int imap_threaded_connect_cmd(Folder * folder, const char * command,
2841 const char * server, int port)
2843 struct connect_cmd_param param;
2844 struct connect_cmd_result result;
2847 mailimap * imap, * oldimap;
2849 oldimap = get_imap(folder);
2851 imap = mailimap_new(0, NULL);
2854 debug_print("deleting old imap %p\n", oldimap);
2855 delete_imap(folder, oldimap);
2859 key.len = sizeof(folder);
2862 chash_set(session_hash, &key, &value, NULL);
2865 param.command = command;
2866 param.server = server;
2869 threaded_run(folder, ¶m, &result, connect_cmd_run);
2871 debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
2873 return result.error;
2877 void imap_main_init(void)
2880 void imap_main_done(void)
2883 void imap_main_set_timeout(int sec)