2007-02-25 [colin] 2.7.2cvs73
[claws.git] / src / main.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 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 2 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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtkmain.h>
29 #include <gtk/gtkrc.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <time.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #ifdef G_OS_UNIX
40 #  include <signal.h>
41 #endif
42 #ifdef HAVE_LIBSM
43 #include <X11/SM/SMlib.h>
44 #include <fcntl.h>
45 #endif
46
47 #include "wizard.h"
48 #ifdef HAVE_STARTUP_NOTIFICATION
49 # define SN_API_NOT_YET_FROZEN
50 # include <libsn/sn-launchee.h>
51 # include <gdk/gdkx.h>
52 #endif
53
54 #include "claws.h"
55 #include "main.h"
56 #include "mainwindow.h"
57 #include "folderview.h"
58 #include "image_viewer.h"
59 #include "summaryview.h"
60 #include "prefs_common.h"
61 #include "prefs_account.h"
62 #include "prefs_actions.h"
63 #include "prefs_ext_prog.h"
64 #include "prefs_fonts.h"
65 #include "prefs_image_viewer.h"
66 #include "prefs_message.h"
67 #include "prefs_receive.h"
68 #include "prefs_msg_colors.h"
69 #include "prefs_quote.h"
70 #include "prefs_spelling.h"
71 #include "prefs_summaries.h"
72 #include "prefs_themes.h"
73 #include "prefs_other.h"
74 #include "prefs_send.h"
75 #include "prefs_wrapping.h"
76 #include "prefs_compose_writing.h"
77 #include "prefs_display_header.h"
78 #include "account.h"
79 #include "procmsg.h"
80 #include "inc.h"
81 #include "import.h"
82 #include "manage_window.h"
83 #include "alertpanel.h"
84 #include "statusbar.h"
85 #include "addressbook.h"
86 #include "compose.h"
87 #include "folder.h"
88 #include "setup.h"
89 #include "utils.h"
90 #include "gtkutils.h"
91 #include "socket.h"
92 #include "log.h"
93 #include "prefs_toolbar.h"
94 #include "plugin.h"
95 #include "mh_gtk.h"
96 #include "imap_gtk.h"
97 #include "news_gtk.h"
98 #include "matcher.h"
99 #ifdef HAVE_LIBETPAN
100 #include "imap-thread.h"
101 #endif
102 #include "stock_pixmap.h"
103 #include "valgrind.h"
104
105 #if USE_OPENSSL
106 #  include "ssl.h"
107 #endif
108
109 #include "version.h"
110
111 #include "crash.h"
112
113 #include "timing.h"
114
115 gchar *prog_version;
116 gchar *argv0;
117
118 #ifdef HAVE_STARTUP_NOTIFICATION
119 static SnLauncheeContext *sn_context = NULL;
120 static SnDisplay *sn_display = NULL;
121 #endif
122
123 static gint lock_socket = -1;
124 static gint lock_socket_tag = 0;
125
126 typedef enum 
127 {
128         ONLINE_MODE_DONT_CHANGE,
129         ONLINE_MODE_ONLINE,
130         ONLINE_MODE_OFFLINE
131 } OnlineMode;
132
133 static struct RemoteCmd {
134         gboolean receive;
135         gboolean receive_all;
136         gboolean compose;
137         const gchar *compose_mailto;
138         GPtrArray *attach_files;
139         gboolean status;
140         gboolean status_full;
141         GPtrArray *status_folders;
142         GPtrArray *status_full_folders;
143         gboolean send;
144         gboolean crash;
145         int online_mode;
146         gchar   *crash_params;
147         gboolean exit;
148         gboolean subscribe;
149         const gchar *subscribe_uri;
150         const gchar *target;
151 } cmd;
152
153 static void parse_cmd_opt(int argc, char *argv[]);
154
155 static gint prohibit_duplicate_launch   (void);
156 static gchar * get_crashfile_name       (void);
157 static gint lock_socket_remove          (void);
158 static void lock_socket_input_cb        (gpointer          data,
159                                          gint              source,
160                                          GdkInputCondition condition);
161
162 static void open_compose_new            (const gchar    *address,
163                                          GPtrArray      *attach_files);
164
165 static void send_queue                  (void);
166 static void initial_processing          (FolderItem *item, gpointer data);
167 static void quit_signal_handler         (int sig);
168 static void install_basic_sighandlers   (void);
169 static void exit_claws                  (MainWindow *mainwin);
170
171 #define MAKE_DIR_IF_NOT_EXIST(dir) \
172 { \
173         if (!is_dir_exist(dir)) { \
174                 if (is_file_exist(dir)) { \
175                         alertpanel_warning \
176                                 (_("File '%s' already exists.\n" \
177                                    "Can't create folder."), \
178                                  dir); \
179                         return 1; \
180                 } \
181                 if (make_dir(dir) < 0) \
182                         return 1; \
183         } \
184 }
185
186 static MainWindow *static_mainwindow;
187 static gboolean emergency_exit = FALSE;
188
189 #ifdef HAVE_STARTUP_NOTIFICATION
190 static void sn_error_trap_push(SnDisplay *display, Display *xdisplay)
191 {
192         gdk_error_trap_push();
193 }
194
195 static void sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
196 {
197         gdk_error_trap_pop();
198 }
199
200 static void startup_notification_complete(gboolean with_window)
201 {
202         Display *xdisplay;
203         GtkWidget *hack = NULL;
204
205         if (with_window) {
206                 /* this is needed to make the startup notification leave,
207                  * if we have been launched from a menu.
208                  * We have to display a window, so let it be very little */
209                 hack = gtk_window_new(GTK_WINDOW_POPUP);
210                 gtk_widget_set_uposition(hack, 0, 0);
211                 gtk_widget_set_size_request(hack, 1, 1);
212                 gtk_widget_show(hack);
213         }
214
215         xdisplay = GDK_DISPLAY();
216         sn_display = sn_display_new(xdisplay,
217                                 sn_error_trap_push,
218                                 sn_error_trap_pop);
219         sn_context = sn_launchee_context_new_from_environment(sn_display,
220                                                  DefaultScreen(xdisplay));
221
222         if (sn_context != NULL) {
223                 sn_launchee_context_complete(sn_context);
224                 sn_launchee_context_unref(sn_context);
225                 sn_display_unref(sn_display);
226         }
227         if (with_window) {
228                 gtk_widget_destroy(hack);
229         }
230 }
231 #endif /* HAVE_STARTUP_NOTIFICATION */
232
233 static void claws_gtk_idle(void) 
234 {
235         while(gtk_events_pending()) {
236                 gtk_main_iteration();
237         }
238         g_usleep(50000);
239 }
240
241 static gboolean defer_check_all(void *data)
242 {
243         gboolean autochk = GPOINTER_TO_INT(data);
244
245         inc_all_account_mail(static_mainwindow, autochk, 
246                         prefs_common.newmail_notify_manu);
247
248         return FALSE;
249 }
250
251 static gboolean defer_check(void *data)
252 {
253         inc_mail(static_mainwindow, prefs_common.newmail_notify_manu);
254
255         return FALSE;
256 }
257
258 static gboolean defer_jump(void *data)
259 {
260         mainwindow_jump_to(data);
261         return FALSE;
262 }
263
264 static void chk_update_val(GtkWidget *widget, gpointer data)
265 {
266         gboolean *val = (gboolean *)data;
267         *val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
268 }
269
270 static gboolean migrate_old_config(const gchar *old_cfg_dir, const gchar *new_cfg_dir, const gchar *oldversion)
271 {
272         gchar *message = g_strdup_printf(_("Configuration for %s (or previous) found.\n"
273                          "Do you want to migrate this configuration?"), oldversion);
274         gint r = 0;
275         GtkWidget *window = NULL;
276         GtkWidget *keep_backup_chk;
277         GtkTooltips *tips = gtk_tooltips_new();
278         gboolean backup = TRUE;
279
280         keep_backup_chk = gtk_check_button_new_with_label (_("Keep old configuration"));
281         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keep_backup_chk), TRUE);
282         gtk_tooltips_set_tip(GTK_TOOLTIPS(tips), keep_backup_chk,
283                              _("Keeping a backup will allow you to go back to an "
284                                "older version, but may take a while if you have "
285                                "cached IMAP or News data, and will take some extra "
286                                "room on your disk."),
287                              NULL);
288
289         g_signal_connect(G_OBJECT(keep_backup_chk), "toggled", 
290                         G_CALLBACK(chk_update_val), &backup);
291
292         if (alertpanel_full(_("Migration of configuration"), message,
293                         GTK_STOCK_NO, "+" GTK_STOCK_YES, NULL, FALSE,
294                         keep_backup_chk, ALERT_QUESTION, G_ALERTDEFAULT) != G_ALERTALTERNATE) {
295                 return FALSE;
296         }
297         
298         /* we can either do a fast migration requiring not any extra disk
299          * space, or a slow one that copies the old configuration and leaves
300          * it in place. */
301         if (backup) {
302 backup_mode:
303                 window = label_window_create(_("Copying configuration... This may take a while..."));
304                 GTK_EVENTS_FLUSH();
305                 
306                 r = copy_dir(old_cfg_dir, new_cfg_dir);
307                 gtk_widget_destroy(window);
308                 
309                 /* if copy failed, we'll remove the partially copied
310                  * new directory */
311                 if (r != 0) {
312                         alertpanel_error(_("Migration failed!"));
313                         remove_dir_recursive(new_cfg_dir);
314                 } else {
315                         if (!backup) {
316                                 /* fast mode failed, but we don't want backup */
317                                 remove_dir_recursive(old_cfg_dir);
318                         }
319                 }
320         } else {
321                 window = label_window_create(_("Migrating configuration..."));
322                 GTK_EVENTS_FLUSH();
323                 
324                 r = g_rename(old_cfg_dir, new_cfg_dir);
325                 gtk_widget_destroy(window);
326                 
327                 /* if g_rename failed, we'll try to copy */
328                 if (r != 0) {
329                         FILE_OP_ERROR(new_cfg_dir, "g_rename failed, trying copy\n");
330                         goto backup_mode;
331                 }
332         }
333         return (r == 0);
334 }
335
336 static void migrate_common_rc(const gchar *old_rc, const gchar *new_rc)
337 {
338         FILE *oldfp, *newfp;
339         gchar *plugin_path, *old_plugin_path, *new_plugin_path;
340         gchar buf[BUFFSIZE];
341         oldfp = g_fopen(old_rc, "r");
342         if (!oldfp)
343                 return;
344         newfp = g_fopen(new_rc, "w");
345         if (!newfp) {
346                 fclose(oldfp);
347                 return;
348         }
349         
350         plugin_path = g_strdup(get_plugin_dir());
351         new_plugin_path = g_strdup(plugin_path);
352         
353         if (strstr(plugin_path, "/claws-mail/")) {
354                 gchar *end = g_strdup(strstr(plugin_path, "/claws-mail/")+strlen("/claws-mail/"));
355                 *(strstr(plugin_path, "/claws-mail/")) = '\0';
356                 old_plugin_path = g_strconcat(plugin_path, "/sylpheed-claws/", end, NULL);
357                 g_free(end);
358         } else {
359                 old_plugin_path = g_strdup(new_plugin_path);
360         }
361         debug_print("replacing %s with %s\n", old_plugin_path, new_plugin_path);
362         while (fgets(buf, sizeof(buf), oldfp)) {
363                 if (strncmp(buf, old_plugin_path, strlen(old_plugin_path))) {
364                         fputs(buf, newfp);
365                 } else {
366                         debug_print("->replacing %s", buf);
367                         debug_print("  with %s%s", new_plugin_path, buf+strlen(old_plugin_path));
368                         fputs(new_plugin_path, newfp);
369                         fputs(buf+strlen(old_plugin_path), newfp);
370                 }
371         }
372         g_free(plugin_path);
373         g_free(new_plugin_path);
374         g_free(old_plugin_path);
375         fclose(oldfp);
376         fclose(newfp);
377 }
378
379 #ifdef HAVE_LIBSM
380 static void
381 sc_client_set_value (MainWindow *mainwin,
382                   gchar       *name,
383                   char        *type,
384                   int          num_vals,
385                   SmPropValue *vals)
386 {
387         SmProp *proplist[1];
388         SmProp prop;
389
390         prop.name = name;
391         prop.type = type;
392         prop.num_vals = num_vals;
393         prop.vals = vals;
394
395         proplist[0]= &prop;
396         if (mainwin->smc_conn)
397                 SmcSetProperties ((SmcConn) mainwin->smc_conn, 1, proplist);
398 }
399
400 static void sc_die_callback (SmcConn smc_conn, SmPointer client_data)
401 {
402         clean_quit(NULL);
403 }
404
405 static void sc_save_complete_callback(SmcConn smc_conn, SmPointer client_data)
406 {
407 }
408
409 static void sc_shutdown_cancelled_callback (SmcConn smc_conn, SmPointer client_data)
410 {
411         MainWindow *mainwin = (MainWindow *)client_data;
412         if (mainwin->smc_conn)
413                 SmcSaveYourselfDone ((SmcConn) mainwin->smc_conn, TRUE);
414 }
415
416 static void sc_save_yourself_callback (SmcConn   smc_conn,
417                                SmPointer client_data,
418                                int       save_style,
419                                gboolean  shutdown,
420                                int       interact_style,
421                                gboolean  fast) {
422
423         MainWindow *mainwin = (MainWindow *)client_data;
424         if (mainwin->smc_conn)
425                 SmcSaveYourselfDone ((SmcConn) mainwin->smc_conn, TRUE);
426 }
427
428 static IceIOErrorHandler sc_ice_installed_handler;
429
430 static void sc_ice_io_error_handler (IceConn connection)
431 {
432         if (sc_ice_installed_handler)
433                 (*sc_ice_installed_handler) (connection);
434 }
435 static gboolean sc_process_ice_messages (GIOChannel   *source,
436                       GIOCondition  condition,
437                       gpointer      data)
438 {
439         IceConn connection = (IceConn) data;
440         IceProcessMessagesStatus status;
441
442         status = IceProcessMessages (connection, NULL, NULL);
443
444         if (status == IceProcessMessagesIOError) {
445                 IcePointer context = IceGetConnectionContext (connection);
446
447                 if (context && GTK_IS_OBJECT (context)) {
448                 guint disconnect_id = g_signal_lookup ("disconnect", G_OBJECT_TYPE (context));
449
450                 if (disconnect_id > 0)
451                         g_signal_emit (context, disconnect_id, 0);
452                 } else {
453                         IceSetShutdownNegotiation (connection, False);
454                         IceCloseConnection (connection);
455                 }
456         }
457
458         return TRUE;
459 }
460
461 static void new_ice_connection (IceConn connection, IcePointer client_data, Bool opening,
462                     IcePointer *watch_data)
463 {
464         guint input_id;
465
466         if (opening) {
467                 GIOChannel *channel;
468                 /* Make sure we don't pass on these file descriptors to any
469                 exec'ed children */
470                 fcntl(IceConnectionNumber(connection),F_SETFD,
471                 fcntl(IceConnectionNumber(connection),F_GETFD,0) | FD_CLOEXEC);
472
473                 channel = g_io_channel_unix_new (IceConnectionNumber (connection));
474                 input_id = g_io_add_watch (channel,
475                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
476                 sc_process_ice_messages,
477                 connection);
478                 g_io_channel_unref (channel);
479
480                 *watch_data = (IcePointer) GUINT_TO_POINTER (input_id);
481         } else {
482                 input_id = GPOINTER_TO_UINT ((gpointer) *watch_data);
483                 g_source_remove (input_id);
484         }
485 }
486
487 static void sc_session_manager_connect(MainWindow *mainwin)
488 {
489         static gboolean connected = FALSE;
490         SmcCallbacks      callbacks;
491         gchar            *client_id;
492         IceIOErrorHandler default_handler;
493
494         if (connected)
495                 return;
496         connected = TRUE;
497
498
499         sc_ice_installed_handler = IceSetIOErrorHandler (NULL);
500         default_handler = IceSetIOErrorHandler (sc_ice_io_error_handler);
501
502         if (sc_ice_installed_handler == default_handler)
503                 sc_ice_installed_handler = NULL;
504
505         IceAddConnectionWatch (new_ice_connection, NULL);
506       
507       
508         callbacks.save_yourself.callback      = sc_save_yourself_callback;
509         callbacks.die.callback                = sc_die_callback;
510         callbacks.save_complete.callback      = sc_save_complete_callback;
511         callbacks.shutdown_cancelled.callback = sc_shutdown_cancelled_callback;
512
513         callbacks.save_yourself.client_data =
514                 callbacks.die.client_data =
515                 callbacks.save_complete.client_data =
516                 callbacks.shutdown_cancelled.client_data = (SmPointer) mainwin;
517         if (g_getenv ("SESSION_MANAGER")) {
518                 gchar error_string_ret[256] = "";
519
520                 mainwin->smc_conn = (gpointer)
521                         SmcOpenConnection (NULL, mainwin,
522                                 SmProtoMajor, SmProtoMinor,
523                                 SmcSaveYourselfProcMask | SmcDieProcMask |
524                                 SmcSaveCompleteProcMask |
525                                 SmcShutdownCancelledProcMask,
526                                 &callbacks,
527                                 NULL, &client_id,
528                                 256, error_string_ret);
529
530                 if (error_string_ret[0] || mainwin->smc_conn == NULL)
531                         g_warning ("While connecting to session manager:\n%s.",
532                                 error_string_ret);
533                 else {
534                         SmPropValue *vals;
535                         vals = g_new (SmPropValue, 1);
536                         vals[0].length = strlen(argv0);
537                         vals[0].value = argv0;
538                         sc_client_set_value (mainwin, SmCloneCommand, SmLISTofARRAY8, 1, vals);
539                         sc_client_set_value (mainwin, SmRestartCommand, SmLISTofARRAY8, 1, vals);
540                         sc_client_set_value (mainwin, SmProgram, SmARRAY8, 1, vals);
541
542                         vals[0].length = strlen(g_get_user_name()?g_get_user_name():"");
543                         vals[0].value = g_strdup(g_get_user_name()?g_get_user_name():"");
544                         sc_client_set_value (mainwin, SmUserID, SmARRAY8, 1, vals);
545                 }
546         }
547 }
548 #endif
549
550 static gboolean sc_exiting = FALSE;
551 static gboolean sc_starting = FALSE;
552 static gboolean show_at_startup = TRUE;
553
554 void main_set_show_at_startup(gboolean show)
555 {
556         show_at_startup = show;
557 }
558
559 int main(int argc, char *argv[])
560 {
561         gchar *userrc;
562         MainWindow *mainwin;
563         FolderView *folderview;
564         GdkPixbuf *icon;
565         gboolean crash_file_present = FALSE;
566         gint num_folder_class = 0;
567         gboolean asked_for_migration = FALSE;
568
569         START_TIMING("startup");
570         
571         sc_starting = TRUE;
572
573         if (!claws_init(&argc, &argv)) {
574                 return 0;
575         }
576
577         prefs_prepare_cache();
578         prog_version = PROG_VERSION;
579         argv0 = g_strdup(argv[0]);
580
581         parse_cmd_opt(argc, argv);
582
583 #ifdef CRASH_DIALOG
584         if (cmd.crash) {
585                 gtk_set_locale();
586                 gtk_init(&argc, &argv);
587                 crash_main(cmd.crash_params);
588                 return 0;
589         }
590         crash_install_handlers();
591 #endif
592         install_basic_sighandlers();
593         sock_init();
594
595         /* check and create unix domain socket for remote operation */
596 #ifdef G_OS_UNIX
597         lock_socket = prohibit_duplicate_launch();
598         if (lock_socket < 0) {
599 #ifdef HAVE_STARTUP_NOTIFICATION
600                 if(gtk_init_check(&argc, &argv))
601                         startup_notification_complete(TRUE);
602 #endif
603                 return 0;
604         }
605
606         if (cmd.status || cmd.status_full) {
607                 puts("0 Claws Mail not running.");
608                 lock_socket_remove();
609                 return 0;
610         }
611         
612         if (cmd.exit)
613                 return 0;
614 #endif
615         if (!g_thread_supported())
616                 g_thread_init(NULL);
617
618         gtk_set_locale();
619         gtk_init(&argc, &argv);
620
621         gdk_rgb_init();
622         gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
623         gtk_widget_set_default_visual(gdk_rgb_get_visual());
624
625         if (!g_thread_supported()) {
626                 g_error(_("g_thread is not supported by glib.\n"));
627         }
628
629         /* check that we're not on a too recent/old gtk+ */
630 #if GTK_CHECK_VERSION(2, 9, 0)
631         if (gtk_check_version(2, 9, 0) != NULL) {
632                 alertpanel_error(_("Claws Mail has been compiled with "
633                                    "a more recent GTK+ library than is "
634                                    "currently available. This will cause "
635                                    "crashes. You need to upgrade GTK+ or "
636                                    "recompile Claws Mail."));
637                 exit(1);
638         }
639 #else
640         if (gtk_check_version(2, 9, 0) == NULL) {
641                 alertpanel_error(_("Claws Mail has been compiled with "
642                                    "an older GTK+ library than is "
643                                    "currently available. This will cause "
644                                    "crashes. You need to recompile "
645                                    "Claws Mail."));
646                 exit(1);
647         }
648 #endif  
649         /* parse gtkrc files */
650         userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtkrc-2.0",
651                              NULL);
652         gtk_rc_parse(userrc);
653         g_free(userrc);
654         userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtk",
655                              G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL);
656         gtk_rc_parse(userrc);
657         g_free(userrc);
658
659         CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
660         
661         /* no config dir exists. See if we can migrate an old config. */
662         if (!is_dir_exist(RC_DIR)) {
663                 prefs_destroy_cache();
664                 gboolean r = FALSE;
665                 
666                 /* if one of the old dirs exist, we'll ask if the user 
667                  * want to migrates, and r will be TRUE if he said yes
668                  * and migration succeeded, and FALSE otherwise.
669                  */
670                 if (is_dir_exist(OLD_GTK2_RC_DIR)) {
671                         r = migrate_old_config(OLD_GTK2_RC_DIR, RC_DIR, "Sylpheed-Claws 2.6.0");
672                         asked_for_migration = TRUE;
673                 } else if (is_dir_exist(OLDER_GTK2_RC_DIR)) {
674                         r = migrate_old_config(OLDER_GTK2_RC_DIR, RC_DIR, "Sylpheed-Claws 1.9.15");
675                         asked_for_migration = TRUE;
676                 } else if (is_dir_exist(OLD_GTK1_RC_DIR)) {
677                         r = migrate_old_config(OLD_GTK1_RC_DIR, RC_DIR, "Sylpheed-Claws 1.0.5");
678                         asked_for_migration = TRUE;
679                 }
680                 
681                 /* If migration failed or the user didn't want to do it,
682                  * we create a new one (and we'll hit wizard later). 
683                  */
684                 if (r == FALSE && !is_dir_exist(RC_DIR) && make_dir(RC_DIR) < 0)
685                         exit(1);
686         }
687         
688
689         if (!is_file_exist(RC_DIR G_DIR_SEPARATOR_S COMMON_RC) &&
690             is_file_exist(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC)) {
691                 /* post 2.6 name change */
692                 migrate_common_rc(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC,
693                           RC_DIR G_DIR_SEPARATOR_S COMMON_RC);
694         }
695
696         if (!cmd.exit)
697                 plugin_load_all("Common");
698
699         userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL);
700         gtk_rc_parse(userrc);
701         g_free(userrc);
702
703         userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
704         gtk_accel_map_load (userrc);
705         g_free(userrc);
706
707         CHDIR_RETURN_VAL_IF_FAIL(get_rc_dir(), 1);
708
709         MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
710         MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
711         MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
712         MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
713         MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
714         MAKE_DIR_IF_NOT_EXIST(UIDL_DIR);
715
716         crash_file_present = is_file_exist(get_crashfile_name());
717         /* remove temporary files */
718         remove_all_files(get_tmp_dir());
719         remove_all_files(get_mime_tmp_dir());
720
721         if (is_file_exist("claws.log")) {
722                 if (rename_force("claws.log", "claws.log.bak") < 0)
723                         FILE_OP_ERROR("claws.log", "rename");
724         }
725         set_log_file("claws.log");
726
727         CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
728
729         folder_system_init();
730         prefs_common_read_config();
731
732         prefs_themes_init();
733         prefs_fonts_init();
734         prefs_ext_prog_init();
735         prefs_wrapping_init();
736         prefs_compose_writing_init();
737         prefs_msg_colors_init();
738         image_viewer_init();
739         prefs_image_viewer_init();
740         prefs_quote_init();
741         prefs_summaries_init();
742         prefs_message_init();
743         prefs_other_init();
744         prefs_receive_init();
745         prefs_send_init();
746 #ifdef USE_ASPELL
747         gtkaspell_checkers_init();
748         prefs_spelling_init();
749 #endif
750
751         sock_set_io_timeout(prefs_common.io_timeout_secs);
752 #ifdef HAVE_LIBETPAN
753         imap_main_set_timeout(prefs_common.io_timeout_secs);
754 #endif
755         prefs_actions_read_config();
756         prefs_display_header_read_config();
757         /* prefs_filtering_read_config(); */
758         addressbook_read_file();
759         renderer_read_config();
760
761         gtkut_widget_init();
762         stock_pixbuf_gdk(NULL, STOCK_PIXMAP_CLAWS_MAIL_ICON, &icon);
763         gtk_window_set_default_icon(icon);
764
765         folderview_initialize();
766
767         mh_gtk_init();
768         imap_gtk_init();
769         news_gtk_init();
770
771         mainwin = main_window_create();
772
773         manage_window_focus_in(mainwin->window, NULL, NULL);
774         folderview = mainwin->folderview;
775
776         gtk_clist_freeze(GTK_CLIST(mainwin->folderview->ctree));
777         folder_item_update_freeze();
778
779         /* register the callback of unix domain socket input */
780 #ifdef G_OS_UNIX
781         lock_socket_tag = gdk_input_add(lock_socket,
782                                         GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
783                                         lock_socket_input_cb,
784                                         mainwin);
785 #endif
786
787         prefs_account_init();
788         account_read_config_all();
789
790         /* If we can't read a folder list or don't have accounts,
791          * it means the configuration's not done. Either this is
792          * a brand new install, either a failed/refused migration.
793          * So we'll start the wizard.
794          */
795         if (folder_read_list() < 0) {
796                 prefs_destroy_cache();
797                 
798                 /* if run_wizard returns FALSE it's because it's
799                  * been cancelled. We can't do much but exit.
800                  * however, if the user was asked for a migration,
801                  * we remove the newly created directory so that
802                  * he's asked again for migration on next launch.*/
803                 if (!run_wizard(mainwin, TRUE)) {
804                         if (asked_for_migration)
805                                 remove_dir_recursive(RC_DIR);
806                         exit(1);
807                 }
808                 main_window_reflect_prefs_all_now();
809                 folder_write_list();
810         }
811
812         if (!account_get_list()) {
813                 prefs_destroy_cache();
814                 if (!run_wizard(mainwin, FALSE)) {
815                         if (asked_for_migration)
816                                 remove_dir_recursive(RC_DIR);
817                         exit(1);
818                 }
819                 account_read_config_all();
820                 if(!account_get_list()) {
821                         exit_claws(mainwin);
822                         exit(1);
823                 }
824         }
825
826         
827         toolbar_main_set_sensitive(mainwin);
828         main_window_set_menu_sensitive(mainwin);
829
830         /* if crashed, show window early so that the user
831          * sees what's happening */
832         if (!cmd.crash && crash_file_present)
833                 main_window_popup(mainwin);
834
835 #ifdef HAVE_LIBETPAN
836         imap_main_init(prefs_common.skip_ssl_cert_check);
837 #endif  
838         account_set_missing_folder();
839         folder_set_missing_folders();
840         folderview_set(folderview);
841
842         prefs_matcher_read_config();
843
844         /* make one all-folder processing before using claws */
845         main_window_cursor_wait(mainwin);
846         folder_func_to_all_folders(initial_processing, (gpointer *)mainwin);
847
848         /* if claws crashed, rebuild caches */
849         if (!cmd.crash && crash_file_present) {
850                 GTK_EVENTS_FLUSH();
851                 debug_print("Claws Mail crashed, checking for new messages in local folders\n");
852                 folder_item_update_thaw();
853                 folderview_check_new(NULL);
854                 folder_clean_cache_memory_force();
855                 folder_item_update_freeze();
856         }
857         /* make the crash-indicator file */
858         str_write_to_file("foo", get_crashfile_name());
859
860         inc_autocheck_timer_init(mainwin);
861
862         /* ignore SIGPIPE signal for preventing sudden death of program */
863 #ifdef G_OS_UNIX
864         signal(SIGPIPE, SIG_IGN);
865 #endif
866         if (cmd.online_mode == ONLINE_MODE_OFFLINE) {
867                 main_window_toggle_work_offline(mainwin, TRUE, FALSE);
868         }
869         if (cmd.online_mode == ONLINE_MODE_ONLINE) {
870                 main_window_toggle_work_offline(mainwin, FALSE, FALSE);
871         }
872
873         if (cmd.status_folders) {
874                 g_ptr_array_free(cmd.status_folders, TRUE);
875                 cmd.status_folders = NULL;
876         }
877         if (cmd.status_full_folders) {
878                 g_ptr_array_free(cmd.status_full_folders, TRUE);
879                 cmd.status_full_folders = NULL;
880         }
881
882         claws_register_idle_function(claws_gtk_idle);
883
884         prefs_toolbar_init();
885
886         num_folder_class = g_list_length(folder_get_list());
887
888         plugin_load_all("GTK2");
889
890         if (g_list_length(folder_get_list()) != num_folder_class) {
891                 debug_print("new folders loaded, reloading processing rules\n");
892                 prefs_matcher_read_config();
893         }
894         
895         if (plugin_get_unloaded_list() != NULL) {
896                 main_window_cursor_normal(mainwin);
897                 alertpanel_warning(_("Some plugin(s) failed to load. "
898                                      "Check the Plugins configuration "
899                                      "for more information."));
900                 main_window_cursor_wait(mainwin);
901         }
902
903         plugin_load_standard_plugins ();
904        
905         /* if not crashed, show window now */
906         if (!(!cmd.crash && crash_file_present)) {
907                 /* apart if something told not to show */
908                 if (show_at_startup)
909                         main_window_popup(mainwin);
910         }
911
912         if (!folder_have_mailbox()) {
913                 prefs_destroy_cache();
914                 main_window_cursor_normal(mainwin);
915                 if (folder_get_list() != NULL) {
916                         alertpanel_error(_("Claws Mail has detected a configured "
917                                    "mailbox, but is it incomplete. It is "
918                                    "possibly due to a failing IMAP account. Use "
919                                    "\"Rebuild folder tree\" on the mailbox's folder "
920                                    "to try to fix it."));
921                 } else {
922                         alertpanel_error(_("Claws Mail has detected a configured "
923                                    "mailbox, but could not load it. It is "
924                                    "probably provided by an out-of-date "
925                                    "external plugin. Please reinstall the "
926                                    "plugin and try again."));
927                         exit_claws(mainwin);
928                         exit(1);
929                 }
930         }
931         
932         static_mainwindow = mainwin;
933
934 #ifdef HAVE_STARTUP_NOTIFICATION
935         startup_notification_complete(FALSE);
936 #endif
937 #ifdef HAVE_LIBSM
938         sc_session_manager_connect(mainwin);
939 #endif
940         folder_item_update_thaw();
941         gtk_clist_thaw(GTK_CLIST(mainwin->folderview->ctree));
942         main_window_cursor_normal(mainwin);
943
944         if (cmd.receive_all) {
945                 g_timeout_add(1000, defer_check_all, GINT_TO_POINTER(FALSE));
946         } else if (prefs_common.chk_on_startup) {
947                 g_timeout_add(1000, defer_check_all, GINT_TO_POINTER(TRUE));
948         } else if (cmd.receive) {
949                 g_timeout_add(1000, defer_check, NULL);
950         } else {
951                 gtk_widget_grab_focus(folderview->ctree);
952         }
953
954         if (cmd.compose) {
955                 open_compose_new(cmd.compose_mailto, cmd.attach_files);
956         }
957         if (cmd.attach_files) {
958                 ptr_array_free_strings(cmd.attach_files);
959                 g_ptr_array_free(cmd.attach_files, TRUE);
960                 cmd.attach_files = NULL;
961         }
962         if (cmd.subscribe) {
963                 folder_subscribe(cmd.subscribe_uri);
964         }
965
966         if (cmd.send) {
967                 send_queue();
968         }
969         
970         if (cmd.target) {
971                 g_timeout_add(500, defer_jump, (gpointer)cmd.target);
972         }
973
974         prefs_destroy_cache();
975         
976         compose_reopen_exit_drafts();
977
978         sc_starting = FALSE;
979         END_TIMING();
980
981         gtk_main();
982
983         exit_claws(mainwin);
984
985         return 0;
986 }
987
988 static void save_all_caches(FolderItem *item, gpointer data)
989 {
990         if (!item->cache) {
991                 return;
992         }
993
994         if (item->opened)
995                 folder_item_close(item);
996         
997         folder_item_free_cache(item, TRUE);
998 }
999
1000 static void exit_claws(MainWindow *mainwin)
1001 {
1002         gchar *filename;
1003
1004         sc_exiting = TRUE;
1005
1006         debug_print("shutting down\n");
1007         inc_autocheck_timer_remove();
1008
1009         if (prefs_common.clean_on_exit && !emergency_exit) {
1010                 main_window_empty_trash(mainwin, prefs_common.ask_on_clean);
1011         }
1012
1013         /* save prefs for opened folder */
1014         if(mainwin->folderview->opened) {
1015                 FolderItem *item;
1016
1017                 item = gtk_ctree_node_get_row_data(GTK_CTREE(mainwin->folderview->ctree), mainwin->folderview->opened);
1018                 summary_save_prefs_to_folderitem(mainwin->folderview->summaryview, item);
1019         }
1020
1021         /* save all state before exiting */
1022         folder_func_to_all_folders(save_all_caches, NULL);
1023         folder_write_list();
1024
1025         main_window_get_size(mainwin);
1026         main_window_get_position(mainwin);
1027
1028         prefs_common_write_config();
1029         account_write_config_all();
1030         addressbook_export_to_file();
1031
1032         filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
1033         gtk_accel_map_save(filename);
1034         g_free(filename);
1035
1036         /* delete temporary files */
1037         remove_all_files(get_tmp_dir());
1038         remove_all_files(get_mime_tmp_dir());
1039
1040         close_log_file();
1041
1042 #ifdef HAVE_LIBETPAN
1043         imap_main_done();
1044 #endif
1045         /* delete crashfile */
1046         if (!cmd.crash)
1047                 g_unlink(get_crashfile_name());
1048
1049         lock_socket_remove();
1050
1051 #ifdef HAVE_LIBSM
1052         if (mainwin->smc_conn)
1053                 SmcCloseConnection ((SmcConn)mainwin->smc_conn, 0, NULL);
1054         mainwin->smc_conn = NULL;
1055 #endif
1056
1057         main_window_destroy_all();
1058         
1059         plugin_unload_all("GTK2");
1060
1061         prefs_toolbar_done();
1062
1063         addressbook_destroy();
1064
1065         prefs_themes_done();
1066         prefs_fonts_done();
1067         prefs_ext_prog_done();
1068         prefs_wrapping_done();
1069         prefs_compose_writing_done();
1070         prefs_msg_colors_done();
1071         prefs_image_viewer_done();
1072         image_viewer_done();
1073         prefs_quote_done();
1074         prefs_summaries_done();
1075         prefs_message_done();
1076         prefs_other_done();
1077         prefs_receive_done();
1078         prefs_send_done();
1079 #ifdef USE_ASPELL       
1080         prefs_spelling_done();
1081         gtkaspell_checkers_quit();
1082 #endif
1083         plugin_unload_all("Common");
1084         claws_done();
1085 }
1086
1087 static void parse_cmd_opt(int argc, char *argv[])
1088 {
1089         gint i;
1090
1091         for (i = 1; i < argc; i++) {
1092                 if (!strncmp(argv[i], "--receive-all", 13)) {
1093                         cmd.receive_all = TRUE;
1094                 } else if (!strncmp(argv[i], "--receive", 9)) {
1095                         cmd.receive = TRUE;
1096                 } else if (!strncmp(argv[i], "--compose", 9)) {
1097                         const gchar *p = argv[i + 1];
1098
1099                         cmd.compose = TRUE;
1100                         cmd.compose_mailto = NULL;
1101                         if (p && *p != '\0' && *p != '-') {
1102                                 if (!strncmp(p, "mailto:", 7)) {
1103                                         cmd.compose_mailto = p + 7;
1104                                 } else {
1105                                         cmd.compose_mailto = p;
1106                                 }
1107                                 i++;
1108                         }
1109                 } else if (!strncmp(argv[i], "--subscribe", 11)) {
1110                         const gchar *p = argv[i + 1];
1111                         if (p && *p != '\0' && *p != '-') {
1112                                 cmd.subscribe = TRUE;
1113                                 cmd.subscribe_uri = p;
1114                         }
1115                 } else if (!strncmp(argv[i], "--attach", 8)) {
1116                         const gchar *p = argv[i + 1];
1117                         gchar *file = NULL;
1118
1119                         while (p && *p != '\0' && *p != '-') {
1120                                 if (!cmd.attach_files) {
1121                                         cmd.attach_files = g_ptr_array_new();
1122                                 }
1123                                 if ((file = g_filename_from_uri(p, NULL, NULL)) != NULL) {
1124                                         if (!is_file_exist(file)) {
1125                                                 g_free(file);
1126                                                 file = NULL;
1127                                         }
1128                                 }
1129                                 if (file == NULL && *p != G_DIR_SEPARATOR) {
1130                                         file = g_strconcat(claws_get_startup_dir(),
1131                                                            G_DIR_SEPARATOR_S,
1132                                                            p, NULL);
1133                                 } else if (file == NULL) {
1134                                         file = g_strdup(p);
1135                                 }
1136                                 g_ptr_array_add(cmd.attach_files, file);
1137                                 i++;
1138                                 p = argv[i + 1];
1139                         }
1140                 } else if (!strncmp(argv[i], "--send", 6)) {
1141                         cmd.send = TRUE;
1142                 } else if (!strncmp(argv[i], "--version", 9) ||
1143                            !strncmp(argv[i], "-v", 2)) {
1144                         puts("Claws Mail version " VERSION);
1145                         exit(0);
1146                 } else if (!strncmp(argv[i], "--status-full", 13)) {
1147                         const gchar *p = argv[i + 1];
1148  
1149                         cmd.status_full = TRUE;
1150                         while (p && *p != '\0' && *p != '-') {
1151                                 if (!cmd.status_full_folders) {
1152                                         cmd.status_full_folders =
1153                                                 g_ptr_array_new();
1154                                 }
1155                                 g_ptr_array_add(cmd.status_full_folders,
1156                                                 g_strdup(p));
1157                                 i++;
1158                                 p = argv[i + 1];
1159                         }
1160                 } else if (!strncmp(argv[i], "--status", 8)) {
1161                         const gchar *p = argv[i + 1];
1162  
1163                         cmd.status = TRUE;
1164                         while (p && *p != '\0' && *p != '-') {
1165                                 if (!cmd.status_folders)
1166                                         cmd.status_folders = g_ptr_array_new();
1167                                 g_ptr_array_add(cmd.status_folders,
1168                                                 g_strdup(p));
1169                                 i++;
1170                                 p = argv[i + 1];
1171                         }
1172                 } else if (!strncmp(argv[i], "--online", 8)) {
1173                         cmd.online_mode = ONLINE_MODE_ONLINE;
1174                 } else if (!strncmp(argv[i], "--offline", 9)) {
1175                         cmd.online_mode = ONLINE_MODE_OFFLINE;
1176                 } else if (!strncmp(argv[i], "--help", 6) ||
1177                            !strncmp(argv[i], "-h", 2)) {
1178                         gchar *base = g_path_get_basename(argv[0]);
1179                         g_print(_("Usage: %s [OPTION]...\n"), base);
1180
1181                         g_print("%s\n", _("  --compose [address]    open composition window"));
1182                         g_print("%s\n", _("  --subscribe [uri]      subscribe to the given URI if possible"));
1183                         g_print("%s\n", _("  --attach file1 [file2]...\n"
1184                                   "                         open composition window with specified files\n"
1185                                   "                         attached"));
1186                         g_print("%s\n", _("  --receive              receive new messages"));
1187                         g_print("%s\n", _("  --receive-all          receive new messages of all accounts"));
1188                         g_print("%s\n", _("  --send                 send all queued messages"));
1189                         g_print("%s\n", _("  --status [folder]...   show the total number of messages"));
1190                         g_print("%s\n", _("  --status-full [folder]...\n"
1191                                "                         show the status of each folder"));
1192                         g_print("%s\n", _("  --select folder[/msg]  jumps to the specified folder/message\n" 
1193                                           "                         folder is a folder id like 'folder/sub_folder'"));
1194                         g_print("%s\n", _("  --online               switch to online mode"));
1195                         g_print("%s\n", _("  --offline              switch to offline mode"));
1196                         g_print("%s\n", _("  --exit --quit -q       exit Claws Mail"));
1197                         g_print("%s\n", _("  --debug                debug mode"));
1198                         g_print("%s\n", _("  --help -h              display this help and exit"));
1199                         g_print("%s\n", _("  --version -v           output version information and exit"));
1200                         g_print("%s\n", _("  --config-dir           output configuration directory"));
1201
1202                         g_free(base);
1203                         exit(1);
1204                 } else if (!strncmp(argv[i], "--crash", 7)) {
1205                         cmd.crash = TRUE;
1206                         cmd.crash_params = g_strdup(argv[i + 1]);
1207                         i++;
1208                 } else if (!strncmp(argv[i], "--config-dir", sizeof "--config-dir" - 1)) {
1209                         puts(RC_DIR);
1210                         exit(0);
1211                 } else if (!strncmp(argv[i], "--exit", 6) ||
1212                            !strncmp(argv[i], "--quit", 6) ||
1213                            !strncmp(argv[i], "-q", 2)) {
1214                         cmd.exit = TRUE;
1215                 } else if (!strncmp(argv[i], "--select", 8) && i+1 < argc) {
1216                         cmd.target = argv[i+1];
1217                 } else if (i == 1 && argc == 2) {
1218                         /* only one parameter. Do something intelligent about it */
1219                         if (strstr(argv[i], "@") && !strstr(argv[i], "://")) {
1220                                 const gchar *p = argv[i];
1221
1222                                 cmd.compose = TRUE;
1223                                 cmd.compose_mailto = NULL;
1224                                 if (p && *p != '\0' && *p != '-') {
1225                                         if (!strncmp(p, "mailto:", 7)) {
1226                                                 cmd.compose_mailto = p + 7;
1227                                         } else {
1228                                                 cmd.compose_mailto = p;
1229                                         }
1230                                 }
1231                         } else if (strstr(argv[i], "://")) {
1232                                 const gchar *p = argv[i];
1233                                 if (p && *p != '\0' && *p != '-') {
1234                                         cmd.subscribe = TRUE;
1235                                         cmd.subscribe_uri = p;
1236                                 }
1237                         } else if (!strcmp(argv[i], "--sync")) {
1238                                 /* gtk debug */
1239                         } else {
1240                                 g_print(_("Unknown option\n"));
1241                                 exit(1);
1242                         }
1243                 }
1244         }
1245
1246         if (cmd.attach_files && cmd.compose == FALSE) {
1247                 cmd.compose = TRUE;
1248                 cmd.compose_mailto = NULL;
1249         }
1250 }
1251
1252 static void initial_processing(FolderItem *item, gpointer data)
1253 {
1254         MainWindow *mainwin = (MainWindow *)data;
1255         gchar *buf;
1256
1257         g_return_if_fail(item);
1258         buf = g_strdup_printf(_("Processing (%s)..."), 
1259                               item->path 
1260                               ? item->path 
1261                               : _("top level folder"));
1262         g_free(buf);
1263
1264         
1265         if (item->prefs->enable_processing) {
1266                 folder_item_apply_processing(item);
1267         }
1268
1269         STATUSBAR_POP(mainwin);
1270 }
1271
1272 static void draft_all_messages(void)
1273 {
1274         GList *compose_list = NULL;
1275         
1276         compose_clear_exit_drafts();
1277         while ((compose_list = compose_get_compose_list()) != NULL) {
1278                 Compose *c = (Compose*)compose_list->data;
1279                 compose_draft(c, COMPOSE_DRAFT_FOR_EXIT);
1280         }       
1281 }
1282 gboolean clean_quit(gpointer data)
1283 {
1284         static gboolean firstrun = TRUE;
1285
1286         if (!firstrun) {
1287                 return FALSE;
1288         }
1289         firstrun = FALSE;
1290
1291         /*!< Good idea to have the main window stored in a 
1292          *   static variable so we can check that variable
1293          *   to see if we're really allowed to do things
1294          *   that actually the spawner is supposed to 
1295          *   do (like: sending mail, composing messages).
1296          *   Because, really, if we're the spawnee, and
1297          *   we touch GTK stuff, we're hosed. See the 
1298          *   next fixme. */
1299
1300         /* FIXME: Use something else to signal that we're
1301          * in the original spawner, and not in a spawned
1302          * child. */
1303         if (!static_mainwindow) {
1304                 return FALSE;
1305         }
1306                 
1307         draft_all_messages();
1308         emergency_exit = TRUE;
1309         exit_claws(static_mainwindow);
1310         exit(0);
1311
1312         return FALSE;
1313 }
1314
1315 void app_will_exit(GtkWidget *widget, gpointer data)
1316 {
1317         MainWindow *mainwin = data;
1318         
1319         if (sc_exiting == TRUE) {
1320                 debug_print("exit pending\n");
1321                 return;
1322         }
1323         sc_exiting = TRUE;
1324         debug_print("exiting\n");
1325         if (compose_get_compose_list()) {
1326                 draft_all_messages();
1327         }
1328
1329         if (prefs_common.warn_queued_on_exit && procmsg_have_queued_mails_fast()) {
1330                 if (alertpanel(_("Queued messages"),
1331                                _("Some unsent messages are queued. Exit now?"),
1332                                GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL)
1333                     != G_ALERTALTERNATE) {
1334                         main_window_popup(mainwin);
1335                         sc_exiting = FALSE;
1336                         return;
1337                 }
1338                 manage_window_focus_in(mainwin->window, NULL, NULL);
1339         }
1340
1341         sock_cleanup();
1342         if (RUNNING_ON_VALGRIND) {
1343                 summary_clear_list(mainwin->summaryview);
1344         }
1345         if (folderview_get_selected_item(mainwin->folderview))
1346                 folder_item_close(folderview_get_selected_item(mainwin->folderview));
1347         gtk_main_quit();
1348 }
1349
1350 gboolean claws_is_exiting(void)
1351 {
1352         return sc_exiting;
1353 }
1354
1355 gboolean claws_is_starting(void)
1356 {
1357         return sc_starting;
1358 }
1359
1360 /*
1361  * CLAWS: want this public so crash dialog can delete the
1362  * lock file too
1363  */
1364 gchar *claws_get_socket_name(void)
1365 {
1366         static gchar *filename = NULL;
1367
1368         if (filename == NULL) {
1369                 filename = g_strdup_printf("%s%cclaws-mail-%d",
1370                                            g_get_tmp_dir(), G_DIR_SEPARATOR,
1371 #if HAVE_GETUID
1372                                            getuid());
1373 #else
1374                                            0);                                          
1375 #endif
1376         }
1377
1378         return filename;
1379 }
1380
1381 static gchar *get_crashfile_name(void)
1382 {
1383         static gchar *filename = NULL;
1384
1385         if (filename == NULL) {
1386                 filename = g_strdup_printf("%s%cclaws-crashed",
1387                                            get_tmp_dir(), G_DIR_SEPARATOR);
1388         }
1389
1390         return filename;
1391 }
1392
1393 static gint prohibit_duplicate_launch(void)
1394 {
1395         gint uxsock;
1396         gchar *path;
1397
1398         path = claws_get_socket_name();
1399         uxsock = fd_connect_unix(path);
1400         if (uxsock < 0) {
1401                 g_unlink(path);
1402                 return fd_open_unix(path);
1403         }
1404
1405         /* remote command mode */
1406
1407         debug_print("another Claws Mail instance is already running.\n");
1408
1409         if (cmd.receive_all) {
1410                 fd_write_all(uxsock, "receive_all\n", 12);
1411         } else if (cmd.receive) {
1412                 fd_write_all(uxsock, "receive\n", 8);
1413         } else if (cmd.compose && cmd.attach_files) {
1414                 gchar *str, *compose_str;
1415                 gint i;
1416
1417                 if (cmd.compose_mailto) {
1418                         compose_str = g_strdup_printf("compose_attach %s\n",
1419                                                       cmd.compose_mailto);
1420                 } else {
1421                         compose_str = g_strdup("compose_attach\n");
1422                 }
1423
1424                 fd_write_all(uxsock, compose_str, strlen(compose_str));
1425                 g_free(compose_str);
1426
1427                 for (i = 0; i < cmd.attach_files->len; i++) {
1428                         str = g_ptr_array_index(cmd.attach_files, i);
1429                         fd_write_all(uxsock, str, strlen(str));
1430                         fd_write_all(uxsock, "\n", 1);
1431                 }
1432
1433                 fd_write_all(uxsock, ".\n", 2);
1434         } else if (cmd.compose) {
1435                 gchar *compose_str;
1436
1437                 if (cmd.compose_mailto) {
1438                         compose_str = g_strdup_printf
1439                                 ("compose %s\n", cmd.compose_mailto);
1440                 } else {
1441                         compose_str = g_strdup("compose\n");
1442                 }
1443
1444                 fd_write_all(uxsock, compose_str, strlen(compose_str));
1445                 g_free(compose_str);
1446         } else if (cmd.subscribe) {
1447                 gchar *str = g_strdup_printf("subscribe %s\n", cmd.subscribe_uri);
1448                 fd_write_all(uxsock, str, strlen(str));
1449                 g_free(str);
1450         } else if (cmd.send) {
1451                 fd_write_all(uxsock, "send\n", 5);
1452         } else if (cmd.online_mode == ONLINE_MODE_ONLINE) {
1453                 fd_write(uxsock, "online\n", 6);
1454         } else if (cmd.online_mode == ONLINE_MODE_OFFLINE) {
1455                 fd_write(uxsock, "offline\n", 7);
1456         } else if (cmd.status || cmd.status_full) {
1457                 gchar buf[BUFFSIZE];
1458                 gint i;
1459                 const gchar *command;
1460                 GPtrArray *folders;
1461                 gchar *folder;
1462  
1463                 command = cmd.status_full ? "status-full\n" : "status\n";
1464                 folders = cmd.status_full ? cmd.status_full_folders :
1465                         cmd.status_folders;
1466  
1467                 fd_write_all(uxsock, command, strlen(command));
1468                 for (i = 0; folders && i < folders->len; ++i) {
1469                         folder = g_ptr_array_index(folders, i);
1470                         fd_write_all(uxsock, folder, strlen(folder));
1471                         fd_write_all(uxsock, "\n", 1);
1472                 }
1473                 fd_write_all(uxsock, ".\n", 2);
1474                 for (;;) {
1475                         fd_gets(uxsock, buf, sizeof(buf));
1476                         if (!strncmp(buf, ".\n", 2)) break;
1477                         fputs(buf, stdout);
1478                 }
1479         } else if (cmd.exit) {
1480                 fd_write_all(uxsock, "exit\n", 5);
1481         } else if (cmd.target) {
1482                 gchar *str = g_strdup_printf("select %s\n", cmd.target);
1483                 fd_write_all(uxsock, str, strlen(str));
1484                 g_free(str);
1485         } else
1486                 fd_write_all(uxsock, "popup\n", 6);
1487
1488         fd_close(uxsock);
1489         return -1;
1490 }
1491
1492 static gint lock_socket_remove(void)
1493 {
1494 #ifdef G_OS_UNIX
1495         gchar *filename;
1496
1497         if (lock_socket < 0) {
1498                 return -1;
1499         }
1500
1501         if (lock_socket_tag > 0) {
1502                 gdk_input_remove(lock_socket_tag);
1503         }
1504         fd_close(lock_socket);
1505         filename = claws_get_socket_name();
1506         g_unlink(filename);
1507 #endif
1508
1509         return 0;
1510 }
1511
1512 static GPtrArray *get_folder_item_list(gint sock)
1513 {
1514         gchar buf[BUFFSIZE];
1515         FolderItem *item;
1516         GPtrArray *folders = NULL;
1517
1518         for (;;) {
1519                 fd_gets(sock, buf, sizeof(buf));
1520                 if (!strncmp(buf, ".\n", 2)) {
1521                         break;
1522                 }
1523                 strretchomp(buf);
1524                 if (!folders) {
1525                         folders = g_ptr_array_new();
1526                 }
1527                 item = folder_find_item_from_identifier(buf);
1528                 if (item) {
1529                         g_ptr_array_add(folders, item);
1530                 } else {
1531                         g_warning("no such folder: %s\n", buf);
1532                 }
1533         }
1534
1535         return folders;
1536 }
1537
1538 static void lock_socket_input_cb(gpointer data,
1539                                  gint source,
1540                                  GdkInputCondition condition)
1541 {
1542         MainWindow *mainwin = (MainWindow *)data;
1543         gint sock;
1544         gchar buf[BUFFSIZE];
1545
1546         sock = fd_accept(source);
1547         fd_gets(sock, buf, sizeof(buf));
1548
1549         if (!strncmp(buf, "popup", 5)) {
1550                 main_window_popup(mainwin);
1551         } else if (!strncmp(buf, "receive_all", 11)) {
1552                 inc_all_account_mail(mainwin, FALSE,
1553                                      prefs_common.newmail_notify_manu);
1554         } else if (!strncmp(buf, "receive", 7)) {
1555                 inc_mail(mainwin, prefs_common.newmail_notify_manu);
1556         } else if (!strncmp(buf, "compose_attach", 14)) {
1557                 GPtrArray *files;
1558                 gchar *mailto;
1559
1560                 mailto = g_strdup(buf + strlen("compose_attach") + 1);
1561                 files = g_ptr_array_new();
1562                 while (fd_gets(sock, buf, sizeof(buf)) > 0) {
1563                         if (buf[0] == '.' && buf[1] == '\n') {
1564                                 break;
1565                         }
1566                         strretchomp(buf);
1567                         g_ptr_array_add(files, g_strdup(buf));
1568                 }
1569                 open_compose_new(mailto, files);
1570                 ptr_array_free_strings(files);
1571                 g_ptr_array_free(files, TRUE);
1572                 g_free(mailto);
1573         } else if (!strncmp(buf, "compose", 7)) {
1574                 open_compose_new(buf + strlen("compose") + 1, NULL);
1575         } else if (!strncmp(buf, "subscribe", 9)) {
1576                 main_window_popup(mainwin);
1577                 folder_subscribe(buf + strlen("subscribe") + 1);
1578         } else if (!strncmp(buf, "send", 4)) {
1579                 send_queue();
1580         } else if (!strncmp(buf, "online", 6)) {
1581                 main_window_toggle_work_offline(mainwin, FALSE, FALSE);
1582         } else if (!strncmp(buf, "offline", 7)) {
1583                 main_window_toggle_work_offline(mainwin, TRUE, FALSE);
1584         } else if (!strncmp(buf, "status-full", 11) ||
1585                    !strncmp(buf, "status", 6)) {
1586                 gchar *status;
1587                 GPtrArray *folders;
1588  
1589                 folders = get_folder_item_list(sock);
1590                 status = folder_get_status
1591                         (folders, !strncmp(buf, "status-full", 11));
1592                 fd_write_all(sock, status, strlen(status));
1593                 fd_write_all(sock, ".\n", 2);
1594                 g_free(status);
1595                 if (folders) g_ptr_array_free(folders, TRUE);
1596         } else if (!strncmp(buf, "select ", 7)) {
1597                 const gchar *target = buf+7;
1598                 mainwindow_jump_to(target);
1599         } else if (!strncmp(buf, "exit", 4)) {
1600                 app_will_exit(NULL, mainwin);
1601         }
1602
1603         fd_close(sock);
1604 }
1605
1606 static void open_compose_new(const gchar *address, GPtrArray *attach_files)
1607 {
1608         gchar *addr = NULL;
1609
1610         if (address) {
1611                 Xstrdup_a(addr, address, return);
1612                 g_strstrip(addr);
1613         }
1614
1615         compose_new(NULL, addr, attach_files);
1616 }
1617
1618 static void send_queue(void)
1619 {
1620         GList *list;
1621         gchar *errstr = NULL;
1622         for (list = folder_get_list(); list != NULL; list = list->next) {
1623                 Folder *folder = list->data;
1624
1625                 if (folder->queue) {
1626                         gint res = procmsg_send_queue
1627                                 (folder->queue, prefs_common.savemsg,
1628                                 &errstr);
1629
1630                         if (res) {
1631                                 folder_item_scan(folder->queue);
1632                         }
1633                 }
1634         }
1635         if (errstr) {
1636                 gchar *tmp = g_strdup_printf(_("Some errors occurred "
1637                                 "while sending queued messages:\n%s"), errstr);
1638                 g_free(errstr);
1639                 alertpanel_error_log(tmp);
1640                 g_free(tmp);
1641         } else {
1642                 alertpanel_error_log("Some errors occurred "
1643                                 "while sending queued messages.");
1644         }
1645 }
1646
1647 static void quit_signal_handler(int sig)
1648 {
1649         debug_print("Quitting on signal %d\n", sig);
1650
1651         g_timeout_add(0, clean_quit, NULL);
1652 }
1653
1654 static void install_basic_sighandlers()
1655 {
1656 #ifndef G_OS_WIN32
1657         sigset_t    mask;
1658         struct sigaction act;
1659
1660         sigemptyset(&mask);
1661
1662 #ifdef SIGTERM
1663         sigaddset(&mask, SIGTERM);
1664 #endif
1665 #ifdef SIGINT
1666         sigaddset(&mask, SIGINT);
1667 #endif
1668 #ifdef SIGHUP
1669         sigaddset(&mask, SIGHUP);
1670 #endif
1671
1672         act.sa_handler = quit_signal_handler;
1673         act.sa_mask    = mask;
1674         act.sa_flags   = 0;
1675
1676 #ifdef SIGTERM
1677         sigaction(SIGTERM, &act, 0);
1678 #endif
1679 #ifdef SIGINT
1680         sigaction(SIGINT, &act, 0);
1681 #endif  
1682 #ifdef SIGHUP
1683         sigaction(SIGHUP, &act, 0);
1684 #endif  
1685
1686         sigprocmask(SIG_UNBLOCK, &mask, 0);
1687 #endif /* !G_OS_WIN32 */
1688 }