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