2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2005-2016 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/>.
21 #include "claws-features.h"
27 #include <glib/gi18n.h>
28 #include "imap-thread.h"
30 #include <sys/types.h>
32 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__))
33 #include <sys/socket.h>
42 #include "etpan-thread-manager.h"
43 #include "etpan-ssl.h"
45 #include "mainwindow.h"
47 #include "safe_fclose.h"
49 #include "ssl_certificate.h"
51 #include "remotefolder.h"
54 #define DISABLE_LOG_DURING_LOGIN
56 static struct etpan_thread_manager * thread_manager = NULL;
57 static chash * courier_workaround_hash = NULL;
58 static chash * imap_hash = NULL;
59 static chash * session_hash = NULL;
60 static guint thread_manager_signal = 0;
61 static GIOChannel * io_channel = NULL;
63 static int do_mailimap_socket_connect(mailimap * imap, const char * server,
64 gushort port, ProxyInfo * proxy_info)
70 return mailimap_socket_connect(imap, server, port);
75 sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
78 return MAILIMAP_ERROR_CONNECTION_REFUSED;
80 if (proxy_connect(sock, server, port, proxy_info) < 0) {
82 return MAILIMAP_ERROR_CONNECTION_REFUSED;
85 stream = mailstream_socket_open_timeout(sock->sock,
89 return MAILIMAP_ERROR_MEMORY;
92 return mailimap_connect(imap, stream);
95 static int do_mailimap_ssl_connect_with_callback(mailimap * imap, const char * server,
97 void (* callback)(struct mailstream_ssl_context * ssl_context, void * data),
99 ProxyInfo *proxy_info)
105 return mailimap_ssl_connect_with_callback(imap, server,
106 port, callback, data);
111 sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
114 debug_print("Can not connect to proxy %s:%d\n",
115 proxy_info->proxy_host, proxy_info->proxy_port);
116 return MAILIMAP_ERROR_CONNECTION_REFUSED;
119 if (proxy_connect(sock, server, port, proxy_info) < 0) {
120 debug_print("Can not make proxy connection via %s:%d\n",
121 proxy_info->proxy_host, proxy_info->proxy_port);
123 return MAILIMAP_ERROR_CONNECTION_REFUSED;
126 stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
127 imap->imap_timeout, callback, data);
128 if (stream == NULL) {
130 return MAILIMAP_ERROR_SSL;
133 return mailimap_connect(imap, stream);
136 static gboolean thread_manager_event(GIOChannel * source,
137 GIOCondition condition,
144 if (condition & G_IO_IN)
145 g_io_channel_read_chars(source, &ch, 1, &bytes_read, NULL);
147 etpan_thread_manager_loop(thread_manager);
152 static void imap_logger_noop(int direction, const char * str, size_t size)
154 /* inhibit logging */
157 static void imap_logger_cmd(int direction, const char * str, size_t size)
164 log_print(LOG_PROTOCOL, "IMAP%c [CMD data - %zd bytes]\n", direction?'>':'<', size);
167 buf = malloc(size+1);
168 memset(buf, 0, size+1);
169 strncpy(buf, str, size);
172 if (!strncmp(buf, "<<<<<<<", 7)
173 || !strncmp(buf, ">>>>>>>", 7)) {
177 while (strstr(buf, "\r"))
178 *strstr(buf, "\r") = ' ';
179 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
180 buf[strlen(buf)-1] = '\0';
182 lines = g_strsplit(buf, "\n", -1);
184 while (lines[i] && *lines[i]) {
185 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
192 static void imap_logger_fetch(int direction, const char * str, size_t size)
198 if (size > 128 && !direction) {
199 log_print(LOG_PROTOCOL, "IMAP%c [FETCH data - %zd bytes]\n", direction?'>':'<', size);
203 buf = malloc(size+1);
204 memset(buf, 0, size+1);
205 strncpy(buf, str, size);
207 if (!strncmp(buf, "<<<<<<<", 7)
208 || !strncmp(buf, ">>>>>>>", 7)) {
212 while (strstr(buf, "\r"))
213 *strstr(buf, "\r") = ' ';
214 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
215 buf[strlen(buf)-1] = '\0';
217 lines = g_strsplit(buf, "\n", -1);
219 if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) {
220 while (lines[i] && *lines[i]) {
221 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
225 log_print(LOG_PROTOCOL, "IMAP%c [data - %zd bytes]\n", direction?'>':'<', size);
231 static void imap_logger_uid(int direction, const char * str, size_t size)
238 log_print(LOG_PROTOCOL, "IMAP%c [UID data - %zd bytes]\n", direction?'>':'<', size);
241 buf = malloc(size+1);
242 memset(buf, 0, size+1);
243 strncpy(buf, str, size);
245 if (!strncmp(buf, "<<<<<<<", 7)
246 || !strncmp(buf, ">>>>>>>", 7)) {
250 while (strstr(buf, "\r"))
251 *strstr(buf, "\r") = ' ';
252 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
253 buf[strlen(buf)-1] = '\0';
255 lines = g_strsplit(buf, "\n", -1);
257 while (lines[i] && *lines[i]) {
258 int llen = strlen(lines[i]);
260 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
263 strncpy2(tmp, lines[i], 63);
264 log_print(LOG_PROTOCOL, "IMAP%c %s[... - %d bytes more]\n", direction?'>':'<', tmp,
273 static void imap_logger_append(int direction, const char * str, size_t size)
280 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
282 } else if (direction == 0 && size > 64) {
283 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %zd bytes]\n", direction?'>':'<', size);
286 buf = malloc(size+1);
287 memset(buf, 0, size+1);
288 strncpy(buf, str, size);
290 if (!strncmp(buf, "<<<<<<<", 7)
291 || !strncmp(buf, ">>>>>>>", 7)) {
295 while (strstr(buf, "\r"))
296 *strstr(buf, "\r") = ' ';
297 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
298 buf[strlen(buf)-1] = '\0';
300 lines = g_strsplit(buf, "\n", -1);
302 if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
303 while (lines[i] && *lines[i]) {
304 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
308 log_print(LOG_PROTOCOL, "IMAP%c [data - %zd bytes]\n", direction?'>':'<', size);
314 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
315 gboolean etpan_skip_ssl_cert_check = FALSE;
316 extern void mailsasl_ref(void);
318 void imap_main_init(gboolean skip_ssl_cert_check)
320 int fd_thread_manager;
322 etpan_skip_ssl_cert_check = skip_ssl_cert_check;
323 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
324 mailstream_network_delay.tv_usec = 0;
326 mailstream_debug = 1;
327 mailstream_logger = imap_logger_cmd;
330 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
331 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
332 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
334 thread_manager = etpan_thread_manager_new();
336 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
339 io_channel = g_io_channel_unix_new(fd_thread_manager);
341 io_channel = g_io_channel_win32_new_fd(fd_thread_manager);
343 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
344 thread_manager_event,
349 void imap_main_set_timeout(int sec)
351 mailstream_network_delay.tv_sec = sec;
352 mailstream_network_delay.tv_usec = 0;
355 void imap_main_done(gboolean have_connectivity)
357 imap_disconnect_all(have_connectivity);
358 etpan_thread_manager_stop(thread_manager);
359 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
362 etpan_thread_manager_join(thread_manager);
364 g_source_remove(thread_manager_signal);
365 g_io_channel_unref(io_channel);
367 etpan_thread_manager_free(thread_manager);
369 chash_free(courier_workaround_hash);
370 chash_free(session_hash);
371 chash_free(imap_hash);
374 void imap_init(Folder * folder)
376 struct etpan_thread * thread;
380 thread = etpan_thread_manager_get_thread(thread_manager);
383 key.len = sizeof(folder);
387 chash_set(imap_hash, &key, &value, NULL);
390 void imap_done(Folder * folder)
392 struct etpan_thread * thread;
398 key.len = sizeof(folder);
400 r = chash_get(imap_hash, &key, &value);
406 etpan_thread_unbind(thread);
408 chash_delete(imap_hash, &key, NULL);
410 debug_print("remove thread\n");
413 static struct etpan_thread * get_thread(Folder * folder)
415 struct etpan_thread * thread;
421 key.len = sizeof(folder);
423 r = chash_get(imap_hash, &key, &value);
432 static mailimap * get_imap(Folder * folder)
440 key.len = sizeof(folder);
442 r = chash_get(session_hash, &key, &value);
447 debug_print("found imap %p\n", imap);
451 static gboolean cb_show_error(gpointer data)
453 mainwindow_show_error();
457 static void generic_cb(int cancelled, void * result, void * callback_data)
459 struct etpan_thread_op * op;
461 op = (struct etpan_thread_op *) callback_data;
463 debug_print("generic_cb\n");
464 if (op->imap && op->imap->imap_response_info &&
465 op->imap->imap_response_info->rsp_alert) {
466 log_error(LOG_PROTOCOL, "IMAP< Alert: %s\n",
467 op->imap->imap_response_info->rsp_alert);
468 g_timeout_add(10, cb_show_error, NULL);
473 /* Please do *not* blindly use imap pointers after this function returns,
474 * someone may have deleted it while this function was waiting for completion.
475 * Check return value to see if imap is still valid.
476 * Run get_imap(folder) again to get a fresh and valid pointer.
478 static int threaded_run(Folder * folder, void * param, void * result,
479 void (* func)(struct etpan_thread_op * ))
481 struct etpan_thread_op * op;
482 struct etpan_thread * thread;
483 struct mailimap * imap = get_imap(folder);
485 imap_folder_ref(folder);
487 op = etpan_thread_op_new();
494 op->callback = generic_cb;
495 op->callback_data = op;
497 thread = get_thread(folder);
498 etpan_thread_op_schedule(thread, op);
500 while (!op->finished) {
501 gtk_main_iteration();
504 etpan_thread_op_free(op);
506 imap_folder_unref(folder);
508 if (imap != get_imap(folder)) {
509 g_warning("returning from operation on a stale imap %p", imap);
519 struct connect_param {
521 PrefsAccount *account;
524 ProxyInfo * proxy_info;
527 struct connect_result {
531 #define CHECK_IMAP() { \
532 if (!param->imap) { \
533 result->error = MAILIMAP_ERROR_BAD_STATE; \
539 static void delete_imap_run(struct etpan_thread_op * op)
541 mailimap * imap = op->imap;
543 /* we don't want libetpan to logout */
544 if (imap->imap_stream) {
545 mailstream_close(imap->imap_stream);
546 imap->imap_stream = NULL;
552 static void threaded_delete_imap(Folder *folder, mailimap *imap)
554 struct etpan_thread_op * op;
556 /* No need to wait for completion, threaded_run() won't work here. */
557 op = etpan_thread_op_new();
559 op->run = delete_imap_run;
560 op->cleanup = etpan_thread_op_free;
562 etpan_thread_op_schedule(get_thread(folder), op);
564 debug_print("threaded delete imap posted\n");
567 static void delete_imap(Folder *folder, mailimap *imap)
572 key.len = sizeof(folder);
573 chash_delete(session_hash, &key, NULL);
578 key.len = sizeof(imap);
579 chash_delete(courier_workaround_hash, &key, NULL);
580 /* We can't just free imap here as there may be ops on it pending
581 * in the thread. Posting freeing as an op will synchronize against
582 * existing jobs and as imap is already removed from session_hash
583 * we are sure no new ops can be posted. */
584 threaded_delete_imap(folder, imap);
587 static void connect_run(struct etpan_thread_op * op)
590 struct connect_param * param;
591 struct connect_result * result;
598 r = do_mailimap_socket_connect(param->imap,
599 param->server, param->port, param->proxy_info);
605 int imap_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
607 struct connect_param param;
608 struct connect_result result;
611 mailimap * imap, * oldimap;
613 oldimap = get_imap(folder);
615 imap = mailimap_new(0, NULL);
618 debug_print("deleting old imap %p\n", oldimap);
619 delete_imap(folder, oldimap);
623 key.len = sizeof(folder);
626 chash_set(session_hash, &key, &value, NULL);
629 param.server = server;
631 param.proxy_info = proxy_info;
634 threaded_run(folder, ¶m, &result, connect_run);
636 debug_print("connect ok %i with imap %p\n", result.error, imap);
641 static void connect_ssl_run(struct etpan_thread_op * op)
644 struct connect_param * param;
645 struct connect_result * result;
652 r = do_mailimap_ssl_connect_with_callback(param->imap,
653 param->server, param->port,
654 etpan_connect_ssl_context_cb, param->account,
659 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
661 struct connect_param param;
662 struct connect_result result;
665 mailimap * imap, * oldimap;
666 gboolean accept_if_valid = FALSE;
668 oldimap = get_imap(folder);
670 imap = mailimap_new(0, NULL);
673 debug_print("deleting old imap %p\n", oldimap);
674 delete_imap(folder, oldimap);
678 key.len = sizeof(folder);
681 chash_set(session_hash, &key, &value, NULL);
684 param.server = server;
686 param.account = folder->account;
687 param.proxy_info = proxy_info;
690 accept_if_valid = folder->account->ssl_certs_auto_accept;
693 if (threaded_run(folder, ¶m, &result, connect_ssl_run))
694 return MAILIMAP_ERROR_INVAL;
696 if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
697 result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
698 if (etpan_certificate_check(imap->imap_stream, server, port,
699 accept_if_valid) != TRUE)
700 result.error = MAILIMAP_ERROR_SSL;
702 debug_print("connect %d with imap %p\n", result.error, imap);
713 struct mailimap_capability_data *caps;
716 static void capability_run(struct etpan_thread_op * op)
719 struct capa_param * param;
720 struct capa_result * result;
721 struct mailimap_capability_data *caps;
728 r = mailimap_capability(param->imap, &caps);
731 result->caps = (r == 0 ? caps : NULL);
735 int imap_threaded_capability(Folder *folder, struct mailimap_capability_data ** caps)
737 struct capa_param param;
738 struct capa_result result;
741 imap = get_imap(folder);
745 threaded_run(folder, ¶m, &result, capability_run);
747 debug_print("capa %d\n", result.error);
749 if (result.error == MAILIMAP_NO_ERROR)
756 struct disconnect_param {
760 struct disconnect_result {
764 static void disconnect_run(struct etpan_thread_op * op)
767 struct disconnect_param * param;
768 struct disconnect_result * result;
775 r = mailimap_logout(param->imap);
780 void imap_threaded_disconnect(Folder * folder)
782 struct connect_param param;
783 struct connect_result result;
786 imap = get_imap(folder);
788 debug_print("was disconnected\n");
794 if (threaded_run(folder, ¶m, &result, disconnect_run)) {
795 debug_print("imap already deleted %p\n", imap);
797 debug_print("deleting old imap %p\n", imap);
798 delete_imap(folder, imap);
801 debug_print("disconnect ok\n");
808 const char * wildcard;
817 static void list_run(struct etpan_thread_op * op)
819 struct list_param * param;
820 struct list_result * result;
831 if (param->base == NULL || param->wildcard == NULL) {
834 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
838 r = mailimap_lsub(param->imap, param->base,
839 param->wildcard, &list);
841 r = mailimap_list(param->imap, param->base,
842 param->wildcard, &list);
845 debug_print("imap list run - end\n");
848 int imap_threaded_list(Folder * folder, const char * base,
849 const char * wildcard,
852 struct list_param param;
853 struct list_result result;
855 debug_print("imap list - begin\n");
857 param.imap = get_imap(folder);
859 param.wildcard = wildcard;
860 param.sub_only = FALSE;
862 threaded_run(folder, ¶m, &result, list_run);
864 * p_result = result.list;
866 debug_print("imap list - end %p\n", result.list);
871 int imap_threaded_lsub(Folder * folder, const char * base,
872 const char * wildcard,
875 struct list_param param;
876 struct list_result result;
878 debug_print("imap lsub - begin\n");
880 param.imap = get_imap(folder);
882 param.wildcard = wildcard;
883 param.sub_only = TRUE;
885 threaded_run(folder, ¶m, &result, list_run);
887 * p_result = result.list;
889 debug_print("imap lsub - end %p\n", result.list);
894 struct subscribe_param {
900 struct subscribe_result {
904 static void subscribe_run(struct etpan_thread_op * op)
906 struct subscribe_param * param;
907 struct subscribe_result * result;
915 if (param->mb == NULL) {
917 debug_print("no mb\n");
920 if (param->subscribe)
921 r = mailimap_subscribe(param->imap, param->mb);
923 r = mailimap_unsubscribe(param->imap, param->mb);
925 debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
928 int imap_threaded_subscribe(Folder * folder, const char * mb,
931 struct subscribe_param param;
932 struct subscribe_result result;
934 debug_print("imap list - begin\n");
936 param.imap = get_imap(folder);
938 param.subscribe = subscribe;
940 threaded_run(folder, ¶m, &result, subscribe_run);
948 const char * password;
953 struct login_result {
957 static void login_run(struct etpan_thread_op * op)
959 struct login_param * param;
960 struct login_result * result;
962 #ifdef DISABLE_LOG_DURING_LOGIN
971 #ifdef DISABLE_LOG_DURING_LOGIN
972 old_debug = mailstream_debug;
973 mailstream_debug = 0;
975 if (!strcmp(param->type, "plaintext"))
976 r = mailimap_login(param->imap,
977 param->login, param->password);
978 else if (!strcmp(param->type, "GSSAPI"))
979 r = mailimap_authenticate(param->imap,
980 param->type, param->server, NULL, NULL,
981 param->login, param->login,
982 param->password, NULL);
983 else if (!strcmp(param->type, "SCRAM-SHA-1"))
984 /* 7th argument has to be NULL here, to stop libetpan sending the
985 * a= attribute in its initial SCRAM-SHA-1 message to server. At least
986 * Dovecot 2.2 doesn't seem to like that, and will not authenticate
988 r = mailimap_authenticate(param->imap,
989 param->type, NULL, NULL, NULL,
991 param->password, NULL);
993 r = mailimap_authenticate(param->imap,
994 param->type, NULL, NULL, NULL,
995 param->login, param->login,
996 param->password, NULL);
997 #ifdef DISABLE_LOG_DURING_LOGIN
998 mailstream_debug = old_debug;
1002 if (param->imap->imap_response)
1003 imap_logger_cmd(0, param->imap->imap_response, strlen(param->imap->imap_response));
1004 debug_print("imap login run - end %i\n", r);
1007 int imap_threaded_login(Folder * folder,
1008 const char * login, const char * password,
1011 struct login_param param;
1012 struct login_result result;
1014 debug_print("imap login - begin\n");
1017 return MAILIMAP_ERROR_INVAL;
1019 param.imap = get_imap(folder);
1020 param.login = login;
1021 param.password = password;
1023 if (folder && folder->account)
1024 param.server = folder->account->recv_server;
1026 param.server = NULL;
1028 threaded_run(folder, ¶m, &result, login_run);
1030 debug_print("imap login - end\n");
1032 return result.error;
1036 struct status_param {
1039 struct mailimap_status_att_list * status_att_list;
1042 struct status_result {
1044 struct mailimap_mailbox_data_status * data_status;
1047 static void status_run(struct etpan_thread_op * op)
1049 struct status_param * param;
1050 struct status_result * result;
1054 result = op->result;
1058 r = mailimap_status(param->imap, param->mb,
1059 param->status_att_list,
1060 &result->data_status);
1063 debug_print("imap status run - end %i\n", r);
1066 int imap_threaded_status(Folder * folder, const char * mb,
1067 struct mailimap_mailbox_data_status ** data_status,
1070 struct status_param param;
1071 struct status_result result;
1072 struct mailimap_status_att_list * status_att_list;
1074 debug_print("imap status - begin\n");
1076 status_att_list = mailimap_status_att_list_new_empty();
1077 if (mask & 1 << 0) {
1078 mailimap_status_att_list_add(status_att_list,
1079 MAILIMAP_STATUS_ATT_MESSAGES);
1081 if (mask & 1 << 1) {
1082 mailimap_status_att_list_add(status_att_list,
1083 MAILIMAP_STATUS_ATT_RECENT);
1085 if (mask & 1 << 2) {
1086 mailimap_status_att_list_add(status_att_list,
1087 MAILIMAP_STATUS_ATT_UIDNEXT);
1089 if (mask & 1 << 3) {
1090 mailimap_status_att_list_add(status_att_list,
1091 MAILIMAP_STATUS_ATT_UIDVALIDITY);
1093 if (mask & 1 << 4) {
1094 mailimap_status_att_list_add(status_att_list,
1095 MAILIMAP_STATUS_ATT_UNSEEN);
1097 param.imap = get_imap(folder);
1099 param.status_att_list = status_att_list;
1101 threaded_run(folder, ¶m, &result, status_run);
1103 debug_print("imap status - end\n");
1105 * data_status = result.data_status;
1107 mailimap_status_att_list_free(status_att_list);
1109 return result.error;
1118 struct noop_result {
1122 static void noop_run(struct etpan_thread_op * op)
1124 struct noop_param * param;
1125 struct noop_result * result;
1129 result = op->result;
1133 r = mailimap_noop(param->imap);
1136 debug_print("imap noop run - end %i\n", r);
1139 int imap_threaded_noop(Folder * folder, unsigned int * p_exists,
1140 unsigned int *p_recent,
1141 unsigned int *p_expunge,
1142 unsigned int *p_unseen,
1143 unsigned int *p_uidnext,
1144 unsigned int *p_uidval)
1146 struct noop_param param;
1147 struct noop_result result;
1150 debug_print("imap noop - begin\n");
1152 imap = get_imap(folder);
1155 if (threaded_run(folder, ¶m, &result, noop_run))
1156 return MAILIMAP_ERROR_INVAL;
1158 if (result.error == 0 && imap && imap->imap_selection_info != NULL) {
1159 * p_exists = imap->imap_selection_info->sel_exists;
1160 * p_recent = imap->imap_selection_info->sel_recent;
1161 * p_unseen = imap->imap_selection_info->sel_unseen;
1162 * p_uidnext = imap->imap_selection_info->sel_uidnext;
1163 * p_uidval = imap->imap_selection_info->sel_uidvalidity;
1171 if (result.error == 0 && imap && imap->imap_response_info != NULL &&
1172 imap->imap_response_info->rsp_expunged != NULL) {
1173 * p_expunge = clist_count(imap->imap_response_info->rsp_expunged);
1177 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1178 *p_exists, *p_recent, *p_expunge, *p_unseen,
1179 *p_uidnext, *p_uidval);
1181 return result.error;
1185 struct starttls_result {
1189 static void starttls_run(struct etpan_thread_op * op)
1191 struct connect_param * param;
1192 struct starttls_result * result;
1196 result = op->result;
1200 r = mailimap_starttls(param->imap);
1203 debug_print("imap STARTTLS run - end %i\n", r);
1206 mailimap *imap = param->imap;
1207 mailstream_low *plain_low = NULL;
1208 mailstream_low *tls_low = NULL;
1211 plain_low = mailstream_get_low(imap->imap_stream);
1212 fd = mailstream_low_get_fd(plain_low);
1214 debug_print("imap STARTTLS run - can't get fd\n");
1215 result->error = MAILIMAP_ERROR_STREAM;
1219 tls_low = mailstream_low_tls_open_with_callback(fd, etpan_connect_ssl_context_cb, param->account);
1220 if (tls_low == NULL) {
1221 debug_print("imap STARTTLS run - can't tls_open\n");
1222 result->error = MAILIMAP_ERROR_STREAM;
1225 mailstream_low_free(plain_low);
1226 mailstream_set_low(imap->imap_stream, tls_low);
1230 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1232 struct connect_param param;
1233 struct starttls_result result;
1234 gboolean accept_if_valid = FALSE;
1236 debug_print("imap STARTTLS - begin\n");
1238 param.imap = get_imap(folder);
1239 param.server = host;
1241 param.account = folder->account;
1243 if (folder->account)
1244 accept_if_valid = folder->account->ssl_certs_auto_accept;
1246 if (threaded_run(folder, ¶m, &result, starttls_run))
1247 return MAILIMAP_ERROR_INVAL;
1249 debug_print("imap STARTTLS - end\n");
1251 if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
1252 if (etpan_certificate_check(param.imap->imap_stream, host, port,
1253 accept_if_valid) != TRUE)
1254 return MAILIMAP_ERROR_SSL;
1256 return result.error;
1260 struct create_param {
1265 struct create_result {
1269 static void create_run(struct etpan_thread_op * op)
1271 struct create_param * param;
1272 struct create_result * result;
1276 result = op->result;
1280 r = mailimap_create(param->imap, param->mb);
1283 debug_print("imap create run - end %i\n", r);
1286 int imap_threaded_create(Folder * folder, const char * mb)
1288 struct create_param param;
1289 struct create_result result;
1291 debug_print("imap create - begin\n");
1293 param.imap = get_imap(folder);
1296 threaded_run(folder, ¶m, &result, create_run);
1298 debug_print("imap create - end\n");
1300 return result.error;
1306 struct rename_param {
1309 const char * new_name;
1312 struct rename_result {
1316 static void rename_run(struct etpan_thread_op * op)
1318 struct rename_param * param;
1319 struct rename_result * result;
1323 result = op->result;
1327 r = mailimap_rename(param->imap, param->mb, param->new_name);
1330 debug_print("imap rename run - end %i\n", r);
1333 int imap_threaded_rename(Folder * folder,
1334 const char * mb, const char * new_name)
1336 struct rename_param param;
1337 struct rename_result result;
1339 debug_print("imap rename - begin\n");
1341 param.imap = get_imap(folder);
1343 param.new_name = new_name;
1345 threaded_run(folder, ¶m, &result, rename_run);
1347 debug_print("imap rename - end\n");
1349 return result.error;
1355 struct delete_param {
1360 struct delete_result {
1364 static void delete_run(struct etpan_thread_op * op)
1366 struct delete_param * param;
1367 struct delete_result * result;
1371 result = op->result;
1375 r = mailimap_delete(param->imap, param->mb);
1378 debug_print("imap delete run - end %i\n", r);
1381 int imap_threaded_delete(Folder * folder, const char * mb)
1383 struct delete_param param;
1384 struct delete_result result;
1386 debug_print("imap delete - begin\n");
1388 param.imap = get_imap(folder);
1391 threaded_run(folder, ¶m, &result, delete_run);
1393 debug_print("imap delete - end\n");
1395 return result.error;
1400 struct select_param {
1405 struct select_result {
1409 static void select_run(struct etpan_thread_op * op)
1411 struct select_param * param;
1412 struct select_result * result;
1416 result = op->result;
1420 r = mailimap_select(param->imap, param->mb);
1423 debug_print("imap select run - end %i\n", r);
1426 int imap_threaded_select(Folder * folder, const char * mb,
1427 gint * exists, gint * recent, gint * unseen,
1428 guint32 * uid_validity,gint *can_create_flags,
1431 struct select_param param;
1432 struct select_result result;
1435 debug_print("imap select - begin\n");
1437 imap = get_imap(folder);
1441 if (threaded_run(folder, ¶m, &result, select_run))
1442 return MAILIMAP_ERROR_INVAL;
1444 if (result.error != MAILIMAP_NO_ERROR)
1445 return result.error;
1447 if (!imap || imap->imap_selection_info == NULL)
1448 return MAILIMAP_ERROR_PARSE;
1450 * exists = imap->imap_selection_info->sel_exists;
1451 * recent = imap->imap_selection_info->sel_recent;
1452 * unseen = imap->imap_selection_info->sel_unseen;
1453 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1454 * can_create_flags = FALSE;
1456 if (imap->imap_selection_info->sel_perm_flags) {
1457 GSList *t_flags = NULL;
1458 clistiter *cur = NULL;
1459 if (imap->imap_selection_info->sel_perm_flags)
1460 cur = clist_begin(imap->imap_selection_info->sel_perm_flags);
1462 for (; cur; cur = clist_next(cur)) {
1463 struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur);
1464 if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL)
1465 *can_create_flags = TRUE;
1466 else if (flag->fl_flag &&
1467 flag->fl_flag->fl_type == 6 &&
1468 !strcmp(flag->fl_flag->fl_data.fl_extension, "*"))
1469 *can_create_flags = TRUE;
1470 if (flag->fl_flag && ok_flags) {
1471 MsgPermFlags c_flag = 0;
1472 switch (flag->fl_flag->fl_type) {
1473 case MAILIMAP_FLAG_ANSWERED:
1474 c_flag = IMAP_FLAG_ANSWERED;
1476 case MAILIMAP_FLAG_FLAGGED:
1477 c_flag = IMAP_FLAG_FLAGGED;
1479 case MAILIMAP_FLAG_DELETED:
1480 c_flag = IMAP_FLAG_DELETED;
1482 case MAILIMAP_FLAG_DRAFT:
1483 c_flag = IMAP_FLAG_DRAFT;
1485 case MAILIMAP_FLAG_SEEN:
1486 c_flag = IMAP_FLAG_SEEN;
1488 case MAILIMAP_FLAG_KEYWORD:
1489 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
1490 c_flag = IMAP_FLAG_FORWARDED;
1491 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
1492 c_flag = IMAP_FLAG_SPAM;
1493 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
1494 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
1495 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
1496 c_flag = IMAP_FLAG_HAM;
1502 t_flags = g_slist_prepend(t_flags,
1503 GUINT_TO_POINTER(c_flag));
1508 *ok_flags = t_flags;
1510 debug_print("imap select - end\n");
1512 return result.error;
1515 static void close_run(struct etpan_thread_op * op)
1517 struct select_param * param;
1518 struct select_result * result;
1522 result = op->result;
1526 r = mailimap_close(param->imap);
1529 debug_print("imap close run - end %i\n", r);
1532 int imap_threaded_close(Folder * folder)
1534 struct select_param param;
1535 struct select_result result;
1538 debug_print("imap close - begin\n");
1540 imap = get_imap(folder);
1543 threaded_run(folder, ¶m, &result, close_run);
1545 if (result.error != MAILIMAP_NO_ERROR)
1546 return result.error;
1548 debug_print("imap close - end\n");
1550 return result.error;
1553 struct examine_param {
1558 struct examine_result {
1562 static void examine_run(struct etpan_thread_op * op)
1564 struct examine_param * param;
1565 struct examine_result * result;
1569 result = op->result;
1573 r = mailimap_examine(param->imap, param->mb);
1576 debug_print("imap examine run - end %i\n", r);
1579 int imap_threaded_examine(Folder * folder, const char * mb,
1580 gint * exists, gint * recent, gint * unseen,
1581 guint32 * uid_validity)
1583 struct examine_param param;
1584 struct examine_result result;
1587 debug_print("imap examine - begin\n");
1589 imap = get_imap(folder);
1593 if (threaded_run(folder, ¶m, &result, examine_run))
1594 return MAILIMAP_ERROR_INVAL;
1596 if (result.error != MAILIMAP_NO_ERROR)
1597 return result.error;
1599 if (!imap || imap->imap_selection_info == NULL)
1600 return MAILIMAP_ERROR_PARSE;
1602 * exists = imap->imap_selection_info->sel_exists;
1603 * recent = imap->imap_selection_info->sel_recent;
1604 * unseen = imap->imap_selection_info->sel_unseen;
1605 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1607 debug_print("imap examine - end\n");
1609 return result.error;
1615 struct search_param {
1618 const char *charset;
1619 struct mailimap_set * set;
1623 struct search_result {
1625 clist * search_result;
1628 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1630 return mailimap_set_item_new(orig->set_first, orig->set_last);
1633 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1635 clist *list = orig ? orig->set_list : NULL;
1642 newlist = clist_new();
1646 for (cur = clist_begin(list); cur; cur = clist_next(cur)) {
1647 if (clist_append(newlist,
1648 sc_mailimap_set_item_copy(
1649 (struct mailimap_set_item *)clist_content(cur))) != 0) {
1650 clist_free(newlist);
1654 return mailimap_set_new(newlist);
1657 static void search_run(struct etpan_thread_op * op)
1659 struct search_param * param;
1660 struct search_result * result;
1662 struct mailimap_search_key * key = NULL;
1663 struct mailimap_search_key * uid_key = NULL;
1664 struct mailimap_search_key * search_type_key = NULL;
1665 clist * search_result;
1668 result = op->result;
1672 /* we copy the mailimap_set because freeing the key is recursive */
1673 if (param->set != NULL) {
1674 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1675 } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1676 uid_key = mailimap_search_key_new_all();
1678 switch (param->type) {
1679 case IMAP_SEARCH_TYPE_SIMPLE:
1680 search_type_key = NULL;
1682 case IMAP_SEARCH_TYPE_SEEN:
1683 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0);
1685 case IMAP_SEARCH_TYPE_UNSEEN:
1686 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0);
1688 case IMAP_SEARCH_TYPE_ANSWERED:
1689 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0);
1691 case IMAP_SEARCH_TYPE_FLAGGED:
1692 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0);
1694 case IMAP_SEARCH_TYPE_DELETED:
1695 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0);
1697 case IMAP_SEARCH_TYPE_FORWARDED:
1698 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0);
1700 case IMAP_SEARCH_TYPE_SPAM:
1701 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0);
1703 case IMAP_SEARCH_TYPE_KEYED:
1704 search_type_key = param->key;
1708 if (search_type_key != NULL) {
1709 if (param->set != NULL) {
1710 key = mailimap_search_key_new_multiple_empty();
1711 mailimap_search_key_multiple_add(key, search_type_key);
1712 mailimap_search_key_multiple_add(key, uid_key);
1714 key = search_type_key;
1716 } else if (uid_key != NULL) {
1721 g_warning("no key!");
1722 result = op->result;
1724 result->search_result = NULL;
1726 mailstream_logger = imap_logger_uid;
1728 r = mailimap_uid_search(param->imap, param->charset, key, &search_result);
1730 mailstream_logger = imap_logger_cmd;
1732 /* free the key (with the imapset) */
1733 mailimap_search_key_free(key);
1736 result->search_result = search_result;
1738 debug_print("imap search run - end %i\n", result->error);
1741 int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key,
1742 const char *charset, struct mailimap_set * set,
1743 clist ** search_result)
1745 struct search_param param;
1746 struct search_result result;
1749 debug_print("imap search - begin\n");
1751 imap = get_imap(folder);
1754 param.charset = charset;
1755 param.type = search_type;
1758 threaded_run(folder, ¶m, &result, search_run);
1760 if (result.error != MAILIMAP_NO_ERROR)
1761 return result.error;
1763 debug_print("imap search - end\n");
1765 * search_result = result.search_result;
1767 return result.error;
1771 struct _IMAPSearchKey {
1772 struct mailimap_search_key* key;
1775 IMAPSearchKey* imap_search_new(gint criteria,
1776 const gchar *header,
1780 char* sk_bcc = NULL;
1781 struct mailimap_date* sk_before = NULL;
1782 char* sk_body = NULL;
1784 char* sk_from = NULL;
1785 char* sk_keyword = NULL;
1786 struct mailimap_date* sk_on = NULL;
1787 struct mailimap_date* sk_since = NULL;
1788 char* sk_subject = NULL;
1789 char* sk_text = NULL;
1791 char* sk_unkeyword = NULL;
1792 char* sk_header_name = NULL;
1793 char* sk_header_value = NULL;
1794 uint32_t sk_larger = 0;
1795 struct mailimap_search_key* sk_not = NULL;
1796 struct mailimap_search_key* sk_or1 = NULL;
1797 struct mailimap_search_key* sk_or2 = NULL;
1798 struct mailimap_date* sk_sentbefore = NULL;
1799 struct mailimap_date* sk_senton = NULL;
1800 struct mailimap_date* sk_sentsince = NULL;
1801 uint32_t sk_smaller = 0;
1802 struct mailimap_set* sk_uid = NULL;
1803 struct mailimap_set* sk_set = NULL;
1804 clist* sk_multiple = NULL;
1805 int etpan_matcher_type;
1808 case IMAP_SEARCH_CRITERIA_ALL: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ALL; break;
1809 case IMAP_SEARCH_CRITERIA_READ: etpan_matcher_type = MAILIMAP_SEARCH_KEY_SEEN; break;
1810 case IMAP_SEARCH_CRITERIA_UNREAD: etpan_matcher_type = MAILIMAP_SEARCH_KEY_UNSEEN; break;
1811 case IMAP_SEARCH_CRITERIA_NEW: etpan_matcher_type = MAILIMAP_SEARCH_KEY_NEW; break;
1812 case IMAP_SEARCH_CRITERIA_MARKED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_FLAGGED; break;
1813 case IMAP_SEARCH_CRITERIA_REPLIED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ANSWERED; break;
1814 case IMAP_SEARCH_CRITERIA_DELETED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_DELETED; break;
1816 case IMAP_SEARCH_CRITERIA_TAG:
1817 sk_keyword = strdup(expr);
1818 etpan_matcher_type = MAILIMAP_SEARCH_KEY_KEYWORD;
1821 case IMAP_SEARCH_CRITERIA_SUBJECT:
1822 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SUBJECT;
1823 sk_subject = strdup(expr);
1826 case IMAP_SEARCH_CRITERIA_TO:
1827 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TO;
1828 sk_to = strdup(expr);
1831 case IMAP_SEARCH_CRITERIA_CC:
1832 etpan_matcher_type = MAILIMAP_SEARCH_KEY_CC;
1833 sk_cc = strdup(expr);
1836 case IMAP_SEARCH_CRITERIA_AGE_GREATER:
1837 case IMAP_SEARCH_CRITERIA_AGE_LOWER:
1840 time_t limit = time(NULL) - 60 * 60 * 24 * value;
1843 localtime_r(&limit, &tm);
1844 if (criteria == IMAP_SEARCH_CRITERIA_AGE_GREATER) {
1845 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTBEFORE;
1846 sk_sentbefore = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1848 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTSINCE;
1849 sk_sentsince = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1854 case IMAP_SEARCH_CRITERIA_BODY:
1855 etpan_matcher_type = MAILIMAP_SEARCH_KEY_BODY;
1856 sk_body = strdup(expr);
1859 case IMAP_SEARCH_CRITERIA_MESSAGE:
1860 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TEXT;
1861 sk_text = strdup(expr);
1864 case IMAP_SEARCH_CRITERIA_HEADER:
1865 etpan_matcher_type = MAILIMAP_SEARCH_KEY_HEADER;
1866 sk_header_name = strdup(header);
1867 sk_header_value = strdup(expr);
1870 case IMAP_SEARCH_CRITERIA_FROM:
1871 etpan_matcher_type = MAILIMAP_SEARCH_KEY_FROM;
1872 sk_from = strdup(expr);
1875 case IMAP_SEARCH_CRITERIA_SIZE_GREATER:
1876 etpan_matcher_type = MAILIMAP_SEARCH_KEY_LARGER;
1880 case IMAP_SEARCH_CRITERIA_SIZE_SMALLER:
1881 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SMALLER;
1889 return mailimap_search_key_new(etpan_matcher_type,
1890 sk_bcc, sk_before, sk_body, sk_cc, sk_from, sk_keyword,
1891 sk_on, sk_since, sk_subject, sk_text, sk_to,
1892 sk_unkeyword, sk_header_name,sk_header_value, sk_larger,
1893 sk_not, sk_or1, sk_or2, sk_sentbefore, sk_senton,
1894 sk_sentsince, sk_smaller, sk_uid, sk_set, sk_multiple);
1897 IMAPSearchKey* imap_search_not(IMAPSearchKey* key)
1899 return mailimap_search_key_new_not(key);
1902 IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r)
1904 return mailimap_search_key_new_or(l, r);
1907 IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r)
1909 IMAPSearchKey* result = mailimap_search_key_new_multiple_empty();
1910 mailimap_search_key_multiple_add(result, l);
1911 mailimap_search_key_multiple_add(result, r);
1916 void imap_search_free(IMAPSearchKey* key)
1921 mailimap_search_key_free(key);
1926 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1930 struct mailimap_msg_att_dynamic ** patt_dyn);
1933 result_to_uid_list(clist * fetch_result, carray ** result)
1935 clistiter * cur = NULL;
1940 tab = carray_new(128);
1942 res = MAILIMAP_ERROR_MEMORY;
1947 cur = clist_begin(fetch_result);
1949 for(; cur != NULL ; cur = clist_next(cur)) {
1950 struct mailimap_msg_att * msg_att;
1954 msg_att = clist_content(cur);
1957 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL);
1959 puid = malloc(sizeof(* puid));
1961 res = MAILIMAP_ERROR_MEMORY;
1966 r = carray_add(tab, puid, NULL);
1969 res = MAILIMAP_ERROR_MEMORY;
1976 return MAILIMAP_NO_ERROR;
1979 imap_fetch_uid_list_free(tab);
1984 static int imap_get_messages_list(mailimap * imap,
1985 uint32_t first_index,
1990 struct mailimap_fetch_att * fetch_att;
1991 struct mailimap_fetch_type * fetch_type;
1992 struct mailimap_set * set;
1993 clist * fetch_result;
1996 set = mailimap_set_new_interval(first_index, 0);
1998 res = MAILIMAP_ERROR_MEMORY;
2002 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2003 if (fetch_type == NULL) {
2004 res = MAILIMAP_ERROR_MEMORY;
2008 fetch_att = mailimap_fetch_att_new_uid();
2009 if (fetch_att == NULL) {
2010 res = MAILIMAP_ERROR_MEMORY;
2011 goto free_fetch_type;
2014 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2015 if (r != MAILIMAP_NO_ERROR) {
2016 mailimap_fetch_att_free(fetch_att);
2017 res = MAILIMAP_ERROR_MEMORY;
2018 goto free_fetch_type;
2021 mailstream_logger = imap_logger_fetch;
2023 r = mailimap_uid_fetch(imap, set,
2024 fetch_type, &fetch_result);
2026 mailstream_logger = imap_logger_cmd;
2027 mailimap_fetch_type_free(fetch_type);
2028 mailimap_set_free(set);
2030 if (r != MAILIMAP_NO_ERROR) {
2036 r = result_to_uid_list(fetch_result, &env_list);
2037 mailimap_fetch_list_free(fetch_result);
2039 * result = env_list;
2041 return MAILIMAP_NO_ERROR;
2044 mailimap_fetch_type_free(fetch_type);
2046 mailimap_set_free(set);
2054 struct fetch_uid_param {
2056 uint32_t first_index;
2059 struct fetch_uid_result {
2061 carray * fetch_result;
2064 static void fetch_uid_run(struct etpan_thread_op * op)
2066 struct fetch_uid_param * param;
2067 struct fetch_uid_result * result;
2068 carray * fetch_result;
2072 result = op->result;
2076 fetch_result = NULL;
2077 mailstream_logger = imap_logger_noop;
2078 log_print(LOG_PROTOCOL, "IMAP- [fetching UIDs...]\n");
2080 r = imap_get_messages_list(param->imap, param->first_index,
2083 mailstream_logger = imap_logger_cmd;
2086 result->fetch_result = fetch_result;
2087 debug_print("imap fetch_uid run - end %i\n", r);
2090 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
2091 carray ** fetch_result)
2093 struct fetch_uid_param param;
2094 struct fetch_uid_result result;
2097 debug_print("imap fetch_uid - begin\n");
2099 imap = get_imap(folder);
2101 param.first_index = first_index;
2103 threaded_run(folder, ¶m, &result, fetch_uid_run);
2105 if (result.error != MAILIMAP_NO_ERROR)
2106 return result.error;
2108 debug_print("imap fetch_uid - end\n");
2110 * fetch_result = result.fetch_result;
2112 return result.error;
2116 void imap_fetch_uid_list_free(carray * uid_list)
2120 for(i = 0 ; i < carray_count(uid_list) ; i ++) {
2123 puid = carray_get(uid_list, i);
2126 carray_free(uid_list);
2132 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags);
2135 result_to_uid_flags_list(clist * fetch_result, carray ** result)
2137 clistiter * cur = NULL;
2141 GSList *tags = NULL;
2143 tab = carray_new(128);
2145 res = MAILIMAP_ERROR_MEMORY;
2150 cur = clist_begin(fetch_result);
2152 for(; cur != NULL ; cur = clist_next(cur)) {
2153 struct mailimap_msg_att * msg_att;
2156 struct mailimap_msg_att_dynamic * att_dyn;
2162 msg_att = clist_content(cur);
2166 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn);
2169 if (att_dyn == NULL)
2172 flags = imap_flags_to_flags(att_dyn, &tags);
2174 puid = malloc(sizeof(* puid));
2176 res = MAILIMAP_ERROR_MEMORY;
2181 r = carray_add(tab, puid, NULL);
2184 res = MAILIMAP_ERROR_MEMORY;
2187 pflags = malloc(sizeof(* pflags));
2188 if (pflags == NULL) {
2189 res = MAILIMAP_ERROR_MEMORY;
2193 r = carray_add(tab, pflags, NULL);
2196 res = MAILIMAP_ERROR_MEMORY;
2199 r = carray_add(tab, tags, NULL);
2202 res = MAILIMAP_ERROR_MEMORY;
2209 return MAILIMAP_NO_ERROR;
2212 imap_fetch_uid_flags_list_free(tab);
2213 slist_free_strings_full(tags);
2218 static int imap_get_messages_flags_list(mailimap * imap,
2219 uint32_t first_index,
2224 struct mailimap_fetch_att * fetch_att;
2225 struct mailimap_fetch_type * fetch_type;
2226 struct mailimap_set * set;
2227 clist * fetch_result;
2230 set = mailimap_set_new_interval(first_index, 0);
2232 res = MAILIMAP_ERROR_MEMORY;
2236 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2237 if (fetch_type == NULL) {
2238 res = MAILIMAP_ERROR_MEMORY;
2242 fetch_att = mailimap_fetch_att_new_flags();
2243 if (fetch_att == NULL) {
2244 res = MAILIMAP_ERROR_MEMORY;
2245 goto free_fetch_type;
2248 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2249 if (r != MAILIMAP_NO_ERROR) {
2250 mailimap_fetch_att_free(fetch_att);
2251 res = MAILIMAP_ERROR_MEMORY;
2252 goto free_fetch_type;
2255 fetch_att = mailimap_fetch_att_new_uid();
2256 if (fetch_att == NULL) {
2257 res = MAILIMAP_ERROR_MEMORY;
2258 goto free_fetch_type;
2261 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2262 if (r != MAILIMAP_NO_ERROR) {
2263 mailimap_fetch_att_free(fetch_att);
2264 res = MAILIMAP_ERROR_MEMORY;
2265 goto free_fetch_type;
2268 mailstream_logger = imap_logger_fetch;
2270 r = mailimap_uid_fetch(imap, set,
2271 fetch_type, &fetch_result);
2273 mailstream_logger = imap_logger_cmd;
2274 mailimap_fetch_type_free(fetch_type);
2275 mailimap_set_free(set);
2277 if (r != MAILIMAP_NO_ERROR) {
2283 r = result_to_uid_flags_list(fetch_result, &env_list);
2284 mailimap_fetch_list_free(fetch_result);
2286 * result = env_list;
2288 return MAILIMAP_NO_ERROR;
2291 mailimap_fetch_type_free(fetch_type);
2293 mailimap_set_free(set);
2300 static void fetch_uid_flags_run(struct etpan_thread_op * op)
2302 struct fetch_uid_param * param;
2303 struct fetch_uid_result * result;
2304 carray * fetch_result;
2308 result = op->result;
2312 fetch_result = NULL;
2313 r = imap_get_messages_flags_list(param->imap, param->first_index,
2317 result->fetch_result = fetch_result;
2318 debug_print("imap fetch_uid run - end %i\n", r);
2321 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index,
2322 carray ** fetch_result)
2324 struct fetch_uid_param param;
2325 struct fetch_uid_result result;
2328 debug_print("imap fetch_uid - begin\n");
2330 imap = get_imap(folder);
2332 param.first_index = first_index;
2334 mailstream_logger = imap_logger_noop;
2335 log_print(LOG_PROTOCOL, "IMAP- [fetching flags...]\n");
2337 threaded_run(folder, ¶m, &result, fetch_uid_flags_run);
2339 mailstream_logger = imap_logger_cmd;
2342 if (result.error != MAILIMAP_NO_ERROR)
2343 return result.error;
2345 debug_print("imap fetch_uid - end\n");
2347 * fetch_result = result.fetch_result;
2349 return result.error;
2353 void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
2357 for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) {
2360 data = carray_get(uid_flags_list, i);
2362 data = carray_get(uid_flags_list, i + 1);
2365 carray_free(uid_flags_list);
2370 static int imap_fetch(mailimap * imap,
2373 size_t * result_len)
2376 struct mailimap_set * set;
2377 struct mailimap_fetch_att * fetch_att;
2378 struct mailimap_fetch_type * fetch_type;
2379 clist * fetch_result;
2380 struct mailimap_msg_att * msg_att;
2381 struct mailimap_msg_att_item * msg_att_item;
2386 struct mailimap_section * section;
2388 set = mailimap_set_new_single(msg_index);
2390 res = MAILIMAP_ERROR_MEMORY;
2394 section = mailimap_section_new(NULL);
2395 if (section == NULL) {
2396 res = MAILIMAP_ERROR_MEMORY;
2400 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2401 if (fetch_att == NULL) {
2402 mailimap_section_free(section);
2403 res = MAILIMAP_ERROR_MEMORY;
2407 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2408 if (fetch_type == NULL) {
2409 res = MAILIMAP_ERROR_MEMORY;
2410 goto free_fetch_att;
2413 mailstream_logger = imap_logger_fetch;
2415 r = mailimap_uid_fetch(imap, set,
2416 fetch_type, &fetch_result);
2418 mailstream_logger = imap_logger_cmd;
2420 mailimap_fetch_type_free(fetch_type);
2421 mailimap_set_free(set);
2424 case MAILIMAP_NO_ERROR:
2430 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2431 mailimap_fetch_list_free(fetch_result);
2432 return MAILIMAP_ERROR_FETCH;
2435 msg_att = clist_begin(fetch_result)->data;
2440 if (msg_att->att_list)
2441 cur = clist_begin(msg_att->att_list);
2445 for(; cur != NULL ; cur = clist_next(cur)) {
2446 msg_att_item = clist_content(cur);
2448 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2449 if (msg_att_item->att_data.att_static->att_type ==
2450 MAILIMAP_MSG_ATT_BODY_SECTION) {
2451 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2453 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2455 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2460 mailimap_fetch_list_free(fetch_result);
2463 return MAILIMAP_ERROR_FETCH;
2466 * result_len = text_length;
2468 return MAILIMAP_NO_ERROR;
2471 mailimap_fetch_att_free(fetch_att);
2473 mailimap_set_free(set);
2478 static int imap_fetch_header(mailimap * imap,
2481 size_t * result_len)
2484 struct mailimap_set * set;
2485 struct mailimap_fetch_att * fetch_att;
2486 struct mailimap_fetch_type * fetch_type;
2487 clist * fetch_result;
2488 struct mailimap_msg_att * msg_att;
2489 struct mailimap_msg_att_item * msg_att_item;
2494 struct mailimap_section * section;
2496 set = mailimap_set_new_single(msg_index);
2498 res = MAILIMAP_ERROR_MEMORY;
2502 section = mailimap_section_new_header();
2503 if (section == NULL) {
2504 res = MAILIMAP_ERROR_MEMORY;
2508 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2509 if (fetch_att == NULL) {
2510 mailimap_section_free(section);
2511 res = MAILIMAP_ERROR_MEMORY;
2515 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2516 if (fetch_type == NULL) {
2517 res = MAILIMAP_ERROR_MEMORY;
2518 goto free_fetch_att;
2521 mailstream_logger = imap_logger_fetch;
2523 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2525 mailstream_logger = imap_logger_cmd;
2526 mailimap_fetch_type_free(fetch_type);
2527 mailimap_set_free(set);
2530 case MAILIMAP_NO_ERROR:
2536 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2537 mailimap_fetch_list_free(fetch_result);
2538 return MAILIMAP_ERROR_FETCH;
2541 msg_att = clist_begin(fetch_result)->data;
2546 if (msg_att->att_list)
2547 cur = clist_begin(msg_att->att_list);
2551 for(; cur != NULL ; cur = clist_next(cur)) {
2552 msg_att_item = clist_content(cur);
2554 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2555 if (msg_att_item->att_data.att_static->att_type ==
2556 MAILIMAP_MSG_ATT_BODY_SECTION) {
2557 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2558 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2560 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2565 mailimap_fetch_list_free(fetch_result);
2568 return MAILIMAP_ERROR_FETCH;
2571 * result_len = text_length;
2573 return MAILIMAP_NO_ERROR;
2576 mailimap_fetch_att_free(fetch_att);
2578 mailimap_set_free(set);
2585 struct fetch_content_param {
2588 const char * filename;
2592 struct fetch_content_result {
2596 static void fetch_content_run(struct etpan_thread_op * op)
2598 struct fetch_content_param * param;
2599 struct fetch_content_result * result;
2601 size_t content_size;
2607 result = op->result;
2613 if (param->with_body)
2614 r = imap_fetch(param->imap, param->msg_index,
2615 &content, &content_size);
2617 r = imap_fetch_header(param->imap, param->msg_index,
2618 &content, &content_size);
2622 if (r == MAILIMAP_NO_ERROR) {
2623 fd = g_open(param->filename, O_RDWR | O_CREAT, 0600);
2625 result->error = MAILIMAP_ERROR_FETCH;
2629 f = fdopen(fd, "wb");
2631 result->error = MAILIMAP_ERROR_FETCH;
2635 r = fwrite(content, 1, content_size, f);
2636 if (r < content_size) {
2637 result->error = MAILIMAP_ERROR_FETCH;
2643 result->error = MAILIMAP_ERROR_FETCH;
2654 claws_unlink(param->filename);
2657 /* mmap_string_unref is a simple free in libetpan
2658 * when it has MMAP_UNAVAILABLE defined */
2659 if (mmap_string_unref(content) != 0)
2663 debug_print("imap fetch_content run - end %i\n", result->error);
2666 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2668 const char * filename)
2670 struct fetch_content_param param;
2671 struct fetch_content_result result;
2674 debug_print("imap fetch_content - begin\n");
2676 imap = get_imap(folder);
2678 param.msg_index = msg_index;
2679 param.filename = filename;
2680 param.with_body = with_body;
2682 threaded_run(folder, ¶m, &result, fetch_content_run);
2684 if (result.error != MAILIMAP_NO_ERROR)
2685 return result.error;
2687 debug_print("imap fetch_content - end\n");
2689 return result.error;
2694 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags)
2699 GSList *tags = NULL;
2703 flag_list = att_dyn->att_list;
2704 if (flag_list == NULL)
2707 for(cur = clist_begin(flag_list) ; cur != NULL ;
2708 cur = clist_next(cur)) {
2709 struct mailimap_flag_fetch * flag_fetch;
2711 flag_fetch = clist_content(cur);
2712 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2715 switch (flag_fetch->fl_flag->fl_type) {
2716 case MAILIMAP_FLAG_ANSWERED:
2717 flags |= MSG_REPLIED;
2719 case MAILIMAP_FLAG_FLAGGED:
2720 flags |= MSG_MARKED;
2722 case MAILIMAP_FLAG_DELETED:
2723 flags |= MSG_DELETED;
2725 case MAILIMAP_FLAG_SEEN:
2726 flags &= ~MSG_UNREAD;
2729 case MAILIMAP_FLAG_KEYWORD:
2730 if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
2731 flags |= MSG_FORWARDED;
2732 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
2734 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
2735 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
2736 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
2739 tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword));
2749 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2753 struct mailimap_msg_att_dynamic ** patt_dyn)
2755 clistiter * item_cur;
2759 struct mailimap_msg_att_dynamic * att_dyn;
2766 if (msg_att->att_list)
2767 item_cur = clist_begin(msg_att->att_list);
2770 for(; item_cur != NULL ; item_cur = clist_next(item_cur)) {
2771 struct mailimap_msg_att_item * item;
2773 item = clist_content(item_cur);
2775 switch (item->att_type) {
2776 case MAILIMAP_MSG_ATT_ITEM_STATIC:
2777 switch (item->att_data.att_static->att_type) {
2778 case MAILIMAP_MSG_ATT_UID:
2779 uid = item->att_data.att_static->att_data.att_uid;
2782 case MAILIMAP_MSG_ATT_BODY_SECTION:
2783 if (headers == NULL) {
2784 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2787 case MAILIMAP_MSG_ATT_RFC822_SIZE:
2788 ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2793 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2794 if (att_dyn == NULL) {
2795 att_dyn = item->att_data.att_dyn;
2803 if (pheaders != NULL)
2804 * pheaders = headers;
2805 if (pref_size != NULL)
2806 * pref_size = ref_size;
2807 if (patt_dyn != NULL)
2808 * patt_dyn = att_dyn;
2810 return MAIL_NO_ERROR;
2813 static struct imap_fetch_env_info *
2814 fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags)
2816 struct imap_fetch_env_info * info;
2820 struct mailimap_msg_att_dynamic * att_dyn;
2822 imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2827 info = malloc(sizeof(* info));
2829 info->headers = strdup(headers);
2831 info->flags = imap_flags_to_flags(att_dyn, tags);
2837 imap_fetch_result_to_envelop_list(clist * fetch_result,
2838 carray ** p_env_list)
2844 env_list = carray_new(16);
2846 for(cur = clist_begin(fetch_result) ; cur != NULL ;
2847 cur = clist_next(cur)) {
2848 struct mailimap_msg_att * msg_att;
2849 struct imap_fetch_env_info * env_info;
2850 GSList *tags = NULL;
2852 msg_att = clist_content(cur);
2854 env_info = fetch_to_env_info(msg_att, &tags);
2856 || carray_add(env_list, env_info, NULL) != 0
2857 || carray_add(env_list, tags, NULL) != 0) {
2858 carray_free(env_list);
2859 return MAILIMAP_ERROR_MEMORY;
2862 * p_env_list = env_list;
2864 * p_env_list = NULL;
2867 return MAIL_NO_ERROR;
2870 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2872 struct mailimap_fetch_att * fetch_att;
2876 struct mailimap_header_list * imap_hdrlist;
2877 struct mailimap_section * section;
2879 "Date", "From", "To", "Cc", "Subject", "Message-ID",
2880 "References", "In-Reply-To", NULL
2883 hdrlist = clist_new();
2885 return MAIL_ERROR_MEMORY;
2887 while (headers[i] != NULL) {
2888 header = strdup(headers[i]);
2889 if (header == NULL || clist_append(hdrlist, header) != 0) {
2890 clist_free(hdrlist);
2891 return MAIL_ERROR_MEMORY;
2896 imap_hdrlist = mailimap_header_list_new(hdrlist);
2897 section = mailimap_section_new_header_fields(imap_hdrlist);
2898 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2899 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2901 return MAIL_NO_ERROR;
2904 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2906 struct mailimap_fetch_att * fetch_att;
2907 struct mailimap_section * section;
2909 section = mailimap_section_new_header();
2910 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2911 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2913 return MAIL_NO_ERROR;
2917 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2918 carray ** p_env_list)
2920 struct mailimap_fetch_att * fetch_att;
2921 struct mailimap_fetch_type * fetch_type;
2923 clist * fetch_result;
2925 carray * env_list = NULL;
2929 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2932 fetch_att = mailimap_fetch_att_new_uid();
2933 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2936 fetch_att = mailimap_fetch_att_new_flags();
2937 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2940 fetch_att = mailimap_fetch_att_new_rfc822_size();
2941 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2945 key.len = sizeof(imap);
2946 r = chash_get(courier_workaround_hash, &key, &value);
2948 r = imap_add_envelope_fetch_att(fetch_type);
2950 r = imap_add_header_fetch_att(fetch_type);
2952 if (r != MAILIMAP_NO_ERROR) {
2953 debug_print("add fetch attr: %d\n", r);
2957 mailstream_logger = imap_logger_fetch;
2959 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2961 mailstream_logger = imap_logger_cmd;
2963 case MAILIMAP_NO_ERROR:
2966 mailimap_fetch_type_free(fetch_type);
2967 debug_print("uid_fetch: %d\n", r);
2971 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2972 res = MAILIMAP_ERROR_FETCH;
2973 debug_print("clist_begin = NULL\n");
2977 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2978 mailimap_fetch_list_free(fetch_result);
2980 if (r != MAILIMAP_NO_ERROR) {
2981 mailimap_fetch_type_free(fetch_type);
2982 res = MAILIMAP_ERROR_MEMORY;
2983 debug_print("fetch_result_to_envelop_list: %d\n", res);
2987 mailimap_fetch_type_free(fetch_type);
2989 * p_env_list = env_list;
2991 return MAILIMAP_NO_ERROR;
2997 struct fetch_env_param {
2999 struct mailimap_set * set;
3002 struct fetch_env_result {
3003 carray * fetch_env_result;
3007 static void fetch_env_run(struct etpan_thread_op * op)
3009 struct fetch_env_param * param;
3010 struct fetch_env_result * result;
3015 result = op->result;
3020 r = imap_get_envelopes_list(param->imap, param->set,
3024 result->fetch_env_result = env_list;
3026 debug_print("imap fetch_env run - end %i\n", r);
3029 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
3030 carray ** p_env_list)
3032 struct fetch_env_param param;
3033 struct fetch_env_result result;
3036 debug_print("imap fetch_env - begin\n");
3038 imap = get_imap(folder);
3042 if (threaded_run(folder, ¶m, &result, fetch_env_run))
3043 return MAILIMAP_ERROR_INVAL;
3045 if (result.error != MAILIMAP_NO_ERROR) {
3051 key.len = sizeof(imap);
3052 r = chash_get(courier_workaround_hash, &key, &value);
3056 chash_set(courier_workaround_hash, &key, &value, NULL);
3058 threaded_run(folder, ¶m, &result, fetch_env_run);
3062 if (result.error != MAILIMAP_NO_ERROR)
3063 return result.error;
3065 debug_print("imap fetch_env - end\n");
3067 * p_env_list = result.fetch_env_result;
3069 return result.error;
3072 void imap_fetch_env_free(carray * env_list)
3076 for(i = 0 ; i < carray_count(env_list) ; i += 2) {
3077 struct imap_fetch_env_info * env_info;
3079 env_info = carray_get(env_list, i);
3080 free(env_info->headers);
3083 carray_free(env_list);
3090 struct append_param {
3092 const char * mailbox;
3093 const char * filename;
3094 struct mailimap_flag_list * flag_list;
3097 struct append_result {
3102 static void append_run(struct etpan_thread_op * op)
3104 struct append_param * param;
3105 struct append_result * result;
3110 struct stat stat_buf;
3113 guint32 uid = 0, val = 0;
3116 result = op->result;
3121 r = stat(param->filename, &stat_buf);
3123 result->error = MAILIMAP_ERROR_APPEND;
3126 size = stat_buf.st_size;
3128 fd = g_open(param->filename, O_RDONLY, 0);
3130 result->error = MAILIMAP_ERROR_APPEND;
3134 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
3135 if (data == (void *) MAP_FAILED) {
3137 result->error = MAILIMAP_ERROR_APPEND;
3141 data = file_read_to_str_no_recode(param->filename);
3143 result->error = MAILIMAP_ERROR_APPEND;
3146 size = strlen(data);
3148 mailstream_logger = imap_logger_append;
3150 r = mailimap_uidplus_append(param->imap, param->mailbox,
3151 param->flag_list, NULL,
3152 data, size, &val, &uid);
3154 mailstream_logger = imap_logger_cmd;
3165 debug_print("imap append run - end %i uid %d\n", r, uid);
3168 int imap_threaded_append(Folder * folder, const char * mailbox,
3169 const char * filename,
3170 struct mailimap_flag_list * flag_list,
3173 struct append_param param;
3174 struct append_result result;
3177 debug_print("imap append - begin\n");
3179 imap = get_imap(folder);
3181 param.mailbox = mailbox;
3182 param.filename = filename;
3183 param.flag_list = flag_list;
3185 threaded_run(folder, ¶m, &result, append_run);
3187 if (result.error != MAILIMAP_NO_ERROR)
3188 return result.error;
3190 debug_print("imap append - end\n");
3194 return result.error;
3200 struct expunge_param {
3204 struct expunge_result {
3208 static void expunge_run(struct etpan_thread_op * op)
3210 struct expunge_param * param;
3211 struct expunge_result * result;
3215 result = op->result;
3219 r = mailimap_expunge(param->imap);
3222 debug_print("imap expunge run - end %i\n", r);
3225 int imap_threaded_expunge(Folder * folder)
3227 struct expunge_param param;
3228 struct expunge_result result;
3230 debug_print("imap expunge - begin\n");
3232 param.imap = get_imap(folder);
3234 threaded_run(folder, ¶m, &result, expunge_run);
3236 debug_print("imap expunge - end\n");
3238 return result.error;
3244 struct mailimap_set * set;
3248 struct copy_result {
3250 struct mailimap_set *source;
3251 struct mailimap_set *dest;
3254 static void copy_run(struct etpan_thread_op * op)
3256 struct copy_param * param;
3257 struct copy_result * result;
3260 struct mailimap_set *source = NULL, *dest = NULL;
3263 result = op->result;
3267 r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
3268 &val, &source, &dest);
3272 result->source = source;
3273 result->dest = dest;
3275 result->source = NULL;
3276 result->dest = NULL;
3278 debug_print("imap copy run - end %i\n", r);
3281 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
3282 const char * mb, struct mailimap_set **source,
3283 struct mailimap_set **dest)
3285 struct copy_param param;
3286 struct copy_result result;
3289 debug_print("imap copy - begin\n");
3291 imap = get_imap(folder);
3296 threaded_run(folder, ¶m, &result, copy_run);
3300 if (result.error != MAILIMAP_NO_ERROR)
3301 return result.error;
3303 *source = result.source;
3304 *dest = result.dest;
3306 debug_print("imap copy - end\n");
3308 return result.error;
3313 struct store_param {
3315 struct mailimap_set * set;
3316 struct mailimap_store_att_flags * store_att_flags;
3319 struct store_result {
3323 static void store_run(struct etpan_thread_op * op)
3325 struct store_param * param;
3326 struct store_result * result;
3330 result = op->result;
3334 r = mailimap_uid_store(param->imap, param->set,
3335 param->store_att_flags);
3339 debug_print("imap store run - end %i\n", r);
3342 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
3343 struct mailimap_store_att_flags * store_att_flags)
3345 struct store_param param;
3346 struct store_result result;
3349 debug_print("imap store - begin\n");
3351 imap = get_imap(folder);
3354 param.store_att_flags = store_att_flags;
3356 threaded_run(folder, ¶m, &result, store_run);
3358 if (result.error != MAILIMAP_NO_ERROR)
3359 return result.error;
3361 debug_print("imap store - end\n");
3363 return result.error;
3367 #define ENV_BUFFER_SIZE 512
3369 static void do_exec_command(int fd, const char * command,
3370 const char * servername, uint16_t port)
3374 char env_buffer[ENV_BUFFER_SIZE];
3378 /* Fork again to become a child of init rather than
3379 the etpan client. */
3384 g_setenv("ETPANSERVER", servername, TRUE);
3386 g_unsetenv("ETPANSERVER");
3391 snprintf(porttext, sizeof(porttext), "%d", port);
3392 g_setenv("ETPANPORT", porttext, TRUE);
3395 g_unsetenv("ETPANPORT");
3398 /* Not a lot we can do if there's an error other than bail. */
3399 if (dup2(fd, 0) == -1)
3401 if (dup2(fd, 1) == -1)
3404 /* Should we close stderr and reopen /dev/null? */
3406 maxopen = sysconf(_SC_OPEN_MAX);
3407 for (i=3; i < maxopen; i++)
3411 /* Detach from the controlling tty if we have one. Otherwise,
3412 SSH might do something stupid like trying to use it instead
3413 of running $SSH_ASKPASS. Doh. */
3414 fd = g_open("/dev/tty", O_RDONLY, 0);
3416 ioctl(fd, TIOCNOTTY, NULL);
3419 #endif /* TIOCNOTTY */
3421 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
3423 /* Eep. Shouldn't reach this */
3427 static int subcommand_connect(const char *command,
3428 const char *servername, uint16_t port)
3430 /* SEB unsupported on Windows */
3434 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
3439 do_exec_command(sockfds[1], command, servername, port);
3441 else if (childpid == -1) {
3449 /* Reap child, leaving grandchild process to run */
3450 waitpid(childpid, NULL, 0);
3455 static int socket_connect_cmd(mailimap * imap, const char * command,
3456 const char * server, int port)
3462 fd = subcommand_connect(command, server, port);
3464 return MAILIMAP_ERROR_STREAM;
3466 s = mailstream_socket_open(fd);
3469 return MAILIMAP_ERROR_STREAM;
3472 r = mailimap_connect(imap, s);
3473 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
3474 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
3475 mailstream_close(s);
3477 imap->imap_stream = NULL;
3486 struct connect_cmd_param {
3488 const char * command;
3489 const char * server;
3493 struct connect_cmd_result {
3497 static void connect_cmd_run(struct etpan_thread_op * op)
3500 struct connect_cmd_param * param;
3501 struct connect_cmd_result * result;
3504 result = op->result;
3508 r = socket_connect_cmd(param->imap, param->command,
3509 param->server, param->port);
3515 int imap_threaded_connect_cmd(Folder * folder, const char * command,
3516 const char * server, int port)
3518 struct connect_cmd_param param;
3519 struct connect_cmd_result result;
3522 mailimap * imap, * oldimap;
3524 oldimap = get_imap(folder);
3526 imap = mailimap_new(0, NULL);
3529 debug_print("deleting old imap %p\n", oldimap);
3530 delete_imap(folder, oldimap);
3534 key.len = sizeof(folder);
3537 chash_set(session_hash, &key, &value, NULL);
3540 param.command = command;
3541 param.server = server;
3544 threaded_run(folder, ¶m, &result, connect_cmd_run);
3546 debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
3548 return result.error;
3550 #endif /* G_OS_WIN32 */
3552 void imap_threaded_cancel(Folder * folder)
3556 imap = get_imap(folder);
3557 if (imap->imap_stream != NULL)
3558 mailstream_cancel(imap->imap_stream);
3563 void imap_main_init(void)
3566 void imap_main_done(gboolean have_connectivity)
3569 void imap_main_set_timeout(int sec)
3573 void imap_threaded_cancel(Folder * folder);