1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2016 Hiroyuki Yamamoto 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 #include "defs.h"
25 
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 
33 #include "main.h"
34 #include "inc.h"
35 #include "mainwindow.h"
36 #include "folderview.h"
37 #include "summaryview.h"
38 #include "prefs_common.h"
39 #include "prefs_account.h"
40 #include "account.h"
41 #include "procmsg.h"
42 #include "proxy.h"
43 #include "socket.h"
44 #include "ssl.h"
45 #include "pop.h"
46 #include "recv.h"
47 #include "mbox.h"
48 #include "file-utils.h"
49 #include "utils.h"
50 #include "gtkutils.h"
51 #include "statusbar.h"
52 #include "msgcache.h"
53 #include "manage_window.h"
54 #include "stock_pixmap.h"
55 #include "progressdialog.h"
56 #include "inputdialog.h"
57 #include "alertpanel.h"
58 #include "folder.h"
59 #include "filtering.h"
60 #include "log.h"
61 #include "hooks.h"
62 #include "logwindow.h"
63 #include "passwordstore.h"
64 #include "oauth2.h"
65 
66 extern SessionStats session_stats;
67 
68 static GList *inc_dialog_list = NULL;
69 
70 static time_t inc_offline_overridden_yes = 0;
71 static time_t inc_offline_overridden_no  = 0;
72 
73 guint inc_lock_count = 0;
74 
75 static GdkPixbuf *currentpix;
76 static GdkPixbuf *errorpix;
77 static GdkPixbuf *okpix;
78 
79 #define MESSAGEBUFSIZE	8192
80 
81 static void inc_update_stats(gint new_msgs);
82 static void inc_finished		(MainWindow		*mainwin,
83 					 gboolean		 new_messages,
84 					 gboolean		 autocheck);
85 static gint inc_account_mail_real	(MainWindow		*mainwin,
86 					 PrefsAccount		*account);
87 
88 static IncProgressDialog *inc_progress_dialog_create
89 					(gboolean		 autocheck);
90 static void inc_progress_dialog_set_list(IncProgressDialog	*inc_dialog);
91 static void inc_progress_dialog_destroy	(IncProgressDialog	*inc_dialog);
92 
93 static IncSession *inc_session_new	(PrefsAccount		*account);
94 static void inc_session_destroy		(IncSession		*session);
95 static gint inc_start			(IncProgressDialog	*inc_dialog);
96 static IncState inc_pop3_session_do	(IncSession		*session);
97 
98 static void inc_progress_dialog_update	(IncProgressDialog	*inc_dialog,
99 					 IncSession		*inc_session);
100 
101 static void inc_progress_dialog_set_label
102 					(IncProgressDialog	*inc_dialog,
103 					 IncSession		*inc_session);
104 static void inc_progress_dialog_set_progress
105 					(IncProgressDialog	*inc_dialog,
106 					 IncSession		*inc_session);
107 
108 static void inc_progress_dialog_update_periodic
109 					(IncProgressDialog	*inc_dialog,
110 					 IncSession		*inc_session);
111 
112 static gint inc_recv_data_progressive	(Session	*session,
113 					 guint		 cur_len,
114 					 guint		 total_len,
115 					 gpointer	 data);
116 static gint inc_recv_data_finished	(Session	*session,
117 					 guint		 len,
118 					 gpointer	 data);
119 static gint inc_recv_message		(Session	*session,
120 					 const gchar	*msg,
121 					 gpointer	 data);
122 static gint inc_drop_message		(Pop3Session	*session,
123 					 const gchar	*file);
124 
125 static void inc_put_error		(IncState	 istate,
126 					 Pop3Session 	*session);
127 
128 static void inc_showlog_cb		(GtkWidget	*widget,
129 					 gpointer	 data);
130 static void inc_cancel_cb		(GtkWidget	*widget,
131 					 gpointer	 data);
132 static gint inc_dialog_delete_cb	(GtkWidget	*widget,
133 					 GdkEventAny	*event,
134 					 gpointer	 data);
135 
136 static gint get_spool			(FolderItem	*dest,
137 					 const gchar	*mbox,
138 					 PrefsAccount	*account);
139 
140 static gint inc_spool_account(PrefsAccount *account);
141 static void inc_autocheck_timer_set_interval	(guint		 interval);
142 static gint inc_autocheck_func			(gpointer	 data);
143 
144 static void inc_notify_cmd		(gint new_msgs,
145  					 gboolean notify);
146 
inc_update_stats(gint new_msgs)147 static void inc_update_stats(gint new_msgs)
148 {
149 	/* update session statistics */
150 	session_stats.received += new_msgs;
151 }
152 
153 /**
154  * inc_finished:
155  * @mainwin: Main window.
156  * @new_messages: TRUE if some messages have been received.
157  *
158  * Update the folder view and the summary view after receiving
159  * messages.  If @new_messages is FALSE, this function avoids unneeded
160  * updating.
161  **/
inc_finished(MainWindow * mainwin,gboolean new_messages,gboolean autocheck)162 static void inc_finished(MainWindow *mainwin, gboolean new_messages, gboolean autocheck)
163 {
164 	if (prefs_common.scan_all_after_inc)
165 		folderview_check_new(NULL);
166 
167 	if (!autocheck && new_messages && prefs_common.open_inbox_on_inc) {
168 		FolderItem *item = NULL;
169 
170 		if (cur_account && cur_account->inbox)
171 			item = folder_find_item_from_identifier(cur_account->inbox);
172 		if (item == NULL && cur_account && cur_account->folder)
173 			item = cur_account->folder->inbox;
174 		if (item == NULL)
175 			item = folder_get_default_inbox();
176 
177 		folderview_unselect(mainwin->folderview);
178 		folderview_select(mainwin->folderview, item);
179 	}
180 	statusbar_progress_all(0,0,0);
181 }
182 
inc_mail(MainWindow * mainwin,gboolean notify)183 void inc_mail(MainWindow *mainwin, gboolean notify)
184 {
185 	gint new_msgs = 0;
186 	gint account_new_msgs = 0;
187 
188 	if (inc_lock_count) return;
189 
190 	if (prefs_common.work_offline &&
191 	    !inc_offline_should_override(TRUE,
192 		_("Claws Mail needs network access in order "
193 		  "to get mails.")))
194 		return;
195 
196 	inc_lock();
197 	inc_autocheck_timer_remove();
198 	main_window_lock(mainwin);
199 
200 	if (prefs_common.use_extinc && prefs_common.extinc_cmd) {
201 		/* external incorporating program */
202 		if (execute_command_line(prefs_common.extinc_cmd, FALSE, NULL) < 0) {
203 			main_window_unlock(mainwin);
204 			inc_autocheck_timer_set();
205 			inc_unlock();
206 			return;
207 		}
208 	} else {
209 		account_new_msgs = inc_account_mail_real(mainwin, cur_account);
210 		if (account_new_msgs > 0)
211 			new_msgs += account_new_msgs;
212 	}
213 
214 	inc_update_stats(new_msgs);
215 	inc_finished(mainwin, new_msgs > 0, FALSE);
216 	main_window_unlock(mainwin);
217  	inc_notify_cmd(new_msgs, notify);
218 	inc_autocheck_timer_set();
219 	inc_unlock();
220 }
221 
inc_pop_before_smtp(PrefsAccount * acc)222 void inc_pop_before_smtp(PrefsAccount *acc)
223 {
224 	IncProgressDialog *inc_dialog;
225 	IncSession *session;
226 	MainWindow *mainwin;
227 
228 	mainwin = mainwindow_get_mainwindow();
229 
230     	session = inc_session_new(acc);
231     	if (!session) return;
232 	POP3_SESSION(session->session)->pop_before_smtp = TRUE;
233 
234     	inc_dialog = inc_progress_dialog_create(FALSE);
235     	inc_dialog->queue_list = g_list_append(inc_dialog->queue_list,
236 					       session);
237 	/* FIXME: assumes to attach to first main window */
238 	inc_dialog->mainwin = mainwin;
239 	inc_progress_dialog_set_list(inc_dialog);
240 
241 	if (mainwin) {
242 		toolbar_main_set_sensitive(mainwin);
243 		main_window_set_menu_sensitive(mainwin);
244 	}
245 
246 	inc_start(inc_dialog);
247 }
248 
inc_account_mail_real(MainWindow * mainwin,PrefsAccount * account)249 static gint inc_account_mail_real(MainWindow *mainwin, PrefsAccount *account)
250 {
251 	IncProgressDialog *inc_dialog;
252 	IncSession *session;
253 
254 	switch (account->protocol) {
255 	case A_IMAP4:
256 	case A_NNTP:
257 		/* Melvin: bug [14]
258 		 * FIXME: it should return foldeview_check_new() value.
259 		 * TODO: do it when bug [19] is fixed (IMAP folder sets
260 		 * an incorrect new message count)
261 		 */
262 		folderview_check_new(FOLDER(account->folder));
263 		return 0;
264 	case A_POP3:
265 		session = inc_session_new(account);
266 		if (!session) return 0;
267 
268 		inc_dialog = inc_progress_dialog_create(FALSE);
269 		inc_dialog->queue_list = g_list_append(inc_dialog->queue_list,
270 						       session);
271 		inc_dialog->mainwin = mainwin;
272 		inc_progress_dialog_set_list(inc_dialog);
273 
274 		if (mainwin) {
275 			toolbar_main_set_sensitive(mainwin);
276 			main_window_set_menu_sensitive(mainwin);
277 		}
278 
279 		return inc_start(inc_dialog);
280 
281 	case A_LOCAL:
282 		return inc_spool_account(account);
283 
284 	default:
285 		break;
286 	}
287 	return 0;
288 }
289 
inc_account_mail(MainWindow * mainwin,PrefsAccount * account)290 gint inc_account_mail(MainWindow *mainwin, PrefsAccount *account)
291 {
292 	gint new_msgs;
293 
294 	if (inc_lock_count) return 0;
295 
296 	if (account->receive_in_progress) return 0;
297 
298 	if (prefs_common.work_offline &&
299 	    !inc_offline_should_override(TRUE,
300 		_("Claws Mail needs network access in order "
301 		  "to get mails.")))
302 		return 0;
303 
304 	inc_autocheck_timer_remove();
305 	main_window_lock(mainwin);
306 
307 	new_msgs = inc_account_mail_real(mainwin, account);
308 
309 	inc_update_stats(new_msgs);
310 	inc_finished(mainwin, new_msgs > 0, FALSE);
311 	main_window_unlock(mainwin);
312 	inc_autocheck_timer_set();
313 
314 	return new_msgs;
315 }
316 
inc_account_list_mail(MainWindow * mainwin,GList * account_list,gboolean autocheck,gboolean notify)317 void inc_account_list_mail(MainWindow *mainwin, GList *account_list, gboolean autocheck,
318 			  gboolean notify)
319 {
320 	GList *list, *queue_list = NULL;
321 	IncProgressDialog *inc_dialog;
322 	gint new_msgs = 0, num;
323 
324 	if (prefs_common.work_offline &&
325 	    !inc_offline_should_override( (autocheck == FALSE),
326 		_("Claws Mail needs network access in order "
327 		  "to get mails.")))
328 		return;
329 
330 	if (inc_lock_count) return;
331 
332 	main_window_lock(mainwin);
333 
334 	if (!account_list) {
335 		inc_update_stats(new_msgs);
336 		inc_finished(mainwin, new_msgs > 0, autocheck);
337 		main_window_unlock(mainwin);
338  		inc_notify_cmd(new_msgs, notify);
339 		return;
340 	}
341 
342 	if (prefs_common.use_extinc && prefs_common.extinc_cmd) {
343 		/* external incorporating program */
344 		if (execute_command_line(prefs_common.extinc_cmd, FALSE, NULL) < 0) {
345 			log_error(LOG_PROTOCOL, _("%s failed\n"), prefs_common.extinc_cmd);
346 
347 			main_window_unlock(mainwin);
348 			return;
349 		}
350 	}
351 
352 	/* Check all accounts in the list, one by one. */
353 	for (list = account_list; list != NULL; list = list->next) {
354 		PrefsAccount *account = list->data;
355 
356 		if (account == NULL) {
357 			debug_print("INC: Huh? inc_account_list_mail() got a NULL account, this should not happen!\n");
358 			continue;
359 		}
360 
361 		debug_print("INC: checking account %d\n", account->account_id);
362 		switch (account->protocol) {
363 			case A_POP3:
364 				if (!(account->receive_in_progress)) {
365 					IncSession *session = inc_session_new(account);
366 
367 					if (session != NULL) {
368 						debug_print("INC: adding POP3 account %d to inc queue\n",
369 								account->account_id);
370 						queue_list = g_list_append(queue_list, session);
371 					}
372 				}
373 				break;
374 
375 			case A_IMAP4:
376 			case A_NNTP:
377 				new_msgs += folderview_check_new(FOLDER(account->folder));
378 				break;
379 
380 			case A_LOCAL:
381 				num = inc_spool_account(account);
382 				if (num > 0)
383 					new_msgs += num;
384 				break;
385 
386 			case A_NONE:
387 				/* Nothing to do here, it's a SMTP-only account. */
388 				break;
389 
390 			default:
391 				debug_print("INC: encountered account %d with unknown protocol %d, ignoring\n",
392 						account->account_id, account->protocol);
393 				break;
394 		}
395 	}
396 
397 
398 
399 	if (queue_list) {
400 		inc_dialog = inc_progress_dialog_create(autocheck);
401 		inc_dialog->queue_list = queue_list;
402 		inc_dialog->mainwin = mainwin;
403 		inc_progress_dialog_set_list(inc_dialog);
404 
405 		toolbar_main_set_sensitive(mainwin);
406 		main_window_set_menu_sensitive(mainwin);
407 		new_msgs += inc_start(inc_dialog);
408 	}
409 
410 	inc_update_stats(new_msgs);
411 	inc_finished(mainwin, new_msgs > 0, autocheck);
412 	main_window_unlock(mainwin);
413  	inc_notify_cmd(new_msgs, notify);
414 }
415 
inc_all_account_mail(MainWindow * mainwin,gboolean autocheck,gboolean check_at_startup,gboolean notify)416 void inc_all_account_mail(MainWindow *mainwin, gboolean autocheck,
417 			  gboolean check_at_startup, gboolean notify)
418 {
419 	GList *list, *list2 = NULL;
420 	gboolean condition;
421 	gboolean hide_dialog = FALSE;
422 
423 	debug_print("INC: inc_all_account_mail(), autocheck: %s\n",
424 			autocheck ? "YES" : "NO");
425 
426 	/* Collect list of accounts which use the global autocheck interval. */
427 	for (list = account_get_list(); list != NULL; list = list->next) {
428 		PrefsAccount *account = list->data;
429 
430 		/* Nothing to do for SMTP-only accounts. */
431 		if (account->protocol == A_NONE)
432 			continue;
433 
434 		/* Set up condition which decides whether or not to check
435 		 * this account, based on whether we're doing global autocheck
436 		 * or a check at startup or a manual 'Get all' check. */
437 		if (autocheck)
438 			condition = prefs_common_get_prefs()->autochk_newmail
439 				&& account->autochk_use_default;
440 		else if (check_at_startup || (!check_at_startup && !autocheck))
441 			condition = account->recv_at_getall;
442 
443 		if (condition) {
444 			debug_print("INC: will check account %d\n", account->account_id);
445 			list2 = g_list_append(list2, account);
446 		}
447 	}
448 
449 	/* Do the check on the collected accounts. */
450 	if (list2 != NULL) {
451 		if (autocheck || check_at_startup)
452 			hide_dialog = TRUE;
453 		inc_account_list_mail(mainwin, list2, hide_dialog, notify);
454 		g_list_free(list2);
455 	}
456 }
457 
inc_progress_dialog_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)458 static void inc_progress_dialog_size_allocate_cb(GtkWidget *widget,
459 					 GtkAllocation *allocation)
460 {
461 	cm_return_if_fail(allocation != NULL);
462 
463 	prefs_common.receivewin_width = allocation->width;
464 	prefs_common.receivewin_height = allocation->height;
465 }
466 
inc_progress_dialog_create(gboolean autocheck)467 static IncProgressDialog *inc_progress_dialog_create(gboolean autocheck)
468 {
469 	IncProgressDialog *dialog;
470 	ProgressDialog *progress;
471 	static GdkGeometry geometry;
472 
473 	dialog = g_new0(IncProgressDialog, 1);
474 
475 	progress = progress_dialog_create();
476 	gtk_window_set_title(GTK_WINDOW(progress->window),
477 			     _("Retrieving new messages"));
478 	g_signal_connect(G_OBJECT(progress->showlog_btn), "clicked",
479 			 G_CALLBACK(inc_showlog_cb), dialog);
480 	g_signal_connect(G_OBJECT(progress->cancel_btn), "clicked",
481 			 G_CALLBACK(inc_cancel_cb), dialog);
482 	g_signal_connect(G_OBJECT(progress->window), "delete_event",
483 			 G_CALLBACK(inc_dialog_delete_cb), dialog);
484 	g_signal_connect(G_OBJECT(progress->window), "size_allocate",
485 			 G_CALLBACK(inc_progress_dialog_size_allocate_cb), NULL);
486  	/* manage_window_set_transient(GTK_WINDOW(progress->window)); */
487 
488 	progress_dialog_get_fraction(progress);
489 
490 	stock_pixbuf_gdk(STOCK_PIXMAP_COMPLETE, &okpix);
491 	stock_pixbuf_gdk(STOCK_PIXMAP_CONTINUE, &currentpix);
492 	stock_pixbuf_gdk(STOCK_PIXMAP_ERROR, &errorpix);
493 
494 	if (!geometry.min_height) {
495 		geometry.min_width = 460;
496 		geometry.min_height = 250;
497 	}
498 
499 	gtk_window_set_geometry_hints(GTK_WINDOW(progress->window), NULL, &geometry,
500 				      GDK_HINT_MIN_SIZE);
501 	gtk_widget_set_size_request(progress->window, prefs_common.receivewin_width,
502 				    prefs_common.receivewin_height);
503 
504 	if (prefs_common.recv_dialog_mode == RECV_DIALOG_ALWAYS ||
505 	    (prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL &&
506 	     !autocheck)) {
507 		dialog->show_dialog = TRUE;
508 		gtk_widget_show_now(progress->window);
509 	}
510 
511 	dialog->dialog = progress;
512 	dialog->progress_tv = g_date_time_new_now_local();
513 	dialog->folder_tv = g_date_time_new_now_local();
514 	dialog->queue_list = NULL;
515 	dialog->cur_row = 0;
516 
517 	inc_dialog_list = g_list_append(inc_dialog_list, dialog);
518 
519 	return dialog;
520 }
521 
inc_progress_dialog_set_list(IncProgressDialog * inc_dialog)522 static void inc_progress_dialog_set_list(IncProgressDialog *inc_dialog)
523 {
524 	GList *list;
525 
526 	for (list = inc_dialog->queue_list; list != NULL; list = list->next) {
527 		IncSession *session = list->data;
528 		Pop3Session *pop3_session = POP3_SESSION(session->session);
529 
530 		session->data = inc_dialog;
531 
532 		progress_dialog_list_set(inc_dialog->dialog,
533 					 -1, NULL,
534 					 pop3_session->ac_prefs->account_name,
535 					 _("Standby"));
536 	}
537 }
538 
inc_progress_dialog_clear(IncProgressDialog * inc_dialog)539 static void inc_progress_dialog_clear(IncProgressDialog *inc_dialog)
540 {
541 	progress_dialog_get_fraction(inc_dialog->dialog);
542 	progress_dialog_set_label(inc_dialog->dialog, "");
543 	if (inc_dialog->mainwin)
544 		main_window_progress_off(inc_dialog->mainwin);
545 }
546 
inc_progress_dialog_destroy(IncProgressDialog * inc_dialog)547 static void inc_progress_dialog_destroy(IncProgressDialog *inc_dialog)
548 {
549 	cm_return_if_fail(inc_dialog != NULL);
550 
551 	inc_dialog_list = g_list_remove(inc_dialog_list, inc_dialog);
552 
553 	if (inc_dialog->mainwin)
554 		main_window_progress_off(inc_dialog->mainwin);
555 	progress_dialog_destroy(inc_dialog->dialog);
556 
557 	g_date_time_unref(inc_dialog->progress_tv);
558 	g_date_time_unref(inc_dialog->folder_tv);
559 
560 	g_free(inc_dialog);
561 }
562 
inc_session_new(PrefsAccount * account)563 static IncSession *inc_session_new(PrefsAccount *account)
564 {
565 	IncSession *session;
566 
567 	cm_return_val_if_fail(account != NULL, NULL);
568 
569 	if (account->protocol != A_POP3)
570 		return NULL;
571 	if (!account->recv_server || !account->userid)
572 		return NULL;
573 
574 	session = g_new0(IncSession, 1);
575 
576 	session->session = pop3_session_new(account);
577 	session->session->data = session;
578 	POP3_SESSION(session->session)->drop_message = inc_drop_message;
579 	session_set_recv_message_notify(session->session,
580 					inc_recv_message, session);
581 	session_set_recv_data_progressive_notify(session->session,
582 						 inc_recv_data_progressive,
583 						 session);
584 	session_set_recv_data_notify(session->session,
585 				     inc_recv_data_finished, session);
586 
587 	return session;
588 }
589 
inc_session_destroy(IncSession * session)590 static void inc_session_destroy(IncSession *session)
591 {
592 	cm_return_if_fail(session != NULL);
593 
594 	session_destroy(session->session);
595 	g_free(session);
596 }
597 
pop3_get_port(Pop3Session * pop3_session)598 static gint pop3_get_port(Pop3Session *pop3_session)
599 {
600 #ifdef USE_GNUTLS
601 	return pop3_session->ac_prefs->set_popport ?
602 		pop3_session->ac_prefs->popport :
603 		pop3_session->ac_prefs->ssl_pop == SSL_TUNNEL ? 995 : 110;
604 #else
605 	return pop3_session->ac_prefs->set_popport ?
606 		pop3_session->ac_prefs->popport : 110;
607 #endif
608 }
609 
inc_start(IncProgressDialog * inc_dialog)610 static gint inc_start(IncProgressDialog *inc_dialog)
611 {
612 	IncSession *session;
613 	GList *qlist;
614 	Pop3Session *pop3_session;
615 	IncState inc_state;
616 	gint error_num = 0;
617 	gint new_msgs = 0;
618 	gchar *msg;
619 	gchar *fin_msg;
620 	FolderItem *processing, *inbox;
621 	GSList *msglist, *msglist_element;
622 	gboolean cancelled = FALSE;
623 
624 	qlist = inc_dialog->queue_list;
625 	while (qlist != NULL) {
626 		GList *next = qlist->next;
627 
628 		session = qlist->data;
629 		pop3_session = POP3_SESSION(session->session);
630 		pop3_session->user = g_strdup(pop3_session->ac_prefs->userid);
631 
632 		if (inc_dialog->show_dialog)
633 			manage_window_focus_in
634 				(inc_dialog->dialog->window,
635 				 NULL, NULL);
636 
637 		if(pop3_session->ac_prefs->use_pop_auth &&
638 		   pop3_session->ac_prefs->pop_auth_type == POPAUTH_OAUTH2)
639 		     oauth2_check_passwds (pop3_session->ac_prefs);
640 
641 		if (password_get(pop3_session->user,
642 					pop3_session->ac_prefs->recv_server,
643 					"pop3", pop3_get_port(pop3_session),
644 					&(pop3_session->pass))) {
645 			/* NOP */;
646 		} else if ((pop3_session->pass = passwd_store_get_account(
647 						pop3_session->ac_prefs->account_id, PWS_ACCOUNT_RECV)) == NULL) {
648 			gchar *pass;
649 
650 			pass = input_dialog_query_password_keep
651 				(pop3_session->ac_prefs->recv_server,
652 				 pop3_session->user,
653 				 &(pop3_session->ac_prefs->session_passwd));
654 
655 			if (pass) {
656 				pop3_session->pass = pass;
657 			}
658 		}
659 
660 		if (inc_dialog->show_dialog)
661 			manage_window_focus_out
662 				(inc_dialog->dialog->window,
663 				 NULL, NULL);
664 
665 		qlist = next;
666 	}
667 
668 #define SET_PIXMAP_AND_TEXT(pix, str)					   \
669 {									   \
670 	progress_dialog_list_set(inc_dialog->dialog,			   \
671 				 inc_dialog->cur_row,			   \
672 				 pix,					   \
673 				 NULL,					   \
674 				 str);					   \
675 }
676 
677 	for (; inc_dialog->queue_list != NULL && !cancelled; inc_dialog->cur_row++) {
678 		session = inc_dialog->queue_list->data;
679 		pop3_session = POP3_SESSION(session->session);
680 		GSList *filtered, *unfiltered;
681 
682 		if (pop3_session->pass == NULL) {
683 			SET_PIXMAP_AND_TEXT(okpix, _("Cancelled"));
684 			inc_session_destroy(session);
685 			inc_dialog->queue_list =
686 				g_list_remove(inc_dialog->queue_list, session);
687 			continue;
688 		}
689 
690 		inc_progress_dialog_clear(inc_dialog);
691 		progress_dialog_scroll_to_row(inc_dialog->dialog,
692 					      inc_dialog->cur_row);
693 
694 		SET_PIXMAP_AND_TEXT(currentpix, _("Retrieving"));
695 
696 		/* begin POP3 session */
697 		inc_state = inc_pop3_session_do(session);
698 
699 		switch (inc_state) {
700 		case INC_SUCCESS:
701 			if (pop3_session->cur_total_num > 0)
702 				msg = g_strdup_printf(
703 					ngettext("Done (%d message (%s) received)",
704 						 "Done (%d messages (%s) received)",
705 					 pop3_session->cur_total_num),
706 					 pop3_session->cur_total_num,
707 					 to_human_readable((goffset)pop3_session->cur_total_recv_bytes));
708 			else
709 				msg = g_strdup_printf(_("Done (no new messages)"));
710 			SET_PIXMAP_AND_TEXT(okpix, msg);
711 			g_free(msg);
712 			break;
713 		case INC_CONNECT_ERROR:
714 			SET_PIXMAP_AND_TEXT(errorpix, _("Connection failed"));
715 			break;
716 		case INC_AUTH_FAILED:
717 			SET_PIXMAP_AND_TEXT(errorpix, _("Auth failed"));
718 			if (pop3_session->ac_prefs->session_passwd) {
719 				g_free(pop3_session->ac_prefs->session_passwd);
720 				pop3_session->ac_prefs->session_passwd = NULL;
721 			}
722 			break;
723 		case INC_LOCKED:
724 			SET_PIXMAP_AND_TEXT(errorpix, _("Locked"));
725 			break;
726 		case INC_ERROR:
727 		case INC_NO_SPACE:
728 		case INC_IO_ERROR:
729 		case INC_SOCKET_ERROR:
730 		case INC_EOF:
731 			SET_PIXMAP_AND_TEXT(errorpix, _("Error"));
732 			break;
733 		case INC_TIMEOUT:
734 			SET_PIXMAP_AND_TEXT(errorpix, _("Timeout"));
735 			break;
736 		case INC_CANCEL:
737 			SET_PIXMAP_AND_TEXT(okpix, _("Cancelled"));
738 			if (!inc_dialog->show_dialog)
739 				cancelled = TRUE;
740 			break;
741 		default:
742 			break;
743 		}
744 
745 		if (pop3_session->error_val == PS_AUTHFAIL) {
746 			if(!prefs_common.no_recv_err_panel) {
747 				if((prefs_common.recv_dialog_mode == RECV_DIALOG_ALWAYS) ||
748 				    ((prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL) && focus_window))
749 					manage_window_focus_in(inc_dialog->dialog->window, NULL, NULL);
750 			}
751 		}
752 
753 		/* CLAWS: perform filtering actions on dropped message */
754 		/* CLAWS: get default inbox (perhaps per account) */
755 		if (pop3_session->ac_prefs->inbox) {
756 			/* CLAWS: get destination folder / mailbox */
757 			inbox = folder_find_item_from_identifier(pop3_session->ac_prefs->inbox);
758 			if (!inbox)
759 				inbox = folder_get_default_inbox();
760 		} else
761 			inbox = folder_get_default_inbox();
762 
763 		/* get list of messages in processing */
764 		processing = folder_get_default_processing(pop3_session->ac_prefs->account_id);
765 		folder_item_scan(processing);
766 		msglist = folder_item_get_msg_list(processing);
767 
768 		/* process messages */
769 		folder_item_update_freeze();
770 
771 		procmsg_msglist_filter(msglist, pop3_session->ac_prefs,
772 				&filtered, &unfiltered,
773 				pop3_session->ac_prefs->filter_on_recv);
774 
775 		filtering_move_and_copy_msgs(msglist);
776 		if (unfiltered != NULL)
777 			folder_item_move_msgs(inbox, unfiltered);
778 
779 		for(msglist_element = msglist; msglist_element != NULL;
780 		    msglist_element = msglist_element->next) {
781 			procmsg_msginfo_free((MsgInfo**)&(msglist_element->data));
782 		}
783 		folder_item_update_thaw();
784 
785 		g_slist_free(msglist);
786 		g_slist_free(filtered);
787 		g_slist_free(unfiltered);
788 
789 		statusbar_pop_all();
790 
791 		new_msgs += pop3_session->cur_total_num;
792 
793 		pop3_write_uidl_list(pop3_session);
794 
795 		if (inc_state != INC_SUCCESS && inc_state != INC_CANCEL) {
796 			error_num++;
797 			if (inc_dialog->show_dialog)
798 				manage_window_focus_in
799 					(inc_dialog->dialog->window,
800 					 NULL, NULL);
801 			inc_put_error(inc_state, pop3_session);
802 			if (inc_dialog->show_dialog)
803 				manage_window_focus_out
804 					(inc_dialog->dialog->window,
805 					 NULL, NULL);
806 			if (inc_state == INC_NO_SPACE ||
807 			    inc_state == INC_IO_ERROR)
808 				break;
809 		}
810 		folder_item_free_cache(processing, TRUE);
811 
812 		inc_session_destroy(session);
813 		inc_dialog->queue_list =
814 			g_list_remove(inc_dialog->queue_list, session);
815 	}
816 
817 #undef SET_PIXMAP_AND_TEXT
818 
819 	if (new_msgs > 0)
820 		fin_msg = g_strdup_printf(ngettext("Finished (%d new message)",
821 					  	   "Finished (%d new messages)",
822 					  	   new_msgs), new_msgs);
823 	else
824 		fin_msg = g_strdup_printf(_("Finished (no new messages)"));
825 
826 	progress_dialog_set_label(inc_dialog->dialog, fin_msg);
827 
828 	while (inc_dialog->queue_list != NULL) {
829 		session = inc_dialog->queue_list->data;
830 		inc_session_destroy(session);
831 		inc_dialog->queue_list =
832 			g_list_remove(inc_dialog->queue_list, session);
833 	}
834 
835 	if (prefs_common.close_recv_dialog || !inc_dialog->show_dialog)
836 		inc_progress_dialog_destroy(inc_dialog);
837 	else {
838 		gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window),
839 				     fin_msg);
840 		gtk_button_set_label(GTK_BUTTON(inc_dialog->dialog->cancel_btn),
841 				     GTK_STOCK_CLOSE);
842 	}
843 
844 	g_free(fin_msg);
845 
846 	return new_msgs;
847 }
848 
inc_pop3_session_do(IncSession * session)849 static IncState inc_pop3_session_do(IncSession *session)
850 {
851 	Pop3Session *pop3_session = POP3_SESSION(session->session);
852 	IncProgressDialog *inc_dialog = (IncProgressDialog *)session->data;
853 	PrefsAccount *ac = pop3_session->ac_prefs;
854 	gchar *server;
855 	gchar *account_name;
856 	gushort port;
857 	gchar *buf;
858 	ProxyInfo *proxy_info = NULL;
859 
860 	debug_print("getting new messages of account %s...\n",
861 		    ac->account_name);
862 
863 	ac->last_pop_login_time = time(NULL);
864 
865 	buf = g_strdup_printf(_("%s: Retrieving new messages"),
866 			      ac->recv_server);
867 	gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), buf);
868 	g_free(buf);
869 
870 	server = ac->recv_server;
871 	account_name = ac->account_name;
872 	port = pop3_get_port(pop3_session);
873 
874 #ifdef USE_GNUTLS
875 	SESSION(pop3_session)->ssl_type = ac->ssl_pop;
876 	if (ac->ssl_pop != SSL_NONE)
877 		SESSION(pop3_session)->nonblocking =
878 			ac->use_nonblocking_ssl;
879 #else
880 	if (ac->ssl_pop != SSL_NONE) {
881 		if (alertpanel_full(_("Insecure connection"),
882 			_("This connection is configured to be secured "
883 			  "using SSL/TLS, but SSL/TLS is not available "
884 			  "in this build of Claws Mail. \n\n"
885 			  "Do you want to continue connecting to this "
886 			  "server? The communication would not be "
887 			  "secure."),
888 			  GTK_STOCK_CANCEL, _("Con_tinue connecting"), NULL,
889 				ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING) != G_ALERTALTERNATE)
890 			return INC_CANCEL;
891 	}
892 #endif
893 
894 	buf = g_strdup_printf(_("Account '%s': Connecting to POP3 server: %s:%d..."),
895 				account_name, server, port);
896 	statusbar_print_all("%s", buf);
897 	log_message(LOG_PROTOCOL, "%s\n", buf);
898 
899 	progress_dialog_set_label(inc_dialog->dialog, buf);
900 
901 	if (ac->use_proxy) {
902 		if (ac->use_default_proxy) {
903 			proxy_info = (ProxyInfo *)&(prefs_common.proxy_info);
904 			if (proxy_info->use_proxy_auth)
905 				proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY,
906 					PWS_CORE_PROXY_PASS);
907 		} else {
908 			proxy_info = (ProxyInfo *)&(ac->proxy_info);
909 			if (proxy_info->use_proxy_auth)
910 				proxy_info->proxy_pass = passwd_store_get_account(ac->account_id,
911 					PWS_ACCOUNT_PROXY_PASS);
912 		}
913 	}
914 	SESSION(pop3_session)->proxy_info = proxy_info;
915 
916 	GTK_EVENTS_FLUSH();
917 	g_free(buf);
918 
919 	session_set_timeout(SESSION(pop3_session),
920 			    prefs_common.io_timeout_secs * 1000);
921 
922 	if (session_connect(SESSION(pop3_session), server, port) < 0) {
923 		if(!prefs_common.no_recv_err_panel) {
924 			if((prefs_common.recv_dialog_mode == RECV_DIALOG_ALWAYS) ||
925 			    ((prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL) && focus_window)) {
926 				manage_window_focus_in(inc_dialog->dialog->window, NULL, NULL);
927 			}
928 			alertpanel_error(_("Can't connect to POP3 server: %s:%d"),
929 					 server, port);
930 			manage_window_focus_out(inc_dialog->dialog->window, NULL, NULL);
931 		} else {
932 			log_error(LOG_PROTOCOL, _("Can't connect to POP3 server: %s:%d\n"),
933 			    server, port);
934 		}
935 		session->inc_state = INC_CONNECT_ERROR;
936 		statusbar_pop_all();
937 		return INC_CONNECT_ERROR;
938 	}
939 
940 	while (session_is_running(SESSION(pop3_session)) &&
941 	       session->inc_state != INC_CANCEL)
942 		gtk_main_iteration();
943 
944 	if (session->inc_state == INC_SUCCESS) {
945 		switch (pop3_session->error_val) {
946 		case PS_SUCCESS:
947 			switch (SESSION(pop3_session)->state) {
948 			case SESSION_ERROR:
949 				if (pop3_session->state == POP3_READY)
950 					session->inc_state = INC_CONNECT_ERROR;
951 				else
952 					session->inc_state = INC_ERROR;
953 				break;
954 			case SESSION_EOF:
955 				session->inc_state = INC_EOF;
956 				break;
957 			case SESSION_TIMEOUT:
958 				session->inc_state = INC_TIMEOUT;
959 				break;
960 			default:
961 				session->inc_state = INC_SUCCESS;
962 				break;
963 			}
964 			break;
965 		case PS_AUTHFAIL:
966 			session->inc_state = INC_AUTH_FAILED;
967 			break;
968 		case PS_IOERR:
969 			session->inc_state = INC_IO_ERROR;
970 			break;
971 		case PS_SOCKET:
972 			session->inc_state = INC_SOCKET_ERROR;
973 			break;
974 		case PS_LOCKBUSY:
975 			session->inc_state = INC_LOCKED;
976 			break;
977 		default:
978 			session->inc_state = INC_ERROR;
979 			break;
980 		}
981 	}
982 
983 	session_disconnect(SESSION(pop3_session));
984 	statusbar_pop_all();
985 
986 	return session->inc_state;
987 }
988 
inc_progress_dialog_update(IncProgressDialog * inc_dialog,IncSession * inc_session)989 static void inc_progress_dialog_update(IncProgressDialog *inc_dialog,
990 				       IncSession *inc_session)
991 {
992 	inc_progress_dialog_set_label(inc_dialog, inc_session);
993 	inc_progress_dialog_set_progress(inc_dialog, inc_session);
994 }
995 
inc_progress_dialog_set_label(IncProgressDialog * inc_dialog,IncSession * inc_session)996 static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog,
997 					  IncSession *inc_session)
998 {
999 	ProgressDialog *dialog = inc_dialog->dialog;
1000 	Pop3Session *session;
1001 
1002 	cm_return_if_fail(inc_session != NULL);
1003 
1004 	session = POP3_SESSION(inc_session->session);
1005 
1006 	switch (session->state) {
1007 	case POP3_GREETING:
1008 		break;
1009 	case POP3_GETAUTH_USER:
1010 	case POP3_GETAUTH_PASS:
1011 	case POP3_GETAUTH_APOP:
1012 		progress_dialog_set_label(dialog, _("Authenticating..."));
1013 		statusbar_pop_all();
1014 		statusbar_print_all(_("Retrieving messages from %s (%s)..."),
1015 				    SESSION(session)->server,
1016 				    session->ac_prefs->account_name);
1017 		break;
1018 	case POP3_GETRANGE_STAT:
1019 		progress_dialog_set_label
1020 			(dialog, _("Getting the number of new messages (STAT)..."));
1021 		break;
1022 	case POP3_GETRANGE_LAST:
1023 		progress_dialog_set_label
1024 			(dialog, _("Getting the number of new messages (LAST)..."));
1025 		break;
1026 	case POP3_GETRANGE_UIDL:
1027 		progress_dialog_set_label
1028 			(dialog, _("Getting the number of new messages (UIDL)..."));
1029 		break;
1030 	case POP3_GETSIZE_LIST:
1031 		progress_dialog_set_label
1032 			(dialog, _("Getting the size of messages (LIST)..."));
1033 		break;
1034 	case POP3_RETR:
1035 	case POP3_RETR_RECV:
1036 	case POP3_DELETE:
1037 		break;
1038 	case POP3_LOGOUT:
1039 		progress_dialog_set_label(dialog, _("Quitting"));
1040 		break;
1041 	default:
1042 		break;
1043 	}
1044 }
1045 
inc_progress_dialog_set_progress(IncProgressDialog * inc_dialog,IncSession * inc_session)1046 static void inc_progress_dialog_set_progress(IncProgressDialog *inc_dialog,
1047 					     IncSession *inc_session)
1048 {
1049 	gchar buf[MESSAGEBUFSIZE];
1050 	Pop3Session *pop3_session = POP3_SESSION(inc_session->session);
1051 	gchar *total_size_str;
1052 	gint cur_total;
1053 	gint total;
1054 
1055 	if (!pop3_session->new_msg_exist) return;
1056 
1057 	cur_total = inc_session->cur_total_bytes;
1058 	total = pop3_session->total_bytes;
1059 	if (pop3_session->state == POP3_RETR ||
1060 	    pop3_session->state == POP3_RETR_RECV ||
1061 	    pop3_session->state == POP3_DELETE) {
1062 		Xstrdup_a(total_size_str, to_human_readable((goffset)total), return);
1063 		g_snprintf(buf, sizeof(buf),
1064 			   _("Retrieving message (%d / %d) (%s / %s)"),
1065 			   pop3_session->cur_msg, pop3_session->count,
1066 			   to_human_readable((goffset)cur_total), total_size_str);
1067 		progress_dialog_set_label(inc_dialog->dialog, buf);
1068 	}
1069 
1070 	progress_dialog_set_fraction
1071 		(inc_dialog->dialog, (total == 0) ? 0: (gfloat)cur_total / (gfloat)total);
1072 
1073 	statusbar_progress_all(pop3_session->cur_msg, pop3_session->count, 1);
1074 
1075 	if (pop3_session->cur_total_num > 0) {
1076 		g_snprintf(buf, sizeof(buf),
1077 			   ngettext("Retrieving (%d message (%s) received)",
1078 			   	    "Retrieving (%d messages (%s) received)",
1079 				    pop3_session->cur_total_num),
1080 			   pop3_session->cur_total_num,
1081 			   to_human_readable
1082 			   ((goffset)pop3_session->cur_total_recv_bytes));
1083 		progress_dialog_list_set_status(inc_dialog->dialog,
1084 						inc_dialog->cur_row,
1085 						buf);
1086 	}
1087 }
1088 
inc_progress_dialog_update_periodic(IncProgressDialog * inc_dialog,IncSession * inc_session)1089 static void inc_progress_dialog_update_periodic(IncProgressDialog *inc_dialog,
1090 						IncSession *inc_session)
1091 {
1092 	GDateTime *tv_cur = g_date_time_new_now_local();
1093 	GTimeSpan tv_result;
1094 
1095 	tv_result = g_date_time_difference(tv_cur, inc_dialog->progress_tv);
1096 	g_date_time_unref(tv_cur);
1097 	if (tv_result < 0) {
1098 	    tv_result += G_USEC_PER_SEC;
1099 	}
1100 
1101 	if (tv_result > PROGRESS_UPDATE_INTERVAL) {
1102                 inc_progress_dialog_update(inc_dialog, inc_session);
1103 		tv_cur = g_date_time_add(inc_dialog->progress_tv, tv_result);
1104 		g_date_time_unref(inc_dialog->progress_tv);
1105                 inc_dialog->progress_tv = tv_cur;
1106 	}
1107 }
1108 
inc_recv_data_progressive(Session * session,guint cur_len,guint total_len,gpointer data)1109 static gint inc_recv_data_progressive(Session *session, guint cur_len,
1110 				      guint total_len, gpointer data)
1111 {
1112 	IncSession *inc_session = (IncSession *)data;
1113 	Pop3Session *pop3_session = POP3_SESSION(session);
1114 	IncProgressDialog *inc_dialog;
1115 	gint cur_total;
1116 
1117 	cm_return_val_if_fail(inc_session != NULL, -1);
1118 
1119 	if (pop3_session->state != POP3_RETR &&
1120 	    pop3_session->state != POP3_RETR_RECV &&
1121 	    pop3_session->state != POP3_DELETE &&
1122 	    pop3_session->state != POP3_LOGOUT) return 0;
1123 
1124 	if (!pop3_session->new_msg_exist) return 0;
1125 
1126 	cur_total = pop3_session->cur_total_bytes + cur_len;
1127 	if (cur_total > pop3_session->total_bytes)
1128 		cur_total = pop3_session->total_bytes;
1129 	inc_session->cur_total_bytes = cur_total;
1130 
1131 	inc_dialog = (IncProgressDialog *)inc_session->data;
1132 	inc_progress_dialog_update_periodic(inc_dialog, inc_session);
1133 
1134 	return 0;
1135 }
1136 
inc_recv_data_finished(Session * session,guint len,gpointer data)1137 static gint inc_recv_data_finished(Session *session, guint len, gpointer data)
1138 {
1139 	IncSession *inc_session = (IncSession *)data;
1140 	IncProgressDialog *inc_dialog;
1141 
1142 	cm_return_val_if_fail(inc_session != NULL, -1);
1143 
1144 	inc_dialog = (IncProgressDialog *)inc_session->data;
1145 
1146 	inc_recv_data_progressive(session, 0, 0, inc_session);
1147 
1148 	if (POP3_SESSION(session)->state == POP3_LOGOUT) {
1149 		inc_progress_dialog_update(inc_dialog, inc_session);
1150 	}
1151 
1152 	return 0;
1153 }
1154 
inc_recv_message(Session * session,const gchar * msg,gpointer data)1155 static gint inc_recv_message(Session *session, const gchar *msg, gpointer data)
1156 {
1157 	IncSession *inc_session = (IncSession *)data;
1158 	IncProgressDialog *inc_dialog;
1159 
1160 	cm_return_val_if_fail(inc_session != NULL, -1);
1161 
1162 	inc_dialog = (IncProgressDialog *)inc_session->data;
1163 
1164 	switch (POP3_SESSION(session)->state) {
1165 	case POP3_GETAUTH_USER:
1166 	case POP3_GETAUTH_PASS:
1167 	case POP3_GETAUTH_APOP:
1168 	case POP3_GETRANGE_STAT:
1169 	case POP3_GETRANGE_LAST:
1170 	case POP3_GETRANGE_UIDL:
1171 	case POP3_GETSIZE_LIST:
1172 		inc_progress_dialog_update(inc_dialog, inc_session);
1173 		break;
1174 	case POP3_RETR:
1175 		inc_recv_data_progressive(session, 0, 0, inc_session);
1176 		break;
1177 	case POP3_LOGOUT:
1178 		inc_progress_dialog_update(inc_dialog, inc_session);
1179 		break;
1180 	default:
1181 		break;
1182 	}
1183 
1184 	return 0;
1185 }
1186 
inc_drop_message(Pop3Session * session,const gchar * file)1187 static gint inc_drop_message(Pop3Session *session, const gchar *file)
1188 {
1189 	FolderItem *inbox;
1190 	FolderItem *dropfolder;
1191 	IncSession *inc_session = (IncSession *)(SESSION(session)->data);
1192 	gint msgnum;
1193 
1194 	cm_return_val_if_fail(inc_session != NULL, -1);
1195 
1196 	if (session->ac_prefs->inbox) {
1197 		inbox = folder_find_item_from_identifier
1198 			(session->ac_prefs->inbox);
1199 		if (!inbox)
1200 			inbox = folder_get_default_inbox();
1201 	} else
1202 		inbox = folder_get_default_inbox();
1203 	if (!inbox) {
1204 		claws_unlink(file);
1205 		return -1;
1206 	}
1207 
1208 	/* CLAWS: claws uses a global .processing folder for the filtering. */
1209 	dropfolder = folder_get_default_processing(session->ac_prefs->account_id);
1210 
1211 	/* add msg file to drop folder */
1212 	if ((msgnum = folder_item_add_msg(
1213 			dropfolder, file, NULL, TRUE)) < 0) {
1214 		claws_unlink(file);
1215 		return -1;
1216 	}
1217 
1218 	return 0;
1219 }
1220 
inc_put_error(IncState istate,Pop3Session * session)1221 static void inc_put_error(IncState istate, Pop3Session *session)
1222 {
1223 	gchar *log_msg = NULL;
1224 	gchar *err_msg = NULL;
1225 	gboolean fatal_error = FALSE;
1226 
1227 	switch (istate) {
1228 	case INC_CONNECT_ERROR:
1229 		fatal_error = TRUE;
1230 		if (prefs_common.no_recv_err_panel)
1231 			break;
1232 		err_msg = g_strdup_printf(_("Connection to %s:%d failed."),
1233 					  SESSION(session)->server,
1234 					  SESSION(session)->port);
1235 		break;
1236 	case INC_ERROR:
1237 		log_msg = _("Error occurred while processing mail.");
1238 		fatal_error = TRUE;
1239 		if (prefs_common.no_recv_err_panel)
1240 			break;
1241 		if (session->error_msg)
1242 			err_msg = g_strdup_printf
1243 				(_("Error occurred while processing mail:\n%s"),
1244 				 session->error_msg);
1245 		else
1246 			err_msg = g_strdup(log_msg);
1247 		break;
1248 	case INC_NO_SPACE:
1249 		log_msg = _("No disk space left.");
1250 		err_msg = g_strdup(log_msg);
1251 		fatal_error = TRUE;
1252 		break;
1253 	case INC_IO_ERROR:
1254 		log_msg = _("Can't write file.");
1255 		err_msg = g_strdup(log_msg);
1256 		fatal_error = TRUE;
1257 		break;
1258 	case INC_SOCKET_ERROR:
1259 		log_msg = _("Socket error.");
1260 		if (prefs_common.no_recv_err_panel)
1261 			break;
1262 		err_msg = g_strdup_printf(_("Socket error on connection to %s:%d."),
1263 					  SESSION(session)->server,
1264 					  SESSION(session)->port);
1265 		break;
1266 	case INC_EOF:
1267 		log_msg = _("Connection closed by the remote host.");
1268 		if (prefs_common.no_recv_err_panel)
1269 			break;
1270 		err_msg = g_strdup_printf(_("Connection to %s:%d closed by the remote host."),
1271 					  SESSION(session)->server,
1272 					  SESSION(session)->port);
1273 		break;
1274 	case INC_LOCKED:
1275 		log_msg = _("Mailbox is locked.");
1276 		if (prefs_common.no_recv_err_panel)
1277 			break;
1278 		if (session->error_msg)
1279 			err_msg = g_strdup_printf(_("Mailbox is locked:\n%s"),
1280 						  session->error_msg);
1281 		else
1282 			err_msg = g_strdup(log_msg);
1283 		break;
1284 	case INC_AUTH_FAILED:
1285 		log_msg = _("Authentication failed.");
1286 		fatal_error = TRUE;
1287 		if (prefs_common.no_recv_err_panel)
1288 			break;
1289 		if (session->error_msg)
1290 			err_msg = g_strdup_printf
1291 				(_("Authentication failed:\n%s"), session->error_msg);
1292 		else
1293 			err_msg = g_strdup(log_msg);
1294 		break;
1295 	case INC_TIMEOUT:
1296 		log_msg = _("Session timed out. You may be able to "
1297 			    "recover by increasing the timeout value in "
1298 			    "Preferences/Other/Miscellaneous.");
1299 		if (prefs_common.no_recv_err_panel)
1300 			break;
1301 		err_msg = g_strdup_printf(_("Connection to %s:%d timed out."),
1302 					  SESSION(session)->server,
1303 					  SESSION(session)->port);
1304 		break;
1305 	default:
1306 		break;
1307 	}
1308 
1309 	if (log_msg) {
1310 		if (fatal_error)
1311 			log_error(LOG_PROTOCOL, "%s\n", log_msg);
1312 		else
1313 			log_warning(LOG_PROTOCOL, "%s\n", log_msg);
1314 	}
1315 	if (prefs_common.no_recv_err_panel && fatal_error)
1316 		mainwindow_show_error();
1317 
1318 	if (err_msg) {
1319 		alertpanel_error_log("%s", err_msg);
1320 		g_free(err_msg);
1321 	}
1322 }
1323 
inc_cancel(IncProgressDialog * dialog)1324 static void inc_cancel(IncProgressDialog *dialog)
1325 {
1326 	IncSession *session;
1327 
1328 	cm_return_if_fail(dialog != NULL);
1329 
1330 	if (dialog->queue_list == NULL) {
1331 		inc_progress_dialog_destroy(dialog);
1332 		return;
1333 	}
1334 
1335 	session = dialog->queue_list->data;
1336 
1337 	session->inc_state = INC_CANCEL;
1338 
1339 	log_message(LOG_PROTOCOL, _("Incorporation cancelled\n"));
1340 }
1341 
inc_is_active(void)1342 gboolean inc_is_active(void)
1343 {
1344 	return (inc_dialog_list != NULL);
1345 }
1346 
inc_cancel_all(void)1347 void inc_cancel_all(void)
1348 {
1349 	GList *cur;
1350 
1351 	for (cur = inc_dialog_list; cur != NULL; cur = cur->next)
1352 		inc_cancel((IncProgressDialog *)cur->data);
1353 }
1354 
inc_showlog_cb(GtkWidget * widget,gpointer data)1355 static void inc_showlog_cb(GtkWidget *widget, gpointer data)
1356 {
1357 	MainWindow *mainwin = mainwindow_get_mainwindow();
1358 
1359 	log_window_show(mainwin->logwin);
1360 }
1361 
inc_cancel_cb(GtkWidget * widget,gpointer data)1362 static void inc_cancel_cb(GtkWidget *widget, gpointer data)
1363 {
1364 	inc_cancel((IncProgressDialog *)data);
1365 }
1366 
inc_dialog_delete_cb(GtkWidget * widget,GdkEventAny * event,gpointer data)1367 static gint inc_dialog_delete_cb(GtkWidget *widget, GdkEventAny *event,
1368 				 gpointer data)
1369 {
1370 	IncProgressDialog *dialog = (IncProgressDialog *)data;
1371 
1372 	if (dialog->queue_list == NULL)
1373 		inc_progress_dialog_destroy(dialog);
1374 
1375 	return TRUE;
1376 }
1377 
inc_spool_account(PrefsAccount * account)1378 static gint inc_spool_account(PrefsAccount *account)
1379 {
1380 	FolderItem *inbox;
1381 	gchar *mbox;
1382 	gint result;
1383 
1384 	if (account->local_inbox) {
1385 		inbox = folder_find_item_from_identifier(account->local_inbox);
1386 		if (!inbox)
1387 			inbox = folder_get_default_inbox();
1388 	} else
1389 		inbox = folder_get_default_inbox();
1390 
1391 	if (account->local_mbox) {
1392 		if (is_file_exist(account->local_mbox))
1393 			mbox = g_strdup(account->local_mbox);
1394 		else if (is_dir_exist(account->local_mbox))
1395 			mbox = g_strconcat(account->local_mbox, G_DIR_SEPARATOR_S,
1396 					   g_get_user_name(), NULL);
1397 		else {
1398 			debug_print("%s: local mailbox not found.\n",
1399 				    account->local_mbox);
1400 			return -1;
1401 		}
1402 	} else {
1403 		debug_print("local mailbox not set in account info.\n");
1404 		return -1;
1405 	}
1406 
1407 	result = get_spool(inbox, mbox, account);
1408 	g_free(mbox);
1409 
1410 	statusbar_pop_all();
1411 
1412 	return result;
1413 }
1414 
get_spool(FolderItem * dest,const gchar * mbox,PrefsAccount * account)1415 static gint get_spool(FolderItem *dest, const gchar *mbox, PrefsAccount *account)
1416 {
1417 	gint msgs, size;
1418 	gint lockfd;
1419 	gchar tmp_mbox[MAXPATHLEN + 1];
1420 
1421 	cm_return_val_if_fail(dest != NULL, -1);
1422 	cm_return_val_if_fail(mbox != NULL, -1);
1423 	cm_return_val_if_fail(account != NULL, -1);
1424 
1425 	if (!is_file_exist(mbox) || (size = get_file_size(mbox)) == 0) {
1426 		debug_print("%s: no messages in local mailbox.\n", mbox);
1427 		return 0;
1428 	} else if (size < 0)
1429 		return -1;
1430 
1431 	if ((lockfd = lock_mbox(mbox, LOCK_FLOCK)) < 0)
1432 		return -1;
1433 
1434 	g_snprintf(tmp_mbox, sizeof(tmp_mbox), "%s%ctmpmbox.%p",
1435 		   get_tmp_dir(), G_DIR_SEPARATOR, mbox);
1436 
1437 	if (copy_mbox(lockfd, tmp_mbox) < 0) {
1438 		unlock_mbox(mbox, lockfd, LOCK_FLOCK);
1439 		return -1;
1440 	}
1441 
1442 	debug_print("Getting new messages from %s into %s...\n",
1443 		    mbox, dest->path);
1444 
1445 	msgs = proc_mbox(dest, tmp_mbox, account->filter_on_recv, account);
1446 
1447 	claws_unlink(tmp_mbox);
1448 	if (msgs >= 0) empty_mbox(mbox);
1449 	unlock_mbox(mbox, lockfd, LOCK_FLOCK);
1450 
1451 	return msgs;
1452 }
1453 
inc_lock_real(void)1454 void inc_lock_real(void)
1455 {
1456 	inc_lock_count++;
1457 }
1458 
inc_unlock_real(void)1459 void inc_unlock_real(void)
1460 {
1461 	if (inc_lock_count > 0)
1462 		inc_lock_count--;
1463 }
1464 
1465 static guint autocheck_timer = 0;
1466 static gpointer autocheck_data = NULL;
1467 
inc_notify_cmd(gint new_msgs,gboolean notify)1468 static void inc_notify_cmd(gint new_msgs, gboolean notify)
1469 {
1470 	gchar *buf, *numpos, *ret_str;
1471 	gssize by_read = 0, by_written = 0;
1472 
1473 	if (!(new_msgs && notify && prefs_common.newmail_notify_cmd &&
1474 	    *prefs_common.newmail_notify_cmd))
1475 		     return;
1476 
1477 	buf = g_strdup(prefs_common.newmail_notify_cmd);
1478 	if ((numpos = strstr(buf, "%d")) != NULL) {
1479 		gchar *buf2;
1480 
1481 		*numpos = '\0';
1482 		buf2 = g_strdup_printf("%s%d%s", buf, new_msgs, numpos + 2);
1483 		g_free(buf);
1484 		buf = buf2;
1485 	}
1486 
1487 	ret_str = g_locale_from_utf8(buf, strlen(buf), &by_read, &by_written,
1488 				     NULL);
1489 	if (ret_str && by_written) {
1490 		g_free(buf);
1491 		buf = ret_str;
1492 	}
1493 	debug_print("executing new mail notification command: %s\n", buf);
1494 	execute_command_line(buf, TRUE, NULL);
1495 
1496 	g_free(buf);
1497 }
1498 
inc_autocheck_timer_init(MainWindow * mainwin)1499 void inc_autocheck_timer_init(MainWindow *mainwin)
1500 {
1501 	autocheck_data = mainwin;
1502 	inc_autocheck_timer_set();
1503 }
1504 
inc_autocheck_timer_set_interval(guint _interval)1505 static void inc_autocheck_timer_set_interval(guint _interval)
1506 {
1507 	guint interval = _interval;
1508 
1509 	/* Convert the interval to seconds if needed. */
1510 	if (_interval % 1000 == 0)
1511 		interval /= 1000;
1512 
1513 	inc_autocheck_timer_remove();
1514 	/* last test is to avoid re-enabling auto_check after modifying
1515 	   the common preferences */
1516 	if (prefs_common.autochk_newmail && autocheck_data
1517 	    && prefs_common.work_offline == FALSE) {
1518 			autocheck_timer =
1519 				g_timeout_add_seconds(interval, inc_autocheck_func, autocheck_data);
1520 		debug_print("added global inc timer %d at %u seconds\n",
1521 				autocheck_timer, interval);
1522 	}
1523 }
1524 
inc_autocheck_timer_set(void)1525 void inc_autocheck_timer_set(void)
1526 {
1527 	inc_autocheck_timer_set_interval(prefs_common.autochk_itv * 1000);
1528 }
1529 
inc_autocheck_timer_remove(void)1530 void inc_autocheck_timer_remove(void)
1531 {
1532 	if (autocheck_timer) {
1533 		debug_print("removed global inc timer %d\n", autocheck_timer);
1534 		g_source_remove(autocheck_timer);
1535 		autocheck_timer = 0;
1536 	}
1537 }
1538 
inc_autocheck_func(gpointer data)1539 static gint inc_autocheck_func(gpointer data)
1540 {
1541 	MainWindow *mainwin = (MainWindow *)data;
1542 
1543 	if (inc_lock_count) {
1544 		debug_print("global inc: autocheck is locked.\n");
1545 		inc_autocheck_timer_set_interval(1000);
1546 		return FALSE;
1547 	}
1548 
1549  	inc_all_account_mail(mainwin, TRUE, FALSE, prefs_common.newmail_notify_auto);
1550 	inc_autocheck_timer_set();
1551 
1552 	return FALSE;
1553 }
1554 
inc_account_autocheck_func(gpointer data)1555 static gboolean inc_account_autocheck_func(gpointer data)
1556 {
1557 	PrefsAccount *account = (PrefsAccount *)data;
1558 	GList *list = NULL;
1559 
1560 	cm_return_val_if_fail(account != NULL, FALSE);
1561 
1562 	debug_print("account %d: inc_account_autocheck_func\n",
1563 			account->account_id);
1564 
1565 	list = g_list_append(list, account);
1566 	inc_account_list_mail(mainwindow_get_mainwindow(),
1567 			list, TRUE, prefs_common.newmail_notify_auto);
1568 	g_list_free(list);
1569 
1570 	inc_account_autocheck_timer_set_interval(account);
1571 
1572 	return FALSE;
1573 }
1574 
inc_account_autocheck_timer_remove(PrefsAccount * account)1575 void inc_account_autocheck_timer_remove(PrefsAccount *account)
1576 {
1577 	cm_return_if_fail(account != NULL);
1578 
1579 	if (account->autocheck_timer != 0) {
1580 		g_source_remove(account->autocheck_timer);
1581 		debug_print("INC: account %d: removed inc timer %d\n", account->account_id,
1582 				account->autocheck_timer);
1583 		account->autocheck_timer = 0;
1584 	}
1585 }
1586 
inc_account_autocheck_timer_set_interval(PrefsAccount * account)1587 void inc_account_autocheck_timer_set_interval(PrefsAccount *account)
1588 {
1589 	cm_return_if_fail(account != NULL);
1590 
1591 	inc_account_autocheck_timer_remove(account);
1592 
1593 	if (account->autochk_use_default
1594 			|| !account->autochk_use_custom
1595 			|| account->autochk_itv == 0)
1596 		return;
1597 
1598 	account->autocheck_timer = g_timeout_add_seconds(
1599 			account->autochk_itv, inc_account_autocheck_func, account);
1600 	debug_print("INC: account %d: added inc timer %d at %u seconds\n",
1601 			account->account_id, account->autocheck_timer, account->autochk_itv);
1602 }
1603 
inc_offline_should_override(gboolean force_ask,const gchar * msg)1604 gboolean inc_offline_should_override(gboolean force_ask, const gchar *msg)
1605 {
1606 	gint length = 10; /* seconds */
1607 	gint answer = G_ALERTDEFAULT;
1608 
1609 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1610 	/* If no network connection is available, override is not possible */
1611 	if(!networkmanager_is_online(NULL))
1612 		return FALSE;
1613 #endif
1614 
1615 	if (prefs_common.autochk_newmail)
1616 		length = prefs_common.autochk_itv; /* seconds */
1617 
1618 	if (force_ask) {
1619 		inc_offline_overridden_no = (time_t)0;
1620 	}
1621 
1622 	if (prefs_common.work_offline) {
1623 		gchar *tmp = NULL;
1624 
1625 		if (time(NULL) - inc_offline_overridden_yes < length * 60) /* seconds */
1626 			 return TRUE;
1627 		else if (time(NULL) - inc_offline_overridden_no < length * 60) /* seconds */
1628 			 return FALSE;
1629 
1630 		if (!force_ask) {
1631 			gchar *unit = _("seconds");
1632 
1633 			/* show the offline override time (length) using the must appropriate unit:
1634 			   the biggest unit possible (hours, minutes, seconds), provided that there
1635 			   is not inferior unit involved: 1 hour, 150 minutes, 25 minutes, 90 minutes,
1636 			   30 seconds, 90 seconds. */
1637 			if ((length / 3600) > 0) { /* hours? */
1638 				if (((length % 3600) % 60) == 0) { /* no seconds left? */
1639 					if ((length % 3600) > 0) { /* minutes left? */
1640 						length = length / 60;
1641 						unit = ngettext("minute", "minutes", length);
1642 					} else {
1643 						length = length / 3600;
1644 						unit = ngettext("hour", "hours", length);
1645 					}
1646 				} /* else: seconds */
1647 			} else {
1648 				if ((length / 60) > 0) { /* minutes left? */
1649 					if ((length % 60) == 0) {
1650 						length = length / 60;
1651 						unit = ngettext("minute", "minutes", length);
1652 					}
1653 				} /* else: seconds */
1654 			}
1655 			tmp = g_strdup_printf(
1656 				_("%s%sYou're working offline. Override for %d %s?"),
1657 				msg?msg:"",
1658 				msg?"\n\n":"",
1659 				length, unit);
1660 		} else
1661 			tmp = g_strdup_printf(
1662 				_("%s%sYou're working offline. Override?"),
1663 				msg?msg:"",
1664 				msg?"\n\n":"");
1665 
1666 		answer = alertpanel(_("Offline warning"),
1667 			       tmp,
1668 			       GTK_STOCK_NO, GTK_STOCK_YES,
1669 				!force_ask? _("On_ly once"):NULL, ALERTFOCUS_SECOND);
1670 		g_free(tmp);
1671 		if (answer == G_ALERTALTERNATE) {
1672 			inc_offline_overridden_yes = time(NULL);
1673 			return TRUE;
1674 		} else if (answer == G_ALERTDEFAULT) {
1675 			if (!force_ask)
1676 				inc_offline_overridden_no  = time(NULL);
1677 			return FALSE;
1678 		} else {
1679 			inc_reset_offline_override_timers();
1680 			return TRUE;
1681 		}
1682 	}
1683 	return TRUE;
1684 }
1685 
inc_reset_offline_override_timers()1686 void inc_reset_offline_override_timers()
1687 {
1688 	debug_print("resetting offline override timers\n");
1689 	inc_offline_overridden_yes = (time_t)0;
1690 	inc_offline_overridden_no  = (time_t)0;
1691 }
1692