Remove wrong initialization from max_message_size
[claws.git] / src / etpan / imap-thread.c
blob86168d74da5dd909039c32c25e8bed1c20f3d6bf
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2005-2022 the Claws Mail team and DINH Viet Hoa
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/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
24 #ifdef HAVE_LIBETPAN
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include "imap-thread.h"
29 #include <imap.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__))
33 #include <sys/socket.h>
34 #endif
35 #include <fcntl.h>
36 #ifndef G_OS_WIN32
37 #include <sys/mman.h>
38 #include <sys/wait.h>
39 #endif
40 #include <gtk/gtk.h>
41 #include <log.h>
42 #include "etpan-thread-manager.h"
43 #include "etpan-ssl.h"
44 #include "utils.h"
45 #include "mainwindow.h"
46 #include "proxy.h"
47 #include "file-utils.h"
48 #include "ssl.h"
49 #include "ssl_certificate.h"
50 #include "socket.h"
51 #include "remotefolder.h"
52 #include "tags.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)
66 SockInfo * sock;
67 mailstream * stream;
69 if (!proxy_info)
70 return mailimap_socket_connect(imap, server, port);
72 if (port == 0)
73 port = 143;
75 sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
77 if (sock == NULL)
78 return MAILIMAP_ERROR_CONNECTION_REFUSED;
80 if (proxy_connect(sock, server, port, proxy_info) < 0) {
81 sock_close(sock, TRUE);
82 return MAILIMAP_ERROR_CONNECTION_REFUSED;
85 stream = mailstream_socket_open_timeout(sock->sock,
86 imap->imap_timeout);
87 if (stream == NULL) {
88 sock_close(sock, TRUE);
89 return MAILIMAP_ERROR_MEMORY;
92 /* Libetpan now has the socket fd, and we're not interested in
93 * rest of the SockInfo struct. Let's free it, while not touching
94 * the socket itself. */
95 sock_close(sock, FALSE);
97 return mailimap_connect(imap, stream);
100 #ifdef USE_GNUTLS
101 static int do_mailimap_ssl_connect_with_callback(mailimap * imap, const char * server,
102 gushort port,
103 void (* callback)(struct mailstream_ssl_context * ssl_context, void * data),
104 void * data,
105 ProxyInfo *proxy_info)
107 SockInfo * sock;
108 mailstream * stream;
110 if (!proxy_info)
111 return mailimap_ssl_connect_with_callback(imap, server,
112 port, callback, data);
114 if (port == 0)
115 port = 993;
117 sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
119 if (sock == NULL) {
120 debug_print("Can not connect to proxy %s:%d\n",
121 proxy_info->proxy_host, proxy_info->proxy_port);
122 return MAILIMAP_ERROR_CONNECTION_REFUSED;
125 if (proxy_connect(sock, server, port, proxy_info) < 0) {
126 debug_print("Can not make proxy connection via %s:%d\n",
127 proxy_info->proxy_host, proxy_info->proxy_port);
128 sock_close(sock, TRUE);
129 return MAILIMAP_ERROR_CONNECTION_REFUSED;
132 stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
133 imap->imap_timeout, callback, data);
134 if (stream == NULL) {
135 sock_close(sock, TRUE);
136 return MAILIMAP_ERROR_SSL;
139 /* Libetpan now has the socket fd, and we're not interested in
140 * rest of the SockInfo struct. Let's free it, while not touching
141 * the socket itself. */
142 sock_close(sock, FALSE);
144 return mailimap_connect(imap, stream);
146 #endif
148 static gboolean thread_manager_event(GIOChannel * source,
149 GIOCondition condition,
150 gpointer data)
152 #ifdef G_OS_WIN32
153 gsize bytes_read;
154 gchar ch;
156 if (condition & G_IO_IN)
157 g_io_channel_read_chars(source, &ch, 1, &bytes_read, NULL);
158 #endif
159 etpan_thread_manager_loop(thread_manager);
161 return TRUE;
164 static void imap_logger_noop(int direction, const char * str, size_t size)
166 /* inhibit logging */
169 static void imap_logger_cmd(int direction, const char * str, size_t size)
171 gchar *buf;
172 gchar **lines;
173 int i = 0;
175 if (size > 8192) {
176 log_print(LOG_PROTOCOL, "IMAP%c [CMD data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
177 return;
179 buf = malloc(size+1);
180 memset(buf, 0, size+1);
181 strncpy(buf, str, size);
182 buf[size] = '\0';
184 if (!strncmp(buf, "<<<<<<<", 7)
185 || !strncmp(buf, ">>>>>>>", 7)) {
186 free(buf);
187 return;
189 while (strstr(buf, "\r"))
190 *strstr(buf, "\r") = ' ';
191 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
192 buf[strlen(buf)-1] = '\0';
194 lines = g_strsplit(buf, "\n", -1);
196 while (lines[i] && *lines[i]) {
197 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
198 i++;
200 g_strfreev(lines);
201 free(buf);
204 static void imap_logger_fetch(int direction, const char * str, size_t size)
206 gchar *buf;
207 gchar **lines;
208 int i = 0;
210 if (size > 128 && !direction) {
211 log_print(LOG_PROTOCOL, "IMAP%c [FETCH data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
212 return;
215 buf = malloc(size+1);
216 memset(buf, 0, size+1);
217 strncpy(buf, str, size);
218 buf[size] = '\0';
219 if (!strncmp(buf, "<<<<<<<", 7)
220 || !strncmp(buf, ">>>>>>>", 7)) {
221 free(buf);
222 return;
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 < 32) {
232 while (lines[i] && *lines[i]) {
233 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
234 i++;
236 } else {
237 log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
239 g_strfreev(lines);
240 free(buf);
243 static void imap_logger_uid(int direction, const char * str, size_t size)
245 gchar *buf;
246 gchar **lines;
247 int i = 0;
249 if (size > 8192) {
250 log_print(LOG_PROTOCOL, "IMAP%c [UID data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
251 return;
253 buf = malloc(size+1);
254 memset(buf, 0, size+1);
255 strncpy(buf, str, size);
256 buf[size] = '\0';
257 if (!strncmp(buf, "<<<<<<<", 7)
258 || !strncmp(buf, ">>>>>>>", 7)) {
259 free(buf);
260 return;
262 while (strstr(buf, "\r"))
263 *strstr(buf, "\r") = ' ';
264 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
265 buf[strlen(buf)-1] = '\0';
267 lines = g_strsplit(buf, "\n", -1);
269 while (lines[i] && *lines[i]) {
270 int llen = strlen(lines[i]);
271 if (llen < 64)
272 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
273 else {
274 gchar tmp[64];
275 strncpy2(tmp, lines[i], 63);
276 log_print(LOG_PROTOCOL, "IMAP%c %s[... - %d bytes more]\n", direction?'>':'<', tmp,
277 llen-64);
279 i++;
281 g_strfreev(lines);
282 free(buf);
285 static void imap_logger_append(int direction, const char * str, size_t size)
287 gchar *buf;
288 gchar **lines;
289 int i = 0;
291 if (size > 8192) {
292 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
293 return;
294 } else if (direction == 0 && size > 64) {
295 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
296 return;
298 buf = malloc(size+1);
299 memset(buf, 0, size+1);
300 strncpy(buf, str, size);
301 buf[size] = '\0';
302 if (!strncmp(buf, "<<<<<<<", 7)
303 || !strncmp(buf, ">>>>>>>", 7)) {
304 free(buf);
305 return;
307 while (strstr(buf, "\r"))
308 *strstr(buf, "\r") = ' ';
309 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
310 buf[strlen(buf)-1] = '\0';
312 lines = g_strsplit(buf, "\n", -1);
314 if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
315 while (lines[i] && *lines[i]) {
316 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
317 i++;
319 } else {
320 log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
322 g_strfreev(lines);
323 free(buf);
326 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
327 gboolean etpan_skip_ssl_cert_check = FALSE;
328 extern void mailsasl_ref(void);
330 void imap_main_init(gboolean skip_ssl_cert_check)
332 int fd_thread_manager;
334 etpan_skip_ssl_cert_check = skip_ssl_cert_check;
335 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
336 mailstream_network_delay.tv_usec = 0;
338 mailstream_debug = 1;
339 mailstream_logger = imap_logger_cmd;
340 mailsasl_ref();
342 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
343 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
344 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
346 thread_manager = etpan_thread_manager_new();
348 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
350 #ifndef G_OS_WIN32
351 io_channel = g_io_channel_unix_new(fd_thread_manager);
352 #else
353 io_channel = g_io_channel_win32_new_fd(fd_thread_manager);
354 #endif
355 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
356 thread_manager_event,
357 (gpointer) NULL,
358 NULL);
361 void imap_main_set_timeout(int sec)
363 mailstream_network_delay.tv_sec = sec;
364 mailstream_network_delay.tv_usec = 0;
367 void imap_main_done(gboolean have_connectivity)
369 imap_disconnect_all(have_connectivity);
370 etpan_thread_manager_stop(thread_manager);
371 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
372 return;
373 #endif
374 etpan_thread_manager_join(thread_manager);
376 g_source_remove(thread_manager_signal);
377 g_io_channel_unref(io_channel);
379 etpan_thread_manager_free(thread_manager);
381 chash_free(courier_workaround_hash);
382 chash_free(session_hash);
383 chash_free(imap_hash);
386 void imap_init(Folder * folder)
388 struct etpan_thread * thread;
389 chashdatum key;
390 chashdatum value;
392 thread = etpan_thread_manager_get_thread(thread_manager);
394 key.data = &folder;
395 key.len = sizeof(folder);
396 value.data = thread;
397 value.len = 0;
399 chash_set(imap_hash, &key, &value, NULL);
402 void imap_done(Folder * folder)
404 struct etpan_thread * thread;
405 chashdatum key;
406 chashdatum value;
407 int r;
409 key.data = &folder;
410 key.len = sizeof(folder);
412 r = chash_get(imap_hash, &key, &value);
413 if (r < 0)
414 return;
416 thread = value.data;
418 etpan_thread_unbind(thread);
420 chash_delete(imap_hash, &key, NULL);
422 debug_print("remove thread\n");
425 static struct etpan_thread * get_thread(Folder * folder)
427 struct etpan_thread * thread;
428 chashdatum key;
429 chashdatum value;
430 int r;
432 key.data = &folder;
433 key.len = sizeof(folder);
435 r = chash_get(imap_hash, &key, &value);
436 if (r < 0)
437 return NULL;
439 thread = value.data;
441 return thread;
444 static mailimap * get_imap(Folder * folder)
446 mailimap * imap;
447 chashdatum key;
448 chashdatum value;
449 int r;
451 key.data = &folder;
452 key.len = sizeof(folder);
454 r = chash_get(session_hash, &key, &value);
455 if (r < 0)
456 return NULL;
458 imap = value.data;
459 debug_print("found imap %p\n", imap);
460 return imap;
463 static gboolean cb_show_error(gpointer data)
465 mainwindow_show_error();
466 return FALSE;
469 static void generic_cb(int cancelled, void * result, void * callback_data)
471 struct etpan_thread_op * op;
473 op = (struct etpan_thread_op *) callback_data;
475 debug_print("generic_cb\n");
476 if (op->imap && op->imap->imap_response_info &&
477 op->imap->imap_response_info->rsp_alert) {
478 log_error(LOG_PROTOCOL, "IMAP< Alert: %s\n",
479 op->imap->imap_response_info->rsp_alert);
480 g_timeout_add(10, cb_show_error, NULL);
482 op->finished = 1;
485 /* Please do *not* blindly use imap pointers after this function returns,
486 * someone may have deleted it while this function was waiting for completion.
487 * Check return value to see if imap is still valid.
488 * Run get_imap(folder) again to get a fresh and valid pointer.
490 static int threaded_run(Folder * folder, void * param, void * result,
491 void (* func)(struct etpan_thread_op * ))
493 struct etpan_thread_op * op;
494 struct etpan_thread * thread;
495 struct mailimap * imap = get_imap(folder);
497 imap_folder_ref(folder);
499 op = etpan_thread_op_new();
501 op->imap = imap;
502 op->param = param;
503 op->result = result;
505 op->run = func;
506 op->callback = generic_cb;
507 op->callback_data = op;
509 thread = get_thread(folder);
510 etpan_thread_op_schedule(thread, op);
512 while (!op->finished) {
513 gtk_main_iteration();
516 etpan_thread_op_free(op);
518 imap_folder_unref(folder);
520 if (imap != get_imap(folder)) {
521 g_warning("returning from operation on a stale imap %p", imap);
522 return 1;
525 return 0;
529 /* connect */
531 struct connect_param {
532 mailimap * imap;
533 PrefsAccount *account;
534 const char * server;
535 int port;
536 ProxyInfo * proxy_info;
539 struct connect_result {
540 int error;
543 #define CHECK_IMAP() { \
544 if (!param->imap) { \
545 result->error = MAILIMAP_ERROR_BAD_STATE; \
546 return; \
551 static void delete_imap_run(struct etpan_thread_op * op)
553 mailimap * imap = op->imap;
555 /* we don't want libetpan to logout */
556 if (imap->imap_stream) {
557 mailstream_close(imap->imap_stream);
558 imap->imap_stream = NULL;
561 mailimap_free(imap);
564 static void threaded_delete_imap(Folder *folder, mailimap *imap)
566 struct etpan_thread_op * op;
568 /* No need to wait for completion, threaded_run() won't work here. */
569 op = etpan_thread_op_new();
570 op->imap = imap;
571 op->run = delete_imap_run;
572 op->cleanup = etpan_thread_op_free;
574 etpan_thread_op_schedule(get_thread(folder), op);
576 debug_print("threaded delete imap posted\n");
579 static void delete_imap(Folder *folder, mailimap *imap)
581 chashdatum key;
583 key.data = &folder;
584 key.len = sizeof(folder);
585 chash_delete(session_hash, &key, NULL);
587 if (!imap)
588 return;
589 key.data = &imap;
590 key.len = sizeof(imap);
591 chash_delete(courier_workaround_hash, &key, NULL);
592 /* We can't just free imap here as there may be ops on it pending
593 * in the thread. Posting freeing as an op will synchronize against
594 * existing jobs and as imap is already removed from session_hash
595 * we are sure no new ops can be posted. */
596 threaded_delete_imap(folder, imap);
599 static void connect_run(struct etpan_thread_op * op)
601 int r;
602 struct connect_param * param;
603 struct connect_result * result;
605 param = op->param;
606 result = op->result;
608 CHECK_IMAP();
610 r = do_mailimap_socket_connect(param->imap,
611 param->server, param->port, param->proxy_info);
613 result->error = r;
617 int imap_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
619 struct connect_param param;
620 struct connect_result result;
621 chashdatum key;
622 chashdatum value;
623 mailimap * imap, * oldimap;
625 oldimap = get_imap(folder);
627 imap = mailimap_new(0, NULL);
629 if (oldimap) {
630 debug_print("deleting old imap %p\n", oldimap);
631 delete_imap(folder, oldimap);
634 key.data = &folder;
635 key.len = sizeof(folder);
636 value.data = imap;
637 value.len = 0;
638 chash_set(session_hash, &key, &value, NULL);
640 param.imap = imap;
641 param.server = server;
642 param.port = port;
643 param.proxy_info = proxy_info;
645 refresh_resolvers();
646 threaded_run(folder, &param, &result, connect_run);
648 debug_print("connect ok %i with imap %p\n", result.error, imap);
650 return result.error;
652 #ifdef USE_GNUTLS
653 static void connect_ssl_run(struct etpan_thread_op * op)
655 int r;
656 struct connect_param * param;
657 struct connect_result * result;
659 param = op->param;
660 result = op->result;
662 CHECK_IMAP();
664 r = do_mailimap_ssl_connect_with_callback(param->imap,
665 param->server, param->port,
666 etpan_connect_ssl_context_cb, param->account,
667 param->proxy_info);
668 result->error = r;
671 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
673 struct connect_param param;
674 struct connect_result result;
675 chashdatum key;
676 chashdatum value;
677 mailimap * imap, * oldimap;
678 gboolean accept_if_valid = FALSE;
680 oldimap = get_imap(folder);
682 imap = mailimap_new(0, NULL);
684 if (oldimap) {
685 debug_print("deleting old imap %p\n", oldimap);
686 delete_imap(folder, oldimap);
689 key.data = &folder;
690 key.len = sizeof(folder);
691 value.data = imap;
692 value.len = 0;
693 chash_set(session_hash, &key, &value, NULL);
695 param.imap = imap;
696 param.server = server;
697 param.port = port;
698 param.account = folder->account;
699 param.proxy_info = proxy_info;
701 if (folder->account)
702 accept_if_valid = folder->account->ssl_certs_auto_accept;
704 refresh_resolvers();
705 if (threaded_run(folder, &param, &result, connect_ssl_run))
706 return MAILIMAP_ERROR_INVAL;
708 if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
709 result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
710 if (etpan_certificate_check(imap->imap_stream, server, port,
711 accept_if_valid) != TRUE)
712 result.error = MAILIMAP_ERROR_SSL;
714 debug_print("connect %d with imap %p\n", result.error, imap);
716 return result.error;
718 #endif
719 struct capa_param {
720 mailimap * imap;
723 struct capa_result {
724 int error;
725 struct mailimap_capability_data *caps;
728 static void capability_run(struct etpan_thread_op * op)
730 int r;
731 struct capa_param * param;
732 struct capa_result * result;
733 struct mailimap_capability_data *caps;
735 param = op->param;
736 result = op->result;
738 CHECK_IMAP();
740 r = mailimap_capability(param->imap, &caps);
742 result->error = r;
743 result->caps = (r == 0 ? caps : NULL);
747 int imap_threaded_capability(Folder *folder, struct mailimap_capability_data ** caps)
749 struct capa_param param;
750 struct capa_result result;
751 mailimap *imap;
753 imap = get_imap(folder);
755 param.imap = imap;
757 threaded_run(folder, &param, &result, capability_run);
759 debug_print("capa %d\n", result.error);
761 if (result.error == MAILIMAP_NO_ERROR)
762 *caps = result.caps;
764 return result.error;
768 struct disconnect_param {
769 mailimap * imap;
772 struct disconnect_result {
773 int error;
776 static void disconnect_run(struct etpan_thread_op * op)
778 int r;
779 struct disconnect_param * param;
780 struct disconnect_result * result;
782 param = op->param;
783 result = op->result;
785 CHECK_IMAP();
787 r = mailimap_logout(param->imap);
789 result->error = r;
792 void imap_threaded_disconnect(Folder * folder)
794 struct connect_param param;
795 struct connect_result result;
796 mailimap * imap;
798 imap = get_imap(folder);
799 if (imap == NULL) {
800 debug_print("was disconnected\n");
801 return;
804 param.imap = imap;
806 if (threaded_run(folder, &param, &result, disconnect_run)) {
807 debug_print("imap already deleted %p\n", imap);
808 } else {
809 debug_print("deleting old imap %p\n", imap);
810 delete_imap(folder, imap);
813 debug_print("disconnect ok\n");
817 struct list_param {
818 mailimap * imap;
819 const char * base;
820 const char * wildcard;
821 gboolean sub_only;
824 struct list_result {
825 int error;
826 clist * list;
829 static void list_run(struct etpan_thread_op * op)
831 struct list_param * param;
832 struct list_result * result;
833 int r;
834 clist * list;
836 param = op->param;
837 result = op->result;
839 CHECK_IMAP();
841 list = NULL;
843 if (param->base == NULL || param->wildcard == NULL) {
844 result->list = list;
845 result->error = -1;
846 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
847 return;
849 if (param->sub_only)
850 r = mailimap_lsub(param->imap, param->base,
851 param->wildcard, &list);
852 else
853 r = mailimap_list(param->imap, param->base,
854 param->wildcard, &list);
855 result->error = r;
856 result->list = list;
857 debug_print("imap list run - end\n");
860 int imap_threaded_list(Folder * folder, const char * base,
861 const char * wildcard,
862 clist ** p_result)
864 struct list_param param;
865 struct list_result result;
867 debug_print("imap list - begin\n");
869 param.imap = get_imap(folder);
870 param.base = base;
871 param.wildcard = wildcard;
872 param.sub_only = FALSE;
874 threaded_run(folder, &param, &result, list_run);
876 * p_result = result.list;
878 debug_print("imap list - end %p\n", result.list);
880 return result.error;
883 int imap_threaded_lsub(Folder * folder, const char * base,
884 const char * wildcard,
885 clist ** p_result)
887 struct list_param param;
888 struct list_result result;
890 debug_print("imap lsub - begin\n");
892 param.imap = get_imap(folder);
893 param.base = base;
894 param.wildcard = wildcard;
895 param.sub_only = TRUE;
897 threaded_run(folder, &param, &result, list_run);
899 * p_result = result.list;
901 debug_print("imap lsub - end %p\n", result.list);
903 return result.error;
906 struct subscribe_param {
907 mailimap * imap;
908 const char * mb;
909 gboolean subscribe;
912 struct subscribe_result {
913 int error;
916 static void subscribe_run(struct etpan_thread_op * op)
918 struct subscribe_param * param;
919 struct subscribe_result * result;
920 int r;
922 param = op->param;
923 result = op->result;
925 CHECK_IMAP();
927 if (param->mb == NULL) {
928 result->error = -1;
929 debug_print("no mb\n");
930 return;
932 if (param->subscribe)
933 r = mailimap_subscribe(param->imap, param->mb);
934 else
935 r = mailimap_unsubscribe(param->imap, param->mb);
936 result->error = r;
937 debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
940 int imap_threaded_subscribe(Folder * folder, const char * mb,
941 gboolean subscribe)
943 struct subscribe_param param;
944 struct subscribe_result result;
946 debug_print("imap list - begin\n");
948 param.imap = get_imap(folder);
949 param.mb = mb;
950 param.subscribe = subscribe;
952 threaded_run(folder, &param, &result, subscribe_run);
954 return result.error;
957 struct login_param {
958 mailimap * imap;
959 const char * login;
960 const char * password;
961 const char * type;
962 const char * server;
965 struct login_result {
966 int error;
969 static void login_run(struct etpan_thread_op * op)
971 struct login_param * param;
972 struct login_result * result;
973 int r;
974 #ifdef DISABLE_LOG_DURING_LOGIN
975 int old_debug;
976 #endif
978 param = op->param;
979 result = op->result;
981 CHECK_IMAP();
983 #ifdef DISABLE_LOG_DURING_LOGIN
984 old_debug = mailstream_debug;
985 mailstream_debug = 0;
986 #endif
987 if (!strcmp(param->type, "plaintext"))
988 r = mailimap_login(param->imap,
989 param->login, param->password);
990 else if (!strcmp(param->type, "GSSAPI"))
991 r = mailimap_authenticate(param->imap,
992 param->type, param->server, NULL, NULL,
993 param->login, param->login,
994 param->password, NULL);
995 else if (!strncmp(param->type, "SCRAM-SHA-", 10))
996 /* 7th argument has to be NULL here, to stop libetpan sending the
997 * a= attribute in its initial SCRAM-SHA-1 message to server. At least
998 * Dovecot 2.2 doesn't seem to like that, and will not authenticate
999 * successfully. */
1000 r = mailimap_authenticate(param->imap,
1001 param->type, NULL, NULL, NULL,
1002 NULL, param->login,
1003 param->password, NULL);
1004 #ifdef USE_OAUTH2
1005 else if (!strcmp(param->type, "XOAUTH2"))
1006 r = mailimap_oauth2_authenticate(param->imap, param->login, param->password);
1007 #endif
1008 else
1009 r = mailimap_authenticate(param->imap,
1010 param->type, NULL, NULL, NULL,
1011 param->login, param->login,
1012 param->password, NULL);
1013 #ifdef DISABLE_LOG_DURING_LOGIN
1014 mailstream_debug = old_debug;
1015 #endif
1017 result->error = r;
1018 if (param->imap->imap_response)
1019 imap_logger_cmd(0, param->imap->imap_response, strlen(param->imap->imap_response));
1020 debug_print("imap login run - end %i\n", r);
1023 int imap_threaded_login(Folder * folder,
1024 const char * login, const char * password,
1025 const char * type)
1027 struct login_param param;
1028 struct login_result result;
1030 debug_print("imap login - begin\n");
1032 if (!folder)
1033 return MAILIMAP_ERROR_INVAL;
1035 param.imap = get_imap(folder);
1036 param.login = login;
1037 param.password = password;
1038 param.type = type;
1039 if (folder && folder->account)
1040 param.server = folder->account->recv_server;
1041 else
1042 param.server = NULL;
1044 threaded_run(folder, &param, &result, login_run);
1046 debug_print("imap login - end\n");
1048 return result.error;
1052 struct status_param {
1053 mailimap * imap;
1054 const char * mb;
1055 struct mailimap_status_att_list * status_att_list;
1058 struct status_result {
1059 int error;
1060 struct mailimap_mailbox_data_status * data_status;
1063 static void status_run(struct etpan_thread_op * op)
1065 struct status_param * param;
1066 struct status_result * result;
1067 int r;
1069 param = op->param;
1070 result = op->result;
1072 CHECK_IMAP();
1074 r = mailimap_status(param->imap, param->mb,
1075 param->status_att_list,
1076 &result->data_status);
1078 result->error = r;
1079 debug_print("imap status run - end %i\n", r);
1082 int imap_threaded_status(Folder * folder, const char * mb,
1083 struct mailimap_mailbox_data_status ** data_status,
1084 guint mask)
1086 struct status_param param;
1087 struct status_result result;
1088 struct mailimap_status_att_list * status_att_list;
1090 debug_print("imap status - begin\n");
1092 status_att_list = mailimap_status_att_list_new_empty();
1093 if (mask & 1 << 0) {
1094 mailimap_status_att_list_add(status_att_list,
1095 MAILIMAP_STATUS_ATT_MESSAGES);
1097 if (mask & 1 << 1) {
1098 mailimap_status_att_list_add(status_att_list,
1099 MAILIMAP_STATUS_ATT_RECENT);
1101 if (mask & 1 << 2) {
1102 mailimap_status_att_list_add(status_att_list,
1103 MAILIMAP_STATUS_ATT_UIDNEXT);
1105 if (mask & 1 << 3) {
1106 mailimap_status_att_list_add(status_att_list,
1107 MAILIMAP_STATUS_ATT_UIDVALIDITY);
1109 if (mask & 1 << 4) {
1110 mailimap_status_att_list_add(status_att_list,
1111 MAILIMAP_STATUS_ATT_UNSEEN);
1113 param.imap = get_imap(folder);
1114 param.mb = mb;
1115 param.status_att_list = status_att_list;
1117 threaded_run(folder, &param, &result, status_run);
1119 debug_print("imap status - end\n");
1121 * data_status = result.data_status;
1123 mailimap_status_att_list_free(status_att_list);
1125 return result.error;
1130 struct noop_param {
1131 mailimap * imap;
1134 struct noop_result {
1135 int error;
1138 static void noop_run(struct etpan_thread_op * op)
1140 struct noop_param * param;
1141 struct noop_result * result;
1142 int r;
1144 param = op->param;
1145 result = op->result;
1147 CHECK_IMAP();
1149 r = mailimap_noop(param->imap);
1151 result->error = r;
1152 debug_print("imap noop run - end %i\n", r);
1155 int imap_threaded_noop(Folder * folder, unsigned int * p_exists,
1156 unsigned int *p_recent,
1157 unsigned int *p_expunge,
1158 unsigned int *p_unseen,
1159 unsigned int *p_uidnext,
1160 unsigned int *p_uidval)
1162 struct noop_param param;
1163 struct noop_result result;
1164 mailimap * imap;
1166 debug_print("imap noop - begin\n");
1168 imap = get_imap(folder);
1169 param.imap = imap;
1171 if (threaded_run(folder, &param, &result, noop_run))
1172 return MAILIMAP_ERROR_INVAL;
1174 if (result.error == 0 && imap && imap->imap_selection_info != NULL) {
1175 * p_exists = imap->imap_selection_info->sel_exists;
1176 * p_recent = imap->imap_selection_info->sel_recent;
1177 * p_unseen = imap->imap_selection_info->sel_unseen;
1178 * p_uidnext = imap->imap_selection_info->sel_uidnext;
1179 * p_uidval = imap->imap_selection_info->sel_uidvalidity;
1180 } else {
1181 * p_exists = 0;
1182 * p_recent = 0;
1183 * p_unseen = 0;
1184 * p_uidnext = 0;
1185 * p_uidval = 0;
1187 if (result.error == 0 && imap && imap->imap_response_info != NULL &&
1188 imap->imap_response_info->rsp_expunged != NULL) {
1189 * p_expunge = clist_count(imap->imap_response_info->rsp_expunged);
1190 } else {
1191 * p_expunge = 0;
1193 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1194 *p_exists, *p_recent, *p_expunge, *p_unseen,
1195 *p_uidnext, *p_uidval);
1197 return result.error;
1200 #ifdef USE_GNUTLS
1201 struct starttls_result {
1202 int error;
1205 static void starttls_run(struct etpan_thread_op * op)
1207 struct connect_param * param;
1208 struct starttls_result * result;
1209 int r;
1211 param = op->param;
1212 result = op->result;
1214 CHECK_IMAP();
1216 r = mailimap_starttls(param->imap);
1218 result->error = r;
1219 debug_print("imap STARTTLS run - end %i\n", r);
1221 if (r == 0) {
1222 mailimap *imap = param->imap;
1223 mailstream_low *plain_low = NULL;
1224 mailstream_low *tls_low = NULL;
1225 int fd = -1;
1227 plain_low = mailstream_get_low(imap->imap_stream);
1228 fd = mailstream_low_get_fd(plain_low);
1229 if (fd == -1) {
1230 debug_print("imap STARTTLS run - can't get fd\n");
1231 result->error = MAILIMAP_ERROR_STREAM;
1232 return;
1235 tls_low = mailstream_low_tls_open_with_callback(fd, etpan_connect_ssl_context_cb, param->account);
1236 if (tls_low == NULL) {
1237 debug_print("imap STARTTLS run - can't tls_open\n");
1238 result->error = MAILIMAP_ERROR_STREAM;
1239 return;
1241 mailstream_low_free(plain_low);
1242 mailstream_set_low(imap->imap_stream, tls_low);
1246 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1248 struct connect_param param;
1249 struct starttls_result result;
1250 gboolean accept_if_valid = FALSE;
1252 debug_print("imap STARTTLS - begin\n");
1254 param.imap = get_imap(folder);
1255 param.server = host;
1256 param.port = port;
1257 param.account = folder->account;
1259 if (folder->account)
1260 accept_if_valid = folder->account->ssl_certs_auto_accept;
1262 if (threaded_run(folder, &param, &result, starttls_run))
1263 return MAILIMAP_ERROR_INVAL;
1265 debug_print("imap STARTTLS - end\n");
1267 if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
1268 if (etpan_certificate_check(param.imap->imap_stream, host, port,
1269 accept_if_valid) != TRUE)
1270 return MAILIMAP_ERROR_SSL;
1272 return result.error;
1274 #endif
1276 struct create_param {
1277 mailimap * imap;
1278 const char * mb;
1281 struct create_result {
1282 int error;
1285 static void create_run(struct etpan_thread_op * op)
1287 struct create_param * param;
1288 struct create_result * result;
1289 int r;
1291 param = op->param;
1292 result = op->result;
1294 CHECK_IMAP();
1296 r = mailimap_create(param->imap, param->mb);
1298 result->error = r;
1299 debug_print("imap create run - end %i\n", r);
1302 int imap_threaded_create(Folder * folder, const char * mb)
1304 struct create_param param;
1305 struct create_result result;
1307 debug_print("imap create - begin\n");
1309 param.imap = get_imap(folder);
1310 param.mb = mb;
1312 threaded_run(folder, &param, &result, create_run);
1314 debug_print("imap create - end\n");
1316 return result.error;
1322 struct rename_param {
1323 mailimap * imap;
1324 const char * mb;
1325 const char * new_name;
1328 struct rename_result {
1329 int error;
1332 static void rename_run(struct etpan_thread_op * op)
1334 struct rename_param * param;
1335 struct rename_result * result;
1336 int r;
1338 param = op->param;
1339 result = op->result;
1341 CHECK_IMAP();
1343 r = mailimap_rename(param->imap, param->mb, param->new_name);
1345 result->error = r;
1346 debug_print("imap rename run - end %i\n", r);
1349 int imap_threaded_rename(Folder * folder,
1350 const char * mb, const char * new_name)
1352 struct rename_param param;
1353 struct rename_result result;
1355 debug_print("imap rename - begin\n");
1357 param.imap = get_imap(folder);
1358 param.mb = mb;
1359 param.new_name = new_name;
1361 threaded_run(folder, &param, &result, rename_run);
1363 debug_print("imap rename - end\n");
1365 return result.error;
1371 struct delete_param {
1372 mailimap * imap;
1373 const char * mb;
1376 struct delete_result {
1377 int error;
1380 static void delete_run(struct etpan_thread_op * op)
1382 struct delete_param * param;
1383 struct delete_result * result;
1384 int r;
1386 param = op->param;
1387 result = op->result;
1389 CHECK_IMAP();
1391 r = mailimap_delete(param->imap, param->mb);
1393 result->error = r;
1394 debug_print("imap delete run - end %i\n", r);
1397 int imap_threaded_delete(Folder * folder, const char * mb)
1399 struct delete_param param;
1400 struct delete_result result;
1402 debug_print("imap delete - begin\n");
1404 param.imap = get_imap(folder);
1405 param.mb = mb;
1407 threaded_run(folder, &param, &result, delete_run);
1409 debug_print("imap delete - end\n");
1411 return result.error;
1416 struct select_param {
1417 mailimap * imap;
1418 const char * mb;
1421 struct select_result {
1422 int error;
1425 static void select_run(struct etpan_thread_op * op)
1427 struct select_param * param;
1428 struct select_result * result;
1429 int r;
1431 param = op->param;
1432 result = op->result;
1434 CHECK_IMAP();
1436 r = mailimap_select(param->imap, param->mb);
1438 result->error = r;
1439 debug_print("imap select run - end %i\n", r);
1442 int imap_threaded_select(Folder * folder, const char * mb,
1443 gint * exists, gint * recent, gint * unseen,
1444 guint32 * uid_validity,gint *can_create_flags,
1445 GSList **ok_flags)
1447 struct select_param param;
1448 struct select_result result;
1449 mailimap * imap;
1451 debug_print("imap select - begin\n");
1453 imap = get_imap(folder);
1454 param.imap = imap;
1455 param.mb = mb;
1457 if (threaded_run(folder, &param, &result, select_run))
1458 return MAILIMAP_ERROR_INVAL;
1460 if (result.error != MAILIMAP_NO_ERROR)
1461 return result.error;
1463 if (!imap || imap->imap_selection_info == NULL)
1464 return MAILIMAP_ERROR_PARSE;
1466 * exists = imap->imap_selection_info->sel_exists;
1467 * recent = imap->imap_selection_info->sel_recent;
1468 * unseen = imap->imap_selection_info->sel_unseen;
1469 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1470 * can_create_flags = FALSE;
1472 if (imap->imap_selection_info->sel_perm_flags) {
1473 GSList *t_flags = NULL;
1474 clistiter *cur = NULL;
1475 if (imap->imap_selection_info->sel_perm_flags)
1476 cur = clist_begin(imap->imap_selection_info->sel_perm_flags);
1478 for (; cur; cur = clist_next(cur)) {
1479 struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur);
1480 if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL)
1481 *can_create_flags = TRUE;
1482 else if (flag->fl_flag &&
1483 flag->fl_flag->fl_type == 6 &&
1484 !strcmp(flag->fl_flag->fl_data.fl_extension, "*"))
1485 *can_create_flags = TRUE;
1486 if (flag->fl_flag && ok_flags) {
1487 MsgPermFlags c_flag = 0;
1488 switch (flag->fl_flag->fl_type) {
1489 case MAILIMAP_FLAG_ANSWERED:
1490 c_flag = IMAP_FLAG_ANSWERED;
1491 break;
1492 case MAILIMAP_FLAG_FLAGGED:
1493 c_flag = IMAP_FLAG_FLAGGED;
1494 break;
1495 case MAILIMAP_FLAG_DELETED:
1496 c_flag = IMAP_FLAG_DELETED;
1497 break;
1498 case MAILIMAP_FLAG_DRAFT:
1499 c_flag = IMAP_FLAG_DRAFT;
1500 break;
1501 case MAILIMAP_FLAG_SEEN:
1502 c_flag = IMAP_FLAG_SEEN;
1503 break;
1504 case MAILIMAP_FLAG_KEYWORD:
1505 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
1506 c_flag = IMAP_FLAG_FORWARDED;
1507 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
1508 c_flag = IMAP_FLAG_SPAM;
1509 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
1510 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
1511 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
1512 c_flag = IMAP_FLAG_HAM;
1513 break;
1514 default:
1515 break;
1517 if (c_flag != 0) {
1518 t_flags = g_slist_prepend(t_flags,
1519 GUINT_TO_POINTER(c_flag));
1523 if (ok_flags)
1524 *ok_flags = t_flags;
1526 debug_print("imap select - end\n");
1528 return result.error;
1531 static void close_run(struct etpan_thread_op * op)
1533 struct select_param * param;
1534 struct select_result * result;
1535 int r;
1537 param = op->param;
1538 result = op->result;
1540 CHECK_IMAP();
1542 r = mailimap_close(param->imap);
1544 result->error = r;
1545 debug_print("imap close run - end %i\n", r);
1548 int imap_threaded_close(Folder * folder)
1550 struct select_param param;
1551 struct select_result result;
1552 mailimap * imap;
1554 debug_print("imap close - begin\n");
1556 imap = get_imap(folder);
1557 param.imap = imap;
1559 threaded_run(folder, &param, &result, close_run);
1561 if (result.error != MAILIMAP_NO_ERROR)
1562 return result.error;
1564 debug_print("imap close - end\n");
1566 return result.error;
1569 struct examine_param {
1570 mailimap * imap;
1571 const char * mb;
1574 struct examine_result {
1575 int error;
1578 static void examine_run(struct etpan_thread_op * op)
1580 struct examine_param * param;
1581 struct examine_result * result;
1582 int r;
1584 param = op->param;
1585 result = op->result;
1587 CHECK_IMAP();
1589 r = mailimap_examine(param->imap, param->mb);
1591 result->error = r;
1592 debug_print("imap examine run - end %i\n", r);
1595 int imap_threaded_examine(Folder * folder, const char * mb,
1596 gint * exists, gint * recent, gint * unseen,
1597 guint32 * uid_validity)
1599 struct examine_param param;
1600 struct examine_result result;
1601 mailimap * imap;
1603 debug_print("imap examine - begin\n");
1605 imap = get_imap(folder);
1606 param.imap = imap;
1607 param.mb = mb;
1609 if (threaded_run(folder, &param, &result, examine_run))
1610 return MAILIMAP_ERROR_INVAL;
1612 if (result.error != MAILIMAP_NO_ERROR)
1613 return result.error;
1615 if (!imap || imap->imap_selection_info == NULL)
1616 return MAILIMAP_ERROR_PARSE;
1618 * exists = imap->imap_selection_info->sel_exists;
1619 * recent = imap->imap_selection_info->sel_recent;
1620 * unseen = imap->imap_selection_info->sel_unseen;
1621 * uid_validity = imap->imap_selection_info->sel_uidvalidity;
1623 debug_print("imap examine - end\n");
1625 return result.error;
1631 struct search_param {
1632 mailimap * imap;
1633 int type;
1634 const char *charset;
1635 struct mailimap_set * set;
1636 IMAPSearchKey* key;
1639 struct search_result {
1640 int error;
1641 clist * search_result;
1644 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1646 return mailimap_set_item_new(orig->set_first, orig->set_last);
1649 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1651 clist *list = orig ? orig->set_list : NULL;
1652 clist *newlist;
1653 clistiter *cur;
1655 if (!orig)
1656 return NULL;
1658 newlist = clist_new();
1659 if (!newlist)
1660 return NULL;
1662 for (cur = clist_begin(list); cur; cur = clist_next(cur)) {
1663 if (clist_append(newlist,
1664 sc_mailimap_set_item_copy(
1665 (struct mailimap_set_item *)clist_content(cur))) != 0) {
1666 clist_free(newlist);
1667 return NULL;
1670 return mailimap_set_new(newlist);
1673 static void search_run(struct etpan_thread_op * op)
1675 struct search_param * param;
1676 struct search_result * result;
1677 int r;
1678 struct mailimap_search_key * key = NULL;
1679 struct mailimap_search_key * uid_key = NULL;
1680 struct mailimap_search_key * search_type_key = NULL;
1681 clist * search_result;
1683 param = op->param;
1684 result = op->result;
1686 CHECK_IMAP();
1688 /* we copy the mailimap_set because freeing the key is recursive */
1689 if (param->set != NULL) {
1690 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1691 } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1692 uid_key = mailimap_search_key_new_all();
1694 switch (param->type) {
1695 case IMAP_SEARCH_TYPE_SIMPLE:
1696 search_type_key = NULL;
1697 break;
1698 case IMAP_SEARCH_TYPE_SEEN:
1699 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0);
1700 break;
1701 case IMAP_SEARCH_TYPE_UNSEEN:
1702 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0);
1703 break;
1704 case IMAP_SEARCH_TYPE_ANSWERED:
1705 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0);
1706 break;
1707 case IMAP_SEARCH_TYPE_FLAGGED:
1708 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0);
1709 break;
1710 case IMAP_SEARCH_TYPE_DELETED:
1711 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0);
1712 break;
1713 case IMAP_SEARCH_TYPE_FORWARDED:
1714 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0);
1715 break;
1716 case IMAP_SEARCH_TYPE_SPAM:
1717 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0);
1718 break;
1719 case IMAP_SEARCH_TYPE_KEYED:
1720 search_type_key = param->key;
1721 break;
1724 if (search_type_key != NULL) {
1725 if (param->set != NULL) {
1726 key = mailimap_search_key_new_multiple_empty();
1727 mailimap_search_key_multiple_add(key, search_type_key);
1728 mailimap_search_key_multiple_add(key, uid_key);
1729 } else {
1730 key = search_type_key;
1732 } else if (uid_key != NULL) {
1733 key = uid_key;
1736 if (key == NULL) {
1737 g_warning("no key!");
1738 result = op->result;
1739 result->error = -1;
1740 result->search_result = NULL;
1741 } else {
1742 mailstream_logger = imap_logger_uid;
1744 r = mailimap_uid_search(param->imap, param->charset, key, &search_result);
1746 mailstream_logger = imap_logger_cmd;
1748 /* free the key (with the imapset) */
1749 mailimap_search_key_free(key);
1751 result->error = r;
1752 result->search_result = search_result;
1754 debug_print("imap search run - end %i\n", result->error);
1757 int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key,
1758 const char *charset, struct mailimap_set * set,
1759 clist ** search_result)
1761 struct search_param param;
1762 struct search_result result;
1763 mailimap * imap;
1765 debug_print("imap search - begin\n");
1767 imap = get_imap(folder);
1768 param.imap = imap;
1769 param.set = set;
1770 param.charset = charset;
1771 param.type = search_type;
1772 param.key = key;
1774 threaded_run(folder, &param, &result, search_run);
1776 if (result.error != MAILIMAP_NO_ERROR)
1777 return result.error;
1779 debug_print("imap search - end\n");
1781 * search_result = result.search_result;
1783 return result.error;
1787 struct _IMAPSearchKey {
1788 struct mailimap_search_key* key;
1791 IMAPSearchKey* imap_search_new(gint criteria,
1792 const gchar *header,
1793 const gchar *expr,
1794 int value)
1796 char* sk_bcc = NULL;
1797 struct mailimap_date* sk_before = NULL;
1798 char* sk_body = NULL;
1799 char* sk_cc = NULL;
1800 char* sk_from = NULL;
1801 char* sk_keyword = NULL;
1802 struct mailimap_date* sk_on = NULL;
1803 struct mailimap_date* sk_since = NULL;
1804 char* sk_subject = NULL;
1805 char* sk_text = NULL;
1806 char* sk_to = NULL;
1807 char* sk_unkeyword = NULL;
1808 char* sk_header_name = NULL;
1809 char* sk_header_value = NULL;
1810 uint32_t sk_larger = 0;
1811 struct mailimap_search_key* sk_not = NULL;
1812 struct mailimap_search_key* sk_or1 = NULL;
1813 struct mailimap_search_key* sk_or2 = NULL;
1814 struct mailimap_date* sk_sentbefore = NULL;
1815 struct mailimap_date* sk_senton = NULL;
1816 struct mailimap_date* sk_sentsince = NULL;
1817 uint32_t sk_smaller = 0;
1818 struct mailimap_set* sk_uid = NULL;
1819 struct mailimap_set* sk_set = NULL;
1820 clist* sk_multiple = NULL;
1821 int etpan_matcher_type;
1823 switch (criteria) {
1824 case IMAP_SEARCH_CRITERIA_ALL: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ALL; break;
1825 case IMAP_SEARCH_CRITERIA_READ: etpan_matcher_type = MAILIMAP_SEARCH_KEY_SEEN; break;
1826 case IMAP_SEARCH_CRITERIA_UNREAD: etpan_matcher_type = MAILIMAP_SEARCH_KEY_UNSEEN; break;
1827 case IMAP_SEARCH_CRITERIA_NEW: etpan_matcher_type = MAILIMAP_SEARCH_KEY_NEW; break;
1828 case IMAP_SEARCH_CRITERIA_MARKED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_FLAGGED; break;
1829 case IMAP_SEARCH_CRITERIA_REPLIED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ANSWERED; break;
1830 case IMAP_SEARCH_CRITERIA_DELETED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_DELETED; break;
1832 case IMAP_SEARCH_CRITERIA_TAG:
1833 sk_keyword = strdup(expr);
1834 etpan_matcher_type = MAILIMAP_SEARCH_KEY_KEYWORD;
1835 break;
1837 case IMAP_SEARCH_CRITERIA_SUBJECT:
1838 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SUBJECT;
1839 sk_subject = strdup(expr);
1840 break;
1842 case IMAP_SEARCH_CRITERIA_TO:
1843 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TO;
1844 sk_to = strdup(expr);
1845 break;
1847 case IMAP_SEARCH_CRITERIA_CC:
1848 etpan_matcher_type = MAILIMAP_SEARCH_KEY_CC;
1849 sk_cc = strdup(expr);
1850 break;
1852 case IMAP_SEARCH_CRITERIA_AGE_GREATER:
1853 case IMAP_SEARCH_CRITERIA_AGE_LOWER:
1855 struct tm tm;
1856 time_t limit = time(NULL) - 60 * 60 * 24 * value;
1858 tzset();
1859 localtime_r(&limit, &tm);
1860 if (criteria == IMAP_SEARCH_CRITERIA_AGE_GREATER) {
1861 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTBEFORE;
1862 sk_sentbefore = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1863 } else {
1864 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTSINCE;
1865 sk_sentsince = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1867 break;
1870 case IMAP_SEARCH_CRITERIA_BODY:
1871 etpan_matcher_type = MAILIMAP_SEARCH_KEY_BODY;
1872 sk_body = strdup(expr);
1873 break;
1875 case IMAP_SEARCH_CRITERIA_MESSAGE:
1876 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TEXT;
1877 sk_text = strdup(expr);
1878 break;
1880 case IMAP_SEARCH_CRITERIA_HEADER:
1881 etpan_matcher_type = MAILIMAP_SEARCH_KEY_HEADER;
1882 sk_header_name = strdup(header);
1883 sk_header_value = strdup(expr);
1884 break;
1886 case IMAP_SEARCH_CRITERIA_FROM:
1887 etpan_matcher_type = MAILIMAP_SEARCH_KEY_FROM;
1888 sk_from = strdup(expr);
1889 break;
1891 case IMAP_SEARCH_CRITERIA_SIZE_GREATER:
1892 etpan_matcher_type = MAILIMAP_SEARCH_KEY_LARGER;
1893 sk_larger = value;
1894 break;
1896 case IMAP_SEARCH_CRITERIA_SIZE_SMALLER:
1897 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SMALLER;
1898 sk_smaller = value;
1899 break;
1901 default:
1902 return NULL;
1905 return mailimap_search_key_new(etpan_matcher_type,
1906 sk_bcc, sk_before, sk_body, sk_cc, sk_from, sk_keyword,
1907 sk_on, sk_since, sk_subject, sk_text, sk_to,
1908 sk_unkeyword, sk_header_name,sk_header_value, sk_larger,
1909 sk_not, sk_or1, sk_or2, sk_sentbefore, sk_senton,
1910 sk_sentsince, sk_smaller, sk_uid, sk_set, sk_multiple);
1913 IMAPSearchKey* imap_search_not(IMAPSearchKey* key)
1915 return mailimap_search_key_new_not(key);
1918 IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r)
1920 return mailimap_search_key_new_or(l, r);
1923 IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r)
1925 IMAPSearchKey* result = mailimap_search_key_new_multiple_empty();
1926 mailimap_search_key_multiple_add(result, l);
1927 mailimap_search_key_multiple_add(result, r);
1929 return result;
1932 void imap_search_free(IMAPSearchKey* key)
1934 if (!key)
1935 return;
1937 mailimap_search_key_free(key);
1942 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1943 uint32_t * puid,
1944 char ** pheaders,
1945 size_t * pref_size,
1946 struct mailimap_msg_att_dynamic ** patt_dyn);
1948 static int
1949 result_to_uid_list(clist * fetch_result, carray ** result)
1951 clistiter * cur = NULL;
1952 int r;
1953 int res;
1954 carray * tab;
1956 tab = carray_new(128);
1957 if (tab == NULL) {
1958 res = MAILIMAP_ERROR_MEMORY;
1959 goto err;
1962 if (fetch_result)
1963 cur = clist_begin(fetch_result);
1965 for(; cur != NULL ; cur = clist_next(cur)) {
1966 struct mailimap_msg_att * msg_att;
1967 uint32_t uid;
1968 uint32_t * puid;
1970 msg_att = clist_content(cur);
1972 uid = 0;
1973 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL);
1975 puid = malloc(sizeof(* puid));
1976 if (puid == NULL) {
1977 res = MAILIMAP_ERROR_MEMORY;
1978 goto free_list;
1980 * puid = uid;
1982 r = carray_add(tab, puid, NULL);
1983 if (r < 0) {
1984 free(puid);
1985 res = MAILIMAP_ERROR_MEMORY;
1986 goto free_list;
1990 * result = tab;
1992 return MAILIMAP_NO_ERROR;
1994 free_list:
1995 imap_fetch_uid_list_free(tab);
1996 err:
1997 return res;
2000 static int imap_get_messages_list(mailimap * imap,
2001 uint32_t first_index,
2002 carray ** result)
2004 carray * env_list;
2005 int r;
2006 struct mailimap_fetch_att * fetch_att;
2007 struct mailimap_fetch_type * fetch_type;
2008 struct mailimap_set * set;
2009 clist * fetch_result;
2010 int res;
2012 set = mailimap_set_new_interval(first_index, 0);
2013 if (set == NULL) {
2014 res = MAILIMAP_ERROR_MEMORY;
2015 goto err;
2018 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2019 if (fetch_type == NULL) {
2020 res = MAILIMAP_ERROR_MEMORY;
2021 goto free_set;
2024 fetch_att = mailimap_fetch_att_new_uid();
2025 if (fetch_att == NULL) {
2026 res = MAILIMAP_ERROR_MEMORY;
2027 goto free_fetch_type;
2030 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2031 if (r != MAILIMAP_NO_ERROR) {
2032 mailimap_fetch_att_free(fetch_att);
2033 res = MAILIMAP_ERROR_MEMORY;
2034 goto free_fetch_type;
2037 mailstream_logger = imap_logger_fetch;
2039 r = mailimap_uid_fetch(imap, set,
2040 fetch_type, &fetch_result);
2042 mailstream_logger = imap_logger_cmd;
2043 mailimap_fetch_type_free(fetch_type);
2044 mailimap_set_free(set);
2046 if (r != MAILIMAP_NO_ERROR) {
2047 res = r;
2048 goto err;
2051 env_list = NULL;
2052 r = result_to_uid_list(fetch_result, &env_list);
2053 mailimap_fetch_list_free(fetch_result);
2055 * result = env_list;
2057 return MAILIMAP_NO_ERROR;
2059 free_fetch_type:
2060 mailimap_fetch_type_free(fetch_type);
2061 free_set:
2062 mailimap_set_free(set);
2063 err:
2064 return res;
2070 struct fetch_uid_param {
2071 mailimap * imap;
2072 uint32_t first_index;
2075 struct fetch_uid_result {
2076 int error;
2077 carray * fetch_result;
2080 static void fetch_uid_run(struct etpan_thread_op * op)
2082 struct fetch_uid_param * param;
2083 struct fetch_uid_result * result;
2084 carray * fetch_result;
2085 int r;
2087 param = op->param;
2088 result = op->result;
2090 CHECK_IMAP();
2092 fetch_result = NULL;
2093 mailstream_logger = imap_logger_noop;
2094 log_print(LOG_PROTOCOL, "IMAP- [fetching UIDs...]\n");
2096 r = imap_get_messages_list(param->imap, param->first_index,
2097 &fetch_result);
2099 mailstream_logger = imap_logger_cmd;
2101 result->error = r;
2102 result->fetch_result = fetch_result;
2103 debug_print("imap fetch_uid run - end %i\n", r);
2106 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
2107 carray ** fetch_result)
2109 struct fetch_uid_param param;
2110 struct fetch_uid_result result;
2111 mailimap * imap;
2113 debug_print("imap fetch_uid - begin\n");
2115 imap = get_imap(folder);
2116 param.imap = imap;
2117 param.first_index = first_index;
2119 threaded_run(folder, &param, &result, fetch_uid_run);
2121 if (result.error != MAILIMAP_NO_ERROR)
2122 return result.error;
2124 debug_print("imap fetch_uid - end\n");
2126 * fetch_result = result.fetch_result;
2128 return result.error;
2132 void imap_fetch_uid_list_free(carray * uid_list)
2134 unsigned int i;
2136 for(i = 0 ; i < carray_count(uid_list) ; i ++) {
2137 uint32_t * puid;
2139 puid = carray_get(uid_list, i);
2140 free(puid);
2142 carray_free(uid_list);
2148 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags);
2150 static int
2151 result_to_uid_flags_list(clist * fetch_result, carray ** result)
2153 clistiter * cur = NULL;
2154 int r;
2155 int res;
2156 carray * tab;
2157 GSList *tags = NULL;
2159 tab = carray_new(128);
2160 if (tab == NULL) {
2161 res = MAILIMAP_ERROR_MEMORY;
2162 goto err;
2165 if (fetch_result)
2166 cur = clist_begin(fetch_result);
2168 for(; cur != NULL ; cur = clist_next(cur)) {
2169 struct mailimap_msg_att * msg_att;
2170 uint32_t uid;
2171 uint32_t * puid;
2172 struct mailimap_msg_att_dynamic * att_dyn;
2173 int flags;
2174 int * pflags;
2176 tags = NULL;
2178 msg_att = clist_content(cur);
2180 uid = 0;
2181 att_dyn = NULL;
2182 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn);
2183 if (uid == 0)
2184 continue;
2185 if (att_dyn == NULL)
2186 continue;
2188 flags = imap_flags_to_flags(att_dyn, &tags);
2190 puid = malloc(sizeof(* puid));
2191 if (puid == NULL) {
2192 res = MAILIMAP_ERROR_MEMORY;
2193 goto free_list;
2195 * puid = uid;
2197 r = carray_add(tab, puid, NULL);
2198 if (r < 0) {
2199 free(puid);
2200 res = MAILIMAP_ERROR_MEMORY;
2201 goto free_list;
2203 pflags = malloc(sizeof(* pflags));
2204 if (pflags == NULL) {
2205 res = MAILIMAP_ERROR_MEMORY;
2206 goto free_list;
2208 * pflags = flags;
2209 r = carray_add(tab, pflags, NULL);
2210 if (r < 0) {
2211 free(pflags);
2212 res = MAILIMAP_ERROR_MEMORY;
2213 goto free_list;
2215 r = carray_add(tab, tags, NULL);
2216 if (r < 0) {
2217 free(pflags);
2218 res = MAILIMAP_ERROR_MEMORY;
2219 goto free_list;
2223 * result = tab;
2225 return MAILIMAP_NO_ERROR;
2227 free_list:
2228 imap_fetch_uid_flags_list_free(tab);
2229 slist_free_strings_full(tags);
2230 err:
2231 return res;
2234 static int imap_get_messages_flags_list(mailimap * imap,
2235 uint32_t first_index,
2236 carray ** result)
2238 carray * env_list;
2239 int r;
2240 struct mailimap_fetch_att * fetch_att;
2241 struct mailimap_fetch_type * fetch_type;
2242 struct mailimap_set * set;
2243 clist * fetch_result;
2244 int res;
2246 set = mailimap_set_new_interval(first_index, 0);
2247 if (set == NULL) {
2248 res = MAILIMAP_ERROR_MEMORY;
2249 goto err;
2252 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2253 if (fetch_type == NULL) {
2254 res = MAILIMAP_ERROR_MEMORY;
2255 goto free_set;
2258 fetch_att = mailimap_fetch_att_new_flags();
2259 if (fetch_att == NULL) {
2260 res = MAILIMAP_ERROR_MEMORY;
2261 goto free_fetch_type;
2264 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2265 if (r != MAILIMAP_NO_ERROR) {
2266 mailimap_fetch_att_free(fetch_att);
2267 res = MAILIMAP_ERROR_MEMORY;
2268 goto free_fetch_type;
2271 fetch_att = mailimap_fetch_att_new_uid();
2272 if (fetch_att == NULL) {
2273 res = MAILIMAP_ERROR_MEMORY;
2274 goto free_fetch_type;
2277 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2278 if (r != MAILIMAP_NO_ERROR) {
2279 mailimap_fetch_att_free(fetch_att);
2280 res = MAILIMAP_ERROR_MEMORY;
2281 goto free_fetch_type;
2284 mailstream_logger = imap_logger_fetch;
2286 r = mailimap_uid_fetch(imap, set,
2287 fetch_type, &fetch_result);
2289 mailstream_logger = imap_logger_cmd;
2290 mailimap_fetch_type_free(fetch_type);
2291 mailimap_set_free(set);
2293 if (r != MAILIMAP_NO_ERROR) {
2294 res = r;
2295 goto err;
2298 env_list = NULL;
2299 r = result_to_uid_flags_list(fetch_result, &env_list);
2300 mailimap_fetch_list_free(fetch_result);
2302 * result = env_list;
2304 return MAILIMAP_NO_ERROR;
2306 free_fetch_type:
2307 mailimap_fetch_type_free(fetch_type);
2308 free_set:
2309 mailimap_set_free(set);
2310 err:
2311 return res;
2316 static void fetch_uid_flags_run(struct etpan_thread_op * op)
2318 struct fetch_uid_param * param;
2319 struct fetch_uid_result * result;
2320 carray * fetch_result;
2321 int r;
2323 param = op->param;
2324 result = op->result;
2326 CHECK_IMAP();
2328 fetch_result = NULL;
2329 r = imap_get_messages_flags_list(param->imap, param->first_index,
2330 &fetch_result);
2332 result->error = r;
2333 result->fetch_result = fetch_result;
2334 debug_print("imap fetch_uid run - end %i\n", r);
2337 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index,
2338 carray ** fetch_result)
2340 struct fetch_uid_param param;
2341 struct fetch_uid_result result;
2342 mailimap * imap;
2344 debug_print("imap fetch_uid - begin\n");
2346 imap = get_imap(folder);
2347 param.imap = imap;
2348 param.first_index = first_index;
2350 mailstream_logger = imap_logger_noop;
2351 log_print(LOG_PROTOCOL, "IMAP- [fetching flags...]\n");
2353 threaded_run(folder, &param, &result, fetch_uid_flags_run);
2355 mailstream_logger = imap_logger_cmd;
2358 if (result.error != MAILIMAP_NO_ERROR)
2359 return result.error;
2361 debug_print("imap fetch_uid - end\n");
2363 * fetch_result = result.fetch_result;
2365 return result.error;
2369 void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
2371 unsigned int i;
2373 for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) {
2374 void * data;
2376 data = carray_get(uid_flags_list, i);
2377 free(data);
2378 data = carray_get(uid_flags_list, i + 1);
2379 free(data);
2381 carray_free(uid_flags_list);
2386 static int imap_fetch(mailimap * imap,
2387 uint32_t msg_index,
2388 char ** result,
2389 size_t * result_len)
2391 int r;
2392 struct mailimap_set * set;
2393 struct mailimap_fetch_att * fetch_att;
2394 struct mailimap_fetch_type * fetch_type;
2395 clist * fetch_result;
2396 struct mailimap_msg_att * msg_att;
2397 struct mailimap_msg_att_item * msg_att_item;
2398 char * text;
2399 size_t text_length;
2400 int res;
2401 clistiter * cur;
2402 struct mailimap_section * section;
2404 set = mailimap_set_new_single(msg_index);
2405 if (set == NULL) {
2406 res = MAILIMAP_ERROR_MEMORY;
2407 goto err;
2410 section = mailimap_section_new(NULL);
2411 if (section == NULL) {
2412 res = MAILIMAP_ERROR_MEMORY;
2413 goto free_set;
2416 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2417 if (fetch_att == NULL) {
2418 mailimap_section_free(section);
2419 res = MAILIMAP_ERROR_MEMORY;
2420 goto free_set;
2423 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2424 if (fetch_type == NULL) {
2425 res = MAILIMAP_ERROR_MEMORY;
2426 goto free_fetch_att;
2429 mailstream_logger = imap_logger_fetch;
2431 r = mailimap_uid_fetch(imap, set,
2432 fetch_type, &fetch_result);
2434 mailstream_logger = imap_logger_cmd;
2436 mailimap_fetch_type_free(fetch_type);
2437 mailimap_set_free(set);
2439 switch (r) {
2440 case MAILIMAP_NO_ERROR:
2441 break;
2442 default:
2443 return r;
2446 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2447 mailimap_fetch_list_free(fetch_result);
2448 return MAILIMAP_ERROR_FETCH;
2451 msg_att = clist_begin(fetch_result)->data;
2453 text = NULL;
2454 text_length = 0;
2456 if (msg_att->att_list)
2457 cur = clist_begin(msg_att->att_list);
2458 else
2459 cur = NULL;
2461 for(; cur != NULL ; cur = clist_next(cur)) {
2462 msg_att_item = clist_content(cur);
2464 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2465 if (msg_att_item->att_data.att_static->att_type ==
2466 MAILIMAP_MSG_ATT_BODY_SECTION) {
2467 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2468 /* detach */
2469 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2470 text_length =
2471 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2476 mailimap_fetch_list_free(fetch_result);
2478 if (text == NULL)
2479 return MAILIMAP_ERROR_FETCH;
2481 * result = text;
2482 * result_len = text_length;
2484 return MAILIMAP_NO_ERROR;
2486 free_fetch_att:
2487 mailimap_fetch_att_free(fetch_att);
2488 free_set:
2489 mailimap_set_free(set);
2490 err:
2491 return res;
2494 static int imap_fetch_header(mailimap * imap,
2495 uint32_t msg_index,
2496 char ** result,
2497 size_t * result_len)
2499 int r;
2500 struct mailimap_set * set;
2501 struct mailimap_fetch_att * fetch_att;
2502 struct mailimap_fetch_type * fetch_type;
2503 clist * fetch_result;
2504 struct mailimap_msg_att * msg_att;
2505 struct mailimap_msg_att_item * msg_att_item;
2506 char * text;
2507 size_t text_length;
2508 int res;
2509 clistiter * cur;
2510 struct mailimap_section * section;
2512 set = mailimap_set_new_single(msg_index);
2513 if (set == NULL) {
2514 res = MAILIMAP_ERROR_MEMORY;
2515 goto err;
2518 section = mailimap_section_new_header();
2519 if (section == NULL) {
2520 res = MAILIMAP_ERROR_MEMORY;
2521 goto free_set;
2524 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2525 if (fetch_att == NULL) {
2526 mailimap_section_free(section);
2527 res = MAILIMAP_ERROR_MEMORY;
2528 goto free_set;
2531 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2532 if (fetch_type == NULL) {
2533 res = MAILIMAP_ERROR_MEMORY;
2534 goto free_fetch_att;
2537 mailstream_logger = imap_logger_fetch;
2539 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2541 mailstream_logger = imap_logger_cmd;
2542 mailimap_fetch_type_free(fetch_type);
2543 mailimap_set_free(set);
2545 switch (r) {
2546 case MAILIMAP_NO_ERROR:
2547 break;
2548 default:
2549 return r;
2552 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2553 mailimap_fetch_list_free(fetch_result);
2554 return MAILIMAP_ERROR_FETCH;
2557 msg_att = clist_begin(fetch_result)->data;
2559 text = NULL;
2560 text_length = 0;
2562 if (msg_att->att_list)
2563 cur = clist_begin(msg_att->att_list);
2564 else
2565 cur = NULL;
2567 for(; cur != NULL ; cur = clist_next(cur)) {
2568 msg_att_item = clist_content(cur);
2570 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2571 if (msg_att_item->att_data.att_static->att_type ==
2572 MAILIMAP_MSG_ATT_BODY_SECTION) {
2573 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2574 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2575 text_length =
2576 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2581 mailimap_fetch_list_free(fetch_result);
2583 if (text == NULL)
2584 return MAILIMAP_ERROR_FETCH;
2586 * result = text;
2587 * result_len = text_length;
2589 return MAILIMAP_NO_ERROR;
2591 free_fetch_att:
2592 mailimap_fetch_att_free(fetch_att);
2593 free_set:
2594 mailimap_set_free(set);
2595 err:
2596 return res;
2601 struct fetch_content_param {
2602 mailimap * imap;
2603 uint32_t msg_index;
2604 const char * filename;
2605 int with_body;
2608 struct fetch_content_result {
2609 int error;
2612 static void fetch_content_run(struct etpan_thread_op * op)
2614 struct fetch_content_param * param;
2615 struct fetch_content_result * result;
2616 char * content;
2617 size_t content_size;
2618 int r;
2619 int fd;
2620 FILE * f;
2622 param = op->param;
2623 result = op->result;
2625 CHECK_IMAP();
2627 content = NULL;
2628 content_size = 0;
2629 if (param->with_body)
2630 r = imap_fetch(param->imap, param->msg_index,
2631 &content, &content_size);
2632 else
2633 r = imap_fetch_header(param->imap, param->msg_index,
2634 &content, &content_size);
2636 result->error = r;
2638 if (r == MAILIMAP_NO_ERROR) {
2639 fd = g_open(param->filename, O_RDWR | O_CREAT, 0600);
2640 if (fd < 0) {
2641 result->error = MAILIMAP_ERROR_FETCH;
2642 goto free;
2645 f = claws_fdopen(fd, "wb");
2646 if (f == NULL) {
2647 result->error = MAILIMAP_ERROR_FETCH;
2648 goto close;
2651 r = claws_fwrite(content, 1, content_size, f);
2652 if (r < content_size) {
2653 result->error = MAILIMAP_ERROR_FETCH;
2654 goto do_fclose;
2657 r = claws_safe_fclose(f);
2658 if (r == EOF) {
2659 result->error = MAILIMAP_ERROR_FETCH;
2660 goto unlink;
2662 goto free;
2664 do_fclose:
2665 claws_fclose(f);
2666 goto unlink;
2667 close:
2668 close(fd);
2669 unlink:
2670 if (claws_unlink(param->filename) < 0)
2671 FILE_OP_ERROR(param->filename, "claws_unlink");
2673 free:
2674 /* mmap_string_unref is a simple free in libetpan
2675 * when it has MMAP_UNAVAILABLE defined */
2676 if (mmap_string_unref(content) != 0)
2677 free(content);
2680 debug_print("imap fetch_content run - end %i\n", result->error);
2683 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2684 int with_body,
2685 const char * filename)
2687 struct fetch_content_param param;
2688 struct fetch_content_result result;
2689 mailimap * imap;
2691 debug_print("imap fetch_content - begin\n");
2693 imap = get_imap(folder);
2694 param.imap = imap;
2695 param.msg_index = msg_index;
2696 param.filename = filename;
2697 param.with_body = with_body;
2699 threaded_run(folder, &param, &result, fetch_content_run);
2701 if (result.error != MAILIMAP_NO_ERROR)
2702 return result.error;
2704 debug_print("imap fetch_content - end\n");
2706 return result.error;
2711 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags)
2713 int flags;
2714 clist * flag_list;
2715 clistiter * cur;
2716 GSList *tags = NULL;
2718 flags = MSG_UNREAD;
2720 flag_list = att_dyn->att_list;
2721 if (flag_list == NULL)
2722 return flags;
2724 for(cur = clist_begin(flag_list) ; cur != NULL ;
2725 cur = clist_next(cur)) {
2726 struct mailimap_flag_fetch * flag_fetch;
2728 flag_fetch = clist_content(cur);
2729 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2730 flags |= MSG_NEW;
2731 else {
2732 switch (flag_fetch->fl_flag->fl_type) {
2733 case MAILIMAP_FLAG_ANSWERED:
2734 flags |= MSG_REPLIED;
2735 break;
2736 case MAILIMAP_FLAG_FLAGGED:
2737 flags |= MSG_MARKED;
2738 break;
2739 case MAILIMAP_FLAG_DELETED:
2740 flags |= MSG_DELETED;
2741 break;
2742 case MAILIMAP_FLAG_SEEN:
2743 flags &= ~MSG_UNREAD;
2744 flags &= ~MSG_NEW;
2745 break;
2746 case MAILIMAP_FLAG_KEYWORD:
2747 if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
2748 flags |= MSG_FORWARDED;
2749 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
2750 flags |= MSG_SPAM;
2751 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
2752 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
2753 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
2754 flags &= ~MSG_SPAM;
2755 else if (s_tags)
2756 tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword));
2757 break;
2761 if (s_tags)
2762 *s_tags = tags;
2763 return flags;
2766 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2767 uint32_t * puid,
2768 char ** pheaders,
2769 size_t * pref_size,
2770 struct mailimap_msg_att_dynamic ** patt_dyn)
2772 clistiter * item_cur;
2773 uint32_t uid;
2774 char * headers;
2775 size_t ref_size;
2776 struct mailimap_msg_att_dynamic * att_dyn;
2778 uid = 0;
2779 headers = NULL;
2780 ref_size = 0;
2781 att_dyn = NULL;
2783 if (msg_att->att_list)
2784 item_cur = clist_begin(msg_att->att_list);
2785 else
2786 item_cur = NULL;
2787 for(; item_cur != NULL ; item_cur = clist_next(item_cur)) {
2788 struct mailimap_msg_att_item * item;
2790 item = clist_content(item_cur);
2792 switch (item->att_type) {
2793 case MAILIMAP_MSG_ATT_ITEM_STATIC:
2794 switch (item->att_data.att_static->att_type) {
2795 case MAILIMAP_MSG_ATT_UID:
2796 uid = item->att_data.att_static->att_data.att_uid;
2797 break;
2799 case MAILIMAP_MSG_ATT_BODY_SECTION:
2800 if (headers == NULL) {
2801 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2803 break;
2804 case MAILIMAP_MSG_ATT_RFC822_SIZE:
2805 ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2806 break;
2808 break;
2810 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2811 if (att_dyn == NULL) {
2812 att_dyn = item->att_data.att_dyn;
2814 break;
2818 if (puid != NULL)
2819 * puid = uid;
2820 if (pheaders != NULL)
2821 * pheaders = headers;
2822 if (pref_size != NULL)
2823 * pref_size = ref_size;
2824 if (patt_dyn != NULL)
2825 * patt_dyn = att_dyn;
2827 return MAIL_NO_ERROR;
2830 static struct imap_fetch_env_info *
2831 fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags)
2833 struct imap_fetch_env_info * info;
2834 uint32_t uid;
2835 char * headers;
2836 size_t size;
2837 struct mailimap_msg_att_dynamic * att_dyn;
2839 imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2840 &att_dyn);
2842 if (!headers)
2843 return NULL;
2844 info = malloc(sizeof(* info));
2845 info->uid = uid;
2846 info->headers = strdup(headers);
2847 info->size = size;
2848 info->flags = imap_flags_to_flags(att_dyn, tags);
2850 return info;
2853 static int
2854 imap_fetch_result_to_envelop_list(clist * fetch_result,
2855 carray ** p_env_list)
2857 clistiter * cur;
2859 if (fetch_result) {
2860 carray * env_list;
2861 env_list = carray_new(16);
2863 for(cur = clist_begin(fetch_result) ; cur != NULL ;
2864 cur = clist_next(cur)) {
2865 struct mailimap_msg_att * msg_att;
2866 struct imap_fetch_env_info * env_info;
2867 GSList *tags = NULL;
2869 msg_att = clist_content(cur);
2871 env_info = fetch_to_env_info(msg_att, &tags);
2872 if (!env_info
2873 || carray_add(env_list, env_info, NULL) != 0
2874 || carray_add(env_list, tags, NULL) != 0) {
2875 carray_free(env_list);
2876 return MAILIMAP_ERROR_MEMORY;
2879 * p_env_list = env_list;
2880 } else {
2881 * p_env_list = NULL;
2884 return MAIL_NO_ERROR;
2887 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2889 struct mailimap_fetch_att * fetch_att;
2890 int i;
2891 char * header;
2892 clist * hdrlist;
2893 struct mailimap_header_list * imap_hdrlist;
2894 struct mailimap_section * section;
2895 char *headers[] = {
2896 "Date", "From", "To", "Cc", "Subject", "Message-ID",
2897 "References", "In-Reply-To", NULL
2900 hdrlist = clist_new();
2901 if (!hdrlist)
2902 return MAIL_ERROR_MEMORY;
2903 i = 0;
2904 while (headers[i] != NULL) {
2905 header = strdup(headers[i]);
2906 if (header == NULL || clist_append(hdrlist, header) != 0) {
2907 clist_free(hdrlist);
2908 return MAIL_ERROR_MEMORY;
2910 ++i;
2913 imap_hdrlist = mailimap_header_list_new(hdrlist);
2914 section = mailimap_section_new_header_fields(imap_hdrlist);
2915 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2916 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2918 return MAIL_NO_ERROR;
2921 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2923 struct mailimap_fetch_att * fetch_att;
2924 struct mailimap_section * section;
2926 section = mailimap_section_new_header();
2927 fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2928 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2930 return MAIL_NO_ERROR;
2933 static int
2934 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2935 carray ** p_env_list)
2937 struct mailimap_fetch_att * fetch_att;
2938 struct mailimap_fetch_type * fetch_type;
2939 int res;
2940 clist * fetch_result;
2941 int r;
2942 carray * env_list = NULL;
2943 chashdatum key;
2944 chashdatum value;
2946 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2948 /* uid */
2949 fetch_att = mailimap_fetch_att_new_uid();
2950 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2952 /* flags */
2953 fetch_att = mailimap_fetch_att_new_flags();
2954 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2956 /* rfc822 size */
2957 fetch_att = mailimap_fetch_att_new_rfc822_size();
2958 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2960 /* headers */
2961 key.data = &imap;
2962 key.len = sizeof(imap);
2963 r = chash_get(courier_workaround_hash, &key, &value);
2964 if (r < 0)
2965 r = imap_add_envelope_fetch_att(fetch_type);
2966 else
2967 r = imap_add_header_fetch_att(fetch_type);
2969 if (r != MAILIMAP_NO_ERROR) {
2970 debug_print("add fetch attr: %d\n", r);
2971 return r;
2974 mailstream_logger = imap_logger_fetch;
2976 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2978 mailstream_logger = imap_logger_cmd;
2979 switch (r) {
2980 case MAILIMAP_NO_ERROR:
2981 break;
2982 default:
2983 mailimap_fetch_type_free(fetch_type);
2984 debug_print("uid_fetch: %d\n", r);
2985 return r;
2988 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2989 res = MAILIMAP_ERROR_FETCH;
2990 debug_print("clist_begin = NULL\n");
2991 goto err;
2994 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2995 mailimap_fetch_list_free(fetch_result);
2997 if (r != MAILIMAP_NO_ERROR) {
2998 mailimap_fetch_type_free(fetch_type);
2999 res = MAILIMAP_ERROR_MEMORY;
3000 debug_print("fetch_result_to_envelop_list: %d\n", res);
3001 goto err;
3004 mailimap_fetch_type_free(fetch_type);
3006 * p_env_list = env_list;
3008 return MAILIMAP_NO_ERROR;
3010 err:
3011 return res;
3014 struct fetch_env_param {
3015 mailimap * imap;
3016 struct mailimap_set * set;
3019 struct fetch_env_result {
3020 carray * fetch_env_result;
3021 int error;
3024 static void fetch_env_run(struct etpan_thread_op * op)
3026 struct fetch_env_param * param;
3027 struct fetch_env_result * result;
3028 carray * env_list;
3029 int r;
3031 param = op->param;
3032 result = op->result;
3034 CHECK_IMAP();
3036 env_list = NULL;
3037 r = imap_get_envelopes_list(param->imap, param->set,
3038 &env_list);
3040 result->error = r;
3041 result->fetch_env_result = env_list;
3043 debug_print("imap fetch_env run - end %i\n", r);
3046 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
3047 carray ** p_env_list)
3049 struct fetch_env_param param;
3050 struct fetch_env_result result;
3051 mailimap * imap;
3053 debug_print("imap fetch_env - begin\n");
3055 imap = get_imap(folder);
3056 param.imap = imap;
3057 param.set = set;
3059 if (threaded_run(folder, &param, &result, fetch_env_run))
3060 return MAILIMAP_ERROR_INVAL;
3062 if (result.error != MAILIMAP_NO_ERROR) {
3063 chashdatum key;
3064 chashdatum value;
3065 int r;
3067 key.data = &imap;
3068 key.len = sizeof(imap);
3069 r = chash_get(courier_workaround_hash, &key, &value);
3070 if (r < 0) {
3071 value.data = NULL;
3072 value.len = 0;
3073 chash_set(courier_workaround_hash, &key, &value, NULL);
3075 threaded_run(folder, &param, &result, fetch_env_run);
3079 if (result.error != MAILIMAP_NO_ERROR)
3080 return result.error;
3082 debug_print("imap fetch_env - end\n");
3084 * p_env_list = result.fetch_env_result;
3086 return result.error;
3089 void imap_fetch_env_free(carray * env_list)
3091 unsigned int i;
3093 for(i = 0 ; i < carray_count(env_list) ; i += 2) {
3094 struct imap_fetch_env_info * env_info;
3096 env_info = carray_get(env_list, i);
3097 free(env_info->headers);
3098 free(env_info);
3100 carray_free(env_list);
3107 struct append_param {
3108 mailimap * imap;
3109 const char * mailbox;
3110 const char * filename;
3111 struct mailimap_flag_list * flag_list;
3114 struct append_result {
3115 int error;
3116 int uid;
3119 static void append_run(struct etpan_thread_op * op)
3121 struct append_param * param;
3122 struct append_result * result;
3123 int r;
3124 char * data;
3125 size_t size;
3126 #ifndef G_OS_WIN32
3127 struct stat stat_buf;
3128 int fd;
3129 #endif
3130 guint32 uid = 0, val = 0;
3132 param = op->param;
3133 result = op->result;
3135 CHECK_IMAP();
3137 #ifndef G_OS_WIN32
3138 r = stat(param->filename, &stat_buf);
3139 if (r < 0) {
3140 result->error = MAILIMAP_ERROR_APPEND;
3141 return;
3143 size = stat_buf.st_size;
3145 fd = g_open(param->filename, O_RDONLY, 0);
3146 if (fd < 0) {
3147 result->error = MAILIMAP_ERROR_APPEND;
3148 return;
3151 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
3152 if (data == (void *) MAP_FAILED) {
3153 close(fd);
3154 result->error = MAILIMAP_ERROR_APPEND;
3155 return;
3157 #else
3158 data = file_read_to_str_no_recode(param->filename);
3159 if (data == NULL) {
3160 result->error = MAILIMAP_ERROR_APPEND;
3161 return;
3163 size = strlen(data);
3164 #endif
3165 mailstream_logger = imap_logger_append;
3167 r = mailimap_uidplus_append(param->imap, param->mailbox,
3168 param->flag_list, NULL,
3169 data, size, &val, &uid);
3171 mailstream_logger = imap_logger_cmd;
3173 #ifndef G_OS_WIN32
3174 munmap(data, size);
3175 close(fd);
3176 #else
3177 g_free(data);
3178 #endif
3180 result->error = r;
3181 result->uid = uid;
3182 debug_print("imap append run - end %i uid %d\n", r, uid);
3185 int imap_threaded_append(Folder * folder, const char * mailbox,
3186 const char * filename,
3187 struct mailimap_flag_list * flag_list,
3188 int *uid)
3190 struct append_param param;
3191 struct append_result result;
3192 mailimap * imap;
3194 debug_print("imap append - begin\n");
3196 imap = get_imap(folder);
3197 param.imap = imap;
3198 param.mailbox = mailbox;
3199 param.filename = filename;
3200 param.flag_list = flag_list;
3202 threaded_run(folder, &param, &result, append_run);
3204 if (result.error != MAILIMAP_NO_ERROR)
3205 return result.error;
3207 debug_print("imap append - end\n");
3208 if (uid != NULL)
3209 *uid = result.uid;
3211 return result.error;
3217 struct expunge_param {
3218 mailimap * imap;
3221 struct expunge_result {
3222 int error;
3225 static void expunge_run(struct etpan_thread_op * op)
3227 struct expunge_param * param;
3228 struct expunge_result * result;
3229 int r;
3231 param = op->param;
3232 result = op->result;
3234 CHECK_IMAP();
3236 r = mailimap_expunge(param->imap);
3238 result->error = r;
3239 debug_print("imap expunge run - end %i\n", r);
3242 int imap_threaded_expunge(Folder * folder)
3244 struct expunge_param param;
3245 struct expunge_result result;
3247 debug_print("imap expunge - begin\n");
3249 param.imap = get_imap(folder);
3251 threaded_run(folder, &param, &result, expunge_run);
3253 debug_print("imap expunge - end\n");
3255 return result.error;
3259 struct copy_param {
3260 mailimap * imap;
3261 struct mailimap_set * set;
3262 const char * mb;
3265 struct copy_result {
3266 int error;
3267 struct mailimap_set *source;
3268 struct mailimap_set *dest;
3271 static void copy_run(struct etpan_thread_op * op)
3273 struct copy_param * param;
3274 struct copy_result * result;
3275 int r;
3276 guint32 val;
3277 struct mailimap_set *source = NULL, *dest = NULL;
3279 param = op->param;
3280 result = op->result;
3282 CHECK_IMAP();
3284 r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
3285 &val, &source, &dest);
3287 result->error = r;
3288 if (r == 0) {
3289 result->source = source;
3290 result->dest = dest;
3291 } else {
3292 result->source = NULL;
3293 result->dest = NULL;
3295 debug_print("imap copy run - end %i\n", r);
3298 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
3299 const char * mb, struct mailimap_set **source,
3300 struct mailimap_set **dest)
3302 struct copy_param param;
3303 struct copy_result result;
3304 mailimap * imap;
3306 debug_print("imap copy - begin\n");
3308 imap = get_imap(folder);
3309 param.imap = imap;
3310 param.set = set;
3311 param.mb = mb;
3313 threaded_run(folder, &param, &result, copy_run);
3314 *source = NULL;
3315 *dest = NULL;
3317 if (result.error != MAILIMAP_NO_ERROR)
3318 return result.error;
3320 *source = result.source;
3321 *dest = result.dest;
3323 debug_print("imap copy - end\n");
3325 return result.error;
3330 struct store_param {
3331 mailimap * imap;
3332 struct mailimap_set * set;
3333 struct mailimap_store_att_flags * store_att_flags;
3336 struct store_result {
3337 int error;
3340 static void store_run(struct etpan_thread_op * op)
3342 struct store_param * param;
3343 struct store_result * result;
3344 int r;
3346 param = op->param;
3347 result = op->result;
3349 CHECK_IMAP();
3351 r = mailimap_uid_store(param->imap, param->set,
3352 param->store_att_flags);
3354 result->error = r;
3356 debug_print("imap store run - end %i\n", r);
3359 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
3360 struct mailimap_store_att_flags * store_att_flags)
3362 struct store_param param;
3363 struct store_result result;
3364 mailimap * imap;
3366 debug_print("imap store - begin\n");
3368 imap = get_imap(folder);
3369 param.imap = imap;
3370 param.set = set;
3371 param.store_att_flags = store_att_flags;
3373 threaded_run(folder, &param, &result, store_run);
3375 if (result.error != MAILIMAP_NO_ERROR)
3376 return result.error;
3378 debug_print("imap store - end\n");
3380 return result.error;
3384 #ifndef G_OS_WIN32
3385 static void do_exec_command(int fd, const char * command,
3386 const char * servername, uint16_t port)
3388 int i, maxopen;
3390 if (fork() > 0) {
3391 /* Fork again to become a child of init rather than
3392 the etpan client. */
3393 exit(0);
3396 if (servername)
3397 g_setenv("ETPANSERVER", servername, TRUE);
3398 else
3399 g_unsetenv("ETPANSERVER");
3401 if (port) {
3402 char porttext[20];
3404 snprintf(porttext, sizeof(porttext), "%d", port);
3405 g_setenv("ETPANPORT", porttext, TRUE);
3407 else {
3408 g_unsetenv("ETPANPORT");
3411 /* Not a lot we can do if there's an error other than bail. */
3412 if (dup2(fd, 0) == -1)
3413 exit(1);
3414 if (dup2(fd, 1) == -1)
3415 exit(1);
3417 /* Should we close stderr and reopen /dev/null? */
3419 maxopen = sysconf(_SC_OPEN_MAX);
3420 for (i=3; i < maxopen; i++)
3421 close(i);
3423 #ifdef TIOCNOTTY
3424 /* Detach from the controlling tty if we have one. Otherwise,
3425 SSH might do something stupid like trying to use it instead
3426 of running $SSH_ASKPASS. Doh. */
3427 fd = g_open("/dev/tty", O_RDONLY, 0);
3428 if (fd != -1) {
3429 ioctl(fd, TIOCNOTTY, NULL);
3430 close(fd);
3432 #endif /* TIOCNOTTY */
3434 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
3436 /* Eep. Shouldn't reach this */
3437 exit(1);
3440 static int subcommand_connect(const char *command,
3441 const char *servername, uint16_t port)
3443 /* SEB unsupported on Windows */
3444 int sockfds[2];
3445 pid_t childpid;
3447 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
3448 return -1;
3450 childpid = fork();
3451 if (!childpid) {
3452 do_exec_command(sockfds[1], command, servername, port);
3454 else if (childpid == -1) {
3455 close(sockfds[0]);
3456 close(sockfds[1]);
3457 return -1;
3460 close(sockfds[1]);
3462 /* Reap child, leaving grandchild process to run */
3463 waitpid(childpid, NULL, 0);
3465 return sockfds[0];
3468 static int socket_connect_cmd(mailimap * imap, const char * command,
3469 const char * server, int port)
3471 int fd;
3472 mailstream * s;
3473 int r;
3475 fd = subcommand_connect(command, server, port);
3476 if (fd < 0)
3477 return MAILIMAP_ERROR_STREAM;
3479 s = mailstream_socket_open(fd);
3480 if (s == NULL) {
3481 close(fd);
3482 return MAILIMAP_ERROR_STREAM;
3485 r = mailimap_connect(imap, s);
3486 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
3487 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
3488 mailstream_close(s);
3489 if (imap)
3490 imap->imap_stream = NULL;
3491 return r;
3494 return r;
3497 /* connect cmd */
3499 struct connect_cmd_param {
3500 mailimap * imap;
3501 const char * command;
3502 const char * server;
3503 int port;
3506 struct connect_cmd_result {
3507 int error;
3510 static void connect_cmd_run(struct etpan_thread_op * op)
3512 int r;
3513 struct connect_cmd_param * param;
3514 struct connect_cmd_result * result;
3516 param = op->param;
3517 result = op->result;
3519 CHECK_IMAP();
3521 r = socket_connect_cmd(param->imap, param->command,
3522 param->server, param->port);
3524 result->error = r;
3528 int imap_threaded_connect_cmd(Folder * folder, const char * command,
3529 const char * server, int port)
3531 struct connect_cmd_param param;
3532 struct connect_cmd_result result;
3533 chashdatum key;
3534 chashdatum value;
3535 mailimap * imap, * oldimap;
3537 oldimap = get_imap(folder);
3539 imap = mailimap_new(0, NULL);
3541 if (oldimap) {
3542 debug_print("deleting old imap %p\n", oldimap);
3543 delete_imap(folder, oldimap);
3546 key.data = &folder;
3547 key.len = sizeof(folder);
3548 value.data = imap;
3549 value.len = 0;
3550 chash_set(session_hash, &key, &value, NULL);
3552 param.imap = imap;
3553 param.command = command;
3554 param.server = server;
3555 param.port = port;
3557 threaded_run(folder, &param, &result, connect_cmd_run);
3559 debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
3561 return result.error;
3563 #endif /* G_OS_WIN32 */
3565 void imap_threaded_cancel(Folder * folder)
3567 mailimap * imap;
3569 imap = get_imap(folder);
3570 if (imap && imap->imap_stream != NULL)
3571 mailstream_cancel(imap->imap_stream);
3574 #else
3576 void imap_main_init(void)
3579 void imap_main_done(gboolean have_connectivity)
3582 void imap_main_set_timeout(int sec)
3586 void imap_threaded_cancel(Folder * folder);
3590 #endif