1 /*
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
4  *
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.
9  *
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.
14  *
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/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23 
24 #ifdef HAVE_LIBETPAN
25 
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"
53 
54 #define DISABLE_LOG_DURING_LOGIN
55 
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;
62 
do_mailimap_socket_connect(mailimap * imap,const char * server,gushort port,ProxyInfo * proxy_info)63 static int do_mailimap_socket_connect(mailimap * imap, const char * server,
64 			       gushort port, ProxyInfo * proxy_info)
65 {
66 	SockInfo * sock;
67 	mailstream * stream;
68 
69 	if (!proxy_info)
70 		return mailimap_socket_connect(imap, server, port);
71 
72 	if (port == 0)
73 		port = 143;
74 
75 	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
76 
77 	if (sock == NULL)
78 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
79 
80 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
81 		sock_close(sock, TRUE);
82 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
83 	}
84 
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;
90 	}
91 
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);
96 
97 	return mailimap_connect(imap, stream);
98 }
99 
do_mailimap_ssl_connect_with_callback(mailimap * imap,const char * server,gushort port,void (* callback)(struct mailstream_ssl_context * ssl_context,void * data),void * data,ProxyInfo * proxy_info)100 static int do_mailimap_ssl_connect_with_callback(mailimap * imap, const char * server,
101 	gushort port,
102 	void (* callback)(struct mailstream_ssl_context * ssl_context, void * data),
103 	void * data,
104 	ProxyInfo *proxy_info)
105 {
106 	SockInfo * sock;
107 	mailstream * stream;
108 
109 	if (!proxy_info)
110 		return mailimap_ssl_connect_with_callback(imap, server,
111 				port, callback, data);
112 
113 	if (port == 0)
114 		port = 993;
115 
116 	sock = sock_connect(proxy_info->proxy_host, proxy_info->proxy_port);
117 
118 	if (sock == NULL) {
119 		debug_print("Can not connect to proxy %s:%d\n",
120 				proxy_info->proxy_host, proxy_info->proxy_port);
121 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
122 	}
123 
124 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
125 		debug_print("Can not make proxy connection via %s:%d\n",
126 				proxy_info->proxy_host, proxy_info->proxy_port);
127 		sock_close(sock, TRUE);
128 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
129 	}
130 
131 	stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
132 			imap->imap_timeout, callback, data);
133 	if (stream == NULL) {
134 		sock_close(sock, TRUE);
135 		return MAILIMAP_ERROR_SSL;
136 	}
137 
138 	/* Libetpan now has the socket fd, and we're not interested in
139 	 * rest of the SockInfo struct. Let's free it, while not touching
140 	 * the socket itself. */
141 	sock_close(sock, FALSE);
142 
143 	return mailimap_connect(imap, stream);
144 }
145 
thread_manager_event(GIOChannel * source,GIOCondition condition,gpointer data)146 static gboolean thread_manager_event(GIOChannel * source,
147     GIOCondition condition,
148     gpointer data)
149 {
150 #ifdef G_OS_WIN32
151 	gsize bytes_read;
152 	gchar ch;
153 
154 	if (condition & G_IO_IN)
155 		g_io_channel_read_chars(source, &ch, 1, &bytes_read, NULL);
156 #endif
157 	etpan_thread_manager_loop(thread_manager);
158 
159 	return TRUE;
160 }
161 
imap_logger_noop(int direction,const char * str,size_t size)162 static void imap_logger_noop(int direction, const char * str, size_t size)
163 {
164 	/* inhibit logging */
165 }
166 
imap_logger_cmd(int direction,const char * str,size_t size)167 static void imap_logger_cmd(int direction, const char * str, size_t size)
168 {
169 	gchar *buf;
170 	gchar **lines;
171 	int i = 0;
172 
173 	if (size > 8192) {
174 		log_print(LOG_PROTOCOL, "IMAP%c [CMD data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
175 		return;
176 	}
177 	buf = malloc(size+1);
178 	memset(buf, 0, size+1);
179 	strncpy(buf, str, size);
180 	buf[size] = '\0';
181 
182 	if (!strncmp(buf, "<<<<<<<", 7)
183 	||  !strncmp(buf, ">>>>>>>", 7)) {
184 		free(buf);
185 		return;
186 	}
187 	while (strstr(buf, "\r"))
188 		*strstr(buf, "\r") = ' ';
189 	while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
190 		buf[strlen(buf)-1] = '\0';
191 
192 	lines = g_strsplit(buf, "\n", -1);
193 
194 	while (lines[i] && *lines[i]) {
195 		log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
196 		i++;
197 	}
198 	g_strfreev(lines);
199 	free(buf);
200 }
201 
imap_logger_fetch(int direction,const char * str,size_t size)202 static void imap_logger_fetch(int direction, const char * str, size_t size)
203 {
204 	gchar *buf;
205 	gchar **lines;
206 	int i = 0;
207 
208 	if (size > 128 && !direction) {
209 		log_print(LOG_PROTOCOL, "IMAP%c [FETCH data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
210 		return;
211 	}
212 
213 	buf = malloc(size+1);
214 	memset(buf, 0, size+1);
215 	strncpy(buf, str, size);
216 	buf[size] = '\0';
217 	if (!strncmp(buf, "<<<<<<<", 7)
218 	||  !strncmp(buf, ">>>>>>>", 7)) {
219 		free(buf);
220 		return;
221 	}
222 	while (strstr(buf, "\r"))
223 		*strstr(buf, "\r") = ' ';
224 	while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
225 		buf[strlen(buf)-1] = '\0';
226 
227 	lines = g_strsplit(buf, "\n", -1);
228 
229 	if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) {
230 		while (lines[i] && *lines[i]) {
231 			log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
232 			i++;
233 		}
234 	} else {
235 		log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
236 	}
237 	g_strfreev(lines);
238 	free(buf);
239 }
240 
imap_logger_uid(int direction,const char * str,size_t size)241 static void imap_logger_uid(int direction, const char * str, size_t size)
242 {
243 	gchar *buf;
244 	gchar **lines;
245 	int i = 0;
246 
247 	if (size > 8192) {
248 		log_print(LOG_PROTOCOL, "IMAP%c [UID data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
249 		return;
250 	}
251 	buf = malloc(size+1);
252 	memset(buf, 0, size+1);
253 	strncpy(buf, str, size);
254 	buf[size] = '\0';
255 	if (!strncmp(buf, "<<<<<<<", 7)
256 	||  !strncmp(buf, ">>>>>>>", 7)) {
257 		free(buf);
258 		return;
259 	}
260 	while (strstr(buf, "\r"))
261 		*strstr(buf, "\r") = ' ';
262 	while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
263 		buf[strlen(buf)-1] = '\0';
264 
265 	lines = g_strsplit(buf, "\n", -1);
266 
267 	while (lines[i] && *lines[i]) {
268 		int llen = strlen(lines[i]);
269 		if (llen < 64)
270 			log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
271 		else {
272 			gchar tmp[64];
273 			strncpy2(tmp, lines[i], 63);
274 			log_print(LOG_PROTOCOL, "IMAP%c %s[... - %d bytes more]\n", direction?'>':'<', tmp,
275 				  llen-64);
276 		}
277 		i++;
278 	}
279 	g_strfreev(lines);
280 	free(buf);
281 }
282 
imap_logger_append(int direction,const char * str,size_t size)283 static void imap_logger_append(int direction, const char * str, size_t size)
284 {
285 	gchar *buf;
286 	gchar **lines;
287 	int i = 0;
288 
289 	if (size > 8192) {
290 		log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
291 		return;
292 	} else if (direction == 0 && size > 64) {
293 		log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
294 		return;
295 	}
296 	buf = malloc(size+1);
297 	memset(buf, 0, size+1);
298 	strncpy(buf, str, size);
299 	buf[size] = '\0';
300 	if (!strncmp(buf, "<<<<<<<", 7)
301 	||  !strncmp(buf, ">>>>>>>", 7)) {
302 		free(buf);
303 		return;
304 	}
305 	while (strstr(buf, "\r"))
306 		*strstr(buf, "\r") = ' ';
307 	while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
308 		buf[strlen(buf)-1] = '\0';
309 
310 	lines = g_strsplit(buf, "\n", -1);
311 
312 	if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) {
313 		while (lines[i] && *lines[i]) {
314 			log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]);
315 			i++;
316 		}
317 	} else {
318 		log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size);
319 	}
320 	g_strfreev(lines);
321 	free(buf);
322 }
323 
324 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
325 gboolean etpan_skip_ssl_cert_check = FALSE;
326 extern void mailsasl_ref(void);
327 
imap_main_init(gboolean skip_ssl_cert_check)328 void imap_main_init(gboolean skip_ssl_cert_check)
329 {
330 	int fd_thread_manager;
331 
332 	etpan_skip_ssl_cert_check = skip_ssl_cert_check;
333 	mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT;
334 	mailstream_network_delay.tv_usec = 0;
335 
336 	mailstream_debug = 1;
337 	mailstream_logger = imap_logger_cmd;
338 	mailsasl_ref();
339 
340 	imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
341 	session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
342 	courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE);
343 
344 	thread_manager = etpan_thread_manager_new();
345 
346 	fd_thread_manager = etpan_thread_manager_get_fd(thread_manager);
347 
348 #ifndef G_OS_WIN32
349 	io_channel = g_io_channel_unix_new(fd_thread_manager);
350 #else
351 	io_channel = g_io_channel_win32_new_fd(fd_thread_manager);
352 #endif
353 	thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN,
354 						    thread_manager_event,
355 						    (gpointer) NULL,
356 						    NULL);
357 }
358 
imap_main_set_timeout(int sec)359 void imap_main_set_timeout(int sec)
360 {
361 	mailstream_network_delay.tv_sec = sec;
362 	mailstream_network_delay.tv_usec = 0;
363 }
364 
imap_main_done(gboolean have_connectivity)365 void imap_main_done(gboolean have_connectivity)
366 {
367 	imap_disconnect_all(have_connectivity);
368 	etpan_thread_manager_stop(thread_manager);
369 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
370 	return;
371 #endif
372 	etpan_thread_manager_join(thread_manager);
373 
374 	g_source_remove(thread_manager_signal);
375 	g_io_channel_unref(io_channel);
376 
377 	etpan_thread_manager_free(thread_manager);
378 
379 	chash_free(courier_workaround_hash);
380 	chash_free(session_hash);
381 	chash_free(imap_hash);
382 }
383 
imap_init(Folder * folder)384 void imap_init(Folder * folder)
385 {
386 	struct etpan_thread * thread;
387 	chashdatum key;
388 	chashdatum value;
389 
390 	thread = etpan_thread_manager_get_thread(thread_manager);
391 
392 	key.data = &folder;
393 	key.len = sizeof(folder);
394 	value.data = thread;
395 	value.len = 0;
396 
397 	chash_set(imap_hash, &key, &value, NULL);
398 }
399 
imap_done(Folder * folder)400 void imap_done(Folder * folder)
401 {
402 	struct etpan_thread * thread;
403 	chashdatum key;
404 	chashdatum value;
405 	int r;
406 
407 	key.data = &folder;
408 	key.len = sizeof(folder);
409 
410 	r = chash_get(imap_hash, &key, &value);
411 	if (r < 0)
412 		return;
413 
414 	thread = value.data;
415 
416 	etpan_thread_unbind(thread);
417 
418 	chash_delete(imap_hash, &key, NULL);
419 
420 	debug_print("remove thread\n");
421 }
422 
get_thread(Folder * folder)423 static struct etpan_thread * get_thread(Folder * folder)
424 {
425 	struct etpan_thread * thread;
426 	chashdatum key;
427 	chashdatum value;
428 	int r;
429 
430 	key.data = &folder;
431 	key.len = sizeof(folder);
432 
433 	r = chash_get(imap_hash, &key, &value);
434 	if (r < 0)
435 		return NULL;
436 
437 	thread = value.data;
438 
439 	return thread;
440 }
441 
get_imap(Folder * folder)442 static mailimap * get_imap(Folder * folder)
443 {
444 	mailimap * imap;
445 	chashdatum key;
446 	chashdatum value;
447 	int r;
448 
449 	key.data = &folder;
450 	key.len = sizeof(folder);
451 
452 	r = chash_get(session_hash, &key, &value);
453 	if (r < 0)
454 		return NULL;
455 
456 	imap = value.data;
457 	debug_print("found imap %p\n", imap);
458 	return imap;
459 }
460 
cb_show_error(gpointer data)461 static gboolean cb_show_error(gpointer data)
462 {
463 	mainwindow_show_error();
464 	return FALSE;
465 }
466 
generic_cb(int cancelled,void * result,void * callback_data)467 static void generic_cb(int cancelled, void * result, void * callback_data)
468 {
469 	struct etpan_thread_op * op;
470 
471 	op = (struct etpan_thread_op *) callback_data;
472 
473 	debug_print("generic_cb\n");
474 	if (op->imap && op->imap->imap_response_info &&
475 	    op->imap->imap_response_info->rsp_alert) {
476 		log_error(LOG_PROTOCOL, "IMAP< Alert: %s\n",
477 			op->imap->imap_response_info->rsp_alert);
478 		g_timeout_add(10, cb_show_error, NULL);
479 	}
480 	op->finished = 1;
481 }
482 
483 /* Please do *not* blindly use imap pointers after this function returns,
484  * someone may have deleted it while this function was waiting for completion.
485  * Check return value to see if imap is still valid.
486  * Run get_imap(folder) again to get a fresh and valid pointer.
487  */
threaded_run(Folder * folder,void * param,void * result,void (* func)(struct etpan_thread_op *))488 static int threaded_run(Folder * folder, void * param, void * result,
489 			void (* func)(struct etpan_thread_op * ))
490 {
491 	struct etpan_thread_op * op;
492 	struct etpan_thread * thread;
493 	struct mailimap * imap = get_imap(folder);
494 
495 	imap_folder_ref(folder);
496 
497 	op = etpan_thread_op_new();
498 
499 	op->imap = imap;
500 	op->param = param;
501 	op->result = result;
502 
503 	op->run = func;
504 	op->callback = generic_cb;
505 	op->callback_data = op;
506 
507 	thread = get_thread(folder);
508 	etpan_thread_op_schedule(thread, op);
509 
510 	while (!op->finished) {
511 		gtk_main_iteration();
512 	}
513 
514 	etpan_thread_op_free(op);
515 
516 	imap_folder_unref(folder);
517 
518 	if (imap != get_imap(folder)) {
519 		g_warning("returning from operation on a stale imap %p", imap);
520 		return 1;
521 	}
522 
523 	return 0;
524 }
525 
526 
527 /* connect */
528 
529 struct connect_param {
530 	mailimap * imap;
531 	PrefsAccount *account;
532 	const char * server;
533 	int port;
534 	ProxyInfo * proxy_info;
535 };
536 
537 struct connect_result {
538 	int error;
539 };
540 
541 #define CHECK_IMAP() {						\
542 	if (!param->imap) {					\
543 		result->error = MAILIMAP_ERROR_BAD_STATE;	\
544 		return;						\
545 	}							\
546 }
547 
548 
delete_imap_run(struct etpan_thread_op * op)549 static void delete_imap_run(struct etpan_thread_op * op)
550 {
551 	mailimap * imap = op->imap;
552 
553 	/* we don't want libetpan to logout */
554 	if (imap->imap_stream) {
555 		mailstream_close(imap->imap_stream);
556 		imap->imap_stream = NULL;
557 	}
558 
559 	mailimap_free(imap);
560 }
561 
threaded_delete_imap(Folder * folder,mailimap * imap)562 static void threaded_delete_imap(Folder *folder, mailimap *imap)
563 {
564 	struct etpan_thread_op * op;
565 
566 	/* No need to wait for completion, threaded_run() won't work here. */
567 	op = etpan_thread_op_new();
568 	op->imap = imap;
569 	op->run = delete_imap_run;
570 	op->cleanup = etpan_thread_op_free;
571 
572 	etpan_thread_op_schedule(get_thread(folder), op);
573 
574 	debug_print("threaded delete imap posted\n");
575 }
576 
delete_imap(Folder * folder,mailimap * imap)577 static void delete_imap(Folder *folder, mailimap *imap)
578 {
579 	chashdatum key;
580 
581 	key.data = &folder;
582 	key.len = sizeof(folder);
583 	chash_delete(session_hash, &key, NULL);
584 
585 	if (!imap)
586 		return;
587 	key.data = &imap;
588 	key.len = sizeof(imap);
589 	chash_delete(courier_workaround_hash, &key, NULL);
590 	/* We can't just free imap here as there may be ops on it pending
591 	 * in the thread. Posting freeing as an op will synchronize against
592 	 * existing jobs and as imap is already removed from session_hash
593 	 * we are sure no new ops can be posted. */
594 	threaded_delete_imap(folder, imap);
595 }
596 
connect_run(struct etpan_thread_op * op)597 static void connect_run(struct etpan_thread_op * op)
598 {
599 	int r;
600 	struct connect_param * param;
601 	struct connect_result * result;
602 
603 	param = op->param;
604 	result = op->result;
605 
606 	CHECK_IMAP();
607 
608 	r = do_mailimap_socket_connect(param->imap,
609 				    param->server, param->port, param->proxy_info);
610 
611 	result->error = r;
612 }
613 
614 
imap_threaded_connect(Folder * folder,const char * server,int port,ProxyInfo * proxy_info)615 int imap_threaded_connect(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
616 {
617 	struct connect_param param;
618 	struct connect_result result;
619 	chashdatum key;
620 	chashdatum value;
621 	mailimap * imap, * oldimap;
622 
623 	oldimap = get_imap(folder);
624 
625 	imap = mailimap_new(0, NULL);
626 
627 	if (oldimap) {
628 		debug_print("deleting old imap %p\n", oldimap);
629 		delete_imap(folder, oldimap);
630 	}
631 
632 	key.data = &folder;
633 	key.len = sizeof(folder);
634 	value.data = imap;
635 	value.len = 0;
636 	chash_set(session_hash, &key, &value, NULL);
637 
638 	param.imap = imap;
639 	param.server = server;
640 	param.port = port;
641 	param.proxy_info = proxy_info;
642 
643 	refresh_resolvers();
644 	threaded_run(folder, &param, &result, connect_run);
645 
646 	debug_print("connect ok %i with imap %p\n", result.error, imap);
647 
648 	return result.error;
649 }
650 #ifdef USE_GNUTLS
connect_ssl_run(struct etpan_thread_op * op)651 static void connect_ssl_run(struct etpan_thread_op * op)
652 {
653 	int r;
654 	struct connect_param * param;
655 	struct connect_result * result;
656 
657 	param = op->param;
658 	result = op->result;
659 
660 	CHECK_IMAP();
661 
662 	r = do_mailimap_ssl_connect_with_callback(param->imap,
663 				 		param->server, param->port,
664 						etpan_connect_ssl_context_cb, param->account,
665 						param->proxy_info);
666 	result->error = r;
667 }
668 
imap_threaded_connect_ssl(Folder * folder,const char * server,int port,ProxyInfo * proxy_info)669 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port, ProxyInfo *proxy_info)
670 {
671 	struct connect_param param;
672 	struct connect_result result;
673 	chashdatum key;
674 	chashdatum value;
675 	mailimap * imap, * oldimap;
676 	gboolean accept_if_valid = FALSE;
677 
678 	oldimap = get_imap(folder);
679 
680 	imap = mailimap_new(0, NULL);
681 
682 	if (oldimap) {
683 		debug_print("deleting old imap %p\n", oldimap);
684 		delete_imap(folder, oldimap);
685 	}
686 
687 	key.data = &folder;
688 	key.len = sizeof(folder);
689 	value.data = imap;
690 	value.len = 0;
691 	chash_set(session_hash, &key, &value, NULL);
692 
693 	param.imap = imap;
694 	param.server = server;
695 	param.port = port;
696 	param.account = folder->account;
697 	param.proxy_info = proxy_info;
698 
699 	if (folder->account)
700 		accept_if_valid = folder->account->ssl_certs_auto_accept;
701 
702 	refresh_resolvers();
703 	if (threaded_run(folder, &param, &result, connect_ssl_run))
704 		return MAILIMAP_ERROR_INVAL;
705 
706 	if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
707 	     result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
708 		if (etpan_certificate_check(imap->imap_stream, server, port,
709 					    accept_if_valid) != TRUE)
710 			result.error = MAILIMAP_ERROR_SSL;
711 	}
712 	debug_print("connect %d with imap %p\n", result.error, imap);
713 
714 	return result.error;
715 }
716 #endif
717 struct capa_param {
718 	mailimap * imap;
719 };
720 
721 struct capa_result {
722 	int error;
723 	struct mailimap_capability_data *caps;
724 };
725 
capability_run(struct etpan_thread_op * op)726 static void capability_run(struct etpan_thread_op * op)
727 {
728 	int r;
729 	struct capa_param * param;
730 	struct capa_result * result;
731 	struct mailimap_capability_data *caps;
732 
733 	param = op->param;
734 	result = op->result;
735 
736 	CHECK_IMAP();
737 
738 	r = mailimap_capability(param->imap, &caps);
739 
740 	result->error = r;
741 	result->caps = (r == 0 ? caps : NULL);
742 }
743 
744 
imap_threaded_capability(Folder * folder,struct mailimap_capability_data ** caps)745 int imap_threaded_capability(Folder *folder, struct mailimap_capability_data ** caps)
746 {
747 	struct capa_param param;
748 	struct capa_result result;
749 	mailimap *imap;
750 
751 	imap = get_imap(folder);
752 
753 	param.imap = imap;
754 
755 	threaded_run(folder, &param, &result, capability_run);
756 
757 	debug_print("capa %d\n", result.error);
758 
759 	if (result.error == MAILIMAP_NO_ERROR)
760 		*caps = result.caps;
761 
762 	return result.error;
763 
764 }
765 
766 struct disconnect_param {
767 	mailimap * imap;
768 };
769 
770 struct disconnect_result {
771 	int error;
772 };
773 
disconnect_run(struct etpan_thread_op * op)774 static void disconnect_run(struct etpan_thread_op * op)
775 {
776 	int r;
777 	struct disconnect_param * param;
778 	struct disconnect_result * result;
779 
780 	param = op->param;
781 	result = op->result;
782 
783 	CHECK_IMAP();
784 
785 	r = mailimap_logout(param->imap);
786 
787 	result->error = r;
788 }
789 
imap_threaded_disconnect(Folder * folder)790 void imap_threaded_disconnect(Folder * folder)
791 {
792 	struct connect_param param;
793 	struct connect_result result;
794 	mailimap * imap;
795 
796 	imap = get_imap(folder);
797 	if (imap == NULL) {
798 		debug_print("was disconnected\n");
799 		return;
800 	}
801 
802 	param.imap = imap;
803 
804 	if (threaded_run(folder, &param, &result, disconnect_run)) {
805 		debug_print("imap already deleted %p\n", imap);
806 	} else {
807 		debug_print("deleting old imap %p\n", imap);
808 		delete_imap(folder, imap);
809 	}
810 
811 	debug_print("disconnect ok\n");
812 }
813 
814 
815 struct list_param {
816 	mailimap * imap;
817 	const char * base;
818 	const char * wildcard;
819 	gboolean sub_only;
820 };
821 
822 struct list_result {
823 	int error;
824 	clist * list;
825 };
826 
list_run(struct etpan_thread_op * op)827 static void list_run(struct etpan_thread_op * op)
828 {
829 	struct list_param * param;
830 	struct list_result * result;
831 	int r;
832 	clist * list;
833 
834 	param = op->param;
835 	result = op->result;
836 
837 	CHECK_IMAP();
838 
839 	list = NULL;
840 
841 	if (param->base == NULL || param->wildcard == NULL) {
842 		result->list = list;
843 		result->error = -1;
844 		debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard);
845 		return;
846 	}
847 	if (param->sub_only)
848 		r = mailimap_lsub(param->imap, param->base,
849 			  param->wildcard, &list);
850 	else
851 		r = mailimap_list(param->imap, param->base,
852 			  param->wildcard, &list);
853 	result->error = r;
854 	result->list = list;
855 	debug_print("imap list run - end\n");
856 }
857 
imap_threaded_list(Folder * folder,const char * base,const char * wildcard,clist ** p_result)858 int imap_threaded_list(Folder * folder, const char * base,
859 		       const char * wildcard,
860 		       clist ** p_result)
861 {
862 	struct list_param param;
863 	struct list_result result;
864 
865 	debug_print("imap list - begin\n");
866 
867 	param.imap = get_imap(folder);
868 	param.base = base;
869 	param.wildcard = wildcard;
870 	param.sub_only = FALSE;
871 
872 	threaded_run(folder, &param, &result, list_run);
873 
874 	* p_result = result.list;
875 
876 	debug_print("imap list - end %p\n", result.list);
877 
878 	return result.error;
879 }
880 
imap_threaded_lsub(Folder * folder,const char * base,const char * wildcard,clist ** p_result)881 int imap_threaded_lsub(Folder * folder, const char * base,
882 		       const char * wildcard,
883 		       clist ** p_result)
884 {
885 	struct list_param param;
886 	struct list_result result;
887 
888 	debug_print("imap lsub - begin\n");
889 
890 	param.imap = get_imap(folder);
891 	param.base = base;
892 	param.wildcard = wildcard;
893 	param.sub_only = TRUE;
894 
895 	threaded_run(folder, &param, &result, list_run);
896 
897 	* p_result = result.list;
898 
899 	debug_print("imap lsub - end %p\n", result.list);
900 
901 	return result.error;
902 }
903 
904 struct subscribe_param {
905 	mailimap * imap;
906 	const char * mb;
907 	gboolean subscribe;
908 };
909 
910 struct subscribe_result {
911 	int error;
912 };
913 
subscribe_run(struct etpan_thread_op * op)914 static void subscribe_run(struct etpan_thread_op * op)
915 {
916 	struct subscribe_param * param;
917 	struct subscribe_result * result;
918 	int r;
919 
920 	param = op->param;
921 	result = op->result;
922 
923 	CHECK_IMAP();
924 
925 	if (param->mb == NULL) {
926 		result->error = -1;
927 		debug_print("no mb\n");
928 		return;
929 	}
930 	if (param->subscribe)
931 		r = mailimap_subscribe(param->imap, param->mb);
932 	else
933 		r = mailimap_unsubscribe(param->imap, param->mb);
934 	result->error = r;
935 	debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r);
936 }
937 
imap_threaded_subscribe(Folder * folder,const char * mb,gboolean subscribe)938 int imap_threaded_subscribe(Folder * folder, const char * mb,
939 		       gboolean subscribe)
940 {
941 	struct subscribe_param param;
942 	struct subscribe_result result;
943 
944 	debug_print("imap list - begin\n");
945 
946 	param.imap = get_imap(folder);
947 	param.mb = mb;
948 	param.subscribe = subscribe;
949 
950 	threaded_run(folder, &param, &result, subscribe_run);
951 
952 	return result.error;
953 }
954 
955 struct login_param {
956 	mailimap * imap;
957 	const char * login;
958 	const char * password;
959 	const char * type;
960 	const char * server;
961 };
962 
963 struct login_result {
964 	int error;
965 };
966 
login_run(struct etpan_thread_op * op)967 static void login_run(struct etpan_thread_op * op)
968 {
969 	struct login_param * param;
970 	struct login_result * result;
971 	int r;
972 #ifdef DISABLE_LOG_DURING_LOGIN
973 	int old_debug;
974 #endif
975 
976 	param = op->param;
977 	result = op->result;
978 
979 	CHECK_IMAP();
980 
981 #ifdef DISABLE_LOG_DURING_LOGIN
982 	old_debug = mailstream_debug;
983 	mailstream_debug = 0;
984 #endif
985 	if (!strcmp(param->type, "plaintext"))
986 		r = mailimap_login(param->imap,
987 			   param->login, param->password);
988 	else if (!strcmp(param->type, "GSSAPI"))
989 		r = mailimap_authenticate(param->imap,
990 			param->type, param->server, NULL, NULL,
991 			param->login, param->login,
992 			param->password, NULL);
993 	else if (!strcmp(param->type, "SCRAM-SHA-1"))
994 		/* 7th argument has to be NULL here, to stop libetpan sending the
995 		 * a= attribute in its initial SCRAM-SHA-1 message to server. At least
996 		 * Dovecot 2.2 doesn't seem to like that, and will not authenticate
997 		 * successfully. */
998 		r = mailimap_authenticate(param->imap,
999 			param->type, NULL, NULL, NULL,
1000 			NULL, param->login,
1001 			param->password, NULL);
1002 	else if (!strcmp(param->type, "XOAUTH2")) {
1003                 r = mailimap_oauth2_authenticate(param->imap, param->login, param->password);
1004 	} else
1005 		r = mailimap_authenticate(param->imap,
1006 			param->type, NULL, NULL, NULL,
1007 			param->login, param->login,
1008 			param->password, NULL);
1009 #ifdef DISABLE_LOG_DURING_LOGIN
1010 	mailstream_debug = old_debug;
1011 #endif
1012 
1013 	result->error = r;
1014 	if (param->imap->imap_response)
1015 		imap_logger_cmd(0, param->imap->imap_response, strlen(param->imap->imap_response));
1016 	debug_print("imap login run - end %i\n", r);
1017 }
1018 
imap_threaded_login(Folder * folder,const char * login,const char * password,const char * type)1019 int imap_threaded_login(Folder * folder,
1020 			const char * login, const char * password,
1021 			const char * type)
1022 {
1023 	struct login_param param;
1024 	struct login_result result;
1025 
1026 	debug_print("imap login - begin\n");
1027 
1028 	if (!folder)
1029 		return MAILIMAP_ERROR_INVAL;
1030 
1031 	param.imap = get_imap(folder);
1032 	param.login = login;
1033 	param.password = password;
1034 	param.type = type;
1035 	if (folder && folder->account)
1036 		param.server = folder->account->recv_server;
1037 	else
1038 		param.server = NULL;
1039 
1040 	threaded_run(folder, &param, &result, login_run);
1041 
1042 	debug_print("imap login - end\n");
1043 
1044 	return result.error;
1045 }
1046 
1047 
1048 struct status_param {
1049 	mailimap * imap;
1050 	const char * mb;
1051 	struct mailimap_status_att_list * status_att_list;
1052 };
1053 
1054 struct status_result {
1055 	int error;
1056 	struct mailimap_mailbox_data_status * data_status;
1057 };
1058 
status_run(struct etpan_thread_op * op)1059 static void status_run(struct etpan_thread_op * op)
1060 {
1061 	struct status_param * param;
1062 	struct status_result * result;
1063 	int r;
1064 
1065 	param = op->param;
1066 	result = op->result;
1067 
1068 	CHECK_IMAP();
1069 
1070 	r = mailimap_status(param->imap, param->mb,
1071 			    param->status_att_list,
1072 			    &result->data_status);
1073 
1074 	result->error = r;
1075 	debug_print("imap status run - end %i\n", r);
1076 }
1077 
imap_threaded_status(Folder * folder,const char * mb,struct mailimap_mailbox_data_status ** data_status,guint mask)1078 int imap_threaded_status(Folder * folder, const char * mb,
1079 			 struct mailimap_mailbox_data_status ** data_status,
1080 			 guint mask)
1081 {
1082 	struct status_param param;
1083 	struct status_result result;
1084 	struct mailimap_status_att_list * status_att_list;
1085 
1086 	debug_print("imap status - begin\n");
1087 
1088 	status_att_list = mailimap_status_att_list_new_empty();
1089 	if (mask & 1 << 0) {
1090 		mailimap_status_att_list_add(status_att_list,
1091 				     MAILIMAP_STATUS_ATT_MESSAGES);
1092 	}
1093 	if (mask & 1 << 1) {
1094 		mailimap_status_att_list_add(status_att_list,
1095 				     MAILIMAP_STATUS_ATT_RECENT);
1096 	}
1097 	if (mask & 1 << 2) {
1098 		mailimap_status_att_list_add(status_att_list,
1099 				     MAILIMAP_STATUS_ATT_UIDNEXT);
1100 	}
1101 	if (mask & 1 << 3) {
1102 		mailimap_status_att_list_add(status_att_list,
1103 				     MAILIMAP_STATUS_ATT_UIDVALIDITY);
1104 	}
1105 	if (mask & 1 << 4) {
1106 		mailimap_status_att_list_add(status_att_list,
1107 				     MAILIMAP_STATUS_ATT_UNSEEN);
1108 	}
1109 	param.imap = get_imap(folder);
1110 	param.mb = mb;
1111 	param.status_att_list = status_att_list;
1112 
1113 	threaded_run(folder, &param, &result, status_run);
1114 
1115 	debug_print("imap status - end\n");
1116 
1117 	* data_status = result.data_status;
1118 
1119 	mailimap_status_att_list_free(status_att_list);
1120 
1121 	return result.error;
1122 }
1123 
1124 
1125 
1126 struct noop_param {
1127 	mailimap * imap;
1128 };
1129 
1130 struct noop_result {
1131 	int error;
1132 };
1133 
noop_run(struct etpan_thread_op * op)1134 static void noop_run(struct etpan_thread_op * op)
1135 {
1136 	struct noop_param * param;
1137 	struct noop_result * result;
1138 	int r;
1139 
1140 	param = op->param;
1141 	result = op->result;
1142 
1143 	CHECK_IMAP();
1144 
1145 	r = mailimap_noop(param->imap);
1146 
1147 	result->error = r;
1148 	debug_print("imap noop run - end %i\n", r);
1149 }
1150 
imap_threaded_noop(Folder * folder,unsigned int * p_exists,unsigned int * p_recent,unsigned int * p_expunge,unsigned int * p_unseen,unsigned int * p_uidnext,unsigned int * p_uidval)1151 int imap_threaded_noop(Folder * folder, unsigned int * p_exists,
1152 		       unsigned int *p_recent,
1153 		       unsigned int *p_expunge,
1154 		       unsigned int *p_unseen,
1155 		       unsigned int *p_uidnext,
1156 		       unsigned int *p_uidval)
1157 {
1158 	struct noop_param param;
1159 	struct noop_result result;
1160 	mailimap * imap;
1161 
1162 	debug_print("imap noop - begin\n");
1163 
1164 	imap = get_imap(folder);
1165 	param.imap = imap;
1166 
1167 	if (threaded_run(folder, &param, &result, noop_run))
1168 		return MAILIMAP_ERROR_INVAL;
1169 
1170 	if (result.error == 0 && imap && imap->imap_selection_info != NULL) {
1171 		* p_exists = imap->imap_selection_info->sel_exists;
1172 		* p_recent = imap->imap_selection_info->sel_recent;
1173 		* p_unseen = imap->imap_selection_info->sel_unseen;
1174 		* p_uidnext = imap->imap_selection_info->sel_uidnext;
1175 		* p_uidval = imap->imap_selection_info->sel_uidvalidity;
1176 	} else {
1177 		* p_exists = 0;
1178 		* p_recent = 0;
1179 		* p_unseen = 0;
1180 		* p_uidnext = 0;
1181 		* p_uidval = 0;
1182 	}
1183 	if (result.error == 0 && imap && imap->imap_response_info != NULL &&
1184 	    imap->imap_response_info->rsp_expunged != NULL) {
1185 		* p_expunge = clist_count(imap->imap_response_info->rsp_expunged);
1186 	} else {
1187 		* p_expunge = 0;
1188 	}
1189 	debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1190 		*p_exists, *p_recent, *p_expunge, *p_unseen,
1191 		*p_uidnext, *p_uidval);
1192 
1193 	return result.error;
1194 }
1195 
1196 #ifdef USE_GNUTLS
1197 struct starttls_result {
1198 	int error;
1199 };
1200 
starttls_run(struct etpan_thread_op * op)1201 static void starttls_run(struct etpan_thread_op * op)
1202 {
1203 	struct connect_param * param;
1204 	struct starttls_result * result;
1205 	int r;
1206 
1207 	param = op->param;
1208 	result = op->result;
1209 
1210 	CHECK_IMAP();
1211 
1212 	r = mailimap_starttls(param->imap);
1213 
1214 	result->error = r;
1215 	debug_print("imap STARTTLS run - end %i\n", r);
1216 
1217 	if (r == 0) {
1218 		mailimap *imap = param->imap;
1219 		mailstream_low *plain_low = NULL;
1220 		mailstream_low *tls_low = NULL;
1221 		int fd = -1;
1222 
1223 		plain_low = mailstream_get_low(imap->imap_stream);
1224 		fd = mailstream_low_get_fd(plain_low);
1225 		if (fd == -1) {
1226 			debug_print("imap STARTTLS run - can't get fd\n");
1227 			result->error = MAILIMAP_ERROR_STREAM;
1228 			return;
1229 		}
1230 
1231 		tls_low = mailstream_low_tls_open_with_callback(fd, etpan_connect_ssl_context_cb, param->account);
1232 		if (tls_low == NULL) {
1233 			debug_print("imap STARTTLS run - can't tls_open\n");
1234 			result->error = MAILIMAP_ERROR_STREAM;
1235 			return;
1236 		}
1237 		mailstream_low_free(plain_low);
1238 		mailstream_set_low(imap->imap_stream, tls_low);
1239 	}
1240 }
1241 
imap_threaded_starttls(Folder * folder,const gchar * host,int port)1242 int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
1243 {
1244 	struct connect_param param;
1245 	struct starttls_result result;
1246 	gboolean accept_if_valid = FALSE;
1247 
1248 	debug_print("imap STARTTLS - begin\n");
1249 
1250 	param.imap = get_imap(folder);
1251 	param.server = host;
1252 	param.port = port;
1253 	param.account = folder->account;
1254 
1255 	if (folder->account)
1256 		accept_if_valid = folder->account->ssl_certs_auto_accept;
1257 
1258 	if (threaded_run(folder, &param, &result, starttls_run))
1259 		return MAILIMAP_ERROR_INVAL;
1260 
1261 	debug_print("imap STARTTLS - end\n");
1262 
1263 	if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
1264 		if (etpan_certificate_check(param.imap->imap_stream, host, port,
1265 					    accept_if_valid) != TRUE)
1266 			return MAILIMAP_ERROR_SSL;
1267 	}
1268 	return result.error;
1269 }
1270 #endif
1271 
1272 struct create_param {
1273 	mailimap * imap;
1274 	const char * mb;
1275 };
1276 
1277 struct create_result {
1278 	int error;
1279 };
1280 
create_run(struct etpan_thread_op * op)1281 static void create_run(struct etpan_thread_op * op)
1282 {
1283 	struct create_param * param;
1284 	struct create_result * result;
1285 	int r;
1286 
1287 	param = op->param;
1288 	result = op->result;
1289 
1290 	CHECK_IMAP();
1291 
1292 	r = mailimap_create(param->imap, param->mb);
1293 
1294 	result->error = r;
1295 	debug_print("imap create run - end %i\n", r);
1296 }
1297 
imap_threaded_create(Folder * folder,const char * mb)1298 int imap_threaded_create(Folder * folder, const char * mb)
1299 {
1300 	struct create_param param;
1301 	struct create_result result;
1302 
1303 	debug_print("imap create - begin\n");
1304 
1305 	param.imap = get_imap(folder);
1306 	param.mb = mb;
1307 
1308 	threaded_run(folder, &param, &result, create_run);
1309 
1310 	debug_print("imap create - end\n");
1311 
1312 	return result.error;
1313 }
1314 
1315 
1316 
1317 
1318 struct rename_param {
1319 	mailimap * imap;
1320 	const char * mb;
1321 	const char * new_name;
1322 };
1323 
1324 struct rename_result {
1325 	int error;
1326 };
1327 
rename_run(struct etpan_thread_op * op)1328 static void rename_run(struct etpan_thread_op * op)
1329 {
1330 	struct rename_param * param;
1331 	struct rename_result * result;
1332 	int r;
1333 
1334 	param = op->param;
1335 	result = op->result;
1336 
1337 	CHECK_IMAP();
1338 
1339 	r = mailimap_rename(param->imap, param->mb, param->new_name);
1340 
1341 	result->error = r;
1342 	debug_print("imap rename run - end %i\n", r);
1343 }
1344 
imap_threaded_rename(Folder * folder,const char * mb,const char * new_name)1345 int imap_threaded_rename(Folder * folder,
1346 			 const char * mb, const char * new_name)
1347 {
1348 	struct rename_param param;
1349 	struct rename_result result;
1350 
1351 	debug_print("imap rename - begin\n");
1352 
1353 	param.imap = get_imap(folder);
1354 	param.mb = mb;
1355 	param.new_name = new_name;
1356 
1357 	threaded_run(folder, &param, &result, rename_run);
1358 
1359 	debug_print("imap rename - end\n");
1360 
1361 	return result.error;
1362 }
1363 
1364 
1365 
1366 
1367 struct delete_param {
1368 	mailimap * imap;
1369 	const char * mb;
1370 };
1371 
1372 struct delete_result {
1373 	int error;
1374 };
1375 
delete_run(struct etpan_thread_op * op)1376 static void delete_run(struct etpan_thread_op * op)
1377 {
1378 	struct delete_param * param;
1379 	struct delete_result * result;
1380 	int r;
1381 
1382 	param = op->param;
1383 	result = op->result;
1384 
1385 	CHECK_IMAP();
1386 
1387 	r = mailimap_delete(param->imap, param->mb);
1388 
1389 	result->error = r;
1390 	debug_print("imap delete run - end %i\n", r);
1391 }
1392 
imap_threaded_delete(Folder * folder,const char * mb)1393 int imap_threaded_delete(Folder * folder, const char * mb)
1394 {
1395 	struct delete_param param;
1396 	struct delete_result result;
1397 
1398 	debug_print("imap delete - begin\n");
1399 
1400 	param.imap = get_imap(folder);
1401 	param.mb = mb;
1402 
1403 	threaded_run(folder, &param, &result, delete_run);
1404 
1405 	debug_print("imap delete - end\n");
1406 
1407 	return result.error;
1408 }
1409 
1410 
1411 
1412 struct select_param {
1413 	mailimap * imap;
1414 	const char * mb;
1415 };
1416 
1417 struct select_result {
1418 	int error;
1419 };
1420 
select_run(struct etpan_thread_op * op)1421 static void select_run(struct etpan_thread_op * op)
1422 {
1423 	struct select_param * param;
1424 	struct select_result * result;
1425 	int r;
1426 
1427 	param = op->param;
1428 	result = op->result;
1429 
1430 	CHECK_IMAP();
1431 
1432 	r = mailimap_select(param->imap, param->mb);
1433 
1434 	result->error = r;
1435 	debug_print("imap select run - end %i\n", r);
1436 }
1437 
imap_threaded_select(Folder * folder,const char * mb,gint * exists,gint * recent,gint * unseen,guint32 * uid_validity,gint * can_create_flags,GSList ** ok_flags)1438 int imap_threaded_select(Folder * folder, const char * mb,
1439 			 gint * exists, gint * recent, gint * unseen,
1440 			 guint32 * uid_validity,gint *can_create_flags,
1441 			 GSList **ok_flags)
1442 {
1443 	struct select_param param;
1444 	struct select_result result;
1445 	mailimap * imap;
1446 
1447 	debug_print("imap select - begin\n");
1448 
1449 	imap = get_imap(folder);
1450 	param.imap = imap;
1451 	param.mb = mb;
1452 
1453 	if (threaded_run(folder, &param, &result, select_run))
1454 		return MAILIMAP_ERROR_INVAL;
1455 
1456 	if (result.error != MAILIMAP_NO_ERROR)
1457 		return result.error;
1458 
1459 	if (!imap || imap->imap_selection_info == NULL)
1460 		return MAILIMAP_ERROR_PARSE;
1461 
1462 	* exists = imap->imap_selection_info->sel_exists;
1463 	* recent = imap->imap_selection_info->sel_recent;
1464 	* unseen = imap->imap_selection_info->sel_unseen;
1465 	* uid_validity = imap->imap_selection_info->sel_uidvalidity;
1466 	* can_create_flags = FALSE;
1467 
1468 	if (imap->imap_selection_info->sel_perm_flags) {
1469 		GSList *t_flags = NULL;
1470 		clistiter *cur = NULL;
1471 		if (imap->imap_selection_info->sel_perm_flags)
1472 			cur = clist_begin(imap->imap_selection_info->sel_perm_flags);
1473 
1474 		for (; cur; cur = clist_next(cur)) {
1475 			struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur);
1476 			if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL)
1477 				*can_create_flags = TRUE;
1478 			else if (flag->fl_flag &&
1479 					flag->fl_flag->fl_type == 6 &&
1480 					!strcmp(flag->fl_flag->fl_data.fl_extension, "*"))
1481 				*can_create_flags = TRUE;
1482 			if (flag->fl_flag && ok_flags) {
1483 				MsgPermFlags c_flag = 0;
1484 				switch (flag->fl_flag->fl_type) {
1485 				case MAILIMAP_FLAG_ANSWERED:
1486 					c_flag = IMAP_FLAG_ANSWERED;
1487 					break;
1488 				case MAILIMAP_FLAG_FLAGGED:
1489 					c_flag = IMAP_FLAG_FLAGGED;
1490 					break;
1491 				case MAILIMAP_FLAG_DELETED:
1492 					c_flag = IMAP_FLAG_DELETED;
1493 					break;
1494 				case MAILIMAP_FLAG_DRAFT:
1495 					c_flag = IMAP_FLAG_DRAFT;
1496 					break;
1497 				case MAILIMAP_FLAG_SEEN:
1498 					c_flag = IMAP_FLAG_SEEN;
1499 					break;
1500 				case MAILIMAP_FLAG_KEYWORD:
1501 					if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
1502 						c_flag = IMAP_FLAG_FORWARDED;
1503 					if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
1504 						c_flag = IMAP_FLAG_SPAM;
1505 					if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
1506 					    !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
1507 					    !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
1508 						c_flag = IMAP_FLAG_HAM;
1509 					break;
1510 				default:
1511 					break;
1512 				}
1513 				if (c_flag != 0) {
1514 					t_flags = g_slist_prepend(t_flags,
1515 						GUINT_TO_POINTER(c_flag));
1516 				}
1517 			}
1518 		}
1519 		if (ok_flags)
1520 			*ok_flags = t_flags;
1521 	}
1522 	debug_print("imap select - end\n");
1523 
1524 	return result.error;
1525 }
1526 
close_run(struct etpan_thread_op * op)1527 static void close_run(struct etpan_thread_op * op)
1528 {
1529 	struct select_param * param;
1530 	struct select_result * result;
1531 	int r;
1532 
1533 	param = op->param;
1534 	result = op->result;
1535 
1536 	CHECK_IMAP();
1537 
1538 	r = mailimap_close(param->imap);
1539 
1540 	result->error = r;
1541 	debug_print("imap close run - end %i\n", r);
1542 }
1543 
imap_threaded_close(Folder * folder)1544 int imap_threaded_close(Folder * folder)
1545 {
1546 	struct select_param param;
1547 	struct select_result result;
1548 	mailimap * imap;
1549 
1550 	debug_print("imap close - begin\n");
1551 
1552 	imap = get_imap(folder);
1553 	param.imap = imap;
1554 
1555 	threaded_run(folder, &param, &result, close_run);
1556 
1557 	if (result.error != MAILIMAP_NO_ERROR)
1558 		return result.error;
1559 
1560 	debug_print("imap close - end\n");
1561 
1562 	return result.error;
1563 }
1564 
1565 struct examine_param {
1566 	mailimap * imap;
1567 	const char * mb;
1568 };
1569 
1570 struct examine_result {
1571 	int error;
1572 };
1573 
examine_run(struct etpan_thread_op * op)1574 static void examine_run(struct etpan_thread_op * op)
1575 {
1576 	struct examine_param * param;
1577 	struct examine_result * result;
1578 	int r;
1579 
1580 	param = op->param;
1581 	result = op->result;
1582 
1583 	CHECK_IMAP();
1584 
1585 	r = mailimap_examine(param->imap, param->mb);
1586 
1587 	result->error = r;
1588 	debug_print("imap examine run - end %i\n", r);
1589 }
1590 
imap_threaded_examine(Folder * folder,const char * mb,gint * exists,gint * recent,gint * unseen,guint32 * uid_validity)1591 int imap_threaded_examine(Folder * folder, const char * mb,
1592 			  gint * exists, gint * recent, gint * unseen,
1593 			  guint32 * uid_validity)
1594 {
1595 	struct examine_param param;
1596 	struct examine_result result;
1597 	mailimap * imap;
1598 
1599 	debug_print("imap examine - begin\n");
1600 
1601 	imap = get_imap(folder);
1602 	param.imap = imap;
1603 	param.mb = mb;
1604 
1605 	if (threaded_run(folder, &param, &result, examine_run))
1606 		return MAILIMAP_ERROR_INVAL;
1607 
1608 	if (result.error != MAILIMAP_NO_ERROR)
1609 		return result.error;
1610 
1611 	if (!imap || imap->imap_selection_info == NULL)
1612 		return MAILIMAP_ERROR_PARSE;
1613 
1614 	* exists = imap->imap_selection_info->sel_exists;
1615 	* recent = imap->imap_selection_info->sel_recent;
1616 	* unseen = imap->imap_selection_info->sel_unseen;
1617 	* uid_validity = imap->imap_selection_info->sel_uidvalidity;
1618 
1619 	debug_print("imap examine - end\n");
1620 
1621 	return result.error;
1622 }
1623 
1624 
1625 
1626 
1627 struct search_param {
1628 	mailimap * imap;
1629 	int type;
1630 	const char *charset;
1631 	struct mailimap_set * set;
1632 	IMAPSearchKey* key;
1633 };
1634 
1635 struct search_result {
1636 	int error;
1637 	clist * search_result;
1638 };
1639 
sc_mailimap_set_item_copy(struct mailimap_set_item * orig)1640 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig)
1641 {
1642 	return mailimap_set_item_new(orig->set_first, orig->set_last);
1643 }
1644 
sc_mailimap_set_copy(struct mailimap_set * orig)1645 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig)
1646 {
1647 	clist *list = orig ? orig->set_list : NULL;
1648 	clist *newlist;
1649 	clistiter *cur;
1650 
1651 	if (!orig)
1652 		return NULL;
1653 
1654 	newlist = clist_new();
1655 	if (!newlist)
1656 		return NULL;
1657 
1658 	for (cur = clist_begin(list); cur; cur = clist_next(cur)) {
1659 		if (clist_append(newlist,
1660 			sc_mailimap_set_item_copy(
1661 			(struct mailimap_set_item *)clist_content(cur))) != 0) {
1662 			clist_free(newlist);
1663 			return NULL;
1664 		}
1665 	}
1666 	return mailimap_set_new(newlist);
1667 }
1668 
search_run(struct etpan_thread_op * op)1669 static void search_run(struct etpan_thread_op * op)
1670 {
1671 	struct search_param * param;
1672 	struct search_result * result;
1673 	int r;
1674 	struct mailimap_search_key * key = NULL;
1675 	struct mailimap_search_key * uid_key = NULL;
1676 	struct mailimap_search_key * search_type_key = NULL;
1677 	clist * search_result;
1678 
1679 	param = op->param;
1680 	result = op->result;
1681 
1682 	CHECK_IMAP();
1683 
1684 	/* we copy the mailimap_set because freeing the key is recursive */
1685 	if (param->set != NULL) {
1686 		uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set));
1687 	} else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) {
1688 		uid_key = mailimap_search_key_new_all();
1689 	}
1690 	switch (param->type) {
1691 	case IMAP_SEARCH_TYPE_SIMPLE:
1692 		search_type_key = NULL;
1693 		break;
1694 	case IMAP_SEARCH_TYPE_SEEN:
1695 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0);
1696 		break;
1697 	case IMAP_SEARCH_TYPE_UNSEEN:
1698 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0);
1699 		break;
1700 	case IMAP_SEARCH_TYPE_ANSWERED:
1701 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0);
1702 		break;
1703 	case IMAP_SEARCH_TYPE_FLAGGED:
1704 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0);
1705 		break;
1706 	case IMAP_SEARCH_TYPE_DELETED:
1707 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0);
1708 		break;
1709 	case IMAP_SEARCH_TYPE_FORWARDED:
1710 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0);
1711 		break;
1712 	case IMAP_SEARCH_TYPE_SPAM:
1713 		search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0);
1714 		break;
1715 	case IMAP_SEARCH_TYPE_KEYED:
1716 		search_type_key = param->key;
1717 		break;
1718 	}
1719 
1720 	if (search_type_key != NULL) {
1721 		if (param->set != NULL) {
1722 			key = mailimap_search_key_new_multiple_empty();
1723 			mailimap_search_key_multiple_add(key, search_type_key);
1724 			mailimap_search_key_multiple_add(key, uid_key);
1725 		} else {
1726 			key = search_type_key;
1727 		}
1728 	} else if (uid_key != NULL) {
1729 		key = uid_key;
1730 	}
1731 
1732 	if (key == NULL) {
1733 		g_warning("no key!");
1734 		result = op->result;
1735 		result->error = -1;
1736 		result->search_result = NULL;
1737 	} else {
1738 		mailstream_logger = imap_logger_uid;
1739 
1740 		r = mailimap_uid_search(param->imap, param->charset, key, &search_result);
1741 
1742 		mailstream_logger = imap_logger_cmd;
1743 
1744 		/* free the key (with the imapset) */
1745 		mailimap_search_key_free(key);
1746 
1747 		result->error = r;
1748 		result->search_result = search_result;
1749 	}
1750 	debug_print("imap search run - end %i\n", result->error);
1751 }
1752 
imap_threaded_search(Folder * folder,int search_type,IMAPSearchKey * key,const char * charset,struct mailimap_set * set,clist ** search_result)1753 int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key,
1754 			 const char *charset, struct mailimap_set * set,
1755 			 clist ** search_result)
1756 {
1757 	struct search_param param;
1758 	struct search_result result;
1759 	mailimap * imap;
1760 
1761 	debug_print("imap search - begin\n");
1762 
1763 	imap = get_imap(folder);
1764 	param.imap = imap;
1765 	param.set = set;
1766 	param.charset = charset;
1767 	param.type = search_type;
1768 	param.key = key;
1769 
1770 	threaded_run(folder, &param, &result, search_run);
1771 
1772 	if (result.error != MAILIMAP_NO_ERROR)
1773 		return result.error;
1774 
1775 	debug_print("imap search - end\n");
1776 
1777 	* search_result = result.search_result;
1778 
1779 	return result.error;
1780 }
1781 
1782 
1783 struct _IMAPSearchKey {
1784 	struct mailimap_search_key* key;
1785 };
1786 
imap_search_new(gint criteria,const gchar * header,const gchar * expr,int value)1787 IMAPSearchKey*	imap_search_new(gint		 criteria,
1788 				const gchar	*header,
1789 				const gchar	*expr,
1790 				int		 value)
1791 {
1792 	char* sk_bcc = NULL;
1793 	struct mailimap_date* sk_before = NULL;
1794 	char* sk_body = NULL;
1795 	char* sk_cc = NULL;
1796 	char* sk_from = NULL;
1797 	char* sk_keyword = NULL;
1798 	struct mailimap_date* sk_on = NULL;
1799 	struct mailimap_date* sk_since = NULL;
1800 	char* sk_subject = NULL;
1801 	char* sk_text = NULL;
1802 	char* sk_to = NULL;
1803 	char* sk_unkeyword = NULL;
1804 	char* sk_header_name = NULL;
1805 	char* sk_header_value = NULL;
1806 	uint32_t sk_larger = 0;
1807 	struct mailimap_search_key* sk_not = NULL;
1808 	struct mailimap_search_key* sk_or1 = NULL;
1809 	struct mailimap_search_key* sk_or2 = NULL;
1810 	struct mailimap_date* sk_sentbefore = NULL;
1811 	struct mailimap_date* sk_senton = NULL;
1812 	struct mailimap_date* sk_sentsince = NULL;
1813 	uint32_t sk_smaller = 0;
1814 	struct mailimap_set* sk_uid = NULL;
1815 	struct mailimap_set* sk_set = NULL;
1816 	clist* sk_multiple = NULL;
1817 	int etpan_matcher_type;
1818 
1819 	switch (criteria) {
1820 	case IMAP_SEARCH_CRITERIA_ALL: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ALL; break;
1821 	case IMAP_SEARCH_CRITERIA_READ: etpan_matcher_type = MAILIMAP_SEARCH_KEY_SEEN; break;
1822 	case IMAP_SEARCH_CRITERIA_UNREAD: etpan_matcher_type = MAILIMAP_SEARCH_KEY_UNSEEN; break;
1823 	case IMAP_SEARCH_CRITERIA_NEW: etpan_matcher_type = MAILIMAP_SEARCH_KEY_NEW; break;
1824 	case IMAP_SEARCH_CRITERIA_MARKED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_FLAGGED; break;
1825 	case IMAP_SEARCH_CRITERIA_REPLIED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ANSWERED; break;
1826 	case IMAP_SEARCH_CRITERIA_DELETED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_DELETED; break;
1827 
1828 	case IMAP_SEARCH_CRITERIA_TAG:
1829 		sk_keyword = strdup(expr);
1830 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_KEYWORD;
1831 		break;
1832 
1833 	case IMAP_SEARCH_CRITERIA_SUBJECT:
1834 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_SUBJECT;
1835 		sk_subject = strdup(expr);
1836 		break;
1837 
1838 	case IMAP_SEARCH_CRITERIA_TO:
1839 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_TO;
1840 		sk_to = strdup(expr);
1841 		break;
1842 
1843 	case IMAP_SEARCH_CRITERIA_CC:
1844 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_CC;
1845 		sk_cc = strdup(expr);
1846 		break;
1847 
1848 	case IMAP_SEARCH_CRITERIA_AGE_GREATER:
1849 	case IMAP_SEARCH_CRITERIA_AGE_LOWER:
1850 		{
1851 			struct tm tm;
1852 			time_t limit = time(NULL) - 60 * 60 * 24 * value;
1853 
1854 			tzset();
1855 			localtime_r(&limit, &tm);
1856 			if (criteria == IMAP_SEARCH_CRITERIA_AGE_GREATER) {
1857 				etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTBEFORE;
1858 				sk_sentbefore = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1859 			} else {
1860 				etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTSINCE;
1861 				sk_sentsince = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
1862 			}
1863 			break;
1864 		}
1865 
1866 	case IMAP_SEARCH_CRITERIA_BODY:
1867 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_BODY;
1868 		sk_body = strdup(expr);
1869 		break;
1870 
1871 	case IMAP_SEARCH_CRITERIA_MESSAGE:
1872 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_TEXT;
1873 		sk_text = strdup(expr);
1874 		break;
1875 
1876 	case IMAP_SEARCH_CRITERIA_HEADER:
1877 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_HEADER;
1878 		sk_header_name = strdup(header);
1879 		sk_header_value = strdup(expr);
1880 		break;
1881 
1882 	case IMAP_SEARCH_CRITERIA_FROM:
1883 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_FROM;
1884 		sk_from = strdup(expr);
1885 		break;
1886 
1887 	case IMAP_SEARCH_CRITERIA_SIZE_GREATER:
1888 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_LARGER;
1889 		sk_larger = value;
1890 		break;
1891 
1892 	case IMAP_SEARCH_CRITERIA_SIZE_SMALLER:
1893 		etpan_matcher_type = MAILIMAP_SEARCH_KEY_SMALLER;
1894 		sk_smaller = value;
1895 		break;
1896 
1897 	default:
1898 		return NULL;
1899 	}
1900 
1901 	return mailimap_search_key_new(etpan_matcher_type,
1902 		sk_bcc, sk_before, sk_body, sk_cc, sk_from, sk_keyword,
1903 		sk_on, sk_since, sk_subject, sk_text, sk_to,
1904 		sk_unkeyword, sk_header_name,sk_header_value, sk_larger,
1905 		sk_not, sk_or1, sk_or2, sk_sentbefore, sk_senton,
1906 		sk_sentsince, sk_smaller, sk_uid, sk_set, sk_multiple);
1907 }
1908 
imap_search_not(IMAPSearchKey * key)1909 IMAPSearchKey* imap_search_not(IMAPSearchKey* key)
1910 {
1911 	return mailimap_search_key_new_not(key);
1912 }
1913 
imap_search_or(IMAPSearchKey * l,IMAPSearchKey * r)1914 IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r)
1915 {
1916 	return mailimap_search_key_new_or(l, r);
1917 }
1918 
imap_search_and(IMAPSearchKey * l,IMAPSearchKey * r)1919 IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r)
1920 {
1921 	IMAPSearchKey* result = mailimap_search_key_new_multiple_empty();
1922 	mailimap_search_key_multiple_add(result, l);
1923 	mailimap_search_key_multiple_add(result, r);
1924 
1925 	return result;
1926 }
1927 
imap_search_free(IMAPSearchKey * key)1928 void imap_search_free(IMAPSearchKey* key)
1929 {
1930 	if (!key)
1931 	    return;
1932 
1933 	mailimap_search_key_free(key);
1934 }
1935 
1936 
1937 
1938 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
1939 				 uint32_t * puid,
1940 				 char ** pheaders,
1941 				 size_t * pref_size,
1942 				 struct mailimap_msg_att_dynamic ** patt_dyn);
1943 
1944 static int
result_to_uid_list(clist * fetch_result,carray ** result)1945 result_to_uid_list(clist * fetch_result, carray ** result)
1946 {
1947 	clistiter * cur = NULL;
1948 	int r;
1949 	int res;
1950 	carray * tab;
1951 
1952 	tab = carray_new(128);
1953 	if (tab == NULL) {
1954 		res = MAILIMAP_ERROR_MEMORY;
1955 		goto err;
1956 	}
1957 
1958 	if (fetch_result)
1959 		cur = clist_begin(fetch_result);
1960 
1961 	for(; cur != NULL ; cur = clist_next(cur)) {
1962 		struct mailimap_msg_att * msg_att;
1963 		uint32_t uid;
1964 		uint32_t * puid;
1965 
1966 		msg_att = clist_content(cur);
1967 
1968 		uid = 0;
1969 		imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL);
1970 
1971 		puid = malloc(sizeof(* puid));
1972 		if (puid == NULL) {
1973 			res = MAILIMAP_ERROR_MEMORY;
1974 			goto free_list;
1975 		}
1976 		* puid = uid;
1977 
1978 		r = carray_add(tab, puid, NULL);
1979 		if (r < 0) {
1980 			free(puid);
1981 			res = MAILIMAP_ERROR_MEMORY;
1982 			goto free_list;
1983 		}
1984 	}
1985 
1986 	* result = tab;
1987 
1988 	return MAILIMAP_NO_ERROR;
1989 
1990  free_list:
1991 	imap_fetch_uid_list_free(tab);
1992  err:
1993 	return res;
1994 }
1995 
imap_get_messages_list(mailimap * imap,uint32_t first_index,carray ** result)1996 static int imap_get_messages_list(mailimap * imap,
1997 				  uint32_t first_index,
1998 				  carray ** result)
1999 {
2000 	carray * env_list;
2001 	int r;
2002 	struct mailimap_fetch_att * fetch_att;
2003 	struct mailimap_fetch_type * fetch_type;
2004 	struct mailimap_set * set;
2005 	clist * fetch_result;
2006 	int res;
2007 
2008 	set = mailimap_set_new_interval(first_index, 0);
2009 	if (set == NULL) {
2010 		res = MAILIMAP_ERROR_MEMORY;
2011 		goto err;
2012 	}
2013 
2014 	fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2015 	if (fetch_type == NULL) {
2016 		res = MAILIMAP_ERROR_MEMORY;
2017 		goto free_set;
2018 	}
2019 
2020 	fetch_att = mailimap_fetch_att_new_uid();
2021 	if (fetch_att == NULL) {
2022 		res = MAILIMAP_ERROR_MEMORY;
2023 		goto free_fetch_type;
2024 	}
2025 
2026 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2027 	if (r != MAILIMAP_NO_ERROR) {
2028 		mailimap_fetch_att_free(fetch_att);
2029 		res = MAILIMAP_ERROR_MEMORY;
2030 		goto free_fetch_type;
2031 	}
2032 
2033 	mailstream_logger = imap_logger_fetch;
2034 
2035 	r = mailimap_uid_fetch(imap, set,
2036 			       fetch_type, &fetch_result);
2037 
2038 	mailstream_logger = imap_logger_cmd;
2039 	mailimap_fetch_type_free(fetch_type);
2040 	mailimap_set_free(set);
2041 
2042 	if (r != MAILIMAP_NO_ERROR) {
2043 		res = r;
2044 		goto err;
2045 	}
2046 
2047 	env_list = NULL;
2048 	r = result_to_uid_list(fetch_result, &env_list);
2049 	mailimap_fetch_list_free(fetch_result);
2050 
2051 	* result = env_list;
2052 
2053 	return MAILIMAP_NO_ERROR;
2054 
2055  free_fetch_type:
2056 	mailimap_fetch_type_free(fetch_type);
2057  free_set:
2058 	mailimap_set_free(set);
2059  err:
2060 	return res;
2061 }
2062 
2063 
2064 
2065 
2066 struct fetch_uid_param {
2067 	mailimap * imap;
2068 	uint32_t first_index;
2069 };
2070 
2071 struct fetch_uid_result {
2072 	int error;
2073 	carray * fetch_result;
2074 };
2075 
fetch_uid_run(struct etpan_thread_op * op)2076 static void fetch_uid_run(struct etpan_thread_op * op)
2077 {
2078 	struct fetch_uid_param * param;
2079 	struct fetch_uid_result * result;
2080 	carray * fetch_result;
2081 	int r;
2082 
2083 	param = op->param;
2084 	result = op->result;
2085 
2086 	CHECK_IMAP();
2087 
2088 	fetch_result = NULL;
2089 	mailstream_logger = imap_logger_noop;
2090 	log_print(LOG_PROTOCOL, "IMAP- [fetching UIDs...]\n");
2091 
2092 	r = imap_get_messages_list(param->imap, param->first_index,
2093 				   &fetch_result);
2094 
2095 	mailstream_logger = imap_logger_cmd;
2096 
2097 	result->error = r;
2098 	result->fetch_result = fetch_result;
2099 	debug_print("imap fetch_uid run - end %i\n", r);
2100 }
2101 
imap_threaded_fetch_uid(Folder * folder,uint32_t first_index,carray ** fetch_result)2102 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index,
2103 			    carray ** fetch_result)
2104 {
2105 	struct fetch_uid_param param;
2106 	struct fetch_uid_result result;
2107 	mailimap * imap;
2108 
2109 	debug_print("imap fetch_uid - begin\n");
2110 
2111 	imap = get_imap(folder);
2112 	param.imap = imap;
2113 	param.first_index = first_index;
2114 
2115 	threaded_run(folder, &param, &result, fetch_uid_run);
2116 
2117 	if (result.error != MAILIMAP_NO_ERROR)
2118 		return result.error;
2119 
2120 	debug_print("imap fetch_uid - end\n");
2121 
2122 	* fetch_result = result.fetch_result;
2123 
2124 	return result.error;
2125 }
2126 
2127 
imap_fetch_uid_list_free(carray * uid_list)2128 void imap_fetch_uid_list_free(carray * uid_list)
2129 {
2130 	unsigned int i;
2131 
2132 	for(i = 0 ; i < carray_count(uid_list) ; i ++) {
2133 		uint32_t * puid;
2134 
2135 		puid = carray_get(uid_list, i);
2136 		free(puid);
2137 	}
2138 	carray_free(uid_list);
2139 }
2140 
2141 
2142 
2143 
2144 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags);
2145 
2146 static int
result_to_uid_flags_list(clist * fetch_result,carray ** result)2147 result_to_uid_flags_list(clist * fetch_result, carray ** result)
2148 {
2149 	clistiter * cur = NULL;
2150 	int r;
2151 	int res;
2152 	carray * tab;
2153 	GSList *tags = NULL;
2154 
2155 	tab = carray_new(128);
2156 	if (tab == NULL) {
2157 		res = MAILIMAP_ERROR_MEMORY;
2158 		goto err;
2159 	}
2160 
2161 	if (fetch_result)
2162 		cur = clist_begin(fetch_result);
2163 
2164 	for(; cur != NULL ; cur = clist_next(cur)) {
2165 		struct mailimap_msg_att * msg_att;
2166 		uint32_t uid;
2167 		uint32_t * puid;
2168 		struct mailimap_msg_att_dynamic * att_dyn;
2169 		int flags;
2170 		int * pflags;
2171 
2172 		tags = NULL;
2173 
2174 		msg_att = clist_content(cur);
2175 
2176 		uid = 0;
2177 		att_dyn = NULL;
2178 		imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn);
2179 		if (uid == 0)
2180 			continue;
2181 		if (att_dyn == NULL)
2182 			continue;
2183 
2184 		flags = imap_flags_to_flags(att_dyn, &tags);
2185 
2186 		puid = malloc(sizeof(* puid));
2187 		if (puid == NULL) {
2188 			res = MAILIMAP_ERROR_MEMORY;
2189 			goto free_list;
2190 		}
2191 		* puid = uid;
2192 
2193 		r = carray_add(tab, puid, NULL);
2194 		if (r < 0) {
2195 			free(puid);
2196 			res = MAILIMAP_ERROR_MEMORY;
2197 			goto free_list;
2198 		}
2199 		pflags = malloc(sizeof(* pflags));
2200 		if (pflags == NULL) {
2201 			res = MAILIMAP_ERROR_MEMORY;
2202 			goto free_list;
2203 		}
2204 		* pflags = flags;
2205 		r = carray_add(tab, pflags, NULL);
2206 		if (r < 0) {
2207 			free(pflags);
2208 			res = MAILIMAP_ERROR_MEMORY;
2209 			goto free_list;
2210 		}
2211 		r = carray_add(tab, tags, NULL);
2212 		if (r < 0) {
2213 			free(pflags);
2214 			res = MAILIMAP_ERROR_MEMORY;
2215 			goto free_list;
2216 		}
2217 	}
2218 
2219 	* result = tab;
2220 
2221 	return MAILIMAP_NO_ERROR;
2222 
2223  free_list:
2224 	imap_fetch_uid_flags_list_free(tab);
2225 	slist_free_strings_full(tags);
2226  err:
2227 	return res;
2228 }
2229 
imap_get_messages_flags_list(mailimap * imap,uint32_t first_index,carray ** result)2230 static int imap_get_messages_flags_list(mailimap * imap,
2231 					uint32_t first_index,
2232 					carray ** result)
2233 {
2234 	carray * env_list;
2235 	int r;
2236 	struct mailimap_fetch_att * fetch_att;
2237 	struct mailimap_fetch_type * fetch_type;
2238 	struct mailimap_set * set;
2239 	clist * fetch_result;
2240 	int res;
2241 
2242 	set = mailimap_set_new_interval(first_index, 0);
2243 	if (set == NULL) {
2244 		res = MAILIMAP_ERROR_MEMORY;
2245 		goto err;
2246 	}
2247 
2248 	fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2249 	if (fetch_type == NULL) {
2250 		res = MAILIMAP_ERROR_MEMORY;
2251 		goto free_set;
2252 	}
2253 
2254 	fetch_att = mailimap_fetch_att_new_flags();
2255 	if (fetch_att == NULL) {
2256 		res = MAILIMAP_ERROR_MEMORY;
2257 		goto free_fetch_type;
2258 	}
2259 
2260 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2261 	if (r != MAILIMAP_NO_ERROR) {
2262 		mailimap_fetch_att_free(fetch_att);
2263 		res = MAILIMAP_ERROR_MEMORY;
2264 		goto free_fetch_type;
2265 	}
2266 
2267 	fetch_att = mailimap_fetch_att_new_uid();
2268 	if (fetch_att == NULL) {
2269 		res = MAILIMAP_ERROR_MEMORY;
2270 		goto free_fetch_type;
2271 	}
2272 
2273 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2274 	if (r != MAILIMAP_NO_ERROR) {
2275 		mailimap_fetch_att_free(fetch_att);
2276 		res = MAILIMAP_ERROR_MEMORY;
2277 		goto free_fetch_type;
2278 	}
2279 
2280 	mailstream_logger = imap_logger_fetch;
2281 
2282 	r = mailimap_uid_fetch(imap, set,
2283 			       fetch_type, &fetch_result);
2284 
2285 	mailstream_logger = imap_logger_cmd;
2286 	mailimap_fetch_type_free(fetch_type);
2287 	mailimap_set_free(set);
2288 
2289 	if (r != MAILIMAP_NO_ERROR) {
2290 		res = r;
2291 		goto err;
2292 	}
2293 
2294 	env_list = NULL;
2295 	r = result_to_uid_flags_list(fetch_result, &env_list);
2296 	mailimap_fetch_list_free(fetch_result);
2297 
2298 	* result = env_list;
2299 
2300 	return MAILIMAP_NO_ERROR;
2301 
2302  free_fetch_type:
2303 	mailimap_fetch_type_free(fetch_type);
2304  free_set:
2305 	mailimap_set_free(set);
2306  err:
2307 	return res;
2308 }
2309 
2310 
2311 
fetch_uid_flags_run(struct etpan_thread_op * op)2312 static void fetch_uid_flags_run(struct etpan_thread_op * op)
2313 {
2314 	struct fetch_uid_param * param;
2315 	struct fetch_uid_result * result;
2316 	carray * fetch_result;
2317 	int r;
2318 
2319 	param = op->param;
2320 	result = op->result;
2321 
2322 	CHECK_IMAP();
2323 
2324 	fetch_result = NULL;
2325 	r = imap_get_messages_flags_list(param->imap, param->first_index,
2326 					 &fetch_result);
2327 
2328 	result->error = r;
2329 	result->fetch_result = fetch_result;
2330 	debug_print("imap fetch_uid run - end %i\n", r);
2331 }
2332 
imap_threaded_fetch_uid_flags(Folder * folder,uint32_t first_index,carray ** fetch_result)2333 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index,
2334 				  carray ** fetch_result)
2335 {
2336 	struct fetch_uid_param param;
2337 	struct fetch_uid_result result;
2338 	mailimap * imap;
2339 
2340 	debug_print("imap fetch_uid - begin\n");
2341 
2342 	imap = get_imap(folder);
2343 	param.imap = imap;
2344 	param.first_index = first_index;
2345 
2346 	mailstream_logger = imap_logger_noop;
2347 	log_print(LOG_PROTOCOL, "IMAP- [fetching flags...]\n");
2348 
2349 	threaded_run(folder, &param, &result, fetch_uid_flags_run);
2350 
2351 	mailstream_logger = imap_logger_cmd;
2352 
2353 
2354 	if (result.error != MAILIMAP_NO_ERROR)
2355 		return result.error;
2356 
2357 	debug_print("imap fetch_uid - end\n");
2358 
2359 	* fetch_result = result.fetch_result;
2360 
2361 	return result.error;
2362 }
2363 
2364 
imap_fetch_uid_flags_list_free(carray * uid_flags_list)2365 void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
2366 {
2367 	unsigned int i;
2368 
2369 	for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) {
2370 		void * data;
2371 
2372 		data = carray_get(uid_flags_list, i);
2373 		free(data);
2374 		data = carray_get(uid_flags_list, i + 1);
2375 		free(data);
2376 	}
2377 	carray_free(uid_flags_list);
2378 }
2379 
2380 
2381 
imap_fetch(mailimap * imap,uint32_t msg_index,char ** result,size_t * result_len)2382 static int imap_fetch(mailimap * imap,
2383 		      uint32_t msg_index,
2384 		      char ** result,
2385 		      size_t * result_len)
2386 {
2387 	int r;
2388 	struct mailimap_set * set;
2389 	struct mailimap_fetch_att * fetch_att;
2390 	struct mailimap_fetch_type * fetch_type;
2391 	clist * fetch_result;
2392 	struct mailimap_msg_att * msg_att;
2393 	struct mailimap_msg_att_item * msg_att_item;
2394 	char * text;
2395 	size_t text_length;
2396 	int res;
2397 	clistiter * cur;
2398 	struct mailimap_section * section;
2399 
2400 	set = mailimap_set_new_single(msg_index);
2401 	if (set == NULL) {
2402 		res = MAILIMAP_ERROR_MEMORY;
2403 		goto err;
2404 	}
2405 
2406 	section = mailimap_section_new(NULL);
2407 	if (section == NULL) {
2408 		res = MAILIMAP_ERROR_MEMORY;
2409 		goto free_set;
2410 	}
2411 
2412 	fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2413 	if (fetch_att == NULL) {
2414 		mailimap_section_free(section);
2415 		res = MAILIMAP_ERROR_MEMORY;
2416 		goto free_set;
2417 	}
2418 
2419 	fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2420 	if (fetch_type == NULL) {
2421 		res = MAILIMAP_ERROR_MEMORY;
2422 		goto free_fetch_att;
2423 	}
2424 
2425 	mailstream_logger = imap_logger_fetch;
2426 
2427 	r = mailimap_uid_fetch(imap, set,
2428 			       fetch_type, &fetch_result);
2429 
2430 	mailstream_logger = imap_logger_cmd;
2431 
2432 	mailimap_fetch_type_free(fetch_type);
2433 	mailimap_set_free(set);
2434 
2435 	switch (r) {
2436 	case MAILIMAP_NO_ERROR:
2437 		break;
2438 	default:
2439 		return r;
2440 	}
2441 
2442 	if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2443 		mailimap_fetch_list_free(fetch_result);
2444 		return MAILIMAP_ERROR_FETCH;
2445 	}
2446 
2447 	msg_att = clist_begin(fetch_result)->data;
2448 
2449 	text = NULL;
2450 	text_length = 0;
2451 
2452 	if (msg_att->att_list)
2453 		cur = clist_begin(msg_att->att_list);
2454 	else
2455 		cur = NULL;
2456 
2457 	for(; cur != NULL ; cur = clist_next(cur)) {
2458 		msg_att_item = clist_content(cur);
2459 
2460 		if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2461 			if (msg_att_item->att_data.att_static->att_type ==
2462 			    MAILIMAP_MSG_ATT_BODY_SECTION) {
2463 				text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2464 				/* detach */
2465 				msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2466 				text_length =
2467 					msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2468 			}
2469 		}
2470 	}
2471 
2472 	mailimap_fetch_list_free(fetch_result);
2473 
2474 	if (text == NULL)
2475 		return MAILIMAP_ERROR_FETCH;
2476 
2477 	* result = text;
2478 	* result_len = text_length;
2479 
2480 	return MAILIMAP_NO_ERROR;
2481 
2482  free_fetch_att:
2483 	mailimap_fetch_att_free(fetch_att);
2484  free_set:
2485 	mailimap_set_free(set);
2486  err:
2487 	return res;
2488 }
2489 
imap_fetch_header(mailimap * imap,uint32_t msg_index,char ** result,size_t * result_len)2490 static int imap_fetch_header(mailimap * imap,
2491 			     uint32_t msg_index,
2492 			     char ** result,
2493 			     size_t * result_len)
2494 {
2495   int r;
2496   struct mailimap_set * set;
2497   struct mailimap_fetch_att * fetch_att;
2498   struct mailimap_fetch_type * fetch_type;
2499   clist * fetch_result;
2500   struct mailimap_msg_att * msg_att;
2501   struct mailimap_msg_att_item * msg_att_item;
2502   char * text;
2503   size_t text_length;
2504   int res;
2505   clistiter * cur;
2506   struct mailimap_section * section;
2507 
2508   set = mailimap_set_new_single(msg_index);
2509   if (set == NULL) {
2510     res = MAILIMAP_ERROR_MEMORY;
2511     goto err;
2512   }
2513 
2514   section = mailimap_section_new_header();
2515   if (section == NULL) {
2516     res = MAILIMAP_ERROR_MEMORY;
2517     goto free_set;
2518   }
2519 
2520   fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2521   if (fetch_att == NULL) {
2522     mailimap_section_free(section);
2523     res = MAILIMAP_ERROR_MEMORY;
2524     goto free_set;
2525   }
2526 
2527   fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att);
2528   if (fetch_type == NULL) {
2529     res = MAILIMAP_ERROR_MEMORY;
2530     goto free_fetch_att;
2531   }
2532 
2533   mailstream_logger = imap_logger_fetch;
2534 
2535   r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2536 
2537   mailstream_logger = imap_logger_cmd;
2538   mailimap_fetch_type_free(fetch_type);
2539   mailimap_set_free(set);
2540 
2541   switch (r) {
2542   case MAILIMAP_NO_ERROR:
2543     break;
2544   default:
2545     return r;
2546   }
2547 
2548   if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2549     mailimap_fetch_list_free(fetch_result);
2550     return MAILIMAP_ERROR_FETCH;
2551   }
2552 
2553   msg_att = clist_begin(fetch_result)->data;
2554 
2555   text = NULL;
2556   text_length = 0;
2557 
2558   if (msg_att->att_list)
2559      cur = clist_begin(msg_att->att_list);
2560   else
2561      cur = NULL;
2562 
2563   for(; cur != NULL ; cur = clist_next(cur)) {
2564     msg_att_item = clist_content(cur);
2565 
2566     if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) {
2567       if (msg_att_item->att_data.att_static->att_type ==
2568 	  MAILIMAP_MSG_ATT_BODY_SECTION) {
2569 	text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part;
2570 	msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL;
2571 	text_length =
2572 	  msg_att_item->att_data.att_static->att_data.att_body_section->sec_length;
2573       }
2574     }
2575   }
2576 
2577   mailimap_fetch_list_free(fetch_result);
2578 
2579   if (text == NULL)
2580     return MAILIMAP_ERROR_FETCH;
2581 
2582   * result = text;
2583   * result_len = text_length;
2584 
2585   return MAILIMAP_NO_ERROR;
2586 
2587  free_fetch_att:
2588   mailimap_fetch_att_free(fetch_att);
2589  free_set:
2590   mailimap_set_free(set);
2591  err:
2592   return res;
2593 }
2594 
2595 
2596 
2597 struct fetch_content_param {
2598 	mailimap * imap;
2599 	uint32_t msg_index;
2600 	const char * filename;
2601 	int with_body;
2602 };
2603 
2604 struct fetch_content_result {
2605 	int error;
2606 };
2607 
fetch_content_run(struct etpan_thread_op * op)2608 static void fetch_content_run(struct etpan_thread_op * op)
2609 {
2610 	struct fetch_content_param * param;
2611 	struct fetch_content_result * result;
2612 	char * content;
2613 	size_t content_size;
2614 	int r;
2615 	int fd;
2616 	FILE * f;
2617 
2618 	param = op->param;
2619 	result = op->result;
2620 
2621 	CHECK_IMAP();
2622 
2623 	content = NULL;
2624 	content_size = 0;
2625 	if (param->with_body)
2626 		r = imap_fetch(param->imap, param->msg_index,
2627 			       &content, &content_size);
2628 	else
2629 		r = imap_fetch_header(param->imap, param->msg_index,
2630 				      &content, &content_size);
2631 
2632 	result->error = r;
2633 
2634 	if (r == MAILIMAP_NO_ERROR) {
2635 		fd = g_open(param->filename, O_RDWR | O_CREAT, 0600);
2636 		if (fd < 0) {
2637 			result->error = MAILIMAP_ERROR_FETCH;
2638 			goto free;
2639 		}
2640 
2641 		f = claws_fdopen(fd, "wb");
2642 		if (f == NULL) {
2643 			result->error = MAILIMAP_ERROR_FETCH;
2644 			goto close;
2645 		}
2646 
2647 		r = claws_fwrite(content, 1, content_size, f);
2648 		if (r < content_size) {
2649 			result->error = MAILIMAP_ERROR_FETCH;
2650 			goto do_fclose;
2651 		}
2652 
2653 		r = claws_safe_fclose(f);
2654 		if (r == EOF) {
2655 			result->error = MAILIMAP_ERROR_FETCH;
2656 			goto unlink;
2657 		}
2658 		goto free;
2659 
2660 	do_fclose:
2661 		claws_fclose(f);
2662 		goto unlink;
2663 	close:
2664 		close(fd);
2665 	unlink:
2666 		claws_unlink(param->filename);
2667 
2668 	free:
2669 		/* mmap_string_unref is a simple free in libetpan
2670 		 * when it has MMAP_UNAVAILABLE defined */
2671 		if (mmap_string_unref(content) != 0)
2672 			free(content);
2673 	}
2674 
2675 	debug_print("imap fetch_content run - end %i\n", result->error);
2676 }
2677 
imap_threaded_fetch_content(Folder * folder,uint32_t msg_index,int with_body,const char * filename)2678 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
2679 				int with_body,
2680 				const char * filename)
2681 {
2682 	struct fetch_content_param param;
2683 	struct fetch_content_result result;
2684 	mailimap * imap;
2685 
2686 	debug_print("imap fetch_content - begin\n");
2687 
2688 	imap = get_imap(folder);
2689 	param.imap = imap;
2690 	param.msg_index = msg_index;
2691 	param.filename = filename;
2692 	param.with_body = with_body;
2693 
2694 	threaded_run(folder, &param, &result, fetch_content_run);
2695 
2696 	if (result.error != MAILIMAP_NO_ERROR)
2697 		return result.error;
2698 
2699 	debug_print("imap fetch_content - end\n");
2700 
2701 	return result.error;
2702 }
2703 
2704 
2705 
imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn,GSList ** s_tags)2706 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags)
2707 {
2708 	int flags;
2709 	clist * flag_list;
2710 	clistiter * cur;
2711 	GSList *tags = NULL;
2712 
2713 	flags = MSG_UNREAD;
2714 
2715 	flag_list = att_dyn->att_list;
2716 	if (flag_list == NULL)
2717 		return flags;
2718 
2719 	for(cur = clist_begin(flag_list) ; cur != NULL ;
2720 	    cur = clist_next(cur)) {
2721 		struct mailimap_flag_fetch * flag_fetch;
2722 
2723 		flag_fetch = clist_content(cur);
2724 		if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT)
2725 			flags |= MSG_NEW;
2726 		else {
2727 			switch (flag_fetch->fl_flag->fl_type) {
2728 			case MAILIMAP_FLAG_ANSWERED:
2729 				flags |= MSG_REPLIED;
2730 				break;
2731 			case MAILIMAP_FLAG_FLAGGED:
2732 				flags |= MSG_MARKED;
2733 				break;
2734 			case MAILIMAP_FLAG_DELETED:
2735 				flags |= MSG_DELETED;
2736 				break;
2737 			case MAILIMAP_FLAG_SEEN:
2738 				flags &= ~MSG_UNREAD;
2739 				flags &= ~MSG_NEW;
2740 				break;
2741 			case MAILIMAP_FLAG_KEYWORD:
2742 				if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED))
2743 					flags |= MSG_FORWARDED;
2744 				else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_JUNK))
2745 					flags |= MSG_SPAM;
2746 				else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) ||
2747 					 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) ||
2748 					 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK))
2749 					flags &= ~MSG_SPAM;
2750 				else if (s_tags)
2751 					tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword));
2752 				break;
2753 			}
2754 		}
2755 	}
2756 	if (s_tags)
2757 		*s_tags = tags;
2758 	return flags;
2759 }
2760 
imap_get_msg_att_info(struct mailimap_msg_att * msg_att,uint32_t * puid,char ** pheaders,size_t * pref_size,struct mailimap_msg_att_dynamic ** patt_dyn)2761 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
2762 				 uint32_t * puid,
2763 				 char ** pheaders,
2764 				 size_t * pref_size,
2765 				 struct mailimap_msg_att_dynamic ** patt_dyn)
2766 {
2767   clistiter * item_cur;
2768   uint32_t uid;
2769   char * headers;
2770   size_t ref_size;
2771   struct mailimap_msg_att_dynamic * att_dyn;
2772 
2773   uid = 0;
2774   headers = NULL;
2775   ref_size = 0;
2776   att_dyn = NULL;
2777 
2778   if (msg_att->att_list)
2779      item_cur = clist_begin(msg_att->att_list);
2780   else
2781      item_cur = NULL;
2782   for(; item_cur != NULL ; item_cur = clist_next(item_cur)) {
2783     struct mailimap_msg_att_item * item;
2784 
2785     item = clist_content(item_cur);
2786 
2787     switch (item->att_type) {
2788     case MAILIMAP_MSG_ATT_ITEM_STATIC:
2789       switch (item->att_data.att_static->att_type) {
2790       case MAILIMAP_MSG_ATT_UID:
2791 	uid = item->att_data.att_static->att_data.att_uid;
2792 	break;
2793 
2794       case MAILIMAP_MSG_ATT_BODY_SECTION:
2795 	if (headers == NULL) {
2796 	  headers = item->att_data.att_static->att_data.att_body_section->sec_body_part;
2797 	}
2798 	break;
2799       case MAILIMAP_MSG_ATT_RFC822_SIZE:
2800 	      ref_size = item->att_data.att_static->att_data.att_rfc822_size;
2801 	      break;
2802       }
2803       break;
2804 
2805     case MAILIMAP_MSG_ATT_ITEM_DYNAMIC:
2806       if (att_dyn == NULL) {
2807 	att_dyn = item->att_data.att_dyn;
2808       }
2809       break;
2810     }
2811   }
2812 
2813   if (puid != NULL)
2814     * puid = uid;
2815   if (pheaders != NULL)
2816     * pheaders = headers;
2817   if (pref_size != NULL)
2818     * pref_size = ref_size;
2819   if (patt_dyn != NULL)
2820     * patt_dyn = att_dyn;
2821 
2822   return MAIL_NO_ERROR;
2823 }
2824 
2825 static struct imap_fetch_env_info *
fetch_to_env_info(struct mailimap_msg_att * msg_att,GSList ** tags)2826 fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags)
2827 {
2828 	struct imap_fetch_env_info * info;
2829 	uint32_t uid;
2830 	char * headers;
2831 	size_t size;
2832 	struct mailimap_msg_att_dynamic * att_dyn;
2833 
2834 	imap_get_msg_att_info(msg_att, &uid, &headers, &size,
2835 			      &att_dyn);
2836 
2837 	if (!headers)
2838 		return NULL;
2839 	info = malloc(sizeof(* info));
2840 	info->uid = uid;
2841 	info->headers = strdup(headers);
2842 	info->size = size;
2843 	info->flags = imap_flags_to_flags(att_dyn, tags);
2844 
2845 	return info;
2846 }
2847 
2848 static int
imap_fetch_result_to_envelop_list(clist * fetch_result,carray ** p_env_list)2849 imap_fetch_result_to_envelop_list(clist * fetch_result,
2850 				  carray ** p_env_list)
2851 {
2852 	clistiter * cur;
2853 
2854   	if (fetch_result) {
2855 		carray * env_list;
2856 		env_list = carray_new(16);
2857 
2858 		for(cur = clist_begin(fetch_result) ; cur != NULL ;
2859 		    cur = clist_next(cur)) {
2860 			struct mailimap_msg_att * msg_att;
2861 			struct imap_fetch_env_info * env_info;
2862 	    		GSList *tags = NULL;
2863 
2864 			msg_att = clist_content(cur);
2865 
2866 			env_info = fetch_to_env_info(msg_att, &tags);
2867 			if (!env_info
2868 			 || carray_add(env_list, env_info, NULL) != 0
2869 			 || carray_add(env_list, tags, NULL) != 0) {
2870 				carray_free(env_list);
2871 				return MAILIMAP_ERROR_MEMORY;
2872 			}
2873 		}
2874 		* p_env_list = env_list;
2875   	} else {
2876 		* p_env_list = NULL;
2877 	}
2878 
2879 	return MAIL_NO_ERROR;
2880 }
2881 
imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)2882 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type)
2883 {
2884 	struct mailimap_fetch_att * fetch_att;
2885 	int i;
2886 	char * header;
2887 	clist * hdrlist;
2888 	struct mailimap_header_list * imap_hdrlist;
2889 	struct mailimap_section * section;
2890 	char *headers[] = {
2891 			"Date", "From", "To", "Cc", "Subject", "Message-ID",
2892 			"References", "In-Reply-To", NULL
2893 		};
2894 
2895 	hdrlist = clist_new();
2896 	if (!hdrlist)
2897 		return MAIL_ERROR_MEMORY;
2898 	i = 0;
2899 	while (headers[i] != NULL) {
2900   		header = strdup(headers[i]);
2901 		if (header == NULL || clist_append(hdrlist, header) != 0) {
2902 			clist_free(hdrlist);
2903 			return MAIL_ERROR_MEMORY;
2904 		}
2905 		++i;
2906 	}
2907 
2908 	imap_hdrlist = mailimap_header_list_new(hdrlist);
2909 	section = mailimap_section_new_header_fields(imap_hdrlist);
2910 	fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2911 	mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2912 
2913 	return MAIL_NO_ERROR;
2914 }
2915 
imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)2916 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type)
2917 {
2918 	struct mailimap_fetch_att * fetch_att;
2919 	struct mailimap_section * section;
2920 
2921 	section = mailimap_section_new_header();
2922 	fetch_att = mailimap_fetch_att_new_body_peek_section(section);
2923 	mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2924 
2925 	return MAIL_NO_ERROR;
2926 }
2927 
2928 static int
imap_get_envelopes_list(mailimap * imap,struct mailimap_set * set,carray ** p_env_list)2929 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set,
2930 			carray ** p_env_list)
2931 {
2932 	struct mailimap_fetch_att * fetch_att;
2933 	struct mailimap_fetch_type * fetch_type;
2934 	int res;
2935 	clist * fetch_result;
2936 	int r;
2937 	carray * env_list = NULL;
2938 	chashdatum key;
2939 	chashdatum value;
2940 
2941 	fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
2942 
2943 	/* uid */
2944 	fetch_att = mailimap_fetch_att_new_uid();
2945 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2946 
2947 	/* flags */
2948 	fetch_att = mailimap_fetch_att_new_flags();
2949 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2950 
2951 	/* rfc822 size */
2952 	fetch_att = mailimap_fetch_att_new_rfc822_size();
2953 	r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
2954 
2955 	/* headers */
2956 	key.data = &imap;
2957 	key.len = sizeof(imap);
2958 	r = chash_get(courier_workaround_hash, &key, &value);
2959 	if (r < 0)
2960 		r = imap_add_envelope_fetch_att(fetch_type);
2961 	else
2962 		r = imap_add_header_fetch_att(fetch_type);
2963 
2964 	if (r != MAILIMAP_NO_ERROR) {
2965 		debug_print("add fetch attr: %d\n", r);
2966 		return r;
2967 	}
2968 
2969 	mailstream_logger = imap_logger_fetch;
2970 
2971 	r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result);
2972 
2973 	mailstream_logger = imap_logger_cmd;
2974 	switch (r) {
2975 	case MAILIMAP_NO_ERROR:
2976 		break;
2977 	default:
2978 		mailimap_fetch_type_free(fetch_type);
2979 		debug_print("uid_fetch: %d\n", r);
2980 		return r;
2981 	}
2982 
2983 	if (fetch_result == NULL || clist_begin(fetch_result) == NULL) {
2984 		res = MAILIMAP_ERROR_FETCH;
2985 		debug_print("clist_begin = NULL\n");
2986 		goto err;
2987 	}
2988 
2989 	r = imap_fetch_result_to_envelop_list(fetch_result, &env_list);
2990 	mailimap_fetch_list_free(fetch_result);
2991 
2992 	if (r != MAILIMAP_NO_ERROR) {
2993 		mailimap_fetch_type_free(fetch_type);
2994 		res = MAILIMAP_ERROR_MEMORY;
2995 		debug_print("fetch_result_to_envelop_list: %d\n", res);
2996 		goto err;
2997 	}
2998 
2999 	mailimap_fetch_type_free(fetch_type);
3000 
3001 	* p_env_list = env_list;
3002 
3003 	return MAILIMAP_NO_ERROR;
3004 
3005  err:
3006 	return res;
3007 }
3008 
3009 struct fetch_env_param {
3010 	mailimap * imap;
3011 	struct mailimap_set * set;
3012 };
3013 
3014 struct fetch_env_result {
3015 	carray * fetch_env_result;
3016 	int error;
3017 };
3018 
fetch_env_run(struct etpan_thread_op * op)3019 static void fetch_env_run(struct etpan_thread_op * op)
3020 {
3021 	struct fetch_env_param * param;
3022 	struct fetch_env_result * result;
3023 	carray * env_list;
3024 	int r;
3025 
3026 	param = op->param;
3027 	result = op->result;
3028 
3029 	CHECK_IMAP();
3030 
3031 	env_list = NULL;
3032 	r = imap_get_envelopes_list(param->imap, param->set,
3033 				    &env_list);
3034 
3035 	result->error = r;
3036 	result->fetch_env_result = env_list;
3037 
3038 	debug_print("imap fetch_env run - end %i\n", r);
3039 }
3040 
imap_threaded_fetch_env(Folder * folder,struct mailimap_set * set,carray ** p_env_list)3041 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set,
3042 			    carray ** p_env_list)
3043 {
3044 	struct fetch_env_param param;
3045 	struct fetch_env_result result;
3046 	mailimap * imap;
3047 
3048 	debug_print("imap fetch_env - begin\n");
3049 
3050 	imap = get_imap(folder);
3051 	param.imap = imap;
3052 	param.set = set;
3053 
3054 	if (threaded_run(folder, &param, &result, fetch_env_run))
3055 		return MAILIMAP_ERROR_INVAL;
3056 
3057 	if (result.error != MAILIMAP_NO_ERROR) {
3058 		chashdatum key;
3059 		chashdatum value;
3060 		int r;
3061 
3062 		key.data = &imap;
3063 		key.len = sizeof(imap);
3064 		r = chash_get(courier_workaround_hash, &key, &value);
3065 		if (r < 0) {
3066 			value.data = NULL;
3067 			value.len = 0;
3068 			chash_set(courier_workaround_hash, &key, &value, NULL);
3069 
3070 			threaded_run(folder, &param, &result, fetch_env_run);
3071 		}
3072 	}
3073 
3074 	if (result.error != MAILIMAP_NO_ERROR)
3075 		return result.error;
3076 
3077 	debug_print("imap fetch_env - end\n");
3078 
3079 	* p_env_list = result.fetch_env_result;
3080 
3081 	return result.error;
3082 }
3083 
imap_fetch_env_free(carray * env_list)3084 void imap_fetch_env_free(carray * env_list)
3085 {
3086 	unsigned int i;
3087 
3088 	for(i = 0 ; i < carray_count(env_list) ; i += 2) {
3089 		struct imap_fetch_env_info * env_info;
3090 
3091 		env_info = carray_get(env_list, i);
3092 		free(env_info->headers);
3093 		free(env_info);
3094 	}
3095 	carray_free(env_list);
3096 }
3097 
3098 
3099 
3100 
3101 
3102 struct append_param {
3103 	mailimap * imap;
3104 	const char * mailbox;
3105 	const char * filename;
3106 	struct mailimap_flag_list * flag_list;
3107 };
3108 
3109 struct append_result {
3110 	int error;
3111 	int uid;
3112 };
3113 
append_run(struct etpan_thread_op * op)3114 static void append_run(struct etpan_thread_op * op)
3115 {
3116 	struct append_param * param;
3117 	struct append_result * result;
3118 	int r;
3119 	char * data;
3120 	size_t size;
3121 #ifndef G_OS_WIN32
3122 	struct stat stat_buf;
3123 	int fd;
3124 #endif
3125 	guint32 uid = 0, val = 0;
3126 
3127 	param = op->param;
3128 	result = op->result;
3129 
3130 	CHECK_IMAP();
3131 
3132 #ifndef G_OS_WIN32
3133 	r = stat(param->filename, &stat_buf);
3134 	if (r < 0) {
3135 		result->error = MAILIMAP_ERROR_APPEND;
3136 		return;
3137 	}
3138 	size = stat_buf.st_size;
3139 
3140 	fd = g_open(param->filename, O_RDONLY, 0);
3141 	if (fd < 0) {
3142 		result->error = MAILIMAP_ERROR_APPEND;
3143 		return;
3144 	}
3145 
3146 	data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
3147 	if (data == (void *) MAP_FAILED) {
3148 		close(fd);
3149 		result->error = MAILIMAP_ERROR_APPEND;
3150 		return;
3151 	}
3152 #else
3153 	data = file_read_to_str_no_recode(param->filename);
3154 	if (data == NULL) {
3155 		result->error = MAILIMAP_ERROR_APPEND;
3156 		return;
3157 	}
3158 	size = strlen(data);
3159 #endif
3160 	mailstream_logger = imap_logger_append;
3161 
3162 	r = mailimap_uidplus_append(param->imap, param->mailbox,
3163 			    param->flag_list, NULL,
3164 			    data, size, &val, &uid);
3165 
3166 	mailstream_logger = imap_logger_cmd;
3167 
3168 #ifndef G_OS_WIN32
3169 	munmap(data, size);
3170 	close(fd);
3171 #else
3172 	g_free(data);
3173 #endif
3174 
3175 	result->error = r;
3176 	result->uid = uid;
3177 	debug_print("imap append run - end %i uid %d\n", r, uid);
3178 }
3179 
imap_threaded_append(Folder * folder,const char * mailbox,const char * filename,struct mailimap_flag_list * flag_list,int * uid)3180 int imap_threaded_append(Folder * folder, const char * mailbox,
3181 			 const char * filename,
3182 			 struct mailimap_flag_list * flag_list,
3183 			 int *uid)
3184 {
3185 	struct append_param param;
3186 	struct append_result result;
3187 	mailimap * imap;
3188 
3189 	debug_print("imap append - begin\n");
3190 
3191 	imap = get_imap(folder);
3192 	param.imap = imap;
3193 	param.mailbox = mailbox;
3194 	param.filename = filename;
3195 	param.flag_list = flag_list;
3196 
3197 	threaded_run(folder, &param, &result, append_run);
3198 
3199 	if (result.error != MAILIMAP_NO_ERROR)
3200 		return result.error;
3201 
3202 	debug_print("imap append - end\n");
3203 	if (uid != NULL)
3204 		*uid = result.uid;
3205 
3206 	return result.error;
3207 }
3208 
3209 
3210 
3211 
3212 struct expunge_param {
3213 	mailimap * imap;
3214 };
3215 
3216 struct expunge_result {
3217 	int error;
3218 };
3219 
expunge_run(struct etpan_thread_op * op)3220 static void expunge_run(struct etpan_thread_op * op)
3221 {
3222 	struct expunge_param * param;
3223 	struct expunge_result * result;
3224 	int r;
3225 
3226 	param = op->param;
3227 	result = op->result;
3228 
3229 	CHECK_IMAP();
3230 
3231 	r = mailimap_expunge(param->imap);
3232 
3233 	result->error = r;
3234 	debug_print("imap expunge run - end %i\n", r);
3235 }
3236 
imap_threaded_expunge(Folder * folder)3237 int imap_threaded_expunge(Folder * folder)
3238 {
3239 	struct expunge_param param;
3240 	struct expunge_result result;
3241 
3242 	debug_print("imap expunge - begin\n");
3243 
3244 	param.imap = get_imap(folder);
3245 
3246 	threaded_run(folder, &param, &result, expunge_run);
3247 
3248 	debug_print("imap expunge - end\n");
3249 
3250 	return result.error;
3251 }
3252 
3253 
3254 struct copy_param {
3255 	mailimap * imap;
3256 	struct mailimap_set * set;
3257 	const char * mb;
3258 };
3259 
3260 struct copy_result {
3261 	int error;
3262 	struct mailimap_set *source;
3263 	struct mailimap_set *dest;
3264 };
3265 
copy_run(struct etpan_thread_op * op)3266 static void copy_run(struct etpan_thread_op * op)
3267 {
3268 	struct copy_param * param;
3269 	struct copy_result * result;
3270 	int r;
3271 	guint32 val;
3272 	struct mailimap_set *source = NULL, *dest = NULL;
3273 
3274 	param = op->param;
3275 	result = op->result;
3276 
3277 	CHECK_IMAP();
3278 
3279 	r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb,
3280 		&val, &source, &dest);
3281 
3282 	result->error = r;
3283 	if (r == 0) {
3284 		result->source = source;
3285 		result->dest = dest;
3286 	} else {
3287 		result->source = NULL;
3288 		result->dest = NULL;
3289 	}
3290 	debug_print("imap copy run - end %i\n", r);
3291 }
3292 
imap_threaded_copy(Folder * folder,struct mailimap_set * set,const char * mb,struct mailimap_set ** source,struct mailimap_set ** dest)3293 int imap_threaded_copy(Folder * folder, struct mailimap_set * set,
3294 		       const char * mb, struct mailimap_set **source,
3295 		       struct mailimap_set **dest)
3296 {
3297 	struct copy_param param;
3298 	struct copy_result result;
3299 	mailimap * imap;
3300 
3301 	debug_print("imap copy - begin\n");
3302 
3303 	imap = get_imap(folder);
3304 	param.imap = imap;
3305 	param.set = set;
3306 	param.mb = mb;
3307 
3308 	threaded_run(folder, &param, &result, copy_run);
3309 	*source = NULL;
3310 	*dest = NULL;
3311 
3312 	if (result.error != MAILIMAP_NO_ERROR)
3313 		return result.error;
3314 
3315 	*source = result.source;
3316 	*dest = result.dest;
3317 
3318 	debug_print("imap copy - end\n");
3319 
3320 	return result.error;
3321 }
3322 
3323 
3324 
3325 struct store_param {
3326 	mailimap * imap;
3327 	struct mailimap_set * set;
3328 	struct mailimap_store_att_flags * store_att_flags;
3329 };
3330 
3331 struct store_result {
3332 	int error;
3333 };
3334 
store_run(struct etpan_thread_op * op)3335 static void store_run(struct etpan_thread_op * op)
3336 {
3337 	struct store_param * param;
3338 	struct store_result * result;
3339 	int r;
3340 
3341 	param = op->param;
3342 	result = op->result;
3343 
3344 	CHECK_IMAP();
3345 
3346 	r = mailimap_uid_store(param->imap, param->set,
3347 			       param->store_att_flags);
3348 
3349 	result->error = r;
3350 
3351 	debug_print("imap store run - end %i\n", r);
3352 }
3353 
imap_threaded_store(Folder * folder,struct mailimap_set * set,struct mailimap_store_att_flags * store_att_flags)3354 int imap_threaded_store(Folder * folder, struct mailimap_set * set,
3355 			struct mailimap_store_att_flags * store_att_flags)
3356 {
3357 	struct store_param param;
3358 	struct store_result result;
3359 	mailimap * imap;
3360 
3361 	debug_print("imap store - begin\n");
3362 
3363 	imap = get_imap(folder);
3364 	param.imap = imap;
3365 	param.set = set;
3366 	param.store_att_flags = store_att_flags;
3367 
3368 	threaded_run(folder, &param, &result, store_run);
3369 
3370 	if (result.error != MAILIMAP_NO_ERROR)
3371 		return result.error;
3372 
3373 	debug_print("imap store - end\n");
3374 
3375 	return result.error;
3376 }
3377 
3378 
3379 #define ENV_BUFFER_SIZE 512
3380 #ifndef G_OS_WIN32
do_exec_command(int fd,const char * command,const char * servername,uint16_t port)3381 static void do_exec_command(int fd, const char * command,
3382 			    const char * servername, uint16_t port)
3383 {
3384 	int i, maxopen;
3385 #ifdef SOLARIS
3386 	char env_buffer[ENV_BUFFER_SIZE];
3387 #endif
3388 
3389 	if (fork() > 0) {
3390 		/* Fork again to become a child of init rather than
3391 		   the etpan client. */
3392 		exit(0);
3393 	}
3394 
3395 	if (servername)
3396 		g_setenv("ETPANSERVER", servername, TRUE);
3397 	else
3398 		g_unsetenv("ETPANSERVER");
3399 
3400 	if (port) {
3401 		char porttext[20];
3402 
3403 		snprintf(porttext, sizeof(porttext), "%d", port);
3404 		g_setenv("ETPANPORT", porttext, TRUE);
3405 	}
3406 	else {
3407 		g_unsetenv("ETPANPORT");
3408 	}
3409 
3410 	/* Not a lot we can do if there's an error other than bail. */
3411 	if (dup2(fd, 0) == -1)
3412 		exit(1);
3413 	if (dup2(fd, 1) == -1)
3414 		exit(1);
3415 
3416 	/* Should we close stderr and reopen /dev/null? */
3417 
3418 	maxopen = sysconf(_SC_OPEN_MAX);
3419 	for (i=3; i < maxopen; i++)
3420 		close(i);
3421 
3422 #ifdef TIOCNOTTY
3423 	/* Detach from the controlling tty if we have one. Otherwise,
3424 	   SSH might do something stupid like trying to use it instead
3425 	   of running $SSH_ASKPASS. Doh. */
3426 	fd = g_open("/dev/tty", O_RDONLY, 0);
3427 	if (fd != -1) {
3428 		ioctl(fd, TIOCNOTTY, NULL);
3429 		close(fd);
3430 	}
3431 #endif /* TIOCNOTTY */
3432 
3433 	execl("/bin/sh", "/bin/sh", "-c", command, NULL);
3434 
3435 	/* Eep. Shouldn't reach this */
3436 	exit(1);
3437 }
3438 
subcommand_connect(const char * command,const char * servername,uint16_t port)3439 static int subcommand_connect(const char *command,
3440 			      const char *servername, uint16_t port)
3441 {
3442 	/* SEB unsupported on Windows */
3443 	int sockfds[2];
3444 	pid_t childpid;
3445 
3446 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
3447 		return -1;
3448 
3449 	childpid = fork();
3450 	if (!childpid) {
3451 		do_exec_command(sockfds[1], command, servername, port);
3452 	}
3453 	else if (childpid == -1) {
3454 		close(sockfds[0]);
3455 		close(sockfds[1]);
3456 		return -1;
3457 	}
3458 
3459 	close(sockfds[1]);
3460 
3461 	/* Reap child, leaving grandchild process to run */
3462 	waitpid(childpid, NULL, 0);
3463 
3464 	return sockfds[0];
3465 }
3466 
socket_connect_cmd(mailimap * imap,const char * command,const char * server,int port)3467 static int socket_connect_cmd(mailimap * imap, const char * command,
3468 		       const char * server, int port)
3469 {
3470 	int fd;
3471 	mailstream * s;
3472 	int r;
3473 
3474 	fd = subcommand_connect(command, server, port);
3475 	if (fd < 0)
3476 		return MAILIMAP_ERROR_STREAM;
3477 
3478 	s = mailstream_socket_open(fd);
3479 	if (s == NULL) {
3480 		close(fd);
3481 		return MAILIMAP_ERROR_STREAM;
3482 	}
3483 
3484 	r = mailimap_connect(imap, s);
3485 	if (r != MAILIMAP_NO_ERROR_AUTHENTICATED
3486 	&&  r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) {
3487 		mailstream_close(s);
3488 		if (imap)
3489 			imap->imap_stream = NULL;
3490 		return r;
3491 	}
3492 
3493 	return r;
3494 }
3495 
3496 /* connect cmd */
3497 
3498 struct connect_cmd_param {
3499 	mailimap * imap;
3500 	const char * command;
3501 	const char * server;
3502 	int port;
3503 };
3504 
3505 struct connect_cmd_result {
3506 	int error;
3507 };
3508 
connect_cmd_run(struct etpan_thread_op * op)3509 static void connect_cmd_run(struct etpan_thread_op * op)
3510 {
3511 	int r;
3512 	struct connect_cmd_param * param;
3513 	struct connect_cmd_result * result;
3514 
3515 	param = op->param;
3516 	result = op->result;
3517 
3518 	CHECK_IMAP();
3519 
3520 	r = socket_connect_cmd(param->imap, param->command,
3521 			       param->server, param->port);
3522 
3523 	result->error = r;
3524 }
3525 
3526 
imap_threaded_connect_cmd(Folder * folder,const char * command,const char * server,int port)3527 int imap_threaded_connect_cmd(Folder * folder, const char * command,
3528 			      const char * server, int port)
3529 {
3530 	struct connect_cmd_param param;
3531 	struct connect_cmd_result result;
3532 	chashdatum key;
3533 	chashdatum value;
3534 	mailimap * imap, * oldimap;
3535 
3536 	oldimap = get_imap(folder);
3537 
3538 	imap = mailimap_new(0, NULL);
3539 
3540 	if (oldimap) {
3541 		debug_print("deleting old imap %p\n", oldimap);
3542 		delete_imap(folder, oldimap);
3543 	}
3544 
3545 	key.data = &folder;
3546 	key.len = sizeof(folder);
3547 	value.data = imap;
3548 	value.len = 0;
3549 	chash_set(session_hash, &key, &value, NULL);
3550 
3551 	param.imap = imap;
3552 	param.command = command;
3553 	param.server = server;
3554 	param.port = port;
3555 
3556 	threaded_run(folder, &param, &result, connect_cmd_run);
3557 
3558 	debug_print("connect_cmd ok %i with imap %p\n", result.error, imap);
3559 
3560 	return result.error;
3561 }
3562 #endif /* G_OS_WIN32 */
3563 
imap_threaded_cancel(Folder * folder)3564 void imap_threaded_cancel(Folder * folder)
3565 {
3566 	mailimap * imap;
3567 
3568 	imap = get_imap(folder);
3569 	if (imap && imap->imap_stream != NULL)
3570 		mailstream_cancel(imap->imap_stream);
3571 }
3572 
3573 #else
3574 
imap_main_init(void)3575 void imap_main_init(void)
3576 {
3577 }
imap_main_done(gboolean have_connectivity)3578 void imap_main_done(gboolean have_connectivity)
3579 {
3580 }
imap_main_set_timeout(int sec)3581 void imap_main_set_timeout(int sec)
3582 {
3583 }
3584 
3585 void imap_threaded_cancel(Folder * folder);
3586 {
3587 }
3588 
3589 #endif
3590