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