talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

inc.c (36518B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2025 the Claws Mail team and Hiroyuki Yamamoto
      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 #include "defs.h"
     20 
     21 #include <fcntl.h>
     22 #include <glib.h>
     23 #include <glib/gi18n.h>
     24 #include <gtk/gtk.h>
     25 #include <stdio.h>
     26 #include <unistd.h>
     27 #include <string.h>
     28 #include <sys/param.h>
     29 
     30 #include "main.h"
     31 #include "inc.h"
     32 #include "mainwindow.h"
     33 #include "folderview.h"
     34 #include "summaryview.h"
     35 #include "prefs_common.h"
     36 #include "prefs_account.h"
     37 #include "account.h"
     38 #include "procmsg.h"
     39 #include "socket.h"
     40 #include "ssl.h"
     41 #include "pop.h"
     42 #include "mbox.h"
     43 #include "file-utils.h"
     44 #include "utils.h"
     45 #include "gtkutils.h"
     46 #include "statusbar.h"
     47 #include "msgcache.h"
     48 #include "manage_window.h"
     49 #include "stock_pixmap.h"
     50 #include "progressdialog.h"
     51 #include "inputdialog.h"
     52 #include "alertpanel.h"
     53 #include "folder.h"
     54 #include "log.h"
     55 #include "hooks.h"
     56 #include "logwindow.h"
     57 #include "passwordstore.h"
     58 
     59 static GList *inc_dialog_list = NULL;
     60 
     61 static time_t inc_offline_overridden_yes = 0;
     62 static time_t inc_offline_overridden_no  = 0;
     63 
     64 guint inc_lock_count = 0;
     65 
     66 static GdkPixbuf *currentpix;
     67 static GdkPixbuf *errorpix;
     68 static GdkPixbuf *okpix;
     69 
     70 #define MESSAGEBUFSIZE	8192
     71 
     72 static gint inc_account_mail_real	(MainWindow		*mainwin,
     73 					 PrefsAccount		*account);
     74 
     75 static IncProgressDialog *inc_progress_dialog_create
     76 					(gboolean		 autocheck);
     77 static void inc_progress_dialog_set_list(IncProgressDialog	*inc_dialog);
     78 static void inc_progress_dialog_destroy	(IncProgressDialog	*inc_dialog);
     79 
     80 static IncSession *inc_session_new	(PrefsAccount		*account);
     81 static void inc_session_destroy		(IncSession		*session);
     82 static gint inc_start			(IncProgressDialog	*inc_dialog);
     83 static IncState inc_pop3_session_do	(IncSession		*session);
     84 
     85 static void inc_progress_dialog_update	(IncProgressDialog	*inc_dialog,
     86 					 IncSession		*inc_session);
     87 
     88 static void inc_progress_dialog_set_label
     89 					(IncProgressDialog	*inc_dialog,
     90 					 IncSession		*inc_session);
     91 static void inc_progress_dialog_set_progress
     92 					(IncProgressDialog	*inc_dialog,
     93 					 IncSession		*inc_session);
     94 
     95 static void inc_progress_dialog_update_periodic
     96 					(IncProgressDialog	*inc_dialog,
     97 					 IncSession		*inc_session);
     98 
     99 static gint inc_recv_data_progressive	(Session	*session,
    100 					 guint		 cur_len,
    101 					 guint		 total_len,
    102 					 gpointer	 data);
    103 static gint inc_recv_data_finished	(Session	*session,
    104 					 guint		 len,
    105 					 gpointer	 data);
    106 static gint inc_recv_message		(Session	*session,
    107 					 const gchar	*msg,
    108 					 gpointer	 data);
    109 static gint inc_drop_message		(Pop3Session	*session,
    110 					 const gchar	*file);
    111 
    112 static void inc_put_error		(IncState	 istate,
    113 					 Pop3Session 	*session);
    114 
    115 static void inc_showlog_cb		(GtkWidget	*widget,
    116 					 gpointer	 data);
    117 static void inc_cancel_cb		(GtkWidget	*widget,
    118 					 gpointer	 data);
    119 static gint inc_dialog_delete_cb	(GtkWidget	*widget,
    120 					 GdkEventAny	*event,
    121 					 gpointer	 data);
    122 
    123 static gint get_spool			(FolderItem	*dest,
    124 					 const gchar	*mbox,
    125 					 PrefsAccount	*account);
    126 
    127 static gint inc_spool_account(PrefsAccount *account);
    128 
    129 static void inc_notify_cmd(gint new_msgs, gboolean notify);
    130 
    131 void inc_mail(MainWindow *mainwin, gboolean notify)
    132 {
    133 	gint new_msgs = 0;
    134 	gint account_new_msgs = 0;
    135 
    136 	if (inc_lock_count) return;
    137 
    138 	if (prefs_common.work_offline &&
    139 	    !inc_offline_should_override(TRUE,
    140 		_("Claws Mail needs network access in order "
    141 		  "to get mails.")))
    142 		return;
    143 
    144 	inc_lock();
    145 	main_window_lock(mainwin);
    146 
    147 	if (prefs_common.use_extinc && prefs_common.extinc_cmd) {
    148 		/* external incorporating program */
    149 		if (execute_command_line(prefs_common.extinc_cmd, FALSE, NULL) < 0) {
    150 			main_window_unlock(mainwin);
    151 			inc_unlock();
    152 			return;
    153 		}
    154 	} else {
    155 		account_new_msgs = inc_account_mail_real(mainwin, cur_account);
    156 		if (account_new_msgs > 0)
    157 			new_msgs += account_new_msgs;
    158 	}
    159 
    160 	statusbar_progress_all(0,0,0);
    161 	main_window_unlock(mainwin);
    162  	inc_notify_cmd(new_msgs, notify);
    163 	inc_unlock();
    164 }
    165 
    166 void inc_pop_before_smtp(PrefsAccount *acc)
    167 {
    168 	IncProgressDialog *inc_dialog;
    169 	IncSession *session;
    170 	MainWindow *mainwin;
    171 
    172 	mainwin = mainwindow_get_mainwindow();
    173 
    174     	session = inc_session_new(acc);
    175     	if (!session) return;
    176 	POP3_SESSION(session->session)->pop_before_smtp = TRUE;
    177 
    178     	inc_dialog = inc_progress_dialog_create(FALSE);
    179     	inc_dialog->queue_list = g_list_append(inc_dialog->queue_list,
    180 					       session);
    181 	/* FIXME: assumes to attach to first main window */
    182 	inc_dialog->mainwin = mainwin;
    183 	inc_progress_dialog_set_list(inc_dialog);
    184 
    185 	if (mainwin) {
    186 		toolbar_main_set_sensitive(mainwin);
    187 		main_window_set_menu_sensitive(mainwin);
    188 	}
    189 
    190 	inc_start(inc_dialog);
    191 }
    192 
    193 static gint inc_account_mail_real(MainWindow *mainwin, PrefsAccount *account)
    194 {
    195 	IncProgressDialog *inc_dialog;
    196 	IncSession *session;
    197 
    198 	switch (account->protocol) {
    199 	case A_IMAP4:
    200 		/* Melvin: bug [14]
    201 		 * FIXME: it should return foldeview_check_new() value.
    202 		 * TODO: do it when bug [19] is fixed (IMAP folder sets
    203 		 * an incorrect new message count)
    204 		 */
    205 		folderview_check_new(FOLDER(account->folder));
    206 		return 0;
    207 	case A_POP3:
    208 		session = inc_session_new(account);
    209 		if (!session) return 0;
    210 
    211 		inc_dialog = inc_progress_dialog_create(FALSE);
    212 		inc_dialog->queue_list = g_list_append(inc_dialog->queue_list,
    213 						       session);
    214 		inc_dialog->mainwin = mainwin;
    215 		inc_progress_dialog_set_list(inc_dialog);
    216 
    217 		if (mainwin) {
    218 			toolbar_main_set_sensitive(mainwin);
    219 			main_window_set_menu_sensitive(mainwin);
    220 		}
    221 
    222 		return inc_start(inc_dialog);
    223 
    224 	case A_LOCAL:
    225 		return inc_spool_account(account);
    226 
    227 	default:
    228 		break;
    229 	}
    230 	return 0;
    231 }
    232 
    233 gint inc_account_mail(MainWindow *mainwin, PrefsAccount *account)
    234 {
    235 	gint new_msgs;
    236 
    237 	if (inc_lock_count) return 0;
    238 
    239 	if (account->receive_in_progress) return 0;
    240 
    241 	if (prefs_common.work_offline &&
    242 	    !inc_offline_should_override(TRUE,
    243 		_("Claws Mail needs network access in order "
    244 		  "to get mails.")))
    245 		return 0;
    246 
    247 	main_window_lock(mainwin);
    248 
    249 	new_msgs = inc_account_mail_real(mainwin, account);
    250 
    251 	statusbar_progress_all(0,0,0);
    252 	main_window_unlock(mainwin);
    253 
    254 	return new_msgs;
    255 }
    256 
    257 void inc_account_list_mail(MainWindow *mainwin, GList *account_list, gboolean autocheck,
    258 			  gboolean notify)
    259 {
    260 	GList *list, *queue_list = NULL;
    261 	IncProgressDialog *inc_dialog;
    262 	gint new_msgs = 0, num;
    263 
    264 	if (prefs_common.work_offline &&
    265 	    !inc_offline_should_override( (autocheck == FALSE),
    266 		_("Claws Mail needs network access in order "
    267 		  "to get mails.")))
    268 		return;
    269 
    270 	if (inc_lock_count) return;
    271 
    272 	main_window_lock(mainwin);
    273 
    274 	if (!account_list) {
    275 		statusbar_progress_all(0,0,0);
    276 		main_window_unlock(mainwin);
    277  		inc_notify_cmd(new_msgs, notify);
    278 		return;
    279 	}
    280 
    281 	if (prefs_common.use_extinc && prefs_common.extinc_cmd) {
    282 		/* external incorporating program */
    283 		if (execute_command_line(prefs_common.extinc_cmd, FALSE, NULL) < 0) {
    284 			log_error(LOG_PROTOCOL, _("%s failed\n"), prefs_common.extinc_cmd);
    285 
    286 			main_window_unlock(mainwin);
    287 			return;
    288 		}
    289 	}
    290 
    291 	/* Check all accounts in the list, one by one. */
    292 	for (list = account_list; list != NULL; list = list->next) {
    293 		PrefsAccount *account = list->data;
    294 
    295 		if (account == NULL) {
    296 			debug_print("INC: Huh? inc_account_list_mail() got a NULL account, this should not happen!\n");
    297 			continue;
    298 		}
    299 
    300 		debug_print("INC: checking account %d\n", account->account_id);
    301 		switch (account->protocol) {
    302 			case A_POP3:
    303 				if (!(account->receive_in_progress)) {
    304 					IncSession *session = inc_session_new(account);
    305 
    306 					if (session != NULL) {
    307 						debug_print("INC: adding POP3 account %d to inc queue\n",
    308 								account->account_id);
    309 						queue_list = g_list_append(queue_list, session);
    310 					}
    311 				}
    312 				break;
    313 
    314 			case A_IMAP4:
    315 				new_msgs += folderview_check_new(FOLDER(account->folder));
    316 				break;
    317 
    318 			case A_LOCAL:
    319 				num = inc_spool_account(account);
    320 				if (num > 0)
    321 					new_msgs += num;
    322 				break;
    323 
    324 			case A_NONE:
    325 				/* Nothing to do here, it's a SMTP-only account. */
    326 				break;
    327 
    328 			default:
    329 				debug_print("INC: encountered account %d with unknown protocol %d, ignoring\n",
    330 						account->account_id, account->protocol);
    331 				break;
    332 		}
    333 	}
    334 
    335 
    336 
    337 	if (queue_list) {
    338 		inc_dialog = inc_progress_dialog_create(autocheck);
    339 		inc_dialog->queue_list = queue_list;
    340 		inc_dialog->mainwin = mainwin;
    341 		inc_progress_dialog_set_list(inc_dialog);
    342 
    343 		toolbar_main_set_sensitive(mainwin);
    344 		main_window_set_menu_sensitive(mainwin);
    345 		new_msgs += inc_start(inc_dialog);
    346 	}
    347 
    348 	statusbar_progress_all(0,0,0);
    349 	main_window_unlock(mainwin);
    350  	inc_notify_cmd(new_msgs, notify);
    351 }
    352 
    353 void inc_all_account_mail(MainWindow *mainwin, gboolean notify)
    354 {
    355 	GList *list, *list2 = NULL;
    356 	gboolean condition = FALSE;
    357 
    358 	for (list = account_get_list(); list != NULL; list = list->next) {
    359 		PrefsAccount *account = list->data;
    360 		/* Nothing to do for SMTP-only accounts. */
    361 		if (account->protocol == A_NONE)
    362 			continue;
    363 		list2 = g_list_append(list2, account);
    364 	}
    365 
    366 	/* Do the check on the collected accounts. */
    367 	if (list2 != NULL) {
    368 		gboolean hide_dialog = TRUE;
    369 		inc_account_list_mail(mainwin, list2, hide_dialog, notify);
    370 		g_list_free(list2);
    371 	}
    372 }
    373 
    374 static void inc_progress_dialog_size_allocate_cb(GtkWidget *widget,
    375 					 GtkAllocation *allocation)
    376 {
    377 	cm_return_if_fail(allocation != NULL);
    378 
    379 	gtk_window_get_size(GTK_WINDOW(widget),
    380 		&prefs_common.receivewin_width, &prefs_common.receivewin_height);
    381 }
    382 
    383 static IncProgressDialog *inc_progress_dialog_create(gboolean autocheck)
    384 {
    385 	IncProgressDialog *dialog;
    386 	ProgressDialog *progress;
    387 	static GdkGeometry geometry;
    388 
    389 	dialog = g_new0(IncProgressDialog, 1);
    390 
    391 	progress = progress_dialog_create();
    392 	gtk_window_set_title(GTK_WINDOW(progress->window),
    393 			     _("Retrieving new messages"));
    394 	g_signal_connect(G_OBJECT(progress->showlog_btn), "clicked",
    395 			 G_CALLBACK(inc_showlog_cb), dialog);
    396 	g_signal_connect(G_OBJECT(progress->cancel_btn), "clicked",
    397 			 G_CALLBACK(inc_cancel_cb), dialog);
    398 	g_signal_connect(G_OBJECT(progress->window), "delete_event",
    399 			 G_CALLBACK(inc_dialog_delete_cb), dialog);
    400 	g_signal_connect(G_OBJECT(progress->window), "size_allocate",
    401 			 G_CALLBACK(inc_progress_dialog_size_allocate_cb), NULL);
    402  	/* manage_window_set_transient(GTK_WINDOW(progress->window)); */
    403 
    404 	progress_dialog_get_fraction(progress);
    405 
    406 	stock_pixbuf_gdk(STOCK_PIXMAP_COMPLETE, &okpix);
    407 	stock_pixbuf_gdk(STOCK_PIXMAP_CONTINUE, &currentpix);
    408 	stock_pixbuf_gdk(STOCK_PIXMAP_ERROR, &errorpix);
    409 
    410 	if (!geometry.min_height) {
    411 		geometry.min_width = 460;
    412 		geometry.min_height = 250;
    413 	}
    414 
    415 	gtk_window_set_geometry_hints(GTK_WINDOW(progress->window), NULL, &geometry,
    416 				      GDK_HINT_MIN_SIZE);
    417 	gtk_widget_set_size_request(progress->window, prefs_common.receivewin_width,
    418 				    prefs_common.receivewin_height);
    419 
    420 	dialog->dialog = progress;
    421 	dialog->progress_tv = g_date_time_new_now_local();
    422 	dialog->folder_tv = g_date_time_new_now_local();
    423 	dialog->queue_list = NULL;
    424 	dialog->cur_row = 0;
    425 
    426 	inc_dialog_list = g_list_append(inc_dialog_list, dialog);
    427 
    428 	return dialog;
    429 }
    430 
    431 static void inc_progress_dialog_set_list(IncProgressDialog *inc_dialog)
    432 {
    433 	GList *list;
    434 
    435 	for (list = inc_dialog->queue_list; list != NULL; list = list->next) {
    436 		IncSession *session = list->data;
    437 		Pop3Session *pop3_session = POP3_SESSION(session->session);
    438 
    439 		session->data = inc_dialog;
    440 
    441 		progress_dialog_list_set(inc_dialog->dialog,
    442 					 -1, NULL,
    443 					 pop3_session->ac_prefs->account_name,
    444 					 _("Standby"));
    445 	}
    446 }
    447 
    448 static void inc_progress_dialog_clear(IncProgressDialog *inc_dialog)
    449 {
    450 	progress_dialog_get_fraction(inc_dialog->dialog);
    451 	progress_dialog_set_label(inc_dialog->dialog, "");
    452 	if (inc_dialog->mainwin)
    453 		main_window_progress_off(inc_dialog->mainwin);
    454 }
    455 
    456 static void inc_progress_dialog_destroy(IncProgressDialog *inc_dialog)
    457 {
    458 	cm_return_if_fail(inc_dialog != NULL);
    459 
    460 	inc_dialog_list = g_list_remove(inc_dialog_list, inc_dialog);
    461 
    462 	if (inc_dialog->mainwin)
    463 		main_window_progress_off(inc_dialog->mainwin);
    464 	progress_dialog_destroy(inc_dialog->dialog);
    465 
    466 	g_date_time_unref(inc_dialog->progress_tv);
    467 	g_date_time_unref(inc_dialog->folder_tv);
    468 
    469 	g_free(inc_dialog);
    470 }
    471 
    472 static IncSession *inc_session_new(PrefsAccount *account)
    473 {
    474 	IncSession *session;
    475 
    476 	cm_return_val_if_fail(account != NULL, NULL);
    477 
    478 	if (account->protocol != A_POP3)
    479 		return NULL;
    480 	if (!account->recv_server || !account->userid)
    481 		return NULL;
    482 
    483 	session = g_new0(IncSession, 1);
    484 
    485 	session->session = pop3_session_new(account);
    486 	session->session->data = session;
    487 	POP3_SESSION(session->session)->drop_message = inc_drop_message;
    488 	session_set_recv_message_notify(session->session,
    489 					inc_recv_message, session);
    490 	session_set_recv_data_progressive_notify(session->session,
    491 						 inc_recv_data_progressive,
    492 						 session);
    493 	session_set_recv_data_notify(session->session,
    494 				     inc_recv_data_finished, session);
    495 
    496 	return session;
    497 }
    498 
    499 static void inc_session_destroy(IncSession *session)
    500 {
    501 	cm_return_if_fail(session != NULL);
    502 
    503 	session_destroy(session->session);
    504 	g_free(session);
    505 }
    506 
    507 static gint pop3_get_port(Pop3Session *pop3_session)
    508 {
    509 	return pop3_session->ac_prefs->set_popport ?
    510 		pop3_session->ac_prefs->popport :
    511 		pop3_session->ac_prefs->ssl_pop == SSL_TUNNEL ? 995 : 110;
    512 }
    513 
    514 static gint inc_start(IncProgressDialog *inc_dialog)
    515 {
    516 	IncSession *session;
    517 	GList *qlist;
    518 	Pop3Session *pop3_session;
    519 	IncState inc_state;
    520 	gint new_msgs = 0;
    521 	gchar *msg;
    522 	FolderItem *processing, *inbox;
    523 	GSList *msglist, *msglist_element;
    524 	gboolean cancelled = FALSE;
    525 
    526 	qlist = inc_dialog->queue_list;
    527 	while (qlist != NULL) {
    528 		GList *next = qlist->next;
    529 
    530 		session = qlist->data;
    531 		pop3_session = POP3_SESSION(session->session);
    532 		pop3_session->user = g_strdup(pop3_session->ac_prefs->userid);
    533 
    534 		if (inc_dialog->show_dialog)
    535 			manage_window_focus_in
    536 				(inc_dialog->dialog->window,
    537 				 NULL, NULL);
    538 
    539 		if (password_get(pop3_session->user,
    540 					pop3_session->ac_prefs->recv_server,
    541 					"pop3", pop3_get_port(pop3_session),
    542 					&(pop3_session->pass))) {
    543 			/* NOP */;
    544 		} else if ((pop3_session->pass = passwd_store_get_account(
    545 						pop3_session->ac_prefs->account_id, PWS_ACCOUNT_RECV)) == NULL) {
    546 			gchar *pass;
    547 
    548 			pass = input_dialog_query_password_keep
    549 				(pop3_session->ac_prefs->recv_server,
    550 				 pop3_session->user,
    551 				 &(pop3_session->ac_prefs->session_passwd));
    552 
    553 			if (pass) {
    554 				pop3_session->pass = pass;
    555 			}
    556 		}
    557 
    558 		if (inc_dialog->show_dialog)
    559 			manage_window_focus_out
    560 				(inc_dialog->dialog->window,
    561 				 NULL, NULL);
    562 
    563 		qlist = next;
    564 	}
    565 
    566 #define SET_PIXMAP_AND_TEXT(pix, str)					   \
    567 {									   \
    568 	progress_dialog_list_set(inc_dialog->dialog,			   \
    569 				 inc_dialog->cur_row,			   \
    570 				 pix,					   \
    571 				 NULL,					   \
    572 				 str);					   \
    573 }
    574 
    575 	for (; inc_dialog->queue_list != NULL && !cancelled; inc_dialog->cur_row++) {
    576 		session = inc_dialog->queue_list->data;
    577 		pop3_session = POP3_SESSION(session->session);
    578 
    579 		if (pop3_session->pass == NULL) {
    580 			SET_PIXMAP_AND_TEXT(okpix, _("Cancelled"));
    581 			inc_dialog->queue_list =
    582 				g_list_remove(inc_dialog->queue_list, session);
    583 			inc_session_destroy(session);
    584 			continue;
    585 		}
    586 
    587 		inc_progress_dialog_clear(inc_dialog);
    588 		progress_dialog_scroll_to_row(inc_dialog->dialog,
    589 					      inc_dialog->cur_row);
    590 
    591 		SET_PIXMAP_AND_TEXT(currentpix, _("Retrieving"));
    592 
    593 		/* begin POP3 session */
    594 		inc_state = inc_pop3_session_do(session);
    595 
    596 		switch (inc_state) {
    597 		case INC_SUCCESS:
    598 			if (pop3_session->cur_total_num > 0)
    599 				msg = g_strdup_printf(
    600 					"Done (%d messages (%s) received)",
    601 					 pop3_session->cur_total_num,
    602 					 to_human_readable((goffset)pop3_session->cur_total_recv_bytes));
    603 			else
    604 				msg = g_strdup_printf(_("Done (no new messages)"));
    605 			SET_PIXMAP_AND_TEXT(okpix, msg);
    606 			g_free(msg);
    607 			break;
    608 		case INC_CONNECT_ERROR:
    609 			SET_PIXMAP_AND_TEXT(errorpix, _("Connection failed"));
    610 			break;
    611 		case INC_AUTH_FAILED:
    612 			SET_PIXMAP_AND_TEXT(errorpix, _("Auth failed"));
    613 			if (pop3_session->ac_prefs->session_passwd) {
    614 				g_free(pop3_session->ac_prefs->session_passwd);
    615 				pop3_session->ac_prefs->session_passwd = NULL;
    616 			}
    617 			break;
    618 		case INC_LOCKED:
    619 			SET_PIXMAP_AND_TEXT(errorpix, _("Locked"));
    620 			break;
    621 		case INC_ERROR:
    622 		case INC_NO_SPACE:
    623 		case INC_IO_ERROR:
    624 		case INC_SOCKET_ERROR:
    625 		case INC_EOF:
    626 			SET_PIXMAP_AND_TEXT(errorpix, _("Error"));
    627 			break;
    628 		case INC_TIMEOUT:
    629 			SET_PIXMAP_AND_TEXT(errorpix, _("Timeout"));
    630 			break;
    631 		case INC_CANCEL:
    632 			SET_PIXMAP_AND_TEXT(okpix, _("Cancelled"));
    633 			if (!inc_dialog->show_dialog)
    634 				cancelled = TRUE;
    635 			break;
    636 		default:
    637 			break;
    638 		}
    639 
    640 		/* CLAWS: perform filtering actions on dropped message */
    641 		/* CLAWS: get default inbox (perhaps per account) */
    642 		if (pop3_session->ac_prefs->inbox) {
    643 			/* CLAWS: get destination folder / mailbox */
    644 			inbox = folder_find_item_from_identifier(pop3_session->ac_prefs->inbox);
    645 			if (!inbox)
    646 				inbox = folder_get_default_inbox();
    647 		} else
    648 			inbox = folder_get_default_inbox();
    649 
    650 		/* get list of messages in processing */
    651 		processing = folder_get_default_processing(pop3_session->ac_prefs->account_id);
    652 		folder_item_scan(processing);
    653 		msglist = folder_item_get_msg_list(processing);
    654 
    655 		/* process messages */
    656 		folder_item_update_freeze();
    657 
    658 		for(msglist_element = msglist; msglist_element != NULL;
    659 		    msglist_element = msglist_element->next) {
    660 			procmsg_msginfo_free((MsgInfo**)&(msglist_element->data));
    661 		}
    662 		folder_item_update_thaw();
    663 
    664 		g_slist_free(msglist);
    665 
    666 		statusbar_pop_all();
    667 
    668 		new_msgs += pop3_session->cur_total_num;
    669 
    670 		pop3_write_uidl_list(pop3_session);
    671 
    672 		if (inc_state != INC_SUCCESS && inc_state != INC_CANCEL) {
    673 			if (inc_dialog->show_dialog)
    674 				manage_window_focus_in(inc_dialog->dialog->window, NULL, NULL);
    675 			inc_put_error(inc_state, pop3_session);
    676 			if (inc_dialog->show_dialog)
    677 				manage_window_focus_out(inc_dialog->dialog->window, NULL, NULL);
    678 			if (inc_state == INC_NO_SPACE || inc_state == INC_IO_ERROR)
    679 				break;
    680 		}
    681 		folder_item_free_cache(processing, TRUE);
    682 
    683 		inc_session_destroy(session);
    684 		inc_dialog->queue_list = g_list_remove(inc_dialog->queue_list, session);
    685 	}
    686 
    687 #undef SET_PIXMAP_AND_TEXT
    688 
    689 	char fin_msg[BUFSIZ];
    690 	snprintf(fin_msg, sizeof(fin_msg), "Finished (%d new)", new_msgs);
    691 	progress_dialog_set_label(inc_dialog->dialog, fin_msg);
    692 
    693 	while (inc_dialog->queue_list != NULL) {
    694 		session = inc_dialog->queue_list->data;
    695 		inc_session_destroy(session);
    696 		inc_dialog->queue_list = g_list_remove(inc_dialog->queue_list, session);
    697 	}
    698 	inc_progress_dialog_destroy(inc_dialog);
    699 	return new_msgs;
    700 }
    701 
    702 static IncState inc_pop3_session_do(IncSession *session)
    703 {
    704 	Pop3Session *pop3_session = POP3_SESSION(session->session);
    705 	IncProgressDialog *inc_dialog = (IncProgressDialog *)session->data;
    706 	PrefsAccount *ac = pop3_session->ac_prefs;
    707 	gchar *server;
    708 	gchar *account_name;
    709 	gushort port;
    710 	gchar *buf;
    711 
    712 	debug_print("getting new messages of account %s...\n",
    713 		    ac->account_name);
    714 
    715 	ac->last_pop_login_time = time(NULL);
    716 
    717 	buf = g_strdup_printf(_("%s: Retrieving new messages"),
    718 			      ac->recv_server);
    719 	gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), buf);
    720 	g_free(buf);
    721 
    722 	server = ac->recv_server;
    723 	account_name = ac->account_name;
    724 	port = pop3_get_port(pop3_session);
    725 
    726 	SESSION(pop3_session)->ssl_type = ac->ssl_pop;
    727 	if (ac->ssl_pop != SSL_NONE)
    728 		SESSION(pop3_session)->nonblocking =
    729 			ac->use_nonblocking_ssl;
    730 
    731 	buf = g_strdup_printf(_("Account '%s': Connecting to POP3 server: %s:%d..."),
    732 				account_name, server, port);
    733 	statusbar_print_all("%s", buf);
    734 	log_message(LOG_PROTOCOL, "%s\n", buf);
    735 
    736 	progress_dialog_set_label(inc_dialog->dialog, buf);
    737 
    738 	GTK_EVENTS_FLUSH();
    739 	g_free(buf);
    740 
    741 	session_set_timeout(SESSION(pop3_session),
    742 			    prefs_common.io_timeout_secs * 1000);
    743 
    744 	if (session_connect(SESSION(pop3_session), server, port) < 0) {
    745 		char msg[BUFSIZ];
    746 		snprintf(msg, sizeof(msg), "Cannot connect to POP3 server at %s:%d", server, port);
    747 		alertpanel_error(msg);
    748 		manage_window_focus_out(inc_dialog->dialog->window, NULL, NULL);
    749 		log_error(LOG_PROTOCOL, msg);
    750 		session->inc_state = INC_CONNECT_ERROR;
    751 		statusbar_pop_all();
    752 		return INC_CONNECT_ERROR;
    753 	}
    754 
    755 	while (session_is_running(SESSION(pop3_session)) &&
    756 	       session->inc_state != INC_CANCEL)
    757 		gtk_main_iteration();
    758 
    759 	if (session->inc_state == INC_SUCCESS) {
    760 		switch (pop3_session->error_val) {
    761 		case PS_SUCCESS:
    762 			switch (SESSION(pop3_session)->state) {
    763 			case SESSION_ERROR:
    764 				if (pop3_session->state == POP3_READY)
    765 					session->inc_state = INC_CONNECT_ERROR;
    766 				else
    767 					session->inc_state = INC_ERROR;
    768 				break;
    769 			case SESSION_EOF:
    770 				session->inc_state = INC_EOF;
    771 				break;
    772 			case SESSION_TIMEOUT:
    773 				session->inc_state = INC_TIMEOUT;
    774 				break;
    775 			default:
    776 				session->inc_state = INC_SUCCESS;
    777 				break;
    778 			}
    779 			break;
    780 		case PS_AUTHFAIL:
    781 			session->inc_state = INC_AUTH_FAILED;
    782 			break;
    783 		case PS_IOERR:
    784 			session->inc_state = INC_IO_ERROR;
    785 			break;
    786 		case PS_SOCKET:
    787 			session->inc_state = INC_SOCKET_ERROR;
    788 			break;
    789 		case PS_LOCKBUSY:
    790 			session->inc_state = INC_LOCKED;
    791 			break;
    792 		default:
    793 			session->inc_state = INC_ERROR;
    794 			break;
    795 		}
    796 	}
    797 
    798 	session_disconnect(SESSION(pop3_session));
    799 	statusbar_pop_all();
    800 
    801 	return session->inc_state;
    802 }
    803 
    804 static void inc_progress_dialog_update(IncProgressDialog *inc_dialog,
    805 				       IncSession *inc_session)
    806 {
    807 	inc_progress_dialog_set_label(inc_dialog, inc_session);
    808 	inc_progress_dialog_set_progress(inc_dialog, inc_session);
    809 }
    810 
    811 static void inc_progress_dialog_set_label(IncProgressDialog *inc_dialog,
    812 					  IncSession *inc_session)
    813 {
    814 	ProgressDialog *dialog = inc_dialog->dialog;
    815 	Pop3Session *session;
    816 
    817 	cm_return_if_fail(inc_session != NULL);
    818 
    819 	session = POP3_SESSION(inc_session->session);
    820 
    821 	switch (session->state) {
    822 	case POP3_GREETING:
    823 		break;
    824 	case POP3_GETAUTH_USER:
    825 	case POP3_GETAUTH_PASS:
    826 		progress_dialog_set_label(dialog, _("Authenticating..."));
    827 		statusbar_pop_all();
    828 		statusbar_print_all(_("Retrieving messages from %s (%s)..."),
    829 				    SESSION(session)->server,
    830 				    session->ac_prefs->account_name);
    831 		break;
    832 	case POP3_GETRANGE_STAT:
    833 		progress_dialog_set_label
    834 			(dialog, _("Getting the number of new messages (STAT)..."));
    835 		break;
    836 	case POP3_GETRANGE_LAST:
    837 		progress_dialog_set_label
    838 			(dialog, _("Getting the number of new messages (LAST)..."));
    839 		break;
    840 	case POP3_GETRANGE_UIDL:
    841 		progress_dialog_set_label
    842 			(dialog, _("Getting the number of new messages (UIDL)..."));
    843 		break;
    844 	case POP3_GETSIZE_LIST:
    845 		progress_dialog_set_label
    846 			(dialog, _("Getting the size of messages (LIST)..."));
    847 		break;
    848 	case POP3_RETR:
    849 	case POP3_RETR_RECV:
    850 	case POP3_DELETE:
    851 		break;
    852 	case POP3_LOGOUT:
    853 		progress_dialog_set_label(dialog, _("Quitting"));
    854 		break;
    855 	default:
    856 		break;
    857 	}
    858 }
    859 
    860 static void inc_progress_dialog_set_progress(IncProgressDialog *inc_dialog,
    861 					     IncSession *inc_session)
    862 {
    863 	gchar buf[MESSAGEBUFSIZE];
    864 	Pop3Session *pop3_session = POP3_SESSION(inc_session->session);
    865 	gchar *total_size_str;
    866 	gint cur_total;
    867 	gint total;
    868 
    869 	if (!pop3_session->new_msg_exist) return;
    870 
    871 	cur_total = inc_session->cur_total_bytes;
    872 	total = pop3_session->total_bytes;
    873 	if (pop3_session->state == POP3_RETR ||
    874 	    pop3_session->state == POP3_RETR_RECV ||
    875 	    pop3_session->state == POP3_DELETE) {
    876 		Xstrdup_a(total_size_str, to_human_readable((goffset)total), return);
    877 		g_snprintf(buf, sizeof(buf),
    878 			   _("Retrieving message (%d / %d) (%s / %s)"),
    879 			   pop3_session->cur_msg, pop3_session->count,
    880 			   to_human_readable((goffset)cur_total), total_size_str);
    881 		progress_dialog_set_label(inc_dialog->dialog, buf);
    882 	}
    883 
    884 	progress_dialog_set_fraction
    885 		(inc_dialog->dialog, (total == 0) ? 0: (gfloat)cur_total / (gfloat)total);
    886 
    887 	statusbar_progress_all(pop3_session->cur_msg, pop3_session->count, 1);
    888 
    889 	if (pop3_session->cur_total_num > 0) {
    890 		int n = pop3_session->cur_total_num;
    891 		char *recv = to_human_readable((goffset)pop3_session->cur_total_recv_bytes);
    892 		g_snprintf(buf, sizeof(buf), "Retrieving messages (%d (%s) received)", n, recv),
    893 		progress_dialog_list_set_status(inc_dialog->dialog, inc_dialog->cur_row, buf);
    894 	}
    895 }
    896 
    897 static void inc_progress_dialog_update_periodic(IncProgressDialog *inc_dialog,
    898 						IncSession *inc_session)
    899 {
    900 	GDateTime *tv_cur = g_date_time_new_now_local();
    901 	GTimeSpan tv_result;
    902 
    903 	tv_result = g_date_time_difference(tv_cur, inc_dialog->progress_tv);
    904 	g_date_time_unref(tv_cur);
    905 	if (tv_result < 0) {
    906 	    tv_result += G_USEC_PER_SEC;
    907 	}
    908 
    909 	uint progress_update_interval = 200; // milliseconds
    910 	if (tv_result > progress_update_interval) {
    911                 inc_progress_dialog_update(inc_dialog, inc_session);
    912 		tv_cur = g_date_time_add(inc_dialog->progress_tv, tv_result);
    913 		g_date_time_unref(inc_dialog->progress_tv);
    914                 inc_dialog->progress_tv = tv_cur;
    915 	}
    916 }
    917 
    918 static gint inc_recv_data_progressive(Session *session, guint cur_len,
    919 				      guint total_len, gpointer data)
    920 {
    921 	IncSession *inc_session = (IncSession *)data;
    922 	Pop3Session *pop3_session = POP3_SESSION(session);
    923 	IncProgressDialog *inc_dialog;
    924 	gint cur_total;
    925 
    926 	cm_return_val_if_fail(inc_session != NULL, -1);
    927 
    928 	if (pop3_session->state != POP3_RETR &&
    929 	    pop3_session->state != POP3_RETR_RECV &&
    930 	    pop3_session->state != POP3_DELETE &&
    931 	    pop3_session->state != POP3_LOGOUT) return 0;
    932 
    933 	if (!pop3_session->new_msg_exist) return 0;
    934 
    935 	cur_total = pop3_session->cur_total_bytes + cur_len;
    936 	if (cur_total > pop3_session->total_bytes)
    937 		cur_total = pop3_session->total_bytes;
    938 	inc_session->cur_total_bytes = cur_total;
    939 
    940 	inc_dialog = (IncProgressDialog *)inc_session->data;
    941 	inc_progress_dialog_update_periodic(inc_dialog, inc_session);
    942 
    943 	return 0;
    944 }
    945 
    946 static gint inc_recv_data_finished(Session *session, guint len, gpointer data)
    947 {
    948 	IncSession *inc_session = (IncSession *)data;
    949 	IncProgressDialog *inc_dialog;
    950 
    951 	cm_return_val_if_fail(inc_session != NULL, -1);
    952 
    953 	inc_dialog = (IncProgressDialog *)inc_session->data;
    954 
    955 	inc_recv_data_progressive(session, 0, 0, inc_session);
    956 
    957 	if (POP3_SESSION(session)->state == POP3_LOGOUT) {
    958 		inc_progress_dialog_update(inc_dialog, inc_session);
    959 	}
    960 
    961 	return 0;
    962 }
    963 
    964 static gint inc_recv_message(Session *session, const gchar *msg, gpointer data)
    965 {
    966 	IncSession *inc_session = (IncSession *)data;
    967 	IncProgressDialog *inc_dialog;
    968 
    969 	cm_return_val_if_fail(inc_session != NULL, -1);
    970 
    971 	inc_dialog = (IncProgressDialog *)inc_session->data;
    972 
    973 	switch (POP3_SESSION(session)->state) {
    974 	case POP3_GETAUTH_USER:
    975 	case POP3_GETAUTH_PASS:
    976 	case POP3_GETRANGE_STAT:
    977 	case POP3_GETRANGE_LAST:
    978 	case POP3_GETRANGE_UIDL:
    979 	case POP3_GETSIZE_LIST:
    980 		inc_progress_dialog_update(inc_dialog, inc_session);
    981 		break;
    982 	case POP3_RETR:
    983 		inc_recv_data_progressive(session, 0, 0, inc_session);
    984 		break;
    985 	case POP3_LOGOUT:
    986 		inc_progress_dialog_update(inc_dialog, inc_session);
    987 		break;
    988 	default:
    989 		break;
    990 	}
    991 
    992 	return 0;
    993 }
    994 
    995 static gint inc_drop_message(Pop3Session *session, const gchar *file)
    996 {
    997 	FolderItem *inbox;
    998 	FolderItem *dropfolder;
    999 	IncSession *inc_session = (IncSession *)(SESSION(session)->data);
   1000 	gint msgnum;
   1001 
   1002 	cm_return_val_if_fail(inc_session != NULL, -1);
   1003 
   1004 	if (session->ac_prefs->inbox) {
   1005 		inbox = folder_find_item_from_identifier
   1006 			(session->ac_prefs->inbox);
   1007 		if (!inbox)
   1008 			inbox = folder_get_default_inbox();
   1009 	} else
   1010 		inbox = folder_get_default_inbox();
   1011 	if (!inbox) {
   1012 		unlink(file);
   1013 		return -1;
   1014 	}
   1015 
   1016 	/* CLAWS: claws uses a global .processing folder for the filtering. */
   1017 	dropfolder = folder_get_default_processing(session->ac_prefs->account_id);
   1018 
   1019 	/* add msg file to drop folder */
   1020 	if ((msgnum = folder_item_add_msg(
   1021 			dropfolder, file, NULL, TRUE)) < 0) {
   1022 		unlink(file);
   1023 		return -1;
   1024 	}
   1025 
   1026 	return 0;
   1027 }
   1028 
   1029 static void inc_put_error(IncState istate, Pop3Session *session)
   1030 {
   1031 	gchar *log_msg = NULL;
   1032 	gchar *err_msg = NULL;
   1033 	gboolean fatal_error = FALSE;
   1034 
   1035 	switch (istate) {
   1036 	case INC_CONNECT_ERROR:
   1037 		fatal_error = TRUE;
   1038 		err_msg = g_strdup_printf(_("Connection to %s:%d failed."),
   1039 					  SESSION(session)->server,
   1040 					  SESSION(session)->port);
   1041 		break;
   1042 	case INC_ERROR:
   1043 		log_msg = _("Error occurred while processing mail.");
   1044 		fatal_error = TRUE;
   1045 		if (session->error_msg)
   1046 			err_msg = g_strdup_printf
   1047 				(_("Error occurred while processing mail:\n%s"),
   1048 				 session->error_msg);
   1049 		else
   1050 			err_msg = g_strdup(log_msg);
   1051 		break;
   1052 	case INC_NO_SPACE:
   1053 		log_msg = _("No disk space left.");
   1054 		err_msg = g_strdup(log_msg);
   1055 		fatal_error = TRUE;
   1056 		break;
   1057 	case INC_IO_ERROR:
   1058 		log_msg = _("Can't write file.");
   1059 		err_msg = g_strdup(log_msg);
   1060 		fatal_error = TRUE;
   1061 		break;
   1062 	case INC_SOCKET_ERROR:
   1063 		log_msg = _("Socket error.");
   1064 		err_msg = g_strdup_printf(_("Socket error on connection to %s:%d."),
   1065 					  SESSION(session)->server,
   1066 					  SESSION(session)->port);
   1067 		break;
   1068 	case INC_EOF:
   1069 		log_msg = _("Connection closed by the remote host.");
   1070 		err_msg = g_strdup_printf(_("Connection to %s:%d closed by the remote host."),
   1071 					  SESSION(session)->server,
   1072 					  SESSION(session)->port);
   1073 		break;
   1074 	case INC_LOCKED:
   1075 		log_msg = _("Mailbox is locked.");
   1076 		if (session->error_msg)
   1077 			err_msg = g_strdup_printf(_("Mailbox is locked:\n%s"),
   1078 						  session->error_msg);
   1079 		else
   1080 			err_msg = g_strdup(log_msg);
   1081 		break;
   1082 	case INC_AUTH_FAILED:
   1083 		log_msg = _("Authentication failed.");
   1084 		fatal_error = TRUE;
   1085 		if (session->error_msg)
   1086 			err_msg = g_strdup_printf
   1087 				(_("Authentication failed:\n%s"), session->error_msg);
   1088 		else
   1089 			err_msg = g_strdup(log_msg);
   1090 		break;
   1091 	case INC_TIMEOUT:
   1092 		log_msg = _("Session timed out. You may be able to "
   1093 			    "recover by increasing the timeout value in "
   1094 			    "Preferences/Other/Miscellaneous.");
   1095 		err_msg = g_strdup_printf(_("Connection to %s:%d timed out."),
   1096 					  SESSION(session)->server,
   1097 					  SESSION(session)->port);
   1098 		break;
   1099 	default:
   1100 		break;
   1101 	}
   1102 
   1103 	if (log_msg) {
   1104 		if (fatal_error)
   1105 			log_error(LOG_PROTOCOL, "%s\n", log_msg);
   1106 		else
   1107 			log_warning(LOG_PROTOCOL, "%s\n", log_msg);
   1108 	}
   1109 
   1110 	if (err_msg) {
   1111 		alertpanel_error_log("%s", err_msg);
   1112 		g_free(err_msg);
   1113 	}
   1114 }
   1115 
   1116 static void inc_cancel(IncProgressDialog *dialog)
   1117 {
   1118 	IncSession *session;
   1119 
   1120 	cm_return_if_fail(dialog != NULL);
   1121 
   1122 	if (dialog->queue_list == NULL) {
   1123 		inc_progress_dialog_destroy(dialog);
   1124 		return;
   1125 	}
   1126 
   1127 	session = dialog->queue_list->data;
   1128 
   1129 	session->inc_state = INC_CANCEL;
   1130 
   1131 	log_message(LOG_PROTOCOL, _("Incorporation cancelled\n"));
   1132 }
   1133 
   1134 gboolean inc_is_active(void)
   1135 {
   1136 	return (inc_dialog_list != NULL);
   1137 }
   1138 
   1139 void inc_cancel_all(void)
   1140 {
   1141 	GList *cur;
   1142 
   1143 	for (cur = inc_dialog_list; cur != NULL; cur = cur->next)
   1144 		inc_cancel((IncProgressDialog *)cur->data);
   1145 }
   1146 
   1147 static void inc_showlog_cb(GtkWidget *widget, gpointer data)
   1148 {
   1149 	MainWindow *mainwin = mainwindow_get_mainwindow();
   1150 
   1151 	log_window_show(mainwin->logwin);
   1152 }
   1153 
   1154 static void inc_cancel_cb(GtkWidget *widget, gpointer data)
   1155 {
   1156 	inc_cancel((IncProgressDialog *)data);
   1157 }
   1158 
   1159 static gint inc_dialog_delete_cb(GtkWidget *widget, GdkEventAny *event,
   1160 				 gpointer data)
   1161 {
   1162 	IncProgressDialog *dialog = (IncProgressDialog *)data;
   1163 
   1164 	if (dialog->queue_list == NULL)
   1165 		inc_progress_dialog_destroy(dialog);
   1166 
   1167 	return TRUE;
   1168 }
   1169 
   1170 static gint inc_spool_account(PrefsAccount *account)
   1171 {
   1172 	FolderItem *inbox;
   1173 	gchar *mbox;
   1174 	gint result;
   1175 
   1176 	if (account->local_inbox) {
   1177 		inbox = folder_find_item_from_identifier(account->local_inbox);
   1178 		if (!inbox)
   1179 			inbox = folder_get_default_inbox();
   1180 	} else
   1181 		inbox = folder_get_default_inbox();
   1182 
   1183 	if (account->local_mbox) {
   1184 		if (is_file_exist(account->local_mbox))
   1185 			mbox = g_strdup(account->local_mbox);
   1186 		else if (is_dir_exist(account->local_mbox))
   1187 			mbox = g_strconcat(account->local_mbox, G_DIR_SEPARATOR_S,
   1188 					   g_get_user_name(), NULL);
   1189 		else {
   1190 			debug_print("%s: local mailbox not found.\n",
   1191 				    account->local_mbox);
   1192 			return -1;
   1193 		}
   1194 	} else {
   1195 		debug_print("local mailbox not set in account info.\n");
   1196 		return -1;
   1197 	}
   1198 
   1199 	result = get_spool(inbox, mbox, account);
   1200 	g_free(mbox);
   1201 
   1202 	statusbar_pop_all();
   1203 
   1204 	return result;
   1205 }
   1206 
   1207 static gint get_spool(FolderItem *dest, const gchar *mbox, PrefsAccount *account)
   1208 {
   1209 	gint msgs, size;
   1210 	gchar tmp_mbox[MAXPATHLEN + 1];
   1211 
   1212 	cm_return_val_if_fail(dest != NULL, -1);
   1213 	cm_return_val_if_fail(mbox != NULL, -1);
   1214 	cm_return_val_if_fail(account != NULL, -1);
   1215 
   1216 	if (!is_file_exist(mbox) || (size = get_file_size(mbox)) == 0) {
   1217 		debug_print("%s: no messages\n", mbox);
   1218 		return 0;
   1219 	} else if (size < 0)
   1220 		return -1;
   1221 
   1222 	g_snprintf(tmp_mbox, sizeof(tmp_mbox), "%s/tmpmbox.%p", get_tmp_dir(), mbox);
   1223 
   1224 	int spool = open(mbox, O_RDONLY);
   1225 	if (flock(spool, LOCK_EX|LOCK_NB) < 0) {
   1226 		perror("lock mbox");
   1227 		return -1;
   1228 	}
   1229 	debug_print("Getting new messages from %s into %s...\n", mbox, dest->path);
   1230 	if (copy_mbox(spool, tmp_mbox) < 0) {
   1231 		perror("copy mbox");
   1232 		flock(spool, LOCK_UN);
   1233 		close(spool);
   1234 		return -1;
   1235 	}
   1236 	close(spool);
   1237 
   1238 	msgs = proc_mbox(dest, tmp_mbox, account);
   1239 	unlink(tmp_mbox);
   1240 	if (msgs >= 0) {
   1241 		if (truncate(mbox, 0) < 0)
   1242 			perror("truncate mbox");
   1243 	}
   1244 
   1245 	flock(spool, LOCK_UN);
   1246 
   1247 	return msgs;
   1248 }
   1249 
   1250 void inc_lock_real(void)
   1251 {
   1252 	inc_lock_count++;
   1253 }
   1254 
   1255 void inc_unlock_real(void)
   1256 {
   1257 	if (inc_lock_count > 0)
   1258 		inc_lock_count--;
   1259 }
   1260 
   1261 static guint autocheck_timer = 0;
   1262 static gpointer autocheck_data = NULL;
   1263 
   1264 static void inc_notify_cmd(gint new_msgs, gboolean notify)
   1265 {
   1266 	gchar *buf, *numpos, *ret_str;
   1267 	gssize by_read = 0, by_written = 0;
   1268 
   1269 	if (!(new_msgs && notify && prefs_common.newmail_notify_cmd &&
   1270 	    *prefs_common.newmail_notify_cmd))
   1271 		     return;
   1272 
   1273 	buf = g_strdup(prefs_common.newmail_notify_cmd);
   1274 	if ((numpos = strstr(buf, "%d")) != NULL) {
   1275 		gchar *buf2;
   1276 
   1277 		*numpos = '\0';
   1278 		buf2 = g_strdup_printf("%s%d%s", buf, new_msgs, numpos + 2);
   1279 		g_free(buf);
   1280 		buf = buf2;
   1281 	}
   1282 
   1283 	ret_str = g_locale_from_utf8(buf, strlen(buf), &by_read, &by_written,
   1284 				     NULL);
   1285 	if (ret_str) {
   1286 		if (by_written) {
   1287 			g_free(buf);
   1288 			buf = ret_str;
   1289 		} else
   1290 			g_free(ret_str);
   1291 	}
   1292 	debug_print("executing new mail notification command: %s\n", buf);
   1293 	execute_command_line(buf, TRUE, NULL);
   1294 
   1295 	g_free(buf);
   1296 }
   1297 
   1298 gboolean inc_offline_should_override(gboolean force_ask, const gchar *msg)
   1299 {
   1300 	gint length = 10; /* seconds */
   1301 	gint answer = G_ALERTDEFAULT;
   1302 
   1303 	if (force_ask) {
   1304 		inc_offline_overridden_no = (time_t)0;
   1305 	}
   1306 
   1307 	if (prefs_common.work_offline) {
   1308 		gchar *tmp = NULL;
   1309 
   1310 		if (time(NULL) - inc_offline_overridden_yes < length * 60) /* seconds */
   1311 			 return TRUE;
   1312 		else if (time(NULL) - inc_offline_overridden_no < length * 60) /* seconds */
   1313 			 return FALSE;
   1314 
   1315 		if (!force_ask) {
   1316 			char buf[8];
   1317 			char *unit = "seconds";
   1318 
   1319 			/* show the offline override time (length) using the must appropriate unit:
   1320 			   the biggest unit possible (hours, minutes, seconds), provided that there
   1321 			   is not inferior unit involved: 1 hour, 150 minutes, 25 minutes, 90 minutes,
   1322 			   30 seconds, 90 seconds. */
   1323 			if ((length / 3600) > 0) { /* hours? */
   1324 				if (((length % 3600) % 60) == 0) { /* no seconds left? */
   1325 					if ((length % 3600) > 0) { /* minutes left? */
   1326 						length = length / 60;
   1327 						unit = "minute";
   1328 					} else {
   1329 						length = length / 3600;
   1330 						unit = "hour";
   1331 					}
   1332 				} /* else: seconds */
   1333 			} else {
   1334 				if ((length / 60) > 0) { /* minutes left? */
   1335 					if ((length % 60) == 0) {
   1336 						length = length / 60;
   1337 						unit = "minute";
   1338 					}
   1339 				} /* else: seconds */
   1340 			}
   1341 			strlcpy(buf, unit, sizeof(buf));
   1342 			if (length > 1)
   1343 				strlcat(buf, "s", sizeof(buf));
   1344 			tmp = g_strdup_printf("%s\nWorking offline. Override for %d %s?", msg, length, buf);
   1345 		} else
   1346 			tmp = g_strdup_printf("%sWorking offline. Override?", msg),
   1347 
   1348 		answer = alertpanel(_("Offline warning"),
   1349 			       tmp,
   1350 			       NULL, "Cancel", NULL, "Override",
   1351 			       NULL, !force_ask? _("On_ly once"):NULL, ALERTFOCUS_SECOND);
   1352 		g_free(tmp);
   1353 		if (answer == G_ALERTALTERNATE) {
   1354 			inc_offline_overridden_yes = time(NULL);
   1355 			return TRUE;
   1356 		} else if (answer == G_ALERTDEFAULT) {
   1357 			if (!force_ask)
   1358 				inc_offline_overridden_no  = time(NULL);
   1359 			return FALSE;
   1360 		} else {
   1361 			inc_reset_offline_override_timers();
   1362 			return TRUE;
   1363 		}
   1364 	}
   1365 	return TRUE;
   1366 }
   1367 
   1368 void inc_reset_offline_override_timers()
   1369 {
   1370 	debug_print("resetting offline override timers\n");
   1371 	inc_offline_overridden_yes = (time_t)0;
   1372 	inc_offline_overridden_no  = (time_t)0;
   1373 }