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