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