check for return value when setting G_MESSAGES_DEBUG
[claws.git] / src / main.c
bloba9351b052aafdfab71f8211b3e5c37def3b90416
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
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.
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.
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/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
24 #include "defs.h"
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <time.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #ifdef G_OS_UNIX
39 # include <signal.h>
40 # include <errno.h>
41 # include <fcntl.h>
42 #endif
43 #ifdef HAVE_LIBSM
44 #include <X11/SM/SMlib.h>
45 #endif
47 #if HAVE_FLOCK
48 #include <sys/file.h>
49 #endif
51 #include "file_checker.h"
52 #include "wizard.h"
53 #ifdef HAVE_STARTUP_NOTIFICATION
54 #ifdef GDK_WINDOWING_X11
55 # define SN_API_NOT_YET_FROZEN
56 # include <libsn/sn-launchee.h>
57 # include <gdk/gdkx.h>
58 #endif
59 #endif
61 #ifdef HAVE_DBUS_GLIB
62 #include <dbus/dbus-glib.h>
63 #endif
64 #ifdef HAVE_NETWORKMANAGER_SUPPORT
65 #include <NetworkManager.h>
66 #endif
67 #ifdef HAVE_VALGRIND
68 #include <valgrind.h>
69 #endif
70 #ifdef HAVE_SVG
71 #include <librsvg/rsvg.h>
72 #endif
74 #include "claws.h"
75 #include "main.h"
76 #include "mainwindow.h"
77 #include "folderview.h"
78 #include "image_viewer.h"
79 #include "summaryview.h"
80 #include "prefs_common.h"
81 #include "prefs_account.h"
82 #include "prefs_actions.h"
83 #include "prefs_ext_prog.h"
84 #include "prefs_fonts.h"
85 #include "prefs_image_viewer.h"
86 #include "prefs_message.h"
87 #include "prefs_migration.h"
88 #include "prefs_receive.h"
89 #include "prefs_msg_colors.h"
90 #include "prefs_quote.h"
91 #include "prefs_spelling.h"
92 #include "prefs_summaries.h"
93 #include "prefs_themes.h"
94 #include "prefs_other.h"
95 #include "prefs_proxy.h"
96 #include "prefs_logging.h"
97 #include "prefs_send.h"
98 #include "prefs_wrapping.h"
99 #include "prefs_compose_writing.h"
100 #include "prefs_display_header.h"
101 #include "account.h"
102 #include "procmsg.h"
103 #include "inc.h"
104 #include "imap.h"
105 #include "send_message.h"
106 #include "md5.h"
107 #include "import.h"
108 #include "manage_window.h"
109 #include "alertpanel.h"
110 #include "statusbar.h"
111 #ifndef USE_ALT_ADDRBOOK
112 #include "addressbook.h"
113 #else
114 #include "addressbook-dbus.h"
115 #endif
116 #include "compose.h"
117 #include "folder.h"
118 #include "folder_item_prefs.h"
119 #include "setup.h"
120 #include "utils.h"
121 #include "gtkutils.h"
122 #include "socket.h"
123 #include "log.h"
124 #include "prefs_toolbar.h"
125 #include "plugin.h"
126 #include "mh_gtk.h"
127 #include "imap_gtk.h"
128 #include "news_gtk.h"
129 #include "matcher.h"
130 #include "tags.h"
131 #include "hooks.h"
132 #include "menu.h"
133 #include "quicksearch.h"
134 #include "advsearch.h"
135 #include "avatars.h"
136 #include "passwordstore.h"
137 #include "file-utils.h"
139 #ifdef HAVE_LIBETPAN
140 #include "imap-thread.h"
141 #include "nntp-thread.h"
142 #endif
143 #include "stock_pixmap.h"
144 #ifdef USE_GNUTLS
145 # include "ssl.h"
146 #endif
148 #include "version.h"
150 #include "crash.h"
152 #include "timing.h"
154 #ifdef HAVE_NETWORKMANAGER_SUPPORT
155 /* Went offline due to NetworkManager */
156 static gboolean went_offline_nm;
157 #endif
160 #ifdef HAVE_DBUS_GLIB
161 static DBusGProxy *awn_proxy = NULL;
162 #endif
164 gchar *prog_version;
165 #if (defined HAVE_LIBSM || defined CRASH_DIALOG)
166 gchar *argv0;
167 #endif
169 #ifdef HAVE_STARTUP_NOTIFICATION
170 static SnLauncheeContext *sn_context = NULL;
171 static SnDisplay *sn_display = NULL;
172 #endif
174 static gint lock_socket = -1;
175 static gint lock_socket_tag = 0;
177 typedef enum
179 ONLINE_MODE_DONT_CHANGE,
180 ONLINE_MODE_ONLINE,
181 ONLINE_MODE_OFFLINE
182 } OnlineMode;
184 static struct RemoteCmd {
185 gboolean receive;
186 gboolean receive_all;
187 gboolean cancel_receiving;
188 gboolean cancel_sending;
189 gboolean compose;
190 const gchar *compose_mailto;
191 GList *attach_files;
192 gboolean search;
193 const gchar *search_folder;
194 const gchar *search_type;
195 const gchar *search_request;
196 gboolean search_recursive;
197 gboolean status;
198 gboolean status_full;
199 gboolean statistics;
200 gboolean reset_statistics;
201 GPtrArray *status_folders;
202 GPtrArray *status_full_folders;
203 gboolean send;
204 gboolean crash;
205 int online_mode;
206 gchar *crash_params;
207 gboolean exit;
208 gboolean subscribe;
209 const gchar *subscribe_uri;
210 const gchar *target;
211 gboolean debug;
212 const gchar *geometry;
213 } cmd;
215 SessionStats session_stats;
217 static void reset_statistics(void);
219 static void parse_cmd_opt(int argc, char *argv[]);
221 static gint prohibit_duplicate_launch (int *argc,
222 char ***argv);
223 static gchar * get_crashfile_name (void);
224 static gint lock_socket_remove (void);
225 static void lock_socket_input_cb (gpointer data,
226 gint source,
227 GIOCondition condition);
229 static void open_compose_new (const gchar *address,
230 GList *attach_files);
232 static void send_queue (void);
233 static void initial_processing (FolderItem *item, gpointer data);
234 #ifndef G_OS_WIN32
235 static void quit_signal_handler (int sig);
236 #endif
237 static void install_basic_sighandlers (void);
238 #if (defined linux && defined SIGIO)
239 static void install_memory_sighandler (void);
240 #endif
241 static void exit_claws (MainWindow *mainwin);
243 #ifdef HAVE_NETWORKMANAGER_SUPPORT
244 static void networkmanager_state_change_cb(DBusGProxy *proxy, gchar *dev,
245 gpointer data);
246 #endif
248 #define MAKE_DIR_IF_NOT_EXIST(dir) \
250 if (!is_dir_exist(dir)) { \
251 if (is_file_exist(dir)) { \
252 alertpanel_warning \
253 (_("File '%s' already exists.\n" \
254 "Can't create folder."), \
255 dir); \
256 return 1; \
258 if (make_dir(dir) < 0) \
259 return 1; \
263 #define STRNCMP(S1, S2) (strncmp((S1), (S2), sizeof((S2)) - 1))
265 #define CM_FD_WRITE(S) fd_write(sock, (S), strlen((S)))
266 #define CM_FD_WRITE_ALL(S) fd_write_all(sock, (S), strlen((S)))
268 static MainWindow *static_mainwindow;
270 static gboolean emergency_exit = FALSE;
272 #ifdef HAVE_STARTUP_NOTIFICATION
273 static void sn_error_trap_push(SnDisplay *display, Display *xdisplay)
275 gdk_error_trap_push();
278 static void sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
280 gdk_error_trap_pop();
283 static void startup_notification_complete(gboolean with_window)
285 Display *xdisplay;
286 GtkWidget *hack = NULL;
288 if (with_window) {
289 /* this is needed to make the startup notification leave,
290 * if we have been launched from a menu.
291 * We have to display a window, so let it be very little */
292 hack = gtk_window_new(GTK_WINDOW_POPUP);
293 gtk_window_move(GTK_WINDOW(hack), 0, 0);
294 gtk_widget_set_size_request(hack, 1, 1);
295 gtk_widget_show(hack);
298 xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
299 sn_display = sn_display_new(xdisplay,
300 sn_error_trap_push,
301 sn_error_trap_pop);
302 sn_context = sn_launchee_context_new_from_environment(sn_display,
303 DefaultScreen(xdisplay));
305 if (sn_context != NULL) {
306 sn_launchee_context_complete(sn_context);
307 sn_launchee_context_unref(sn_context);
308 sn_display_unref(sn_display);
310 if (with_window) {
311 gtk_widget_destroy(hack);
314 #endif /* HAVE_STARTUP_NOTIFICATION */
316 static void claws_gtk_idle(void)
318 while(gtk_events_pending()) {
319 gtk_main_iteration();
321 g_usleep(50000);
324 static gboolean sc_starting = FALSE;
326 static gboolean defer_check_all(void *data)
328 gboolean autochk = GPOINTER_TO_INT(data);
330 if (!sc_starting) {
331 inc_all_account_mail(static_mainwindow, autochk, FALSE,
332 prefs_common.newmail_notify_manu);
334 } else {
335 inc_all_account_mail(static_mainwindow, FALSE,
336 prefs_common.chk_on_startup,
337 prefs_common.newmail_notify_manu);
338 sc_starting = FALSE;
339 main_window_set_menu_sensitive(static_mainwindow);
340 toolbar_main_set_sensitive(static_mainwindow);
342 return FALSE;
345 static gboolean defer_check(void *data)
347 inc_mail(static_mainwindow, prefs_common.newmail_notify_manu);
349 if (sc_starting) {
350 sc_starting = FALSE;
351 main_window_set_menu_sensitive(static_mainwindow);
352 toolbar_main_set_sensitive(static_mainwindow);
354 return FALSE;
357 static gboolean defer_jump(void *data)
359 if (cmd.receive_all) {
360 defer_check_all(GINT_TO_POINTER(FALSE));
361 } else if (prefs_common.chk_on_startup) {
362 defer_check_all(GINT_TO_POINTER(TRUE));
363 } else if (cmd.receive) {
364 defer_check(NULL);
366 mainwindow_jump_to(data, FALSE);
367 if (sc_starting) {
368 sc_starting = FALSE;
369 main_window_set_menu_sensitive(static_mainwindow);
370 toolbar_main_set_sensitive(static_mainwindow);
372 return FALSE;
375 static void chk_update_val(GtkWidget *widget, gpointer data)
377 gboolean *val = (gboolean *)data;
378 *val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
381 static gboolean migrate_old_config(const gchar *old_cfg_dir, const gchar *new_cfg_dir, const gchar *oldversion)
383 gchar *message = g_strdup_printf(_("Configuration for %s found.\n"
384 "Do you want to migrate this configuration?"), oldversion);
386 if (!strcmp(oldversion, "Sylpheed")) {
387 gchar *message2 = g_strdup_printf(_("\n\nYour Sylpheed filtering rules can be converted by a\n"
388 "script available at %s."), TOOLS_URI);
389 gchar *tmp = g_strconcat(message, message2, NULL);
390 g_free(message2);
391 g_free(message);
392 message = tmp;
395 gint r = 0;
396 GtkWidget *window = NULL;
397 GtkWidget *keep_backup_chk;
398 gboolean backup = TRUE;
400 keep_backup_chk = gtk_check_button_new_with_label (_("Keep old configuration"));
401 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keep_backup_chk), TRUE);
402 CLAWS_SET_TIP(keep_backup_chk,
403 _("Keeping a backup will allow you to go back to an "
404 "older version, but may take a while if you have "
405 "cached IMAP or News data, and will take some extra "
406 "room on your disk."));
408 g_signal_connect(G_OBJECT(keep_backup_chk), "toggled",
409 G_CALLBACK(chk_update_val), &backup);
411 if (alertpanel_full(_("Migration of configuration"), message,
412 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_SECOND,
413 FALSE, keep_backup_chk, ALERT_QUESTION) != G_ALERTALTERNATE) {
414 return FALSE;
417 /* we can either do a fast migration requiring not any extra disk
418 * space, or a slow one that copies the old configuration and leaves
419 * it in place. */
420 if (backup) {
421 backup_mode:
422 window = label_window_create(_("Copying configuration... This may take a while..."));
423 GTK_EVENTS_FLUSH();
425 r = copy_dir(old_cfg_dir, new_cfg_dir);
426 label_window_destroy(window);
428 /* if copy failed, we'll remove the partially copied
429 * new directory */
430 if (r != 0) {
431 alertpanel_error(_("Migration failed!"));
432 remove_dir_recursive(new_cfg_dir);
433 } else {
434 if (!backup) {
435 /* fast mode failed, but we don't want backup */
436 remove_dir_recursive(old_cfg_dir);
439 } else {
440 window = label_window_create(_("Migrating configuration..."));
441 GTK_EVENTS_FLUSH();
443 r = g_rename(old_cfg_dir, new_cfg_dir);
444 label_window_destroy(window);
446 /* if g_rename failed, we'll try to copy */
447 if (r != 0) {
448 FILE_OP_ERROR(new_cfg_dir, "g_rename");
449 debug_print("rename failed, trying copy\n");
450 goto backup_mode;
453 return (r == 0);
456 static int migrate_common_rc(const gchar *old_rc, const gchar *new_rc)
458 FILE *oldfp, *newfp;
459 gchar *plugin_path, *old_plugin_path, *new_plugin_path;
460 gchar buf[BUFFSIZE];
461 gboolean err = FALSE;
463 oldfp = claws_fopen(old_rc, "r");
464 if (!oldfp)
465 return -1;
466 newfp = claws_fopen(new_rc, "w");
467 if (!newfp) {
468 claws_fclose(oldfp);
469 return -1;
472 plugin_path = g_strdup(get_plugin_dir());
473 new_plugin_path = g_strdup(plugin_path);
475 if (strstr(plugin_path, "/claws-mail/")) {
476 gchar *end = g_strdup(strstr(plugin_path, "/claws-mail/")+strlen("/claws-mail/"));
477 *(strstr(plugin_path, "/claws-mail/")) = '\0';
478 old_plugin_path = g_strconcat(plugin_path, "/sylpheed-claws/", end, NULL);
479 g_free(end);
480 } else {
481 old_plugin_path = g_strdup(new_plugin_path);
483 debug_print("replacing %s with %s\n", old_plugin_path, new_plugin_path);
484 while (claws_fgets(buf, sizeof(buf), oldfp)) {
485 if (STRNCMP(buf, old_plugin_path)) {
486 err |= (claws_fputs(buf, newfp) == EOF);
487 } else {
488 debug_print("->replacing %s\n", buf);
489 debug_print(" with %s%s\n", new_plugin_path, buf+strlen(old_plugin_path));
490 err |= (claws_fputs(new_plugin_path, newfp) == EOF);
491 err |= (claws_fputs(buf+strlen(old_plugin_path), newfp) == EOF);
494 g_free(plugin_path);
495 g_free(new_plugin_path);
496 g_free(old_plugin_path);
497 claws_fclose(oldfp);
498 if (claws_safe_fclose(newfp) == EOF)
499 err = TRUE;
501 return (err ? -1:0);
504 #ifdef HAVE_LIBSM
505 static void
506 sc_client_set_value (MainWindow *mainwin,
507 gchar *name,
508 char *type,
509 int num_vals,
510 SmPropValue *vals)
512 SmProp *proplist[1];
513 SmProp prop;
515 prop.name = name;
516 prop.type = type;
517 prop.num_vals = num_vals;
518 prop.vals = vals;
520 proplist[0]= &prop;
521 if (mainwin->smc_conn)
522 SmcSetProperties ((SmcConn) mainwin->smc_conn, 1, proplist);
525 static void sc_die_callback (SmcConn smc_conn, SmPointer client_data)
527 clean_quit(NULL);
530 static void sc_save_complete_callback(SmcConn smc_conn, SmPointer client_data)
534 static void sc_shutdown_cancelled_callback (SmcConn smc_conn, SmPointer client_data)
536 MainWindow *mainwin = (MainWindow *)client_data;
537 if (mainwin->smc_conn)
538 SmcSaveYourselfDone ((SmcConn) mainwin->smc_conn, TRUE);
541 static void sc_save_yourself_callback (SmcConn smc_conn,
542 SmPointer client_data,
543 int save_style,
544 gboolean shutdown,
545 int interact_style,
546 gboolean fast) {
548 MainWindow *mainwin = (MainWindow *)client_data;
549 if (mainwin->smc_conn)
550 SmcSaveYourselfDone ((SmcConn) mainwin->smc_conn, TRUE);
553 static IceIOErrorHandler sc_ice_installed_handler;
555 static void sc_ice_io_error_handler (IceConn connection)
557 if (sc_ice_installed_handler)
558 (*sc_ice_installed_handler) (connection);
560 static gboolean sc_process_ice_messages (GIOChannel *source,
561 GIOCondition condition,
562 gpointer data)
564 IceConn connection = (IceConn) data;
565 IceProcessMessagesStatus status;
567 status = IceProcessMessages (connection, NULL, NULL);
569 if (status == IceProcessMessagesIOError) {
570 IcePointer context = IceGetConnectionContext (connection);
572 if (context && G_IS_OBJECT(context)) {
573 guint disconnect_id = g_signal_lookup ("disconnect", G_OBJECT_TYPE (context));
575 if (disconnect_id > 0)
576 g_signal_emit (context, disconnect_id, 0);
577 } else {
578 IceSetShutdownNegotiation (connection, False);
579 IceCloseConnection (connection);
583 return TRUE;
586 static void new_ice_connection (IceConn connection, IcePointer client_data, Bool opening,
587 IcePointer *watch_data)
589 guint input_id;
591 if (opening) {
592 GIOChannel *channel;
593 /* Make sure we don't pass on these file descriptors to any
594 exec'ed children */
595 fcntl(IceConnectionNumber(connection),F_SETFD,
596 fcntl(IceConnectionNumber(connection),F_GETFD,0) | FD_CLOEXEC);
598 channel = g_io_channel_unix_new (IceConnectionNumber (connection));
599 input_id = g_io_add_watch (channel,
600 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
601 sc_process_ice_messages,
602 connection);
603 g_io_channel_unref (channel);
605 *watch_data = (IcePointer) GUINT_TO_POINTER (input_id);
606 } else {
607 input_id = GPOINTER_TO_UINT ((gpointer) *watch_data);
608 g_source_remove (input_id);
612 static void sc_session_manager_connect(MainWindow *mainwin)
614 static gboolean connected = FALSE;
615 SmcCallbacks callbacks;
616 gchar *client_id;
617 IceIOErrorHandler default_handler;
619 if (connected)
620 return;
621 connected = TRUE;
624 sc_ice_installed_handler = IceSetIOErrorHandler (NULL);
625 default_handler = IceSetIOErrorHandler (sc_ice_io_error_handler);
627 if (sc_ice_installed_handler == default_handler)
628 sc_ice_installed_handler = NULL;
630 IceAddConnectionWatch (new_ice_connection, NULL);
633 callbacks.save_yourself.callback = sc_save_yourself_callback;
634 callbacks.die.callback = sc_die_callback;
635 callbacks.save_complete.callback = sc_save_complete_callback;
636 callbacks.shutdown_cancelled.callback = sc_shutdown_cancelled_callback;
638 callbacks.save_yourself.client_data =
639 callbacks.die.client_data =
640 callbacks.save_complete.client_data =
641 callbacks.shutdown_cancelled.client_data = (SmPointer) mainwin;
642 if (g_getenv ("SESSION_MANAGER")) {
643 gchar error_string_ret[256] = "";
645 mainwin->smc_conn = (gpointer)
646 SmcOpenConnection (NULL, mainwin,
647 SmProtoMajor, SmProtoMinor,
648 SmcSaveYourselfProcMask | SmcDieProcMask |
649 SmcSaveCompleteProcMask |
650 SmcShutdownCancelledProcMask,
651 &callbacks,
652 NULL, &client_id,
653 256, error_string_ret);
655 /* From https://www.x.org/releases/X11R7.7/doc/libSM/SMlib.txt:
656 * If SmcOpenConnection succeeds, it returns an opaque connection
657 * pointer of type SmcConn and the client_id_ret argument contains
658 * the client ID to be used for this session. The client_id_ret
659 * should be freed with a call to free when no longer needed. On
660 * failure, SmcOpenConnection returns NULL, and the reason for
661 * failure is returned in error_string_ret. */
662 if (mainwin->smc_conn != NULL)
663 g_free(client_id);
665 if (error_string_ret[0] || mainwin->smc_conn == NULL)
666 g_warning("while connecting to session manager: %s",
667 error_string_ret);
668 else {
669 SmPropValue *vals;
670 vals = g_new (SmPropValue, 1);
671 vals[0].length = strlen(argv0);
672 vals[0].value = argv0;
673 sc_client_set_value (mainwin, SmCloneCommand, SmLISTofARRAY8, 1, vals);
674 sc_client_set_value (mainwin, SmRestartCommand, SmLISTofARRAY8, 1, vals);
675 sc_client_set_value (mainwin, SmProgram, SmARRAY8, 1, vals);
677 vals[0].length = strlen(g_get_user_name()?g_get_user_name():"");
678 vals[0].value = g_strdup(g_get_user_name()?g_get_user_name():"");
679 sc_client_set_value (mainwin, SmUserID, SmARRAY8, 1, vals);
681 g_free(vals[0].value);
682 g_free(vals);
686 #endif
688 static gboolean sc_exiting = FALSE;
689 static gboolean show_at_startup = TRUE;
690 static gboolean claws_crashed_bool = FALSE;
692 gboolean claws_crashed(void) {
693 return claws_crashed_bool;
696 void main_set_show_at_startup(gboolean show)
698 show_at_startup = show;
701 #ifdef G_OS_WIN32
702 static HANDLE win32_debug_log = NULL;
703 static guint win32_log_handler_app_id;
704 static guint win32_log_handler_glib_id;
705 static guint win32_log_handler_gtk_id;
707 static void win32_log_WriteFile(const gchar *string)
709 BOOL ret;
710 DWORD bytes_written;
712 ret = WriteFile(win32_debug_log, string, strlen(string), &bytes_written, NULL);
713 if (!ret) {
714 DWORD err = GetLastError();
715 gchar *tmp;
717 tmp = g_strdup_printf("Error: WriteFile in failed with error 0x%lx. Buffer contents:\n%s", err, string);
718 OutputDebugString(tmp);
719 g_free(tmp);
723 static void win32_print_stdout(const gchar *string)
725 if (win32_debug_log) {
726 win32_log_WriteFile(string);
730 GLogWriterOutput win32_log_writer(GLogLevelFlags log_level, const GLogField *fields, gsize n_fields, gpointer user_data)
732 gchar *formatted;
733 gchar *out;
735 g_return_val_if_fail(win32_debug_log != NULL, G_LOG_WRITER_UNHANDLED);
736 g_return_val_if_fail(fields != NULL, G_LOG_WRITER_UNHANDLED);
737 g_return_val_if_fail(n_fields > 0, G_LOG_WRITER_UNHANDLED);
739 formatted = g_log_writer_format_fields(log_level, fields, n_fields, FALSE);
740 out = g_strdup_printf("%s\n", formatted);
742 win32_log_WriteFile(out);
744 g_free(formatted);
745 g_free(out);
747 return G_LOG_WRITER_HANDLED;
750 static void win32_log(const gchar *log_domain, GLogLevelFlags log_level, const gchar* message, gpointer user_data)
752 gchar *out;
754 if (win32_debug_log) {
755 const gchar* type;
757 switch(log_level & G_LOG_LEVEL_MASK)
759 case G_LOG_LEVEL_ERROR:
760 type="error";
761 break;
762 case G_LOG_LEVEL_CRITICAL:
763 type="critical";
764 break;
765 case G_LOG_LEVEL_WARNING:
766 type="warning";
767 break;
768 case G_LOG_LEVEL_MESSAGE:
769 type="message";
770 break;
771 case G_LOG_LEVEL_INFO:
772 type="info";
773 break;
774 case G_LOG_LEVEL_DEBUG:
775 type="debug";
776 break;
777 default:
778 type="N/A";
781 if (log_domain)
782 out = g_strdup_printf("%s: %s: %s", log_domain, type, message);
783 else
784 out = g_strdup_printf("%s: %s", type, message);
786 win32_log_WriteFile(out);
788 g_free(out);
792 static void win32_open_log(void)
794 gchar *logfile = win32_debug_log_path();
795 gchar *oldlogfile = g_strconcat(logfile, ".bak", NULL);
797 if (is_file_exist(logfile)) {
798 if (rename_force(logfile, oldlogfile) < 0)
799 FILE_OP_ERROR(logfile, "rename");
802 win32_debug_log = CreateFile(logfile,
803 GENERIC_WRITE,
804 FILE_SHARE_READ,
805 NULL,
806 CREATE_NEW,
807 FILE_ATTRIBUTE_NORMAL,
808 NULL);
810 if (win32_debug_log == INVALID_HANDLE_VALUE) {
811 win32_debug_log = NULL;
814 g_free(logfile);
815 g_free(oldlogfile);
817 if (win32_debug_log) {
818 g_set_print_handler(win32_print_stdout);
819 g_set_printerr_handler(win32_print_stdout);
821 win32_log_handler_app_id = g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
822 | G_LOG_FLAG_RECURSION, win32_log, NULL);
823 win32_log_handler_glib_id = g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
824 | G_LOG_FLAG_RECURSION, win32_log, NULL);
825 win32_log_handler_gtk_id = g_log_set_handler("Gtk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
826 | G_LOG_FLAG_RECURSION, win32_log, NULL);
828 g_log_set_writer_func(&win32_log_writer, NULL, NULL);
832 static void win32_close_log(void)
834 if (win32_debug_log) {
835 g_log_remove_handler("", win32_log_handler_app_id);
836 g_log_remove_handler("GLib", win32_log_handler_glib_id);
837 g_log_remove_handler("Gtk", win32_log_handler_gtk_id);
838 CloseHandle(win32_debug_log);
839 win32_debug_log = NULL;
842 #endif
844 static void main_dump_features_list(gboolean show_debug_only)
845 /* display compiled-in features list */
847 if (show_debug_only && !debug_get_mode())
848 return;
850 if (show_debug_only)
851 debug_print("runtime GTK %d.%d.%d / GLib %d.%d.%d\n",
852 gtk_major_version, gtk_minor_version, gtk_micro_version,
853 glib_major_version, glib_minor_version, glib_micro_version);
854 else
855 g_print("runtime GTK %d.%d.%d / GLib %d.%d.%d\n",
856 gtk_major_version, gtk_minor_version, gtk_micro_version,
857 glib_major_version, glib_minor_version, glib_micro_version);
858 if (show_debug_only)
859 debug_print("buildtime GTK %d.%d.%d / GLib %d.%d.%d\n",
860 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
861 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
862 else
863 g_print("buildtime GTK %d.%d.%d / GLib %d.%d.%d\n",
864 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
865 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
867 if (show_debug_only)
868 debug_print("Compiled-in features:\n");
869 else
870 g_print("Compiled-in features:\n");
871 #if HAVE_LIBCOMPFACE
872 if (show_debug_only)
873 debug_print(" compface\n");
874 else
875 g_print(" compface\n");
876 #endif
877 #if USE_ENCHANT
878 if (show_debug_only)
879 debug_print(" Enchant\n");
880 else
881 g_print(" Enchant\n");
882 #endif
883 #if USE_GNUTLS
884 if (show_debug_only)
885 debug_print(" GnuTLS\n");
886 else
887 g_print(" GnuTLS\n");
888 #endif
889 #if INET6
890 if (show_debug_only)
891 debug_print(" IPv6\n");
892 else
893 g_print(" IPv6\n");
894 #endif
895 #if HAVE_ICONV
896 if (show_debug_only)
897 debug_print(" iconv\n");
898 else
899 g_print(" iconv\n");
900 #endif
901 #if USE_JPILOT
902 if (show_debug_only)
903 debug_print(" JPilot\n");
904 else
905 g_print(" JPilot\n");
906 #endif
907 #if USE_LDAP
908 if (show_debug_only)
909 debug_print(" LDAP\n");
910 else
911 g_print(" LDAP\n");
912 #endif
913 #if HAVE_LIBETPAN
914 if (show_debug_only)
915 debug_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR, LIBETPAN_VERSION_MINOR);
916 else
917 g_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR, LIBETPAN_VERSION_MINOR);
918 #endif
919 #if HAVE_LIBSM
920 if (show_debug_only)
921 debug_print(" libSM\n");
922 else
923 g_print(" libSM\n");
924 #endif
925 #if HAVE_NETWORKMANAGER_SUPPORT
926 if (show_debug_only)
927 debug_print(" NetworkManager\n");
928 else
929 g_print(" NetworkManager\n");
930 #endif
931 #if HAVE_SVG
932 if (show_debug_only)
933 debug_print(" librSVG " LIBRSVG_VERSION "\n");
934 else
935 g_print(" librSVG " LIBRSVG_VERSION "\n");
936 #endif
939 #ifdef HAVE_DBUS_GLIB
940 static gulong dbus_item_hook_id = HOOK_NONE;
941 static gulong dbus_folder_hook_id = HOOK_NONE;
943 static void uninstall_dbus_status_handler(void)
945 if(awn_proxy)
946 g_object_unref(awn_proxy);
947 awn_proxy = NULL;
948 if (dbus_item_hook_id != HOOK_NONE)
949 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, dbus_item_hook_id);
950 if (dbus_folder_hook_id != HOOK_NONE)
951 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, dbus_folder_hook_id);
954 static void dbus_update(FolderItem *removed_item)
956 guint new, unread, unreadmarked, marked, total;
957 guint replied, forwarded, locked, ignored, watched;
958 gchar *buf;
959 GError *error = NULL;
961 folder_count_total_msgs(&new, &unread, &unreadmarked, &marked, &total,
962 &replied, &forwarded, &locked, &ignored,
963 &watched);
964 if (removed_item) {
965 total -= removed_item->total_msgs;
966 new -= removed_item->new_msgs;
967 unread -= removed_item->unread_msgs;
970 if (new > 0) {
971 buf = g_strdup_printf("%d", new);
972 dbus_g_proxy_call(awn_proxy, "SetInfoByName", &error,
973 G_TYPE_STRING, "claws-mail",
974 G_TYPE_STRING, buf,
975 G_TYPE_INVALID, G_TYPE_INVALID);
976 g_free(buf);
978 } else {
979 dbus_g_proxy_call(awn_proxy, "UnsetInfoByName", &error, G_TYPE_STRING,
980 "claws-mail", G_TYPE_INVALID, G_TYPE_INVALID);
982 if (error) {
983 debug_print("%s\n", error->message);
984 g_error_free(error);
988 static gboolean dbus_status_update_folder_hook(gpointer source, gpointer data)
990 FolderUpdateData *hookdata;
991 hookdata = source;
992 if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
993 dbus_update(hookdata->item);
994 else
995 dbus_update(NULL);
997 return FALSE;
1000 static gboolean dbus_status_update_item_hook(gpointer source, gpointer data)
1002 dbus_update(NULL);
1004 return FALSE;
1007 static void install_dbus_status_handler(void)
1009 GError *tmp_error = NULL;
1010 DBusGConnection *connection = dbus_g_bus_get(DBUS_BUS_SESSION, &tmp_error);
1012 if(!connection) {
1013 /* If calling code doesn't do error checking, at least print some debug */
1014 debug_print("Failed to open connection to session bus: %s\n",
1015 tmp_error->message);
1016 g_error_free(tmp_error);
1017 return;
1019 awn_proxy = dbus_g_proxy_new_for_name(connection,
1020 "com.google.code.Awn",
1021 "/com/google/code/Awn",
1022 "com.google.code.Awn");
1023 dbus_item_hook_id = hooks_register_hook (FOLDER_ITEM_UPDATE_HOOKLIST, dbus_status_update_item_hook, NULL);
1024 if (dbus_item_hook_id == HOOK_NONE) {
1025 g_warning("failed to register folder item update hook");
1026 uninstall_dbus_status_handler();
1027 return;
1030 dbus_folder_hook_id = hooks_register_hook (FOLDER_UPDATE_HOOKLIST, dbus_status_update_folder_hook, NULL);
1031 if (dbus_folder_hook_id == HOOK_NONE) {
1032 g_warning("failed to register folder update hook");
1033 uninstall_dbus_status_handler();
1034 return;
1037 #endif
1039 static void reset_statistics(void)
1041 /* (re-)initialize session statistics */
1042 session_stats.received = 0;
1043 session_stats.sent = 0;
1044 session_stats.replied = 0;
1045 session_stats.forwarded = 0;
1046 session_stats.time_started = time(NULL);
1049 int main(int argc, char *argv[])
1051 #ifdef HAVE_DBUS_GLIB
1052 DBusGConnection *connection;
1053 GError *error;
1054 #endif
1055 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1056 DBusGProxy *nm_proxy;
1057 #endif
1058 gchar *userrc;
1059 MainWindow *mainwin;
1060 FolderView *folderview;
1061 GdkPixbuf *icon;
1062 gboolean crash_file_present = FALSE;
1063 guint num_folder_class = 0;
1064 gboolean asked_for_migration = FALSE;
1065 gboolean start_done = TRUE;
1066 GSList *plug_list = NULL;
1067 gboolean never_ran = FALSE;
1068 gboolean mainwin_shown = FALSE;
1069 gint ret;
1071 START_TIMING("startup");
1073 sc_starting = TRUE;
1075 #ifdef G_OS_WIN32
1076 win32_open_log();
1077 #endif
1078 if (!claws_init(&argc, &argv)) {
1079 #ifdef G_OS_WIN32
1080 win32_close_log();
1081 #endif
1082 return 0;
1085 prog_version = PROG_VERSION;
1086 #if (defined HAVE_LIBSM || defined CRASH_DIALOG)
1087 argv0 = g_strdup(argv[0]);
1088 #endif
1090 parse_cmd_opt(argc, argv);
1092 sock_init();
1094 /* check and create unix domain socket for remote operation */
1095 lock_socket = prohibit_duplicate_launch(&argc, &argv);
1096 if (lock_socket < 0) {
1097 #ifdef HAVE_STARTUP_NOTIFICATION
1098 #ifdef GDK_WINDOWING_X11
1099 if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
1100 if (gtk_init_check(&argc, &argv))
1101 startup_notification_complete(TRUE);
1103 #endif
1104 #endif
1105 return 0;
1108 main_dump_features_list(TRUE);
1109 prefs_prepare_cache();
1111 #ifdef CRASH_DIALOG
1112 if (cmd.crash) {
1113 gtk_init(&argc, &argv);
1114 crash_main(cmd.crash_params);
1115 #ifdef G_OS_WIN32
1116 win32_close_log();
1117 #endif
1118 return 0;
1120 crash_install_handlers();
1121 #endif
1122 install_basic_sighandlers();
1123 #if (defined linux && defined SIGIO)
1124 install_memory_sighandler();
1125 #endif
1127 if (cmd.status || cmd.status_full || cmd.search ||
1128 cmd.statistics || cmd.reset_statistics ||
1129 cmd.cancel_receiving || cmd.cancel_sending ||
1130 cmd.debug) {
1131 puts("0 Claws Mail not running.");
1132 lock_socket_remove();
1133 return 0;
1136 if (cmd.exit)
1137 return 0;
1139 reset_statistics();
1141 gtk_init(&argc, &argv);
1143 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1144 went_offline_nm = FALSE;
1145 nm_proxy = NULL;
1146 #endif
1147 #ifdef HAVE_DBUS_GLIB
1148 error = NULL;
1149 connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
1151 if(!connection) {
1152 debug_print("Failed to open connection to system bus: %s\n", error->message);
1153 g_error_free(error);
1155 else {
1156 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1157 nm_proxy = dbus_g_proxy_new_for_name(connection,
1158 "org.freedesktop.NetworkManager",
1159 "/org/freedesktop/NetworkManager",
1160 "org.freedesktop.NetworkManager");
1161 if (nm_proxy) {
1162 dbus_g_proxy_add_signal(nm_proxy, "StateChanged", G_TYPE_UINT, G_TYPE_INVALID);
1163 dbus_g_proxy_connect_signal(nm_proxy, "StateChanged",
1164 G_CALLBACK(networkmanager_state_change_cb),
1165 NULL,NULL);
1167 #endif
1168 install_dbus_status_handler();
1170 #endif
1172 gtkut_create_ui_manager();
1174 /* Create container for all the menus we will be adding */
1175 MENUITEM_ADDUI("/", "Menus", NULL, GTK_UI_MANAGER_MENUBAR);
1177 #ifdef G_OS_WIN32
1178 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1179 #else
1180 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1181 #endif
1183 /* no config dir exists. See if we can migrate an old config. */
1184 if (!is_dir_exist(get_rc_dir())) {
1185 prefs_destroy_cache();
1186 gboolean r = FALSE;
1188 /* if one of the old dirs exist, we'll ask if the user
1189 * want to migrates, and r will be TRUE if he said yes
1190 * and migration succeeded, and FALSE otherwise.
1192 if (is_dir_exist(OLD_GTK2_RC_DIR)) {
1193 r = migrate_old_config(OLD_GTK2_RC_DIR, get_rc_dir(),
1194 g_strconcat("Sylpheed-Claws 2.6.0 ", _("(or older)"), NULL));
1195 asked_for_migration = TRUE;
1196 } else if (is_dir_exist(OLDER_GTK2_RC_DIR)) {
1197 r = migrate_old_config(OLDER_GTK2_RC_DIR, get_rc_dir(),
1198 g_strconcat("Sylpheed-Claws 1.9.15 ",_("(or older)"), NULL));
1199 asked_for_migration = TRUE;
1200 } else if (is_dir_exist(OLD_GTK1_RC_DIR)) {
1201 r = migrate_old_config(OLD_GTK1_RC_DIR, get_rc_dir(),
1202 g_strconcat("Sylpheed-Claws 1.0.5 ",_("(or older)"), NULL));
1203 asked_for_migration = TRUE;
1204 } else if (is_dir_exist(SYLPHEED_RC_DIR)) {
1205 r = migrate_old_config(SYLPHEED_RC_DIR, get_rc_dir(), "Sylpheed");
1206 asked_for_migration = TRUE;
1209 /* If migration failed or the user didn't want to do it,
1210 * we create a new one (and we'll hit wizard later).
1212 if (r == FALSE && !is_dir_exist(get_rc_dir())) {
1213 #ifdef G_OS_UNIX
1214 if (copy_dir(SYSCONFDIR "/skel/.claws-mail", get_rc_dir()) < 0) {
1215 #endif
1216 if (!is_dir_exist(get_rc_dir()) && make_dir(get_rc_dir()) < 0) {
1217 #ifdef G_OS_WIN32
1218 win32_close_log();
1219 #endif
1220 exit(1);
1222 #ifdef G_OS_UNIX
1224 #endif
1229 if (!is_file_exist(RC_DIR G_DIR_SEPARATOR_S COMMON_RC) &&
1230 is_file_exist(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC)) {
1231 /* post 2.6 name change */
1232 migrate_common_rc(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC,
1233 RC_DIR G_DIR_SEPARATOR_S COMMON_RC);
1236 if (!cmd.exit)
1237 plugin_load_all("Common");
1239 userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL);
1240 gtk_rc_parse(userrc);
1241 g_free(userrc);
1243 userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
1244 gtk_accel_map_load (userrc);
1245 g_free(userrc);
1247 #ifdef G_OS_WIN32
1248 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_rc_dir(), 1, win32_close_log(););
1249 #else
1250 CHDIR_RETURN_VAL_IF_FAIL(get_rc_dir(), 1);
1251 #endif
1253 MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
1254 MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
1255 MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
1256 MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
1257 MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
1258 MAKE_DIR_IF_NOT_EXIST(UIDL_DIR);
1260 crash_file_present = is_file_exist(get_crashfile_name());
1261 /* remove temporary files */
1262 remove_all_files(get_tmp_dir());
1263 remove_all_files(get_mime_tmp_dir());
1265 if (!cmd.crash && crash_file_present)
1266 claws_crashed_bool = TRUE;
1268 if (is_file_exist("claws.log")) {
1269 if (rename_force("claws.log", "claws.log.bak") < 0)
1270 FILE_OP_ERROR("claws.log", "rename");
1272 set_log_file(LOG_PROTOCOL, "claws.log");
1274 if (is_file_exist("filtering.log")) {
1275 if (rename_force("filtering.log", "filtering.log.bak") < 0)
1276 FILE_OP_ERROR("filtering.log", "rename");
1278 set_log_file(LOG_DEBUG_FILTERING, "filtering.log");
1280 #ifdef G_OS_WIN32
1281 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1282 #else
1283 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1284 #endif
1286 folder_system_init();
1287 prefs_common_read_config();
1289 if (prefs_update_config_version_common() < 0) {
1290 debug_print("Main configuration file version upgrade failed, exiting\n");
1291 #ifdef G_OS_WIN32
1292 win32_close_log();
1293 #endif
1294 exit(200);
1297 prefs_themes_init();
1298 prefs_fonts_init();
1299 prefs_ext_prog_init();
1300 prefs_wrapping_init();
1301 prefs_compose_writing_init();
1302 prefs_msg_colors_init();
1303 image_viewer_init();
1304 prefs_image_viewer_init();
1305 prefs_quote_init();
1306 prefs_summaries_init();
1307 prefs_message_init();
1308 prefs_other_init();
1309 prefs_proxy_init();
1310 prefs_logging_init();
1311 prefs_receive_init();
1312 prefs_send_init();
1313 tags_read_tags();
1314 matcher_init();
1315 #ifdef USE_ENCHANT
1316 gtkaspell_checkers_init();
1317 prefs_spelling_init();
1318 #endif
1320 codeconv_set_allow_jisx0201_kana(prefs_common.allow_jisx0201_kana);
1321 codeconv_set_broken_are_utf8(prefs_common.broken_are_utf8);
1323 #ifdef G_OS_WIN32
1324 if(prefs_common.gtk_theme && strcmp(prefs_common.gtk_theme, DEFAULT_W32_GTK_THEME))
1325 gtk_settings_set_string_property(gtk_settings_get_default(),
1326 "gtk-theme-name",
1327 prefs_common.gtk_theme,
1328 "XProperty");
1329 #endif
1332 sock_set_io_timeout(prefs_common.io_timeout_secs);
1333 prefs_actions_read_config();
1334 prefs_display_header_read_config();
1335 /* prefs_filtering_read_config(); */
1336 #ifndef USE_ALT_ADDRBOOK
1337 addressbook_read_file();
1338 #else
1339 g_clear_error(&error);
1340 if (! addressbook_start_service(&error)) {
1341 g_warning("%s", error->message);
1342 g_clear_error(&error);
1344 else {
1345 addressbook_install_hooks(&error);
1347 #endif
1348 gtkut_widget_init();
1349 priv_pixbuf_gdk(PRIV_PIXMAP_CLAWS_MAIL_ICON, &icon);
1350 gtk_window_set_default_icon(icon);
1352 folderview_initialize();
1354 mh_gtk_init();
1355 imap_gtk_init();
1356 news_gtk_init();
1358 mainwin = main_window_create();
1360 if (!check_file_integrity())
1361 exit(1);
1363 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1364 networkmanager_state_change_cb(nm_proxy,NULL,mainwin);
1365 #endif
1367 manage_window_focus_in(mainwin->window, NULL, NULL);
1368 folderview = mainwin->folderview;
1370 folderview_freeze(mainwin->folderview);
1371 folder_item_update_freeze();
1373 if ((ret = passwd_store_read_config()) < 0) {
1374 debug_print("Password store configuration file version upgrade failed (%d), exiting\n", ret);
1375 #ifdef G_OS_WIN32
1376 win32_close_log();
1377 #endif
1378 exit(202);
1381 prefs_account_init();
1382 account_read_config_all();
1384 if (prefs_update_config_version_accounts() < 0) {
1385 debug_print("Accounts configuration file version upgrade failed, exiting\n");
1386 #ifdef G_OS_WIN32
1387 win32_close_log();
1388 #endif
1389 exit(201);
1392 #ifdef HAVE_LIBETPAN
1393 imap_main_init(prefs_common.skip_ssl_cert_check);
1394 imap_main_set_timeout(prefs_common.io_timeout_secs);
1395 nntp_main_init(prefs_common.skip_ssl_cert_check);
1396 #endif
1397 /* If we can't read a folder list or don't have accounts,
1398 * it means the configuration's not done. Either this is
1399 * a brand new install, a failed/refused migration,
1400 * or a failed config_version upgrade.
1402 if ((ret = folder_read_list()) < 0) {
1403 debug_print("Folderlist read failed (%d)\n", ret);
1404 prefs_destroy_cache();
1406 if (ret == -2) {
1407 /* config_version update failed in folder_read_list(). We
1408 * do not want to run the wizard, just exit. */
1409 debug_print("Folderlist version upgrade failed, exiting\n");
1410 #ifdef G_OS_WIN32
1411 win32_close_log();
1412 #endif
1413 exit(203);
1416 /* if run_wizard returns FALSE it's because it's
1417 * been cancelled. We can't do much but exit.
1418 * however, if the user was asked for a migration,
1419 * we remove the newly created directory so that
1420 * he's asked again for migration on next launch.*/
1421 if (!run_wizard(mainwin, TRUE)) {
1422 if (asked_for_migration)
1423 remove_dir_recursive(RC_DIR);
1424 #ifdef G_OS_WIN32
1425 win32_close_log();
1426 #endif
1427 exit(1);
1429 main_window_reflect_prefs_all_now();
1430 folder_write_list();
1431 never_ran = TRUE;
1434 if (!account_get_list()) {
1435 prefs_destroy_cache();
1436 if (!run_wizard(mainwin, FALSE)) {
1437 if (asked_for_migration)
1438 remove_dir_recursive(RC_DIR);
1439 #ifdef G_OS_WIN32
1440 win32_close_log();
1441 #endif
1442 exit(1);
1444 if(!account_get_list()) {
1445 exit_claws(mainwin);
1446 exit(1);
1448 never_ran = TRUE;
1452 toolbar_main_set_sensitive(mainwin);
1453 main_window_set_menu_sensitive(mainwin);
1455 /* if crashed, show window early so that the user
1456 * sees what's happening */
1457 if (claws_crashed()) {
1458 main_window_popup(mainwin);
1459 mainwin_shown = TRUE;
1462 account_set_missing_folder();
1463 folder_set_missing_folders();
1464 folderview_set(folderview);
1466 prefs_matcher_read_config();
1467 quicksearch_set_search_strings(mainwin->summaryview->quicksearch);
1469 /* make one all-folder processing before using claws */
1470 main_window_cursor_wait(mainwin);
1471 folder_func_to_all_folders(initial_processing, (gpointer *)mainwin);
1473 /* if claws crashed, rebuild caches */
1474 if (claws_crashed()) {
1475 GTK_EVENTS_FLUSH();
1476 debug_print("Claws Mail crashed, checking for new messages in local folders\n");
1477 folder_item_update_thaw();
1478 folderview_check_new(NULL);
1479 folder_clean_cache_memory_force();
1480 folder_item_update_freeze();
1482 /* make the crash-indicator file */
1483 if (str_write_to_file("foo", get_crashfile_name(), FALSE) < 0) {
1484 g_warning("can't create the crash-indicator file");
1487 inc_autocheck_timer_init(mainwin);
1489 /* ignore SIGPIPE signal for preventing sudden death of program */
1490 #ifdef G_OS_UNIX
1491 signal(SIGPIPE, SIG_IGN);
1492 #endif
1493 if (cmd.online_mode == ONLINE_MODE_OFFLINE) {
1494 main_window_toggle_work_offline(mainwin, TRUE, FALSE);
1496 if (cmd.online_mode == ONLINE_MODE_ONLINE) {
1497 main_window_toggle_work_offline(mainwin, FALSE, FALSE);
1500 if (cmd.status_folders) {
1501 g_ptr_array_free(cmd.status_folders, TRUE);
1502 cmd.status_folders = NULL;
1504 if (cmd.status_full_folders) {
1505 g_ptr_array_free(cmd.status_full_folders, TRUE);
1506 cmd.status_full_folders = NULL;
1509 claws_register_idle_function(claws_gtk_idle);
1511 avatars_init();
1512 prefs_toolbar_init();
1514 num_folder_class = g_list_length(folder_get_list());
1516 plugin_load_all("GTK3");
1518 if (g_list_length(folder_get_list()) != num_folder_class) {
1519 debug_print("new folders loaded, reloading processing rules\n");
1520 prefs_matcher_read_config();
1523 if ((plug_list = plugin_get_unloaded_list()) != NULL) {
1524 GSList *cur;
1525 gchar *list = NULL;
1526 gint num_plugins = 0;
1527 for (cur = plug_list; cur; cur = cur->next) {
1528 Plugin *plugin = (Plugin *)cur->data;
1529 gchar *tmp = g_strdup_printf("%s\n%s",
1530 list? list:"",
1531 plugin_get_name(plugin));
1532 g_free(list);
1533 list = tmp;
1534 num_plugins++;
1536 main_window_cursor_normal(mainwin);
1537 main_window_popup(mainwin);
1538 mainwin_shown = TRUE;
1539 alertpanel_warning(ngettext(
1540 "The following plugin failed to load. "
1541 "Check the Plugins configuration "
1542 "for more information:\n%s",
1543 "The following plugins failed to load. "
1544 "Check the Plugins configuration "
1545 "for more information:\n%s",
1546 num_plugins),
1547 list);
1548 main_window_cursor_wait(mainwin);
1549 g_free(list);
1550 g_slist_free(plug_list);
1553 if (never_ran) {
1554 prefs_common_write_config();
1555 plugin_load_standard_plugins ();
1558 /* if not crashed, show window now */
1559 if (!mainwin_shown) {
1560 /* apart if something told not to show */
1561 if (show_at_startup)
1562 main_window_popup(mainwin);
1565 if (cmd.geometry != NULL) {
1566 if (!gtk_window_parse_geometry(GTK_WINDOW(mainwin->window), cmd.geometry))
1567 g_warning("failed to parse geometry '%s'", cmd.geometry);
1568 else {
1569 int width, height;
1571 if (sscanf(cmd.geometry, "%ux%u+", &width, &height) == 2)
1572 gtk_window_resize(GTK_WINDOW(mainwin->window), width, height);
1573 else
1574 g_warning("failed to parse geometry's width/height");
1578 if (!folder_have_mailbox()) {
1579 prefs_destroy_cache();
1580 main_window_cursor_normal(mainwin);
1581 if (folder_get_list() != NULL) {
1582 alertpanel_error(_("Claws Mail has detected a configured "
1583 "mailbox, but it is incomplete. It is "
1584 "possibly due to a failing IMAP account. Use "
1585 "\"Rebuild folder tree\" on the mailbox parent "
1586 "folder's context menu to try to fix it."));
1587 } else {
1588 alertpanel_error(_("Claws Mail has detected a configured "
1589 "mailbox, but could not load it. It is "
1590 "probably provided by an out-of-date "
1591 "external plugin. Please reinstall the "
1592 "plugin and try again."));
1593 exit_claws(mainwin);
1594 exit(1);
1598 static_mainwindow = mainwin;
1600 #ifdef HAVE_STARTUP_NOTIFICATION
1601 #ifdef GDK_WINDOWING_X11
1602 if (GDK_IS_X11_DISPLAY(gdk_display_get_default()))
1603 startup_notification_complete(FALSE);
1604 #endif
1605 #endif
1606 #ifdef HAVE_LIBSM
1607 sc_session_manager_connect(mainwin);
1608 #endif
1610 folder_item_update_thaw();
1611 folderview_thaw(mainwin->folderview);
1612 main_window_cursor_normal(mainwin);
1614 if (!cmd.target && prefs_common.goto_last_folder_on_startup &&
1615 folder_find_item_from_identifier(prefs_common.last_opened_folder) != NULL &&
1616 !claws_crashed()) {
1617 cmd.target = prefs_common.last_opened_folder;
1620 if (cmd.receive_all && !cmd.target) {
1621 start_done = FALSE;
1622 g_timeout_add(1000, defer_check_all, GINT_TO_POINTER(FALSE));
1623 } else if (prefs_common.chk_on_startup && !cmd.target) {
1624 start_done = FALSE;
1625 g_timeout_add(1000, defer_check_all, GINT_TO_POINTER(TRUE));
1626 } else if (cmd.receive && !cmd.target) {
1627 start_done = FALSE;
1628 g_timeout_add(1000, defer_check, NULL);
1630 folderview_grab_focus(folderview);
1632 if (cmd.compose) {
1633 open_compose_new(cmd.compose_mailto, cmd.attach_files);
1635 if (cmd.attach_files) {
1636 list_free_strings_full(cmd.attach_files);
1637 cmd.attach_files = NULL;
1639 if (cmd.subscribe) {
1640 folder_subscribe(cmd.subscribe_uri);
1643 if (cmd.send) {
1644 send_queue();
1647 if (cmd.target) {
1648 start_done = FALSE;
1649 g_timeout_add(500, defer_jump, (gpointer)cmd.target);
1652 prefs_destroy_cache();
1654 compose_reopen_exit_drafts();
1656 if (start_done) {
1657 sc_starting = FALSE;
1658 main_window_set_menu_sensitive(mainwin);
1659 toolbar_main_set_sensitive(mainwin);
1662 /* register the callback of unix domain socket input */
1663 lock_socket_tag = claws_input_add(lock_socket,
1664 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
1665 lock_socket_input_cb,
1666 mainwin, TRUE);
1668 END_TIMING();
1670 gtk_main();
1672 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1673 if(nm_proxy)
1674 g_object_unref(nm_proxy);
1675 #endif
1676 #ifdef HAVE_DBUS_GLIB
1677 uninstall_dbus_status_handler();
1678 if(connection)
1679 dbus_g_connection_unref(connection);
1680 #endif
1681 utils_free_regex();
1682 exit_claws(mainwin);
1684 return 0;
1687 static void save_all_caches(FolderItem *item, gpointer data)
1689 if (!item->cache) {
1690 return;
1693 if (item->opened) {
1694 folder_item_close(item);
1697 folder_item_free_cache(item, TRUE);
1700 static void exit_claws(MainWindow *mainwin)
1702 gchar *filename;
1703 gboolean have_connectivity;
1704 FolderItem *item;
1706 sc_exiting = TRUE;
1708 debug_print("shutting down\n");
1709 inc_autocheck_timer_remove();
1711 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1712 if (prefs_common.work_offline && went_offline_nm)
1713 prefs_common.work_offline = FALSE;
1714 #endif
1716 /* save prefs for opened folder */
1717 if((item = folderview_get_opened_item(mainwin->folderview)) != NULL) {
1718 summary_save_prefs_to_folderitem(
1719 mainwin->summaryview, item);
1720 if (prefs_common.last_opened_folder != NULL)
1721 g_free(prefs_common.last_opened_folder);
1722 prefs_common.last_opened_folder =
1723 !prefs_common.goto_last_folder_on_startup ? NULL :
1724 folder_item_get_identifier(item);
1727 /* save all state before exiting */
1728 folder_func_to_all_folders(save_all_caches, NULL);
1729 folder_write_list();
1731 main_window_get_size(mainwin);
1732 main_window_get_position(mainwin);
1734 prefs_common_write_config();
1735 account_write_config_all();
1736 passwd_store_write_config();
1737 #ifndef USE_ALT_ADDRBOOK
1738 addressbook_export_to_file();
1739 #endif
1740 filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
1741 gtk_accel_map_save(filename);
1742 g_free(filename);
1744 /* delete temporary files */
1745 remove_all_files(get_tmp_dir());
1746 remove_all_files(get_mime_tmp_dir());
1748 close_log_file(LOG_PROTOCOL);
1749 close_log_file(LOG_DEBUG_FILTERING);
1751 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1752 have_connectivity = networkmanager_is_online(NULL);
1753 #else
1754 have_connectivity = TRUE;
1755 #endif
1756 #ifdef HAVE_LIBETPAN
1757 imap_main_done(have_connectivity);
1758 nntp_main_done(have_connectivity);
1759 #endif
1760 /* delete crashfile */
1761 if (!cmd.crash)
1762 claws_unlink(get_crashfile_name());
1764 lock_socket_remove();
1766 #ifdef HAVE_LIBSM
1767 if (mainwin->smc_conn)
1768 SmcCloseConnection ((SmcConn)mainwin->smc_conn, 0, NULL);
1769 mainwin->smc_conn = NULL;
1770 #endif
1772 main_window_destroy_all();
1774 plugin_unload_all("GTK3");
1776 matcher_done();
1777 prefs_toolbar_done();
1778 avatars_done();
1780 #ifndef USE_ALT_ADDRBOOK
1781 addressbook_destroy();
1782 #endif
1783 prefs_themes_done();
1784 prefs_fonts_done();
1785 prefs_ext_prog_done();
1786 prefs_wrapping_done();
1787 prefs_compose_writing_done();
1788 prefs_msg_colors_done();
1789 prefs_image_viewer_done();
1790 image_viewer_done();
1791 prefs_quote_done();
1792 prefs_summaries_done();
1793 prefs_message_done();
1794 prefs_other_done();
1795 prefs_proxy_done();
1796 prefs_receive_done();
1797 prefs_logging_done();
1798 prefs_send_done();
1799 tags_write_tags();
1800 #ifdef USE_ENCHANT
1801 prefs_spelling_done();
1802 gtkaspell_checkers_quit();
1803 #endif
1804 plugin_unload_all("Common");
1805 #ifdef G_OS_WIN32
1806 win32_close_log();
1807 #endif
1808 claws_done();
1811 #define G_PRINT_EXIT(msg) \
1813 g_print(msg); \
1814 exit(1); \
1817 static void parse_cmd_compose_from_file(const gchar *fn, GString *body)
1819 GString *headers = g_string_new(NULL);
1820 gchar *to = NULL;
1821 gchar *h;
1822 gchar *v;
1823 gchar fb[BUFFSIZE];
1824 FILE *fp;
1825 gboolean isstdin;
1827 if (fn == NULL || *fn == '\0')
1828 G_PRINT_EXIT(_("Missing filename\n"));
1829 isstdin = (*fn == '-' && *(fn + 1) == '\0');
1830 if (isstdin)
1831 fp = stdin;
1832 else {
1833 fp = claws_fopen(fn, "r");
1834 if (!fp)
1835 G_PRINT_EXIT(_("Cannot open filename for reading\n"));
1838 while (claws_fgets(fb, sizeof(fb), fp)) {
1839 gchar *tmp;
1840 strretchomp(fb);
1841 if (*fb == '\0')
1842 break;
1843 h = fb;
1844 while (*h && *h != ':') { ++h; } /* search colon */
1845 if (*h == '\0')
1846 G_PRINT_EXIT(_("Malformed header\n"));
1847 v = h + 1;
1848 while (*v && *v == ' ') { ++v; } /* trim value start */
1849 *h = '\0';
1850 tmp = g_ascii_strdown(fb, -1); /* get header name */
1851 if (!strcmp(tmp, "to")) {
1852 if (to != NULL)
1853 G_PRINT_EXIT(_("Duplicated 'To:' header\n"));
1854 to = g_strdup(v);
1855 } else {
1856 g_string_append_c(headers, '&');
1857 g_string_append(headers, tmp);
1858 g_string_append_c(headers, '=');
1859 g_string_append_uri_escaped(headers, v, NULL, TRUE);
1861 g_free(tmp);
1863 if (to == NULL)
1864 G_PRINT_EXIT(_("Missing required 'To:' header\n"));
1865 g_string_append(body, to);
1866 g_free(to);
1867 g_string_append(body, "?body=");
1868 while (claws_fgets(fb, sizeof(fb), fp)) {
1869 g_string_append_uri_escaped(body, fb, NULL, TRUE);
1871 if (!isstdin)
1872 claws_fclose(fp);
1873 /* append the remaining headers */
1874 g_string_append(body, headers->str);
1875 g_string_free(headers, TRUE);
1878 #undef G_PRINT_EXIT
1880 static void parse_cmd_opt_error(char *errstr, char* optstr)
1882 gchar tmp[BUFSIZ];
1884 cm_return_if_fail(errstr != NULL);
1885 cm_return_if_fail(optstr != NULL);
1887 g_snprintf(tmp, sizeof(tmp), errstr, optstr);
1888 g_print(_("%s. Try -h or --help for usage.\n"), tmp);
1889 exit(1);
1892 static GString mailto; /* used to feed cmd.compose_mailto when --compose-from-file is used */
1894 static void parse_cmd_opt(int argc, char *argv[])
1896 AttachInfo *ainfo;
1897 gint i;
1899 for (i = 1; i < argc; i++) {
1900 if (!strcmp(argv[i], "--receive-all")) {
1901 cmd.receive_all = TRUE;
1902 } else if (!strcmp(argv[i], "--receive")) {
1903 cmd.receive = TRUE;
1904 } else if (!strcmp(argv[i], "--cancel-receiving")) {
1905 cmd.cancel_receiving = TRUE;
1906 } else if (!strcmp(argv[i], "--cancel-sending")) {
1907 cmd.cancel_sending = TRUE;
1908 } else if (!strcmp(argv[i], "--compose-from-file")) {
1909 if (i+1 < argc) {
1910 const gchar *p = argv[i+1];
1912 parse_cmd_compose_from_file(p, &mailto);
1913 cmd.compose = TRUE;
1914 cmd.compose_mailto = mailto.str;
1915 i++;
1916 } else {
1917 parse_cmd_opt_error(_("Missing file argument for option %s"), argv[i]);
1919 } else if (!strcmp(argv[i], "--compose")) {
1920 const gchar *p = (i+1 < argc)?argv[i+1]:NULL;
1922 cmd.compose = TRUE;
1923 cmd.compose_mailto = NULL;
1924 if (p && *p != '\0' && *p != '-') {
1925 if (!STRNCMP(p, "mailto:")) {
1926 cmd.compose_mailto = p + 7;
1927 } else {
1928 cmd.compose_mailto = p;
1930 i++;
1932 } else if (!strcmp(argv[i], "--subscribe")) {
1933 if (i+1 < argc) {
1934 const gchar *p = argv[i+1];
1935 if (p && *p != '\0' && *p != '-') {
1936 cmd.subscribe = TRUE;
1937 cmd.subscribe_uri = p;
1938 } else {
1939 parse_cmd_opt_error(_("Missing or empty uri argument for option %s"), argv[i]);
1941 } else {
1942 parse_cmd_opt_error(_("Missing uri argument for option %s"), argv[i]);
1944 } else if (!strcmp(argv[i], "--attach") ||
1945 !strcmp(argv[i], "--insert")) {
1946 if (i+1 < argc) {
1947 const gchar *p = argv[i+1];
1948 gint ii = i;
1949 gchar *file = NULL;
1950 gboolean insert = !strcmp(argv[i], "--insert");
1952 while (p && *p != '\0' && *p != '-') {
1953 if ((file = g_filename_from_uri(p, NULL, NULL)) != NULL) {
1954 if (!is_file_exist(file)) {
1955 g_free(file);
1956 file = NULL;
1959 if (file == NULL && *p != G_DIR_SEPARATOR) {
1960 file = g_strconcat(claws_get_startup_dir(),
1961 G_DIR_SEPARATOR_S,
1962 p, NULL);
1963 } else if (file == NULL) {
1964 file = g_strdup(p);
1967 ainfo = g_new0(AttachInfo, 1);
1968 ainfo->file = file;
1969 ainfo->insert = insert;
1970 cmd.attach_files = g_list_append(cmd.attach_files, ainfo);
1971 ii++;
1972 p = (ii+1 < argc)?argv[ii+1]:NULL;
1974 if (ii==i) {
1975 parse_cmd_opt_error(_("Missing at least one non-empty file argument for option %s"), argv[i]);
1976 } else {
1977 i=ii;
1979 } else {
1980 parse_cmd_opt_error(_("Missing file argument for option %s"), argv[i]);
1982 } else if (!strcmp(argv[i], "--send")) {
1983 cmd.send = TRUE;
1984 } else if (!strcmp(argv[i], "--version-full") ||
1985 !strcmp(argv[i], "-V")) {
1986 g_print("Claws Mail version " VERSION_GIT_FULL "\n");
1987 main_dump_features_list(FALSE);
1988 exit(0);
1989 } else if (!strcmp(argv[i], "--version") ||
1990 !strcmp(argv[i], "-v")) {
1991 g_print("Claws Mail version " VERSION "\n");
1992 exit(0);
1993 } else if (!strcmp(argv[i], "--status-full")) {
1994 const gchar *p = (i+1 < argc)?argv[i+1]:NULL;
1996 cmd.status_full = TRUE;
1997 while (p && *p != '\0' && *p != '-') {
1998 if (!cmd.status_full_folders) {
1999 cmd.status_full_folders =
2000 g_ptr_array_new();
2002 g_ptr_array_add(cmd.status_full_folders,
2003 g_strdup(p));
2004 i++;
2005 p = (i+1 < argc)?argv[i+1]:NULL;
2007 } else if (!strcmp(argv[i], "--status")) {
2008 const gchar *p = (i+1 < argc)?argv[i+1]:NULL;
2010 cmd.status = TRUE;
2011 while (p && *p != '\0' && *p != '-') {
2012 if (!cmd.status_folders)
2013 cmd.status_folders = g_ptr_array_new();
2014 g_ptr_array_add(cmd.status_folders,
2015 g_strdup(p));
2016 i++;
2017 p = (i+1 < argc)?argv[i+1]:NULL;
2019 } else if (!strcmp(argv[i], "--search")) {
2020 if (i+3 < argc) { /* 3 first arguments are mandatory */
2021 const char* p;
2022 /* only set search parameters if they are valid */
2023 p = argv[i+1];
2024 cmd.search_folder = (p && *p != '\0' && *p != '-')?p:NULL;
2025 p = argv[i+2];
2026 cmd.search_type = (p && *p != '\0' && *p != '-')?p:NULL;
2027 p = argv[i+3];
2028 cmd.search_request = (p && *p != '\0' && *p != '-')?p:NULL;
2029 p = (i+4 < argc)?argv[i+4]:NULL;
2030 const char* rec = (p && *p != '\0' && *p != '-')?p:NULL;
2031 cmd.search_recursive = TRUE;
2032 if (rec) {
2033 i++;
2034 if (tolower(*rec)=='n' || tolower(*rec)=='f' || *rec=='0')
2035 cmd.search_recursive = FALSE;
2037 if (cmd.search_folder && cmd.search_type && cmd.search_request) {
2038 cmd.search = TRUE;
2039 i+=3;
2041 } else {
2042 switch (argc-i-1) {
2043 case 0:
2044 parse_cmd_opt_error(_("Missing folder, type and request arguments for option %s"), argv[i]);
2045 break;
2046 case 1:
2047 parse_cmd_opt_error(_("Missing type and request arguments for option %s"), argv[i]);
2048 break;
2049 case 2:
2050 parse_cmd_opt_error(_("Missing request argument for option %s"), argv[i]);
2053 } else if (!strcmp(argv[i], "--online")) {
2054 cmd.online_mode = ONLINE_MODE_ONLINE;
2055 } else if (!strcmp(argv[i], "--offline")) {
2056 cmd.online_mode = ONLINE_MODE_OFFLINE;
2057 } else if (!strcmp(argv[i], "--toggle-debug")) {
2058 cmd.debug = TRUE;
2059 } else if (!strcmp(argv[i], "--statistics")) {
2060 cmd.statistics = TRUE;
2061 } else if (!strcmp(argv[i], "--reset-statistics")) {
2062 cmd.reset_statistics = TRUE;
2063 } else if (!strcmp(argv[i], "--help") ||
2064 !strcmp(argv[i], "-h")) {
2065 gchar *base = g_path_get_basename(argv[0]);
2066 g_print(_("Usage: %s [OPTION]...\n"), base);
2068 g_print("%s\n", _(" --compose [address] open composition window"));
2069 g_print("%s\n", _(" --compose-from-file file\n"
2070 " open composition window with data from given file;\n"
2071 " use - as file name for reading from standard input;\n"
2072 " content format: headers first (To: required) until an\n"
2073 " empty line, then mail body until end of file."));
2074 g_print("%s\n", _(" --subscribe uri subscribe to the given URI if possible"));
2075 g_print("%s\n", _(" --attach file1 [file2]...\n"
2076 " open composition window with specified files\n"
2077 " attached"));
2078 g_print("%s\n", _(" --insert file1 [file2]...\n"
2079 " open composition window with specified files\n"
2080 " inserted"));
2081 g_print("%s\n", _(" --receive receive new messages"));
2082 g_print("%s\n", _(" --receive-all receive new messages of all accounts"));
2083 g_print("%s\n", _(" --cancel-receiving cancel receiving of messages"));
2084 g_print("%s\n", _(" --cancel-sending cancel sending of messages"));
2085 g_print("%s\n", _(" --search folder type request [recursive]\n"
2086 " searches mail\n"
2087 " folder ex.: \"#mh/Mailbox/inbox\" or \"Mail\"\n"
2088 " type: s[ubject],f[rom],t[o],e[xtended],m[ixed] or g: tag\n"
2089 " request: search string\n"
2090 " recursive: false if arg. starts with 0, n, N, f or F"));
2092 g_print("%s\n", _(" --send send all queued messages"));
2093 g_print("%s\n", _(" --status [folder]... show the total number of messages"));
2094 g_print("%s\n", _(" --status-full [folder]...\n"
2095 " show the status of each folder"));
2096 g_print("%s\n", _(" --statistics show session statistics"));
2097 g_print("%s\n", _(" --reset-statistics reset session statistics"));
2098 g_print("%s\n", _(" --select folder[/msg] jump to the specified folder/message\n"
2099 " folder is a folder id like 'folder/sub_folder', a file:// uri or an absolute path"));
2100 g_print("%s\n", _(" --online switch to online mode"));
2101 g_print("%s\n", _(" --offline switch to offline mode"));
2102 g_print("%s\n", _(" --exit --quit -q exit Claws Mail"));
2103 g_print("%s\n", _(" --debug -d debug mode"));
2104 g_print("%s\n", _(" --toggle-debug toggle debug mode"));
2105 g_print("%s\n", _(" --help -h display this help"));
2106 g_print("%s\n", _(" --version -v output version information"));
2107 g_print("%s\n", _(" --version-full -V output version and built-in features information"));
2108 g_print("%s\n", _(" --config-dir output configuration directory"));
2109 g_print("%s\n", _(" --alternate-config-dir directory\n"
2110 " use specified configuration directory"));
2111 g_print("%s\n", _(" --geometry -geometry [WxH][+X+Y]\n"
2112 " set geometry for main window"));
2114 g_free(base);
2115 exit(1);
2116 } else if (!strcmp(argv[i], "--crash")) {
2117 cmd.crash = TRUE;
2118 cmd.crash_params = g_strdup((i+1 < argc)?argv[i+1]:NULL);
2119 i++;
2120 } else if (!strcmp(argv[i], "--config-dir")) {
2121 g_print(RC_DIR "\n");
2122 exit(0);
2123 } else if (!strcmp(argv[i], "--alternate-config-dir")) {
2124 if (i+1 < argc) {
2125 set_rc_dir(argv[i+1]);
2126 i++;
2127 } else {
2128 parse_cmd_opt_error(_("Missing directory argument for option %s"), argv[i]);
2130 } else if (!strcmp(argv[i], "--geometry") ||
2131 !strcmp(argv[i], "-geometry")) {
2132 if (i+1 < argc) {
2133 cmd.geometry = argv[i+1];
2134 i++;
2135 } else {
2136 parse_cmd_opt_error(_("Missing geometry argument for option %s"), argv[i]);
2138 } else if (!strcmp(argv[i], "--exit") ||
2139 !strcmp(argv[i], "--quit") ||
2140 !strcmp(argv[i], "-q")) {
2141 cmd.exit = TRUE;
2142 } else if (!strcmp(argv[i], "--select")) {
2143 if (i+1 < argc) {
2144 cmd.target = argv[i+1];
2145 i++;
2146 } else {
2147 parse_cmd_opt_error(_("Missing folder argument for option %s"), argv[i]);
2149 } else if (i == 1 && argc == 2) {
2150 /* only one parameter. Do something intelligent about it */
2151 if ((strstr(argv[i], "@") || !STRNCMP(argv[i], "mailto:")) && !strstr(argv[i], "://")) {
2152 const gchar *p = argv[i];
2154 cmd.compose = TRUE;
2155 cmd.compose_mailto = NULL;
2156 if (p && *p != '\0' && *p != '-') {
2157 if (!STRNCMP(p, "mailto:")) {
2158 cmd.compose_mailto = p + 7;
2159 } else {
2160 cmd.compose_mailto = p;
2163 } else if (!STRNCMP(argv[i], "file://")) {
2164 cmd.target = argv[i];
2165 } else if (!STRNCMP(argv[i], "?attach=file://")) {
2166 /* Thunar support as per 3.3.0cvs19 */
2167 cmd.compose = TRUE;
2168 cmd.compose_mailto = argv[i];
2169 } else if (strstr(argv[i], "://")) {
2170 const gchar *p = argv[i];
2171 if (p && *p != '\0' && *p != '-') {
2172 cmd.subscribe = TRUE;
2173 cmd.subscribe_uri = p;
2175 } else if (!strcmp(argv[i], "--sync")) {
2176 /* gtk debug */
2177 } else if (is_dir_exist(argv[i]) || is_file_exist(argv[i])) {
2178 cmd.target = argv[i];
2179 } else {
2180 parse_cmd_opt_error(_("Unknown option %s"), argv[i]);
2182 } else {
2183 parse_cmd_opt_error(_("Unknown option %s"), argv[i]);
2187 if (cmd.attach_files && cmd.compose == FALSE) {
2188 cmd.compose = TRUE;
2189 cmd.compose_mailto = NULL;
2193 static void initial_processing(FolderItem *item, gpointer data)
2195 MainWindow *mainwin = (MainWindow *)data;
2196 gchar *buf;
2198 cm_return_if_fail(item);
2199 buf = g_strdup_printf(_("Processing (%s)..."),
2200 item->path
2201 ? item->path
2202 : _("top level folder"));
2203 g_free(buf);
2205 if (folder_item_parent(item) != NULL && item->prefs->enable_processing) {
2206 item->processing_pending = TRUE;
2207 folder_item_apply_processing(item);
2208 item->processing_pending = FALSE;
2211 STATUSBAR_POP(mainwin);
2214 static gboolean draft_all_messages(void)
2216 const GList *compose_list = NULL;
2218 compose_clear_exit_drafts();
2219 compose_list = compose_get_compose_list();
2220 while (compose_list != NULL) {
2221 Compose *c = (Compose*)compose_list->data;
2222 if (!compose_draft(c, COMPOSE_DRAFT_FOR_EXIT))
2223 return FALSE;
2224 compose_list = compose_get_compose_list();
2226 return TRUE;
2228 gboolean clean_quit(gpointer data)
2230 static gboolean firstrun = TRUE;
2232 if (!firstrun) {
2233 return FALSE;
2235 firstrun = FALSE;
2237 /*!< Good idea to have the main window stored in a
2238 * static variable so we can check that variable
2239 * to see if we're really allowed to do things
2240 * that actually the spawner is supposed to
2241 * do (like: sending mail, composing messages).
2242 * Because, really, if we're the spawnee, and
2243 * we touch GTK stuff, we're hosed. See the
2244 * next fixme. */
2246 /* FIXME: Use something else to signal that we're
2247 * in the original spawner, and not in a spawned
2248 * child. */
2249 if (!static_mainwindow) {
2250 return FALSE;
2253 draft_all_messages();
2254 emergency_exit = TRUE;
2255 exit_claws(static_mainwindow);
2256 exit(0);
2258 return FALSE;
2261 void app_will_exit(GtkWidget *widget, gpointer data)
2263 MainWindow *mainwin = data;
2265 if (gtk_main_level() == 0) {
2266 debug_print("not even started\n");
2267 return;
2269 if (sc_exiting == TRUE) {
2270 debug_print("exit pending\n");
2271 return;
2273 sc_exiting = TRUE;
2274 debug_print("exiting\n");
2275 if (compose_get_compose_list()) {
2276 if (!draft_all_messages()) {
2277 main_window_popup(mainwin);
2278 sc_exiting = FALSE;
2279 return;
2283 if (prefs_common.warn_queued_on_exit && procmsg_have_queued_mails_fast()) {
2284 if (alertpanel(_("Queued messages"),
2285 _("Some unsent messages are queued. Exit now?"),
2286 NULL, _("_Cancel"), NULL, _("_OK"), NULL, NULL,
2287 ALERTFOCUS_FIRST)
2288 != G_ALERTALTERNATE) {
2289 main_window_popup(mainwin);
2290 sc_exiting = FALSE;
2291 return;
2293 manage_window_focus_in(mainwin->window, NULL, NULL);
2296 sock_cleanup();
2297 #ifdef HAVE_VALGRIND
2298 if (RUNNING_ON_VALGRIND) {
2299 summary_clear_list(mainwin->summaryview);
2301 #endif
2302 if (folderview_get_selected_item(mainwin->folderview))
2303 folder_item_close(folderview_get_selected_item(mainwin->folderview));
2304 gtk_main_quit();
2307 gboolean claws_is_exiting(void)
2309 return sc_exiting;
2312 gboolean claws_is_starting(void)
2314 return sc_starting;
2317 #ifdef G_OS_UNIX
2319 * CLAWS: want this public so crash dialog can delete the
2320 * lock file too
2322 gchar *claws_get_socket_name(void)
2324 static gchar *filename = NULL;
2325 gchar *socket_dir = NULL;
2326 gchar md5sum[33];
2328 if (filename == NULL) {
2329 GStatBuf st;
2330 gint stat_ok;
2332 socket_dir = g_strdup_printf("%s%cclaws-mail",
2333 g_get_user_runtime_dir(), G_DIR_SEPARATOR);
2334 stat_ok = g_stat(socket_dir, &st);
2335 if (stat_ok < 0 && errno != ENOENT) {
2336 g_print("Error stat'ing socket_dir %s: %s\n",
2337 socket_dir, g_strerror(errno));
2338 } else if (stat_ok == 0 && S_ISSOCK(st.st_mode)) {
2339 /* old versions used a sock in $TMPDIR/claws-mail-$UID */
2340 debug_print("Using legacy socket %s\n", socket_dir);
2341 filename = g_strdup(socket_dir);
2342 g_free(socket_dir);
2343 return filename;
2346 if (!is_dir_exist(socket_dir) && make_dir(socket_dir) < 0) {
2347 g_print("Error creating socket_dir %s: %s\n",
2348 socket_dir, g_strerror(errno));
2351 md5_hex_digest(md5sum, get_rc_dir());
2353 filename = g_strdup_printf("%s%c%s", socket_dir, G_DIR_SEPARATOR,
2354 md5sum);
2355 g_free(socket_dir);
2356 debug_print("Using control socket %s\n", filename);
2359 return filename;
2361 #endif
2363 static gchar *get_crashfile_name(void)
2365 static gchar *filename = NULL;
2367 if (filename == NULL) {
2368 filename = g_strdup_printf("%s%cclaws-crashed",
2369 get_tmp_dir(), G_DIR_SEPARATOR);
2372 return filename;
2375 static gint prohibit_duplicate_launch(int *argc, char ***argv)
2377 gint sock;
2378 GList *curr;
2379 #ifdef G_OS_UNIX
2380 gchar *path;
2382 path = claws_get_socket_name();
2383 /* Try to connect to the control socket */
2384 sock = fd_connect_unix(path);
2386 if (sock < 0) {
2387 gint ret;
2388 #if HAVE_FLOCK
2389 gchar *socket_lock;
2390 gint lock_fd;
2391 /* If connect failed, no other process is running.
2392 * Unlink the potentially existing socket, then
2393 * open it. This has to be done locking a temporary
2394 * file to avoid the race condition where another
2395 * process could have created the socket just in
2396 * between.
2398 socket_lock = g_strconcat(path, ".lock",
2399 NULL);
2400 lock_fd = g_open(socket_lock, O_RDWR|O_CREAT, 0);
2401 if (lock_fd < 0) {
2402 debug_print("Couldn't open %s: %s (%d)\n", socket_lock,
2403 g_strerror(errno), errno);
2404 g_free(socket_lock);
2405 return -1;
2407 if (flock(lock_fd, LOCK_EX) < 0) {
2408 debug_print("Couldn't lock %s: %s (%d)\n", socket_lock,
2409 g_strerror(errno), errno);
2410 close(lock_fd);
2411 g_free(socket_lock);
2412 return -1;
2414 #endif
2416 claws_unlink(path);
2417 debug_print("Opening socket %s\n", path);
2418 ret = fd_open_unix(path);
2419 #if HAVE_FLOCK
2420 flock(lock_fd, LOCK_UN);
2421 close(lock_fd);
2422 claws_unlink(socket_lock);
2423 g_free(socket_lock);
2424 #endif
2425 return ret;
2427 #else
2428 HANDLE hmutex;
2430 hmutex = CreateMutexA(NULL, FALSE, "ClawsMail");
2431 if (!hmutex) {
2432 debug_print("cannot create Mutex\n");
2433 return -1;
2435 if (GetLastError() != ERROR_ALREADY_EXISTS) {
2436 sock = fd_open_inet(50216);
2437 if (sock < 0)
2438 return 0;
2439 return sock;
2442 sock = fd_connect_inet(50216);
2443 if (sock < 0)
2444 return -1;
2445 #endif
2446 /* remote command mode */
2448 debug_print("another Claws Mail instance is already running.\n");
2450 if (cmd.receive_all) {
2451 CM_FD_WRITE_ALL("receive_all\n");
2452 } else if (cmd.receive) {
2453 CM_FD_WRITE_ALL("receive\n");
2454 } else if (cmd.cancel_receiving) {
2455 CM_FD_WRITE_ALL("cancel_receiving\n");
2456 } else if (cmd.cancel_sending) {
2457 CM_FD_WRITE_ALL("cancel_sending\n");
2458 } else if (cmd.compose && cmd.attach_files) {
2459 gchar *str, *compose_str;
2461 if (cmd.compose_mailto) {
2462 compose_str = g_strdup_printf("compose_attach %s\n",
2463 cmd.compose_mailto);
2464 } else {
2465 compose_str = g_strdup("compose_attach\n");
2468 CM_FD_WRITE_ALL(compose_str);
2469 g_free(compose_str);
2471 for (curr = cmd.attach_files; curr != NULL ; curr = curr->next) {
2472 str = (gchar *) ((AttachInfo *)curr->data)->file;
2473 if (((AttachInfo *)curr->data)->insert)
2474 CM_FD_WRITE_ALL("insert ");
2475 else
2476 CM_FD_WRITE_ALL("attach ");
2477 CM_FD_WRITE_ALL(str);
2478 CM_FD_WRITE_ALL("\n");
2481 CM_FD_WRITE_ALL(".\n");
2482 } else if (cmd.compose) {
2483 gchar *compose_str;
2485 if (cmd.compose_mailto) {
2486 compose_str = g_strdup_printf
2487 ("compose %s\n", cmd.compose_mailto);
2488 } else {
2489 compose_str = g_strdup("compose\n");
2492 CM_FD_WRITE_ALL(compose_str);
2493 g_free(compose_str);
2494 } else if (cmd.subscribe) {
2495 gchar *str = g_strdup_printf("subscribe %s\n", cmd.subscribe_uri);
2496 CM_FD_WRITE_ALL(str);
2497 g_free(str);
2498 } else if (cmd.send) {
2499 CM_FD_WRITE_ALL("send\n");
2500 } else if (cmd.online_mode == ONLINE_MODE_ONLINE) {
2501 CM_FD_WRITE("online\n");
2502 } else if (cmd.online_mode == ONLINE_MODE_OFFLINE) {
2503 CM_FD_WRITE("offline\n");
2504 } else if (cmd.debug) {
2505 CM_FD_WRITE("debug\n");
2506 } else if (cmd.status || cmd.status_full) {
2507 gchar buf[BUFFSIZE];
2508 gint i;
2509 const gchar *command;
2510 GPtrArray *folders;
2511 gchar *folder;
2513 command = cmd.status_full ? "status-full\n" : "status\n";
2514 folders = cmd.status_full ? cmd.status_full_folders :
2515 cmd.status_folders;
2517 CM_FD_WRITE_ALL(command);
2518 for (i = 0; folders && i < folders->len; ++i) {
2519 folder = g_ptr_array_index(folders, i);
2520 CM_FD_WRITE_ALL(folder);
2521 CM_FD_WRITE_ALL("\n");
2523 CM_FD_WRITE_ALL(".\n");
2524 for (;;) {
2525 fd_gets(sock, buf, sizeof(buf) - 1);
2526 buf[sizeof(buf) - 1] = '\0';
2527 if (!STRNCMP(buf, ".\n")) break;
2528 if (claws_fputs(buf, stdout) == EOF) {
2529 g_warning("writing to stdout failed");
2530 break;
2533 } else if (cmd.exit) {
2534 CM_FD_WRITE_ALL("exit\n");
2535 } else if (cmd.statistics) {
2536 gchar buf[BUFSIZ];
2537 CM_FD_WRITE("statistics\n");
2538 for (;;) {
2539 fd_gets(sock, buf, sizeof(buf) - 1);
2540 buf[sizeof(buf) - 1] = '\0';
2541 if (!STRNCMP(buf, ".\n")) break;
2542 if (claws_fputs(buf, stdout) == EOF) {
2543 g_warning("writing to stdout failed");
2544 break;
2547 } else if (cmd.reset_statistics) {
2548 CM_FD_WRITE("reset_statistics\n");
2549 } else if (cmd.target) {
2550 gchar *str = g_strdup_printf("select %s\n", cmd.target);
2551 CM_FD_WRITE_ALL(str);
2552 g_free(str);
2553 } else if (cmd.search) {
2554 gchar buf[BUFFSIZE];
2555 gchar *str =
2556 g_strdup_printf("search %s\n%s\n%s\n%c\n",
2557 cmd.search_folder, cmd.search_type, cmd.search_request,
2558 (cmd.search_recursive==TRUE)?'1':'0');
2559 CM_FD_WRITE_ALL(str);
2560 g_free(str);
2561 for (;;) {
2562 fd_gets(sock, buf, sizeof(buf) - 1);
2563 buf[sizeof(buf) - 1] = '\0';
2564 if (!STRNCMP(buf, ".\n")) break;
2565 if (claws_fputs(buf, stdout) == EOF) {
2566 g_warning("writing to stdout failed");
2567 break;
2570 } else {
2571 #ifdef G_OS_UNIX
2572 gchar buf[BUFSIZ];
2573 CM_FD_WRITE_ALL("get_display\n");
2574 memset(buf, 0, sizeof(buf));
2575 fd_gets(sock, buf, sizeof(buf) - 1);
2576 buf[sizeof(buf) - 1] = '\0';
2578 /* Try to connect to a display; if it is the same one as
2579 * the other Claws instance, then ask it to pop up. */
2580 int diff_display = 1;
2581 if (gtk_init_check(argc, argv)) {
2582 GdkDisplay *display = gdk_display_get_default();
2583 diff_display = g_strcmp0(buf, gdk_display_get_name(display));
2585 if (diff_display) {
2586 g_print("Claws Mail is already running on display %s.\n",
2587 buf);
2588 } else {
2589 g_print("Claws Mail is already running on this display (%s).\n",
2590 buf);
2591 fd_close(sock);
2592 sock = fd_connect_unix(path);
2593 CM_FD_WRITE_ALL("popup\n");
2595 #else
2596 CM_FD_WRITE_ALL("popup\n");
2597 #endif
2600 fd_close(sock);
2601 return -1;
2604 static gint lock_socket_remove(void)
2606 #ifdef G_OS_UNIX
2607 gchar *filename, *dirname;
2608 #endif
2609 if (lock_socket < 0) {
2610 return -1;
2613 if (lock_socket_tag > 0) {
2614 g_source_remove(lock_socket_tag);
2616 fd_close(lock_socket);
2618 #ifdef G_OS_UNIX
2619 filename = claws_get_socket_name();
2620 dirname = g_path_get_dirname(filename);
2621 if (claws_unlink(filename) < 0)
2622 FILE_OP_ERROR(filename, "claws_unlink");
2623 g_rmdir(dirname);
2624 g_free(dirname);
2625 #endif
2627 return 0;
2630 static GPtrArray *get_folder_item_list(gint sock)
2632 gchar buf[BUFFSIZE];
2633 FolderItem *item;
2634 GPtrArray *folders = NULL;
2636 for (;;) {
2637 fd_gets(sock, buf, sizeof(buf) - 1);
2638 buf[sizeof(buf) - 1] = '\0';
2639 if (!STRNCMP(buf, ".\n")) {
2640 break;
2642 strretchomp(buf);
2643 if (!folders) {
2644 folders = g_ptr_array_new();
2646 item = folder_find_item_from_identifier(buf);
2647 if (item) {
2648 g_ptr_array_add(folders, item);
2649 } else {
2650 g_warning("no such folder: %s", buf);
2654 return folders;
2657 static void lock_socket_input_cb(gpointer data,
2658 gint source,
2659 GIOCondition condition)
2661 MainWindow *mainwin = (MainWindow *)data;
2662 gint sock;
2663 gchar buf[BUFFSIZE];
2665 sock = fd_accept(source);
2666 if (sock < 0)
2667 return;
2669 fd_gets(sock, buf, sizeof(buf) - 1);
2670 buf[sizeof(buf) - 1] = '\0';
2672 if (!STRNCMP(buf, "popup")) {
2673 main_window_popup(mainwin);
2674 #ifdef G_OS_UNIX
2675 } else if (!STRNCMP(buf, "get_display")) {
2676 GdkDisplay* display = gtk_widget_get_display(mainwin->window);
2677 const gchar *display_name = gdk_display_get_name(display);
2678 CM_FD_WRITE_ALL(display_name);
2679 #endif
2680 } else if (!STRNCMP(buf, "receive_all")) {
2681 inc_all_account_mail(mainwin, FALSE, FALSE,
2682 prefs_common.newmail_notify_manu);
2683 } else if (!STRNCMP(buf, "receive")) {
2684 inc_mail(mainwin, prefs_common.newmail_notify_manu);
2685 } else if (!STRNCMP(buf, "cancel_receiving")) {
2686 inc_cancel_all();
2687 imap_cancel_all();
2688 } else if (!STRNCMP(buf, "cancel_sending")) {
2689 send_cancel();
2690 } else if (!STRNCMP(buf, "compose_attach")) {
2691 GList *files = NULL, *curr;
2692 AttachInfo *ainfo;
2693 gchar *mailto;
2695 mailto = g_strdup(buf + strlen("compose_attach") + 1);
2696 while (fd_gets(sock, buf, sizeof(buf) - 1) > 0) {
2697 buf[sizeof(buf) - 1] = '\0';
2698 strretchomp(buf);
2699 if (!g_strcmp0(buf, "."))
2700 break;
2702 ainfo = g_new0(AttachInfo, 1);
2703 ainfo->file = g_strdup(strstr(buf, " ") + 1);
2704 ainfo->insert = !STRNCMP(buf, "insert ");
2705 files = g_list_append(files, ainfo);
2707 open_compose_new(mailto, files);
2709 curr = g_list_first(files);
2710 while (curr != NULL) {
2711 ainfo = (AttachInfo *)curr->data;
2712 g_free(ainfo->file);
2713 g_free(ainfo);
2714 curr = curr->next;
2716 g_list_free(files);
2717 g_free(mailto);
2718 } else if (!STRNCMP(buf, "compose")) {
2719 open_compose_new(buf + strlen("compose") + 1, NULL);
2720 } else if (!STRNCMP(buf, "subscribe")) {
2721 main_window_popup(mainwin);
2722 folder_subscribe(buf + strlen("subscribe") + 1);
2723 } else if (!STRNCMP(buf, "send")) {
2724 send_queue();
2725 } else if (!STRNCMP(buf, "online")) {
2726 main_window_toggle_work_offline(mainwin, FALSE, FALSE);
2727 } else if (!STRNCMP(buf, "offline")) {
2728 main_window_toggle_work_offline(mainwin, TRUE, FALSE);
2729 } else if (!STRNCMP(buf, "debug")) {
2730 debug_set_mode(debug_get_mode() ? FALSE : TRUE);
2731 } else if (!STRNCMP(buf, "status-full") ||
2732 !STRNCMP(buf, "status")) {
2733 gchar *status;
2734 GPtrArray *folders;
2736 folders = get_folder_item_list(sock);
2737 status = folder_get_status
2738 (folders, !STRNCMP(buf, "status-full"));
2739 CM_FD_WRITE_ALL(status);
2740 CM_FD_WRITE_ALL(".\n");
2741 g_free(status);
2742 if (folders) g_ptr_array_free(folders, TRUE);
2743 } else if (!STRNCMP(buf, "statistics")) {
2744 gchar tmp[BUFSIZ];
2746 g_snprintf(tmp, sizeof(tmp), _("Session statistics\n"));
2747 CM_FD_WRITE_ALL(tmp);
2749 if (prefs_common.date_format) {
2750 struct tm *lt;
2751 gint len = 100;
2752 gchar date[len];
2754 lt = localtime(&session_stats.time_started);
2755 fast_strftime(date, len, prefs_common.date_format, lt);
2756 g_snprintf(tmp, sizeof(tmp), _("Started: %s\n"),
2757 lt ? date : ctime(&session_stats.time_started));
2758 } else
2759 g_snprintf(tmp, sizeof(tmp), _("Started: %s\n"),
2760 ctime(&session_stats.time_started));
2761 CM_FD_WRITE_ALL(tmp);
2763 CM_FD_WRITE_ALL("\n");
2765 g_snprintf(tmp, sizeof(tmp), _("Incoming traffic\n"));
2766 CM_FD_WRITE_ALL(tmp);
2768 g_snprintf(tmp, sizeof(tmp), _("Received messages: %d\n"),
2769 session_stats.received);
2770 CM_FD_WRITE_ALL(tmp);
2772 CM_FD_WRITE_ALL("\n");
2774 g_snprintf(tmp, sizeof(tmp), _("Outgoing traffic\n"));
2775 CM_FD_WRITE_ALL(tmp);
2777 g_snprintf(tmp, sizeof(tmp), _("New/redirected messages: %d\n"),
2778 session_stats.sent);
2779 CM_FD_WRITE_ALL(tmp);
2781 g_snprintf(tmp, sizeof(tmp), _("Replied messages: %d\n"),
2782 session_stats.replied);
2783 CM_FD_WRITE_ALL(tmp);
2785 g_snprintf(tmp, sizeof(tmp), _("Forwarded messages: %d\n"),
2786 session_stats.forwarded);
2787 CM_FD_WRITE_ALL(tmp);
2789 g_snprintf(tmp, sizeof(tmp), _("Total outgoing messages: %d\n"),
2790 (session_stats.sent + session_stats.replied +
2791 session_stats.forwarded));
2792 CM_FD_WRITE_ALL(tmp);
2794 CM_FD_WRITE_ALL(".\n");
2795 } else if (!STRNCMP(buf, "reset_statistics")) {
2796 reset_statistics();
2797 } else if (!STRNCMP(buf, "select ")) {
2798 const gchar *target = buf+7;
2799 mainwindow_jump_to(target, TRUE);
2800 } else if (!STRNCMP(buf, "search ")) {
2801 FolderItem* folderItem = NULL;
2802 GSList *messages = NULL;
2803 gchar *folder_name = NULL;
2804 gchar *request = NULL;
2805 AdvancedSearch *search;
2806 gboolean recursive;
2807 AdvancedSearchType searchType = ADVANCED_SEARCH_EXTENDED;
2809 search = advsearch_new();
2811 folder_name = g_strdup(buf+7);
2812 strretchomp(folder_name);
2814 if (fd_gets(sock, buf, sizeof(buf) - 1) <= 0)
2815 goto search_exit;
2816 buf[sizeof(buf) - 1] = '\0';
2818 switch (toupper(buf[0])) {
2819 case 'S': searchType = ADVANCED_SEARCH_SUBJECT; break;
2820 case 'F': searchType = ADVANCED_SEARCH_FROM; break;
2821 case 'T': searchType = ADVANCED_SEARCH_TO; break;
2822 case 'M': searchType = ADVANCED_SEARCH_MIXED; break;
2823 case 'G': searchType = ADVANCED_SEARCH_TAG; break;
2824 case 'E': searchType = ADVANCED_SEARCH_EXTENDED; break;
2827 if (fd_gets(sock, buf, sizeof(buf) - 1) <= 0)
2828 goto search_exit;
2830 buf[sizeof(buf) - 1] = '\0';
2831 request = g_strdup(buf);
2832 strretchomp(request);
2834 recursive = TRUE;
2835 if (fd_gets(sock, buf, sizeof(buf) - 1) > 0)
2836 recursive = buf[0] != '0';
2838 buf[sizeof(buf) - 1] = '\0';
2840 debug_print("search: %s %i %s %i\n", folder_name, searchType, request, recursive);
2842 folderItem = folder_find_item_from_identifier(folder_name);
2844 if (folderItem == NULL) {
2845 debug_print("Unknown folder item : '%s', searching folder\n",folder_name);
2846 Folder* folder = folder_find_from_path(folder_name);
2847 if (folder != NULL)
2848 folderItem = FOLDER_ITEM(folder->node->data);
2849 else
2850 debug_print("Unknown folder: '%s'\n",folder_name);
2851 } else {
2852 debug_print("%s %s\n",folderItem->name, folderItem->path);
2855 if (folderItem != NULL) {
2856 advsearch_set(search, searchType, request);
2857 advsearch_search_msgs_in_folders(search, &messages, folderItem, recursive);
2858 } else {
2859 g_print("Folder '%s' not found.\n'", folder_name);
2862 GSList *cur;
2863 for (cur = messages; cur != NULL; cur = cur->next) {
2864 MsgInfo* msg = (MsgInfo *)cur->data;
2865 gchar *file = procmsg_get_message_file_path(msg);
2866 CM_FD_WRITE_ALL(file);
2867 CM_FD_WRITE_ALL("\n");
2868 g_free(file);
2870 CM_FD_WRITE_ALL(".\n");
2872 search_exit:
2873 g_free(folder_name);
2874 g_free(request);
2875 advsearch_free(search);
2876 if (messages != NULL)
2877 procmsg_msg_list_free(messages);
2878 } else if (!STRNCMP(buf, "exit")) {
2879 if (prefs_common.clean_on_exit && !prefs_common.ask_on_clean) {
2880 procmsg_empty_all_trash();
2882 app_will_exit(NULL, mainwin);
2884 fd_close(sock);
2888 static void open_compose_new(const gchar *address, GList *attach_files)
2890 gchar *addr = NULL;
2892 if (address) {
2893 Xstrdup_a(addr, address, return);
2894 g_strstrip(addr);
2897 compose_new(NULL, addr, attach_files);
2900 static void send_queue(void)
2902 GList *list;
2903 gchar *errstr = NULL;
2904 gboolean error = FALSE;
2905 for (list = folder_get_list(); list != NULL; list = list->next) {
2906 Folder *folder = list->data;
2908 if (folder->queue) {
2909 gint res = procmsg_send_queue
2910 (folder->queue, prefs_common.savemsg,
2911 &errstr);
2913 if (res) {
2914 folder_item_scan(folder->queue);
2917 if (res < 0)
2918 error = TRUE;
2921 if (errstr) {
2922 alertpanel_error_log(_("Some errors occurred "
2923 "while sending queued messages:\n%s"), errstr);
2924 g_free(errstr);
2925 } else if (error) {
2926 alertpanel_error_log("Some errors occurred "
2927 "while sending queued messages.");
2931 #ifndef G_OS_WIN32
2932 static void quit_signal_handler(int sig)
2934 debug_print("Quitting on signal %d\n", sig);
2936 g_timeout_add(0, clean_quit, NULL);
2938 #endif
2940 static void install_basic_sighandlers()
2942 #ifndef G_OS_WIN32
2943 sigset_t mask;
2944 struct sigaction act;
2946 sigemptyset(&mask);
2948 #ifdef SIGTERM
2949 sigaddset(&mask, SIGTERM);
2950 #endif
2951 #ifdef SIGINT
2952 sigaddset(&mask, SIGINT);
2953 #endif
2954 #ifdef SIGHUP
2955 sigaddset(&mask, SIGHUP);
2956 #endif
2958 act.sa_handler = quit_signal_handler;
2959 act.sa_mask = mask;
2960 act.sa_flags = 0;
2962 #ifdef SIGTERM
2963 sigaction(SIGTERM, &act, 0);
2964 #endif
2965 #ifdef SIGINT
2966 sigaction(SIGINT, &act, 0);
2967 #endif
2968 #ifdef SIGHUP
2969 sigaction(SIGHUP, &act, 0);
2970 #endif
2972 sigprocmask(SIG_UNBLOCK, &mask, 0);
2973 #endif /* !G_OS_WIN32 */
2976 #if (defined linux && defined SIGIO)
2977 static int mem_notify_fd = 0;
2979 static gboolean clean_caches(gpointer unused)
2981 if (static_mainwindow && static_mainwindow->lock_count > 0)
2982 return TRUE;
2983 debug_print("/dev/mem_notify: callback: Freeing some memory now!\n");
2984 folder_clean_cache_memory_force();
2985 return FALSE;
2988 static void memory_signal_handler(int sig)
2990 debug_print("/dev/mem_notify: Kernel says we should free up some memory!\n");
2991 g_timeout_add(10, clean_caches, NULL);
2994 static void install_memory_sighandler()
2996 sigset_t mask;
2997 struct sigaction act;
2998 int flags;
3000 mem_notify_fd = g_open("/dev/mem_notify", O_RDONLY|O_NONBLOCK, 0);
3001 if (mem_notify_fd == -1) {
3002 debug_print("/dev/mem_notify not available (%s)\n",
3003 g_strerror(errno));
3004 return;
3007 fcntl(mem_notify_fd, F_SETOWN, getpid());
3008 flags = fcntl(mem_notify_fd, F_GETFL);
3009 fcntl(mem_notify_fd, flags|FASYNC);
3011 sigemptyset(&mask);
3013 sigaddset(&mask, SIGIO);
3015 act.sa_handler = memory_signal_handler;
3016 act.sa_mask = mask;
3017 act.sa_flags = 0;
3019 sigaction(SIGIO, &act, 0);
3021 sigprocmask(SIG_UNBLOCK, &mask, 0);
3023 debug_print("/dev/mem_notify: installed handler\n");
3025 #endif /* linux && SIGIO */
3027 #ifdef HAVE_NETWORKMANAGER_SUPPORT
3028 static void networkmanager_state_change_cb(DBusGProxy *proxy, gchar *dev,
3029 gpointer data)
3031 MainWindow *mainWin;
3033 mainWin = NULL;
3034 if (static_mainwindow)
3035 mainWin = static_mainwindow;
3036 else if (data)
3037 mainWin = (MainWindow*)data;
3039 if (!prefs_common.use_networkmanager)
3040 return;
3042 if (mainWin) {
3043 GError *error = NULL;
3044 gboolean online;
3046 online = networkmanager_is_online(&error);
3047 if(!error) {
3048 if(online && went_offline_nm) {
3049 went_offline_nm = FALSE;
3050 main_window_toggle_work_offline(mainWin, FALSE, FALSE);
3051 debug_print("NetworkManager: Went online\n");
3052 log_message(LOG_PROTOCOL, _("NetworkManager: network is online.\n"));
3054 else if(!online) {
3055 went_offline_nm = TRUE;
3056 main_window_toggle_work_offline(mainWin, TRUE, FALSE);
3057 debug_print("NetworkManager: Went offline\n");
3058 log_message(LOG_PROTOCOL, _("NetworkManager: network is offline.\n"));
3061 else {
3062 debug_print("Failed to get online information from NetworkManager: %s\n",
3063 error->message);
3064 g_error_free(error);
3067 else
3068 debug_print("NetworkManager: Cannot change connection state because "
3069 "main window does not exist\n");
3072 /* Returns true (and sets error appropriately, if given) in case of error */
3073 gboolean networkmanager_is_online(GError **error)
3075 DBusGConnection *connection;
3076 DBusGProxy *proxy;
3077 GError *tmp_error = NULL;
3078 gboolean retVal;
3079 guint32 state;
3081 if (!prefs_common.use_networkmanager)
3082 return TRUE;
3084 tmp_error = NULL;
3085 proxy = NULL;
3086 connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &tmp_error);
3088 if(!connection) {
3089 /* If calling code doesn't do error checking, at least print some debug */
3090 if((error == NULL) || (*error == NULL))
3091 debug_print("Failed to open connection to system bus: %s\n",
3092 tmp_error->message);
3093 g_propagate_error(error, tmp_error);
3094 return TRUE;
3097 proxy = dbus_g_proxy_new_for_name(connection,
3098 "org.freedesktop.NetworkManager",
3099 "/org/freedesktop/NetworkManager",
3100 "org.freedesktop.NetworkManager");
3102 retVal = dbus_g_proxy_call(proxy,"state",&tmp_error, G_TYPE_INVALID,
3103 G_TYPE_UINT, &state, G_TYPE_INVALID);
3105 if(proxy)
3106 g_object_unref(proxy);
3107 if(connection)
3108 dbus_g_connection_unref(connection);
3110 if(!retVal) {
3111 /* If calling code doesn't do error checking, at least print some debug */
3112 if((error == NULL) || (*error == NULL))
3113 debug_print("Failed to get state info from NetworkManager: %s\n",
3114 tmp_error->message);
3115 g_propagate_error(error, tmp_error);
3116 return TRUE;
3118 return (state == NM_STATE_CONNECTED_LOCAL ||
3119 state == NM_STATE_CONNECTED_SITE ||
3120 state == NM_STATE_CONNECTED_GLOBAL ||
3121 state == NM_STATE_UNKNOWN);
3123 #endif