2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2016 Hiroyuki Yamamoto and the Claws Mail team
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/>.
21 #include "claws-features.h"
27 #include <glib/gi18n.h>
37 #include <sys/types.h>
44 #include <X11/SM/SMlib.h>
51 #include "file_checker.h"
53 #ifdef HAVE_STARTUP_NOTIFICATION
54 # define SN_API_NOT_YET_FROZEN
55 # include <libsn/sn-launchee.h>
56 # include <gdk/gdkx.h>
60 #include <dbus/dbus-glib.h>
62 #ifdef HAVE_NETWORKMANAGER_SUPPORT
63 #include <NetworkManager.h>
71 #include "mainwindow.h"
72 #include "folderview.h"
73 #include "image_viewer.h"
74 #include "summaryview.h"
75 #include "prefs_common.h"
76 #include "prefs_account.h"
77 #include "prefs_actions.h"
78 #include "prefs_ext_prog.h"
79 #include "prefs_fonts.h"
80 #include "prefs_image_viewer.h"
81 #include "prefs_message.h"
82 #include "prefs_migration.h"
83 #include "prefs_receive.h"
84 #include "prefs_msg_colors.h"
85 #include "prefs_quote.h"
86 #include "prefs_spelling.h"
87 #include "prefs_summaries.h"
88 #include "prefs_themes.h"
89 #include "prefs_other.h"
90 #include "prefs_logging.h"
91 #include "prefs_send.h"
92 #include "prefs_wrapping.h"
93 #include "prefs_compose_writing.h"
94 #include "prefs_display_header.h"
99 #include "send_message.h"
102 #include "manage_window.h"
103 #include "alertpanel.h"
104 #include "statusbar.h"
105 #ifndef USE_ALT_ADDRBOOK
106 #include "addressbook.h"
108 #include "addressbook-dbus.h"
112 #include "folder_item_prefs.h"
115 #include "gtkutils.h"
118 #include "prefs_toolbar.h"
121 #include "imap_gtk.h"
122 #include "news_gtk.h"
127 #include "quicksearch.h"
128 #include "advsearch.h"
130 #include "passwordstore.h"
133 #include "imap-thread.h"
134 #include "nntp-thread.h"
136 #include "stock_pixmap.h"
147 #ifdef HAVE_NETWORKMANAGER_SUPPORT
148 /* Went offline due to NetworkManager */
149 static gboolean went_offline_nm
;
152 #if !defined(NM_CHECK_VERSION)
153 #define NM_CHECK_VERSION(x,y,z) 0
156 #ifdef HAVE_DBUS_GLIB
157 static DBusGProxy
*awn_proxy
= NULL
;
163 #ifdef HAVE_STARTUP_NOTIFICATION
164 static SnLauncheeContext
*sn_context
= NULL
;
165 static SnDisplay
*sn_display
= NULL
;
168 static gint lock_socket
= -1;
169 static gint lock_socket_tag
= 0;
170 static gchar
*x_display
= NULL
;
173 ONLINE_MODE_DONT_CHANGE
,
178 static struct RemoteCmd
{
180 gboolean receive_all
;
181 gboolean cancel_receiving
;
182 gboolean cancel_sending
;
184 const gchar
*compose_mailto
;
187 const gchar
*search_folder
;
188 const gchar
*search_type
;
189 const gchar
*search_request
;
190 gboolean search_recursive
;
192 gboolean status_full
;
194 gboolean reset_statistics
;
195 GPtrArray
*status_folders
;
196 GPtrArray
*status_full_folders
;
203 const gchar
*subscribe_uri
;
206 const gchar
*geometry
;
209 SessionStats session_stats
;
211 static void reset_statistics(void);
213 static void parse_cmd_opt(int argc
, char *argv
[]);
215 static gint
prohibit_duplicate_launch (void);
216 static gchar
* get_crashfile_name (void);
217 static gint
lock_socket_remove (void);
218 static void lock_socket_input_cb (gpointer data
,
220 GIOCondition condition
);
222 static void open_compose_new (const gchar
*address
,
223 GList
*attach_files
);
225 static void send_queue (void);
226 static void initial_processing (FolderItem
*item
, gpointer data
);
227 static void quit_signal_handler (int sig
);
228 static void install_basic_sighandlers (void);
229 #if (defined linux && defined SIGIO)
230 static void install_memory_sighandler (void);
232 static void exit_claws (MainWindow
*mainwin
);
234 #ifdef HAVE_NETWORKMANAGER_SUPPORT
235 static void networkmanager_state_change_cb(DBusGProxy
*proxy
, gchar
*dev
,
239 #define MAKE_DIR_IF_NOT_EXIST(dir) \
241 if (!is_dir_exist(dir)) { \
242 if (is_file_exist(dir)) { \
244 (_("File '%s' already exists.\n" \
245 "Can't create folder."), \
249 if (make_dir(dir) < 0) \
254 static MainWindow
*static_mainwindow
;
256 static gboolean emergency_exit
= FALSE
;
258 #ifdef HAVE_STARTUP_NOTIFICATION
259 static void sn_error_trap_push(SnDisplay
*display
, Display
*xdisplay
)
261 gdk_error_trap_push();
264 static void sn_error_trap_pop(SnDisplay
*display
, Display
*xdisplay
)
266 gdk_error_trap_pop();
269 static void startup_notification_complete(gboolean with_window
)
272 GtkWidget
*hack
= NULL
;
275 /* this is needed to make the startup notification leave,
276 * if we have been launched from a menu.
277 * We have to display a window, so let it be very little */
278 hack
= gtk_window_new(GTK_WINDOW_POPUP
);
279 gtk_window_move(GTK_WINDOW(hack
), 0, 0);
280 gtk_widget_set_size_request(hack
, 1, 1);
281 gtk_widget_show(hack
);
284 xdisplay
= GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
285 sn_display
= sn_display_new(xdisplay
,
288 sn_context
= sn_launchee_context_new_from_environment(sn_display
,
289 DefaultScreen(xdisplay
));
291 if (sn_context
!= NULL
) {
292 sn_launchee_context_complete(sn_context
);
293 sn_launchee_context_unref(sn_context
);
294 sn_display_unref(sn_display
);
297 gtk_widget_destroy(hack
);
300 #endif /* HAVE_STARTUP_NOTIFICATION */
302 static void claws_gtk_idle(void)
304 while(gtk_events_pending()) {
305 gtk_main_iteration();
310 static gboolean sc_starting
= FALSE
;
312 static gboolean
defer_check_all(void *data
)
314 gboolean autochk
= GPOINTER_TO_INT(data
);
316 inc_all_account_mail(static_mainwindow
, autochk
,
317 prefs_common
.newmail_notify_manu
);
321 main_window_set_menu_sensitive(static_mainwindow
);
322 toolbar_main_set_sensitive(static_mainwindow
);
327 static gboolean
defer_check(void *data
)
329 inc_mail(static_mainwindow
, prefs_common
.newmail_notify_manu
);
333 main_window_set_menu_sensitive(static_mainwindow
);
334 toolbar_main_set_sensitive(static_mainwindow
);
339 static gboolean
defer_jump(void *data
)
341 if (cmd
.receive_all
) {
342 defer_check_all(GINT_TO_POINTER(FALSE
));
343 } else if (prefs_common
.chk_on_startup
) {
344 defer_check_all(GINT_TO_POINTER(TRUE
));
345 } else if (cmd
.receive
) {
348 mainwindow_jump_to(data
, FALSE
);
351 main_window_set_menu_sensitive(static_mainwindow
);
352 toolbar_main_set_sensitive(static_mainwindow
);
357 static void chk_update_val(GtkWidget
*widget
, gpointer data
)
359 gboolean
*val
= (gboolean
*)data
;
360 *val
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
363 static gboolean
migrate_old_config(const gchar
*old_cfg_dir
, const gchar
*new_cfg_dir
, const gchar
*oldversion
)
365 gchar
*message
= g_strdup_printf(_("Configuration for %s found.\n"
366 "Do you want to migrate this configuration?"), oldversion
);
367 gchar
*message2
= g_strdup_printf(_("\n\nYour Sylpheed filtering rules can be converted by a\n"
368 "script available at %s."), TOOLS_URI
);
370 if (!strcmp(oldversion
, "Sylpheed"))
371 message
= g_strconcat(message
, message2
, NULL
);
375 GtkWidget
*window
= NULL
;
376 GtkWidget
*keep_backup_chk
;
377 gboolean backup
= TRUE
;
379 keep_backup_chk
= gtk_check_button_new_with_label (_("Keep old configuration"));
380 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keep_backup_chk
), TRUE
);
381 CLAWS_SET_TIP(keep_backup_chk
,
382 _("Keeping a backup will allow you to go back to an "
383 "older version, but may take a while if you have "
384 "cached IMAP or News data, and will take some extra "
385 "room on your disk."));
387 g_signal_connect(G_OBJECT(keep_backup_chk
), "toggled",
388 G_CALLBACK(chk_update_val
), &backup
);
390 if (alertpanel_full(_("Migration of configuration"), message
,
391 GTK_STOCK_NO
, "+" GTK_STOCK_YES
, NULL
, FALSE
,
392 keep_backup_chk
, ALERT_QUESTION
, G_ALERTDEFAULT
) != G_ALERTALTERNATE
) {
396 /* we can either do a fast migration requiring not any extra disk
397 * space, or a slow one that copies the old configuration and leaves
401 window
= label_window_create(_("Copying configuration... This may take a while..."));
404 r
= copy_dir(old_cfg_dir
, new_cfg_dir
);
405 label_window_destroy(window
);
407 /* if copy failed, we'll remove the partially copied
410 alertpanel_error(_("Migration failed!"));
411 remove_dir_recursive(new_cfg_dir
);
414 /* fast mode failed, but we don't want backup */
415 remove_dir_recursive(old_cfg_dir
);
419 window
= label_window_create(_("Migrating configuration..."));
422 r
= g_rename(old_cfg_dir
, new_cfg_dir
);
423 label_window_destroy(window
);
425 /* if g_rename failed, we'll try to copy */
427 FILE_OP_ERROR(new_cfg_dir
, "g_rename failed, trying copy\n");
434 static int migrate_common_rc(const gchar
*old_rc
, const gchar
*new_rc
)
437 gchar
*plugin_path
, *old_plugin_path
, *new_plugin_path
;
439 gboolean err
= FALSE
;
441 oldfp
= g_fopen(old_rc
, "r");
444 newfp
= g_fopen(new_rc
, "w");
450 plugin_path
= g_strdup(get_plugin_dir());
451 new_plugin_path
= g_strdup(plugin_path
);
453 if (strstr(plugin_path
, "/claws-mail/")) {
454 gchar
*end
= g_strdup(strstr(plugin_path
, "/claws-mail/")+strlen("/claws-mail/"));
455 *(strstr(plugin_path
, "/claws-mail/")) = '\0';
456 old_plugin_path
= g_strconcat(plugin_path
, "/sylpheed-claws/", end
, NULL
);
459 old_plugin_path
= g_strdup(new_plugin_path
);
461 debug_print("replacing %s with %s\n", old_plugin_path
, new_plugin_path
);
462 while (fgets(buf
, sizeof(buf
), oldfp
)) {
463 if (strncmp(buf
, old_plugin_path
, strlen(old_plugin_path
))) {
464 err
|= (fputs(buf
, newfp
) == EOF
);
466 debug_print("->replacing %s\n", buf
);
467 debug_print(" with %s%s\n", new_plugin_path
, buf
+strlen(old_plugin_path
));
468 err
|= (fputs(new_plugin_path
, newfp
) == EOF
);
469 err
|= (fputs(buf
+strlen(old_plugin_path
), newfp
) == EOF
);
473 g_free(new_plugin_path
);
474 g_free(old_plugin_path
);
476 if (fclose(newfp
) == EOF
)
484 sc_client_set_value (MainWindow
*mainwin
,
495 prop
.num_vals
= num_vals
;
499 if (mainwin
->smc_conn
)
500 SmcSetProperties ((SmcConn
) mainwin
->smc_conn
, 1, proplist
);
503 static void sc_die_callback (SmcConn smc_conn
, SmPointer client_data
)
508 static void sc_save_complete_callback(SmcConn smc_conn
, SmPointer client_data
)
512 static void sc_shutdown_cancelled_callback (SmcConn smc_conn
, SmPointer client_data
)
514 MainWindow
*mainwin
= (MainWindow
*)client_data
;
515 if (mainwin
->smc_conn
)
516 SmcSaveYourselfDone ((SmcConn
) mainwin
->smc_conn
, TRUE
);
519 static void sc_save_yourself_callback (SmcConn smc_conn
,
520 SmPointer client_data
,
526 MainWindow
*mainwin
= (MainWindow
*)client_data
;
527 if (mainwin
->smc_conn
)
528 SmcSaveYourselfDone ((SmcConn
) mainwin
->smc_conn
, TRUE
);
531 static IceIOErrorHandler sc_ice_installed_handler
;
533 static void sc_ice_io_error_handler (IceConn connection
)
535 if (sc_ice_installed_handler
)
536 (*sc_ice_installed_handler
) (connection
);
538 static gboolean
sc_process_ice_messages (GIOChannel
*source
,
539 GIOCondition condition
,
542 IceConn connection
= (IceConn
) data
;
543 IceProcessMessagesStatus status
;
545 status
= IceProcessMessages (connection
, NULL
, NULL
);
547 if (status
== IceProcessMessagesIOError
) {
548 IcePointer context
= IceGetConnectionContext (connection
);
550 if (context
&& G_IS_OBJECT(context
)) {
551 guint disconnect_id
= g_signal_lookup ("disconnect", G_OBJECT_TYPE (context
));
553 if (disconnect_id
> 0)
554 g_signal_emit (context
, disconnect_id
, 0);
556 IceSetShutdownNegotiation (connection
, False
);
557 IceCloseConnection (connection
);
564 static void new_ice_connection (IceConn connection
, IcePointer client_data
, Bool opening
,
565 IcePointer
*watch_data
)
571 /* Make sure we don't pass on these file descriptors to any
573 fcntl(IceConnectionNumber(connection
),F_SETFD
,
574 fcntl(IceConnectionNumber(connection
),F_GETFD
,0) | FD_CLOEXEC
);
576 channel
= g_io_channel_unix_new (IceConnectionNumber (connection
));
577 input_id
= g_io_add_watch (channel
,
578 G_IO_IN
| G_IO_HUP
| G_IO_ERR
| G_IO_PRI
,
579 sc_process_ice_messages
,
581 g_io_channel_unref (channel
);
583 *watch_data
= (IcePointer
) GUINT_TO_POINTER (input_id
);
585 input_id
= GPOINTER_TO_UINT ((gpointer
) *watch_data
);
586 g_source_remove (input_id
);
590 static void sc_session_manager_connect(MainWindow
*mainwin
)
592 static gboolean connected
= FALSE
;
593 SmcCallbacks callbacks
;
595 IceIOErrorHandler default_handler
;
602 sc_ice_installed_handler
= IceSetIOErrorHandler (NULL
);
603 default_handler
= IceSetIOErrorHandler (sc_ice_io_error_handler
);
605 if (sc_ice_installed_handler
== default_handler
)
606 sc_ice_installed_handler
= NULL
;
608 IceAddConnectionWatch (new_ice_connection
, NULL
);
611 callbacks
.save_yourself
.callback
= sc_save_yourself_callback
;
612 callbacks
.die
.callback
= sc_die_callback
;
613 callbacks
.save_complete
.callback
= sc_save_complete_callback
;
614 callbacks
.shutdown_cancelled
.callback
= sc_shutdown_cancelled_callback
;
616 callbacks
.save_yourself
.client_data
=
617 callbacks
.die
.client_data
=
618 callbacks
.save_complete
.client_data
=
619 callbacks
.shutdown_cancelled
.client_data
= (SmPointer
) mainwin
;
620 if (g_getenv ("SESSION_MANAGER")) {
621 gchar error_string_ret
[256] = "";
623 mainwin
->smc_conn
= (gpointer
)
624 SmcOpenConnection (NULL
, mainwin
,
625 SmProtoMajor
, SmProtoMinor
,
626 SmcSaveYourselfProcMask
| SmcDieProcMask
|
627 SmcSaveCompleteProcMask
|
628 SmcShutdownCancelledProcMask
,
631 256, error_string_ret
);
633 if (error_string_ret
[0] || mainwin
->smc_conn
== NULL
)
634 g_warning ("While connecting to session manager: %s.",
638 vals
= g_new (SmPropValue
, 1);
639 vals
[0].length
= strlen(argv0
);
640 vals
[0].value
= argv0
;
641 sc_client_set_value (mainwin
, SmCloneCommand
, SmLISTofARRAY8
, 1, vals
);
642 sc_client_set_value (mainwin
, SmRestartCommand
, SmLISTofARRAY8
, 1, vals
);
643 sc_client_set_value (mainwin
, SmProgram
, SmARRAY8
, 1, vals
);
645 vals
[0].length
= strlen(g_get_user_name()?g_get_user_name():"");
646 vals
[0].value
= g_strdup(g_get_user_name()?g_get_user_name():"");
647 sc_client_set_value (mainwin
, SmUserID
, SmARRAY8
, 1, vals
);
655 static gboolean sc_exiting
= FALSE
;
656 static gboolean show_at_startup
= TRUE
;
657 static gboolean claws_crashed_bool
= FALSE
;
659 gboolean
claws_crashed(void) {
660 return claws_crashed_bool
;
663 void main_set_show_at_startup(gboolean show
)
665 show_at_startup
= show
;
669 static FILE* win32_debug_fp
=NULL
;
670 static guint win32_log_handler_app_id
;
671 static guint win32_log_handler_glib_id
;
672 static guint win32_log_handler_gtk_id
;
674 static void win32_print_stdout(const gchar
*string
)
676 if (win32_debug_fp
) {
677 fprintf(win32_debug_fp
, "%s", string
);
678 fflush(win32_debug_fp
);
682 static void win32_print_stderr(const gchar
*string
)
684 if (win32_debug_fp
) {
685 fprintf(win32_debug_fp
, "%s", string
);
686 fflush(win32_debug_fp
);
690 static void win32_log(const gchar
*log_domain
, GLogLevelFlags log_level
, const gchar
* message
, gpointer user_data
)
692 if (win32_debug_fp
) {
695 switch(log_level
& G_LOG_LEVEL_MASK
)
697 case G_LOG_LEVEL_ERROR
:
700 case G_LOG_LEVEL_CRITICAL
:
703 case G_LOG_LEVEL_WARNING
:
706 case G_LOG_LEVEL_MESSAGE
:
709 case G_LOG_LEVEL_INFO
:
712 case G_LOG_LEVEL_DEBUG
:
719 fprintf(win32_debug_fp
, "%s: %s: %s", log_domain
, type
, message
);
721 fprintf(win32_debug_fp
, "%s: %s", type
, message
);
722 fflush(win32_debug_fp
);
726 static void win32_open_log(void)
728 gchar
*logfile
= g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S
, "claws-win32.log", NULL
);
729 gchar
*oldlogfile
= g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S
, "claws-win32.log.bak", NULL
);
731 if (is_file_exist(logfile
)) {
732 if (rename_force(logfile
, oldlogfile
) < 0)
733 FILE_OP_ERROR(logfile
, "rename");
735 win32_debug_fp
= g_fopen(logfile
, "w");
740 g_set_print_handler(win32_print_stdout
);
741 g_set_printerr_handler(win32_print_stdout
);
742 win32_log_handler_app_id
= g_log_set_handler(NULL
, G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
743 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
744 win32_log_handler_glib_id
= g_log_set_handler("GLib", G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
745 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
746 win32_log_handler_gtk_id
= g_log_set_handler("Gtk", G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
747 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
751 static void win32_close_log(void)
755 g_log_remove_handler("", win32_log_handler_app_id
);
756 g_log_remove_handler("GLib", win32_log_handler_glib_id
);
757 g_log_remove_handler("Gtk", win32_log_handler_gtk_id
);
758 fclose(win32_debug_fp
);
764 static void main_dump_features_list(gboolean show_debug_only
)
765 /* display compiled-in features list */
767 if (show_debug_only
&& !debug_get_mode())
771 debug_print("runtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
772 gtk_major_version
, gtk_minor_version
, gtk_micro_version
,
773 glib_major_version
, glib_minor_version
, glib_micro_version
);
775 g_print("runtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
776 gtk_major_version
, gtk_minor_version
, gtk_micro_version
,
777 glib_major_version
, glib_minor_version
, glib_micro_version
);
779 debug_print("buildtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
780 GTK_MAJOR_VERSION
, GTK_MINOR_VERSION
, GTK_MICRO_VERSION
,
781 GLIB_MAJOR_VERSION
, GLIB_MINOR_VERSION
, GLIB_MICRO_VERSION
);
783 g_print("buildtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
784 GTK_MAJOR_VERSION
, GTK_MINOR_VERSION
, GTK_MICRO_VERSION
,
785 GLIB_MAJOR_VERSION
, GLIB_MINOR_VERSION
, GLIB_MICRO_VERSION
);
788 debug_print("Compiled-in features:\n");
790 g_print("Compiled-in features:\n");
793 debug_print(" compface\n");
795 g_print(" compface\n");
799 debug_print(" Enchant\n");
801 g_print(" Enchant\n");
805 debug_print(" GnuTLS\n");
807 g_print(" GnuTLS\n");
811 debug_print(" IPv6\n");
817 debug_print(" iconv\n");
823 debug_print(" JPilot\n");
825 g_print(" JPilot\n");
829 debug_print(" LDAP\n");
835 debug_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR
, LIBETPAN_VERSION_MINOR
);
837 g_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR
, LIBETPAN_VERSION_MINOR
);
841 debug_print(" libSM\n");
845 #if HAVE_NETWORKMANAGER_SUPPORT
847 debug_print(" NetworkManager\n");
849 g_print(" NetworkManager\n");
853 #ifdef HAVE_DBUS_GLIB
854 static guint dbus_item_hook_id
= -1;
855 static guint dbus_folder_hook_id
= -1;
857 static void uninstall_dbus_status_handler(void)
860 g_object_unref(awn_proxy
);
862 if (dbus_item_hook_id
!= -1)
863 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, dbus_item_hook_id
);
864 if (dbus_folder_hook_id
!= -1)
865 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST
, dbus_folder_hook_id
);
868 static void dbus_update(FolderItem
*removed_item
)
870 guint
new, unread
, unreadmarked
, marked
, total
;
871 guint replied
, forwarded
, locked
, ignored
, watched
;
873 GError
*error
= NULL
;
875 folder_count_total_msgs(&new, &unread
, &unreadmarked
, &marked
, &total
,
876 &replied
, &forwarded
, &locked
, &ignored
,
879 total
-= removed_item
->total_msgs
;
880 new -= removed_item
->new_msgs
;
881 unread
-= removed_item
->unread_msgs
;
885 buf
= g_strdup_printf("%d", new);
886 dbus_g_proxy_call(awn_proxy
, "SetInfoByName", &error
,
887 G_TYPE_STRING
, "claws-mail",
889 G_TYPE_INVALID
, G_TYPE_INVALID
);
893 dbus_g_proxy_call(awn_proxy
, "UnsetInfoByName", &error
, G_TYPE_STRING
,
894 "claws-mail", G_TYPE_INVALID
, G_TYPE_INVALID
);
897 debug_print("%s\n", error
->message
);
902 static gboolean
dbus_status_update_folder_hook(gpointer source
, gpointer data
)
904 FolderUpdateData
*hookdata
;
906 if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
)
907 dbus_update(hookdata
->item
);
914 static gboolean
dbus_status_update_item_hook(gpointer source
, gpointer data
)
921 static void install_dbus_status_handler(void)
923 GError
*tmp_error
= NULL
;
924 DBusGConnection
*connection
= dbus_g_bus_get(DBUS_BUS_SESSION
, &tmp_error
);
927 /* If calling code doesn't do error checking, at least print some debug */
928 debug_print("Failed to open connection to session bus: %s\n",
930 g_error_free(tmp_error
);
933 awn_proxy
= dbus_g_proxy_new_for_name(connection
,
934 "com.google.code.Awn",
935 "/com/google/code/Awn",
936 "com.google.code.Awn");
937 dbus_item_hook_id
= hooks_register_hook (FOLDER_ITEM_UPDATE_HOOKLIST
, dbus_status_update_item_hook
, NULL
);
938 if (dbus_item_hook_id
== -1) {
939 g_warning("Failed to register folder item update hook");
940 uninstall_dbus_status_handler();
944 dbus_folder_hook_id
= hooks_register_hook (FOLDER_UPDATE_HOOKLIST
, dbus_status_update_folder_hook
, NULL
);
945 if (dbus_folder_hook_id
== -1) {
946 g_warning("Failed to register folder update hook");
947 uninstall_dbus_status_handler();
953 static void reset_statistics(void)
955 /* (re-)initialize session statistics */
956 session_stats
.received
= 0;
957 session_stats
.sent
= 0;
958 session_stats
.replied
= 0;
959 session_stats
.forwarded
= 0;
960 session_stats
.time_started
= time(NULL
);
963 int main(int argc
, char *argv
[])
965 #ifdef HAVE_DBUS_GLIB
966 DBusGConnection
*connection
;
969 #ifdef HAVE_NETWORKMANAGER_SUPPORT
970 DBusGProxy
*nm_proxy
;
974 FolderView
*folderview
;
976 gboolean crash_file_present
= FALSE
;
977 gint num_folder_class
= 0;
978 gboolean asked_for_migration
= FALSE
;
979 gboolean start_done
= TRUE
;
980 GSList
*plug_list
= NULL
;
981 gboolean never_ran
= FALSE
;
982 gboolean mainwin_shown
= FALSE
;
984 START_TIMING("startup");
991 if (!claws_init(&argc
, &argv
)) {
998 prog_version
= PROG_VERSION
;
999 argv0
= g_strdup(argv
[0]);
1001 parse_cmd_opt(argc
, argv
);
1005 /* check and create unix domain socket for remote operation */
1006 lock_socket
= prohibit_duplicate_launch();
1007 if (lock_socket
< 0) {
1008 #ifdef HAVE_STARTUP_NOTIFICATION
1009 if(gtk_init_check(&argc
, &argv
))
1010 startup_notification_complete(TRUE
);
1015 main_dump_features_list(TRUE
);
1016 prefs_prepare_cache();
1020 #if !GTK_CHECK_VERSION(3, 0, 0)
1023 gtk_init(&argc
, &argv
);
1024 crash_main(cmd
.crash_params
);
1030 crash_install_handlers();
1032 install_basic_sighandlers();
1033 #if (defined linux && defined SIGIO)
1034 install_memory_sighandler();
1037 if (cmd
.status
|| cmd
.status_full
|| cmd
.search
||
1038 cmd
.statistics
|| cmd
.reset_statistics
||
1039 cmd
.cancel_receiving
|| cmd
.cancel_sending
||
1041 puts("0 Claws Mail not running.");
1042 lock_socket_remove();
1048 #if !GLIB_CHECK_VERSION(2,32,0)
1049 if (!g_thread_supported())
1050 g_thread_init(NULL
);
1055 #if !GTK_CHECK_VERSION(3, 0, 0)
1058 gtk_init(&argc
, &argv
);
1061 gtk_settings_set_string_property(gtk_settings_get_default(),
1065 gtk_settings_set_long_property(gtk_settings_get_default(),
1066 "gtk-auto-mnemonics",
1071 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1072 went_offline_nm
= FALSE
;
1075 #ifdef HAVE_DBUS_GLIB
1077 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &error
);
1080 debug_print("Failed to open connection to system bus: %s\n", error
->message
);
1081 g_error_free(error
);
1084 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1085 nm_proxy
= dbus_g_proxy_new_for_name(connection
,
1086 "org.freedesktop.NetworkManager",
1087 "/org/freedesktop/NetworkManager",
1088 "org.freedesktop.NetworkManager");
1090 #if NM_CHECK_VERSION(0,8,992)
1091 dbus_g_proxy_add_signal(nm_proxy
, "StateChanged", G_TYPE_UINT
, G_TYPE_INVALID
);
1092 dbus_g_proxy_connect_signal(nm_proxy
, "StateChanged",
1093 G_CALLBACK(networkmanager_state_change_cb
),
1096 dbus_g_proxy_add_signal(nm_proxy
, "StateChange", G_TYPE_UINT
, G_TYPE_INVALID
);
1097 dbus_g_proxy_connect_signal(nm_proxy
, "StateChange",
1098 G_CALLBACK(networkmanager_state_change_cb
),
1103 install_dbus_status_handler();
1107 #if !GTK_CHECK_VERSION(3, 0, 0)
1108 gtk_widget_set_default_colormap(
1109 gdk_screen_get_system_colormap(
1110 gdk_screen_get_default()));
1113 gtkut_create_ui_manager();
1115 /* Create container for all the menus we will be adding */
1116 MENUITEM_ADDUI("/", "Menus", NULL
, GTK_UI_MANAGER_MENUBAR
);
1118 if (!g_thread_supported()) {
1119 g_error(_("g_thread is not supported by glib.\n"));
1123 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1125 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1128 /* no config dir exists. See if we can migrate an old config. */
1129 if (!is_dir_exist(RC_DIR
)) {
1130 prefs_destroy_cache();
1133 /* if one of the old dirs exist, we'll ask if the user
1134 * want to migrates, and r will be TRUE if he said yes
1135 * and migration succeeded, and FALSE otherwise.
1137 if (is_dir_exist(OLD_GTK2_RC_DIR
)) {
1138 r
= migrate_old_config(OLD_GTK2_RC_DIR
, RC_DIR
,
1139 g_strconcat("Sylpheed-Claws 2.6.0 ", _("(or older)"), NULL
));
1140 asked_for_migration
= TRUE
;
1141 } else if (is_dir_exist(OLDER_GTK2_RC_DIR
)) {
1142 r
= migrate_old_config(OLDER_GTK2_RC_DIR
, RC_DIR
,
1143 g_strconcat("Sylpheed-Claws 1.9.15 ",_("(or older)"), NULL
));
1144 asked_for_migration
= TRUE
;
1145 } else if (is_dir_exist(OLD_GTK1_RC_DIR
)) {
1146 r
= migrate_old_config(OLD_GTK1_RC_DIR
, RC_DIR
,
1147 g_strconcat("Sylpheed-Claws 1.0.5 ",_("(or older)"), NULL
));
1148 asked_for_migration
= TRUE
;
1149 } else if (is_dir_exist(SYLPHEED_RC_DIR
)) {
1150 r
= migrate_old_config(SYLPHEED_RC_DIR
, RC_DIR
, "Sylpheed");
1151 asked_for_migration
= TRUE
;
1154 /* If migration failed or the user didn't want to do it,
1155 * we create a new one (and we'll hit wizard later).
1157 if (r
== FALSE
&& !is_dir_exist(RC_DIR
)) {
1159 if (copy_dir(SYSCONFDIR
"/skel/.claws-mail", RC_DIR
) < 0) {
1161 if (!is_dir_exist(RC_DIR
) && make_dir(RC_DIR
) < 0) {
1174 if (!is_file_exist(RC_DIR G_DIR_SEPARATOR_S COMMON_RC
) &&
1175 is_file_exist(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC
)) {
1176 /* post 2.6 name change */
1177 migrate_common_rc(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC
,
1178 RC_DIR G_DIR_SEPARATOR_S COMMON_RC
);
1182 plugin_load_all("Common");
1184 userrc
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, "gtkrc-2.0", NULL
);
1185 gtk_rc_parse(userrc
);
1188 userrc
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, MENU_RC
, NULL
);
1189 gtk_accel_map_load (userrc
);
1193 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_rc_dir(), 1, win32_close_log(););
1195 CHDIR_RETURN_VAL_IF_FAIL(get_rc_dir(), 1);
1198 MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
1199 MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
1200 MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
1201 MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
1202 MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
1203 MAKE_DIR_IF_NOT_EXIST(UIDL_DIR
);
1205 crash_file_present
= is_file_exist(get_crashfile_name());
1206 /* remove temporary files */
1207 remove_all_files(get_tmp_dir());
1208 remove_all_files(get_mime_tmp_dir());
1210 if (!cmd
.crash
&& crash_file_present
)
1211 claws_crashed_bool
= TRUE
;
1213 if (is_file_exist("claws.log")) {
1214 if (rename_force("claws.log", "claws.log.bak") < 0)
1215 FILE_OP_ERROR("claws.log", "rename");
1217 set_log_file(LOG_PROTOCOL
, "claws.log");
1219 if (is_file_exist("filtering.log")) {
1220 if (rename_force("filtering.log", "filtering.log.bak") < 0)
1221 FILE_OP_ERROR("filtering.log", "rename");
1223 set_log_file(LOG_DEBUG_FILTERING
, "filtering.log");
1226 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1228 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1231 folder_system_init();
1232 prefs_common_read_config();
1234 prefs_themes_init();
1236 prefs_ext_prog_init();
1237 prefs_wrapping_init();
1238 prefs_compose_writing_init();
1239 prefs_msg_colors_init();
1240 image_viewer_init();
1241 prefs_image_viewer_init();
1243 prefs_summaries_init();
1244 prefs_message_init();
1246 prefs_logging_init();
1247 prefs_receive_init();
1252 gtkaspell_checkers_init();
1253 prefs_spelling_init();
1257 if(prefs_common
.gtk_theme
&& strcmp(prefs_common
.gtk_theme
, DEFAULT_W32_GTK_THEME
))
1258 gtk_settings_set_string_property(gtk_settings_get_default(),
1260 prefs_common
.gtk_theme
,
1265 sock_set_io_timeout(prefs_common
.io_timeout_secs
);
1266 prefs_actions_read_config();
1267 prefs_display_header_read_config();
1268 /* prefs_filtering_read_config(); */
1269 #ifndef USE_ALT_ADDRBOOK
1270 addressbook_read_file();
1272 g_clear_error(&error
);
1273 if (! addressbook_start_service(&error
)) {
1274 g_warning("%s", error
->message
);
1275 g_clear_error(&error
);
1278 addressbook_install_hooks(&error
);
1281 gtkut_widget_init();
1282 stock_pixbuf_gdk(STOCK_PIXMAP_CLAWS_MAIL_ICON
, &icon
);
1283 gtk_window_set_default_icon(icon
);
1285 folderview_initialize();
1291 mainwin
= main_window_create();
1293 if (!check_file_integrity())
1296 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1297 networkmanager_state_change_cb(nm_proxy
,NULL
,mainwin
);
1300 manage_window_focus_in(mainwin
->window
, NULL
, NULL
);
1301 folderview
= mainwin
->folderview
;
1303 folderview_freeze(mainwin
->folderview
);
1304 folder_item_update_freeze();
1306 passwd_store_read_config();
1307 prefs_account_init();
1308 account_read_config_all();
1310 #ifdef HAVE_LIBETPAN
1311 imap_main_init(prefs_common
.skip_ssl_cert_check
);
1312 imap_main_set_timeout(prefs_common
.io_timeout_secs
);
1313 nntp_main_init(prefs_common
.skip_ssl_cert_check
);
1315 /* If we can't read a folder list or don't have accounts,
1316 * it means the configuration's not done. Either this is
1317 * a brand new install, either a failed/refused migration.
1318 * So we'll start the wizard.
1320 if (folder_read_list() < 0) {
1321 prefs_destroy_cache();
1323 /* if run_wizard returns FALSE it's because it's
1324 * been cancelled. We can't do much but exit.
1325 * however, if the user was asked for a migration,
1326 * we remove the newly created directory so that
1327 * he's asked again for migration on next launch.*/
1328 if (!run_wizard(mainwin
, TRUE
)) {
1329 if (asked_for_migration
)
1330 remove_dir_recursive(RC_DIR
);
1336 main_window_reflect_prefs_all_now();
1337 folder_write_list();
1341 if (!account_get_list()) {
1342 prefs_destroy_cache();
1343 if (!run_wizard(mainwin
, FALSE
)) {
1344 if (asked_for_migration
)
1345 remove_dir_recursive(RC_DIR
);
1351 if(!account_get_list()) {
1352 exit_claws(mainwin
);
1362 toolbar_main_set_sensitive(mainwin
);
1363 main_window_set_menu_sensitive(mainwin
);
1365 /* if crashed, show window early so that the user
1366 * sees what's happening */
1367 if (claws_crashed()) {
1368 main_window_popup(mainwin
);
1369 mainwin_shown
= TRUE
;
1372 account_set_missing_folder();
1373 folder_set_missing_folders();
1374 folderview_set(folderview
);
1376 prefs_matcher_read_config();
1377 quicksearch_set_search_strings(mainwin
->summaryview
->quicksearch
);
1379 /* make one all-folder processing before using claws */
1380 main_window_cursor_wait(mainwin
);
1381 folder_func_to_all_folders(initial_processing
, (gpointer
*)mainwin
);
1383 /* if claws crashed, rebuild caches */
1384 if (claws_crashed()) {
1386 debug_print("Claws Mail crashed, checking for new messages in local folders\n");
1387 folder_item_update_thaw();
1388 folderview_check_new(NULL
);
1389 folder_clean_cache_memory_force();
1390 folder_item_update_freeze();
1392 /* make the crash-indicator file */
1393 str_write_to_file("foo", get_crashfile_name());
1395 inc_autocheck_timer_init(mainwin
);
1397 /* ignore SIGPIPE signal for preventing sudden death of program */
1399 signal(SIGPIPE
, SIG_IGN
);
1401 if (cmd
.online_mode
== ONLINE_MODE_OFFLINE
) {
1402 main_window_toggle_work_offline(mainwin
, TRUE
, FALSE
);
1404 if (cmd
.online_mode
== ONLINE_MODE_ONLINE
) {
1405 main_window_toggle_work_offline(mainwin
, FALSE
, FALSE
);
1408 if (cmd
.status_folders
) {
1409 g_ptr_array_free(cmd
.status_folders
, TRUE
);
1410 cmd
.status_folders
= NULL
;
1412 if (cmd
.status_full_folders
) {
1413 g_ptr_array_free(cmd
.status_full_folders
, TRUE
);
1414 cmd
.status_full_folders
= NULL
;
1417 claws_register_idle_function(claws_gtk_idle
);
1420 prefs_toolbar_init();
1422 num_folder_class
= g_list_length(folder_get_list());
1424 plugin_load_all("GTK2");
1426 if (g_list_length(folder_get_list()) != num_folder_class
) {
1427 debug_print("new folders loaded, reloading processing rules\n");
1428 prefs_matcher_read_config();
1431 if ((plug_list
= plugin_get_unloaded_list()) != NULL
) {
1434 gint num_plugins
= 0;
1435 for (cur
= plug_list
; cur
; cur
= cur
->next
) {
1436 Plugin
*plugin
= (Plugin
*)cur
->data
;
1437 gchar
*tmp
= g_strdup_printf("%s\n%s",
1439 plugin_get_name(plugin
));
1444 main_window_cursor_normal(mainwin
);
1445 main_window_popup(mainwin
);
1446 mainwin_shown
= TRUE
;
1447 alertpanel_warning(ngettext(
1448 "The following plugin failed to load. "
1449 "Check the Plugins configuration "
1450 "for more information:\n%s",
1451 "The following plugins failed to load. "
1452 "Check the Plugins configuration "
1453 "for more information:\n%s",
1456 main_window_cursor_wait(mainwin
);
1458 g_slist_free(plug_list
);
1462 prefs_common_get_prefs()->config_version
= CLAWS_CONFIG_VERSION
;
1463 prefs_common_write_config();
1464 plugin_load_standard_plugins ();
1466 if (prefs_update_config_version() < 0) {
1467 exit_claws(mainwin
);
1475 /* if not crashed, show window now */
1476 if (!mainwin_shown
) {
1477 /* apart if something told not to show */
1478 if (show_at_startup
)
1479 main_window_popup(mainwin
);
1482 if (cmd
.geometry
!= NULL
) {
1483 if (!gtk_window_parse_geometry(GTK_WINDOW(mainwin
->window
), cmd
.geometry
))
1484 g_warning("failed to parse geometry '%s'", cmd
.geometry
);
1488 if (sscanf(cmd
.geometry
, "%ux%u+", &width
, &height
) == 2)
1489 gtk_window_resize(GTK_WINDOW(mainwin
->window
), width
, height
);
1491 g_warning("failed to parse geometry's width/height");
1495 if (!folder_have_mailbox()) {
1496 prefs_destroy_cache();
1497 main_window_cursor_normal(mainwin
);
1498 if (folder_get_list() != NULL
) {
1499 alertpanel_error(_("Claws Mail has detected a configured "
1500 "mailbox, but it is incomplete. It is "
1501 "possibly due to a failing IMAP account. Use "
1502 "\"Rebuild folder tree\" on the mailbox parent "
1503 "folder's context menu to try to fix it."));
1505 alertpanel_error(_("Claws Mail has detected a configured "
1506 "mailbox, but could not load it. It is "
1507 "probably provided by an out-of-date "
1508 "external plugin. Please reinstall the "
1509 "plugin and try again."));
1510 exit_claws(mainwin
);
1518 static_mainwindow
= mainwin
;
1520 #ifdef HAVE_STARTUP_NOTIFICATION
1521 startup_notification_complete(FALSE
);
1524 sc_session_manager_connect(mainwin
);
1527 folder_item_update_thaw();
1528 folderview_thaw(mainwin
->folderview
);
1529 main_window_cursor_normal(mainwin
);
1531 if (!cmd
.target
&& prefs_common
.goto_last_folder_on_startup
&&
1532 folder_find_item_from_identifier(prefs_common
.last_opened_folder
) != NULL
&&
1534 cmd
.target
= prefs_common
.last_opened_folder
;
1537 if (cmd
.receive_all
&& !cmd
.target
) {
1539 g_timeout_add(1000, defer_check_all
, GINT_TO_POINTER(FALSE
));
1540 } else if (prefs_common
.chk_on_startup
&& !cmd
.target
) {
1542 g_timeout_add(1000, defer_check_all
, GINT_TO_POINTER(TRUE
));
1543 } else if (cmd
.receive
&& !cmd
.target
) {
1545 g_timeout_add(1000, defer_check
, NULL
);
1547 folderview_grab_focus(folderview
);
1550 open_compose_new(cmd
.compose_mailto
, cmd
.attach_files
);
1552 if (cmd
.attach_files
) {
1553 list_free_strings(cmd
.attach_files
);
1554 g_list_free(cmd
.attach_files
);
1555 cmd
.attach_files
= NULL
;
1557 if (cmd
.subscribe
) {
1558 folder_subscribe(cmd
.subscribe_uri
);
1567 g_timeout_add(500, defer_jump
, (gpointer
)cmd
.target
);
1570 prefs_destroy_cache();
1572 compose_reopen_exit_drafts();
1575 sc_starting
= FALSE
;
1576 main_window_set_menu_sensitive(mainwin
);
1577 toolbar_main_set_sensitive(mainwin
);
1580 /* register the callback of unix domain socket input */
1581 lock_socket_tag
= claws_input_add(lock_socket
,
1582 G_IO_IN
| G_IO_HUP
| G_IO_ERR
| G_IO_PRI
,
1583 lock_socket_input_cb
,
1590 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1592 g_object_unref(nm_proxy
);
1594 #ifdef HAVE_DBUS_GLIB
1595 uninstall_dbus_status_handler();
1597 dbus_g_connection_unref(connection
);
1603 exit_claws(mainwin
);
1608 static void save_all_caches(FolderItem
*item
, gpointer data
)
1615 folder_item_close(item
);
1618 folder_item_free_cache(item
, TRUE
);
1621 static void exit_claws(MainWindow
*mainwin
)
1624 gboolean have_connectivity
;
1629 debug_print("shutting down\n");
1630 inc_autocheck_timer_remove();
1632 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1633 if (prefs_common
.work_offline
&& went_offline_nm
)
1634 prefs_common
.work_offline
= FALSE
;
1637 /* save prefs for opened folder */
1638 if((item
= folderview_get_opened_item(mainwin
->folderview
)) != NULL
) {
1639 summary_save_prefs_to_folderitem(
1640 mainwin
->summaryview
, item
);
1641 prefs_common
.last_opened_folder
=
1642 folder_item_get_identifier(item
);
1645 /* save all state before exiting */
1646 folder_func_to_all_folders(save_all_caches
, NULL
);
1647 folder_write_list();
1649 main_window_get_size(mainwin
);
1650 main_window_get_position(mainwin
);
1652 prefs_common_write_config();
1653 account_write_config_all();
1654 passwd_store_write_config();
1655 #ifndef USE_ALT_ADDRBOOK
1656 addressbook_export_to_file();
1658 filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, MENU_RC
, NULL
);
1659 gtk_accel_map_save(filename
);
1662 /* delete temporary files */
1663 remove_all_files(get_tmp_dir());
1664 remove_all_files(get_mime_tmp_dir());
1666 close_log_file(LOG_PROTOCOL
);
1667 close_log_file(LOG_DEBUG_FILTERING
);
1669 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1670 have_connectivity
= networkmanager_is_online(NULL
);
1672 have_connectivity
= TRUE
;
1674 #ifdef HAVE_LIBETPAN
1675 imap_main_done(have_connectivity
);
1676 nntp_main_done(have_connectivity
);
1678 /* delete crashfile */
1680 claws_unlink(get_crashfile_name());
1682 lock_socket_remove();
1685 if (mainwin
->smc_conn
)
1686 SmcCloseConnection ((SmcConn
)mainwin
->smc_conn
, 0, NULL
);
1687 mainwin
->smc_conn
= NULL
;
1690 main_window_destroy_all();
1692 plugin_unload_all("GTK2");
1695 prefs_toolbar_done();
1698 #ifndef USE_ALT_ADDRBOOK
1699 addressbook_destroy();
1701 prefs_themes_done();
1703 prefs_ext_prog_done();
1704 prefs_wrapping_done();
1705 prefs_compose_writing_done();
1706 prefs_msg_colors_done();
1707 prefs_image_viewer_done();
1708 image_viewer_done();
1710 prefs_summaries_done();
1711 prefs_message_done();
1713 prefs_receive_done();
1714 prefs_logging_done();
1718 prefs_spelling_done();
1719 gtkaspell_checkers_quit();
1721 plugin_unload_all("Common");
1725 #define G_STRING_APPEND_ENCODED_URI(gstring,source) \
1727 gchar tmpbuf[BUFFSIZE]; \
1728 encode_uri(tmpbuf, BUFFSIZE, (source)); \
1729 g_string_append((gstring), tmpbuf); \
1732 #define G_PRINT_EXIT(msg) \
1738 static GString
* parse_cmd_compose_from_file(const gchar
*fn
)
1740 GString
*headers
= g_string_new(NULL
);
1741 GString
*body
= g_string_new(NULL
);
1749 if (fn
== NULL
|| *fn
== '\0')
1750 G_PRINT_EXIT(_("Missing filename\n"));
1751 isstdin
= (*fn
== '-' && *(fn
+ 1) == '\0');
1755 fp
= g_fopen(fn
, "r");
1757 G_PRINT_EXIT(_("Cannot open filename for reading\n"));
1760 while (fgets(fb
, sizeof(fb
), fp
)) {
1766 while (*h
&& *h
!= ':') { ++h
; } /* search colon */
1768 G_PRINT_EXIT(_("Malformed header\n"));
1770 while (*v
&& *v
== ' ') { ++v
; } /* trim value start */
1772 tmp
= g_ascii_strdown(fb
, -1); /* get header name */
1773 if (!strcmp(tmp
, "to")) {
1775 G_PRINT_EXIT(_("Duplicated 'To:' header\n"));
1778 g_string_append_c(headers
, '&');
1779 g_string_append(headers
, tmp
);
1780 g_string_append_c(headers
, '=');
1781 g_string_append_uri_escaped(headers
, v
, NULL
, TRUE
);
1786 G_PRINT_EXIT(_("Missing required 'To:' header\n"));
1787 g_string_append(body
, to
);
1789 g_string_append(body
, "?body=");
1790 while (fgets(fb
, sizeof(fb
), fp
)) {
1791 g_string_append_uri_escaped(body
, fb
, NULL
, TRUE
);
1795 /* append the remaining headers */
1796 g_string_append(body
, headers
->str
);
1797 g_string_free(headers
, TRUE
);
1802 #undef G_STRING_APPEND_ENCODED_URI
1805 static void parse_cmd_opt(int argc
, char *argv
[])
1810 for (i
= 1; i
< argc
; i
++) {
1811 if (!strncmp(argv
[i
], "--receive-all", 13)) {
1812 cmd
.receive_all
= TRUE
;
1813 } else if (!strncmp(argv
[i
], "--receive", 9)) {
1815 } else if (!strncmp(argv
[i
], "--cancel-receiving", 18)) {
1816 cmd
.cancel_receiving
= TRUE
;
1817 } else if (!strncmp(argv
[i
], "--cancel-sending", 16)) {
1818 cmd
.cancel_sending
= TRUE
;
1819 } else if (!strncmp(argv
[i
], "--compose-from-file", 19)) {
1820 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1822 GString
*mailto
= parse_cmd_compose_from_file(p
);
1824 cmd
.compose_mailto
= mailto
->str
;
1826 } else if (!strncmp(argv
[i
], "--compose", 9)) {
1827 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1830 cmd
.compose_mailto
= NULL
;
1831 if (p
&& *p
!= '\0' && *p
!= '-') {
1832 if (!strncmp(p
, "mailto:", 7)) {
1833 cmd
.compose_mailto
= p
+ 7;
1835 cmd
.compose_mailto
= p
;
1839 } else if (!strncmp(argv
[i
], "--subscribe", 11)) {
1840 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1841 if (p
&& *p
!= '\0' && *p
!= '-') {
1842 cmd
.subscribe
= TRUE
;
1843 cmd
.subscribe_uri
= p
;
1845 } else if (!strncmp(argv
[i
], "--attach", 8)) {
1846 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1849 while (p
&& *p
!= '\0' && *p
!= '-') {
1850 if ((file
= g_filename_from_uri(p
, NULL
, NULL
)) != NULL
) {
1851 if (!is_file_exist(file
)) {
1856 if (file
== NULL
&& *p
!= G_DIR_SEPARATOR
) {
1857 file
= g_strconcat(claws_get_startup_dir(),
1860 } else if (file
== NULL
) {
1863 ainfo
= g_new0(AttachInfo
, 1);
1865 cmd
.attach_files
= g_list_append(cmd
.attach_files
, ainfo
);
1867 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1869 } else if (!strncmp(argv
[i
], "--send", 6)) {
1871 } else if (!strncmp(argv
[i
], "--version-full", 14) ||
1872 !strncmp(argv
[i
], "-V", 2)) {
1873 g_print("Claws Mail version " VERSION
"\n");
1874 main_dump_features_list(FALSE
);
1876 } else if (!strncmp(argv
[i
], "--version", 9) ||
1877 !strncmp(argv
[i
], "-v", 2)) {
1878 g_print("Claws Mail version " VERSION
"\n");
1880 } else if (!strncmp(argv
[i
], "--status-full", 13)) {
1881 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1883 cmd
.status_full
= TRUE
;
1884 while (p
&& *p
!= '\0' && *p
!= '-') {
1885 if (!cmd
.status_full_folders
) {
1886 cmd
.status_full_folders
=
1889 g_ptr_array_add(cmd
.status_full_folders
,
1892 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1894 } else if (!strncmp(argv
[i
], "--status", 8)) {
1895 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1898 while (p
&& *p
!= '\0' && *p
!= '-') {
1899 if (!cmd
.status_folders
)
1900 cmd
.status_folders
= g_ptr_array_new();
1901 g_ptr_array_add(cmd
.status_folders
,
1904 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1906 } else if (!strncmp(argv
[i
], "--search", 8)) {
1907 cmd
.search_folder
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1908 cmd
.search_type
= (i
+2 < argc
)?argv
[i
+2]:NULL
;
1909 cmd
.search_request
= (i
+3 < argc
)?argv
[i
+3]:NULL
;
1910 const char* rec
= (i
+4 < argc
)?argv
[i
+4]:NULL
;
1911 cmd
.search_recursive
= TRUE
;
1912 if (rec
&& (tolower(*rec
)=='n' || tolower(*rec
)=='f' || *rec
=='0'))
1913 cmd
.search_recursive
= FALSE
;
1914 if (cmd
.search_folder
&& cmd
.search_type
&& cmd
.search_request
)
1916 } else if (!strncmp(argv
[i
], "--online", 8)) {
1917 cmd
.online_mode
= ONLINE_MODE_ONLINE
;
1918 } else if (!strncmp(argv
[i
], "--offline", 9)) {
1919 cmd
.online_mode
= ONLINE_MODE_OFFLINE
;
1920 } else if (!strncmp(argv
[i
], "--toggle-debug", 14)) {
1922 } else if (!strncmp(argv
[i
], "--statistics", 12)) {
1923 cmd
.statistics
= TRUE
;
1924 } else if (!strncmp(argv
[i
], "--reset-statistics", 18)) {
1925 cmd
.reset_statistics
= TRUE
;
1926 } else if (!strncmp(argv
[i
], "--help", 6) ||
1927 !strncmp(argv
[i
], "-h", 2)) {
1928 gchar
*base
= g_path_get_basename(argv
[0]);
1929 g_print(_("Usage: %s [OPTION]...\n"), base
);
1931 g_print("%s\n", _(" --compose [address] open composition window"));
1932 g_print("%s\n", _(" --compose-from-file file\n"
1933 " open composition window with data from given file;\n"
1934 " use - as file name for reading from standard input;\n"
1935 " content format: headers first (To: required) until an\n"
1936 " empty line, then mail body until end of file."));
1937 g_print("%s\n", _(" --subscribe [uri] subscribe to the given URI if possible"));
1938 g_print("%s\n", _(" --attach file1 [file2]...\n"
1939 " open composition window with specified files\n"
1941 g_print("%s\n", _(" --receive receive new messages"));
1942 g_print("%s\n", _(" --receive-all receive new messages of all accounts"));
1943 g_print("%s\n", _(" --cancel-receiving cancel receiving of messages"));
1944 g_print("%s\n", _(" --cancel-sending cancel sending of messages"));
1945 g_print("%s\n", _(" --search folder type request [recursive]\n"
1947 " folder ex.: \"#mh/Mailbox/inbox\" or \"Mail\"\n"
1948 " type: s[ubject],f[rom],t[o],e[xtended],m[ixed] or g: tag\n"
1949 " request: search string\n"
1950 " recursive: false if arg. starts with 0, n, N, f or F"));
1952 g_print("%s\n", _(" --send send all queued messages"));
1953 g_print("%s\n", _(" --status [folder]... show the total number of messages"));
1954 g_print("%s\n", _(" --status-full [folder]...\n"
1955 " show the status of each folder"));
1956 g_print("%s\n", _(" --statistics show session statistics"));
1957 g_print("%s\n", _(" --reset-statistics reset session statistics"));
1958 g_print("%s\n", _(" --select folder[/msg] jumps to the specified folder/message\n"
1959 " folder is a folder id like 'folder/sub_folder'"));
1960 g_print("%s\n", _(" --online switch to online mode"));
1961 g_print("%s\n", _(" --offline switch to offline mode"));
1962 g_print("%s\n", _(" --exit --quit -q exit Claws Mail"));
1963 g_print("%s\n", _(" --debug debug mode"));
1964 g_print("%s\n", _(" --toggle-debug toggle debug mode"));
1965 g_print("%s\n", _(" --help -h display this help and exit"));
1966 g_print("%s\n", _(" --version -v output version information and exit"));
1967 g_print("%s\n", _(" --version-full -V output version and built-in features information and exit"));
1968 g_print("%s\n", _(" --config-dir output configuration directory"));
1969 g_print("%s\n", _(" --alternate-config-dir [dir]\n"
1970 " use specified configuration directory"));
1971 g_print("%s\n", _(" --geometry -geometry WxH+X+Y\n"
1972 " set geometry for main window"));
1976 } else if (!strncmp(argv
[i
], "--crash", 7)) {
1978 cmd
.crash_params
= g_strdup((i
+1 < argc
)?argv
[i
+1]:NULL
);
1980 } else if (!strncmp(argv
[i
], "--config-dir", sizeof "--config-dir" - 1)) {
1981 g_print(RC_DIR
"\n");
1983 } else if (!strncmp(argv
[i
], "--alternate-config-dir", sizeof "--alternate-config-dir" - 1) && i
+1 < argc
) {
1984 set_rc_dir(argv
[i
+1]);
1985 } else if (!strncmp(argv
[i
], "--geometry", sizeof "--geometry" - 1)
1986 || !strncmp(argv
[i
], "-geometry", sizeof "-geometry" - 1)) {
1987 cmd
.geometry
= (i
+1 < argc
)? argv
[i
+1]: NULL
;
1988 } else if (!strncmp(argv
[i
], "--exit", 6) ||
1989 !strncmp(argv
[i
], "--quit", 6) ||
1990 !strncmp(argv
[i
], "-q", 2)) {
1992 } else if (!strncmp(argv
[i
], "--select", 8) && i
+1 < argc
) {
1993 cmd
.target
= argv
[i
+1];
1994 } else if (i
== 1 && argc
== 2) {
1995 /* only one parameter. Do something intelligent about it */
1996 if ((strstr(argv
[i
], "@")||!strncmp(argv
[i
], "mailto:", 7)) && !strstr(argv
[i
], "://")) {
1997 const gchar
*p
= argv
[i
];
2000 cmd
.compose_mailto
= NULL
;
2001 if (p
&& *p
!= '\0' && *p
!= '-') {
2002 if (!strncmp(p
, "mailto:", 7)) {
2003 cmd
.compose_mailto
= p
+ 7;
2005 cmd
.compose_mailto
= p
;
2008 } else if (!strncmp(argv
[i
], "file://", 7)) {
2009 cmd
.target
= argv
[i
];
2010 } else if (!strncmp(argv
[i
], "?attach=file://", strlen("?attach=file://"))) {
2012 cmd
.compose_mailto
= argv
[i
];
2013 } else if (strstr(argv
[i
], "://")) {
2014 const gchar
*p
= argv
[i
];
2015 if (p
&& *p
!= '\0' && *p
!= '-') {
2016 cmd
.subscribe
= TRUE
;
2017 cmd
.subscribe_uri
= p
;
2019 } else if (!strcmp(argv
[i
], "--sync")) {
2021 } else if (is_dir_exist(argv
[i
]) || is_file_exist(argv
[i
])) {
2022 cmd
.target
= argv
[i
];
2024 g_print(_("Unknown option\n"));
2030 if (cmd
.attach_files
&& cmd
.compose
== FALSE
) {
2032 cmd
.compose_mailto
= NULL
;
2036 static void initial_processing(FolderItem
*item
, gpointer data
)
2038 MainWindow
*mainwin
= (MainWindow
*)data
;
2041 cm_return_if_fail(item
);
2042 buf
= g_strdup_printf(_("Processing (%s)..."),
2045 : _("top level folder"));
2049 if (item
->prefs
->enable_processing
) {
2050 item
->processing_pending
= TRUE
;
2051 folder_item_apply_processing(item
);
2052 item
->processing_pending
= FALSE
;
2055 STATUSBAR_POP(mainwin
);
2058 static gboolean
draft_all_messages(void)
2060 const GList
*compose_list
= NULL
;
2062 compose_clear_exit_drafts();
2063 compose_list
= compose_get_compose_list();
2064 while (compose_list
!= NULL
) {
2065 Compose
*c
= (Compose
*)compose_list
->data
;
2066 if (!compose_draft(c
, COMPOSE_DRAFT_FOR_EXIT
))
2068 compose_list
= compose_get_compose_list();
2072 gboolean
clean_quit(gpointer data
)
2074 static gboolean firstrun
= TRUE
;
2081 /*!< Good idea to have the main window stored in a
2082 * static variable so we can check that variable
2083 * to see if we're really allowed to do things
2084 * that actually the spawner is supposed to
2085 * do (like: sending mail, composing messages).
2086 * Because, really, if we're the spawnee, and
2087 * we touch GTK stuff, we're hosed. See the
2090 /* FIXME: Use something else to signal that we're
2091 * in the original spawner, and not in a spawned
2093 if (!static_mainwindow
) {
2097 draft_all_messages();
2098 emergency_exit
= TRUE
;
2099 exit_claws(static_mainwindow
);
2105 void app_will_exit(GtkWidget
*widget
, gpointer data
)
2107 MainWindow
*mainwin
= data
;
2109 if (gtk_main_level() == 0) {
2110 debug_print("not even started\n");
2113 if (sc_exiting
== TRUE
) {
2114 debug_print("exit pending\n");
2118 debug_print("exiting\n");
2119 if (compose_get_compose_list()) {
2120 if (!draft_all_messages()) {
2121 main_window_popup(mainwin
);
2127 if (prefs_common
.warn_queued_on_exit
&& procmsg_have_queued_mails_fast()) {
2128 if (alertpanel(_("Queued messages"),
2129 _("Some unsent messages are queued. Exit now?"),
2130 GTK_STOCK_CANCEL
, GTK_STOCK_OK
, NULL
)
2131 != G_ALERTALTERNATE
) {
2132 main_window_popup(mainwin
);
2136 manage_window_focus_in(mainwin
->window
, NULL
, NULL
);
2140 #ifdef HAVE_VALGRIND
2141 if (RUNNING_ON_VALGRIND
) {
2142 summary_clear_list(mainwin
->summaryview
);
2145 if (folderview_get_selected_item(mainwin
->folderview
))
2146 folder_item_close(folderview_get_selected_item(mainwin
->folderview
));
2150 gboolean
claws_is_exiting(void)
2155 gboolean
claws_is_starting(void)
2162 * CLAWS: want this public so crash dialog can delete the
2165 gchar
*claws_get_socket_name(void)
2167 static gchar
*filename
= NULL
;
2168 gchar
*socket_dir
= NULL
;
2171 if (filename
== NULL
) {
2175 socket_dir
= g_strdup_printf("%s%cclaws-mail-%d",
2176 g_get_tmp_dir(), G_DIR_SEPARATOR
,
2182 stat_ok
= g_stat(socket_dir
, &st
);
2183 if (stat_ok
< 0 && errno
!= ENOENT
) {
2184 g_print("Error stat'ing socket_dir %s: %s\n",
2185 socket_dir
, g_strerror(errno
));
2186 } else if (stat_ok
== 0 && S_ISSOCK(st
.st_mode
)) {
2187 /* old versions used a sock in $TMPDIR/claws-mail-$UID */
2188 debug_print("Using legacy socket %s\n", socket_dir
);
2189 filename
= g_strdup(socket_dir
);
2193 if (!is_dir_exist(socket_dir
) && make_dir(socket_dir
) < 0) {
2194 g_print("Error creating socket_dir %s: %s\n",
2195 socket_dir
, g_strerror(errno
));
2198 md5_hex_digest(md5sum
, get_rc_dir());
2200 filename
= g_strdup_printf("%s%c%s", socket_dir
, G_DIR_SEPARATOR
,
2203 debug_print("Using control socket %s\n", filename
);
2210 static gchar
*get_crashfile_name(void)
2212 static gchar
*filename
= NULL
;
2214 if (filename
== NULL
) {
2215 filename
= g_strdup_printf("%s%cclaws-crashed",
2216 get_tmp_dir(), G_DIR_SEPARATOR
);
2222 static gint
prohibit_duplicate_launch(void)
2229 path
= claws_get_socket_name();
2230 /* Try to connect to the control socket */
2231 uxsock
= fd_connect_unix(path
);
2233 if (x_display
== NULL
)
2234 x_display
= g_strdup(g_getenv("DISPLAY"));
2241 /* If connect failed, no other process is running.
2242 * Unlink the potentially existing socket, then
2243 * open it. This has to be done locking a temporary
2244 * file to avoid the race condition where another
2245 * process could have created the socket just in
2248 socket_lock
= g_strconcat(path
, ".lock",
2250 lock_fd
= g_open(socket_lock
, O_RDWR
|O_CREAT
, 0);
2252 debug_print("Couldn't open %s: %s (%d)\n", socket_lock
,
2253 g_strerror(errno
), errno
);
2254 g_free(socket_lock
);
2257 if (flock(lock_fd
, LOCK_EX
) < 0) {
2258 debug_print("Couldn't lock %s: %s (%d)\n", socket_lock
,
2259 g_strerror(errno
), errno
);
2261 g_free(socket_lock
);
2267 debug_print("Opening socket %s\n", path
);
2268 ret
= fd_open_unix(path
);
2270 flock(lock_fd
, LOCK_UN
);
2272 claws_unlink(socket_lock
);
2273 g_free(socket_lock
);
2280 hmutex
= CreateMutexA(NULL
, FALSE
, "ClawsMail");
2282 debug_print("cannot create Mutex\n");
2285 if (GetLastError() != ERROR_ALREADY_EXISTS
) {
2286 uxsock
= fd_open_inet(50216);
2292 uxsock
= fd_connect_inet(50216);
2296 /* remote command mode */
2298 debug_print("another Claws Mail instance is already running.\n");
2300 if (cmd
.receive_all
) {
2301 fd_write_all(uxsock
, "receive_all\n", 12);
2302 } else if (cmd
.receive
) {
2303 fd_write_all(uxsock
, "receive\n", 8);
2304 } else if (cmd
.cancel_receiving
) {
2305 fd_write_all(uxsock
, "cancel_receiving\n", 17);
2306 } else if (cmd
.cancel_sending
) {
2307 fd_write_all(uxsock
, "cancel_sending\n", 15);
2308 } else if (cmd
.compose
&& cmd
.attach_files
) {
2309 gchar
*str
, *compose_str
;
2311 if (cmd
.compose_mailto
) {
2312 compose_str
= g_strdup_printf("compose_attach %s\n",
2313 cmd
.compose_mailto
);
2315 compose_str
= g_strdup("compose_attach\n");
2318 fd_write_all(uxsock
, compose_str
, strlen(compose_str
));
2319 g_free(compose_str
);
2321 for (curr
= cmd
.attach_files
; curr
!= NULL
; curr
= curr
->next
) {
2322 str
= (gchar
*) ((AttachInfo
*)curr
->data
)->file
;
2323 fd_write_all(uxsock
, str
, strlen(str
));
2324 fd_write_all(uxsock
, "\n", 1);
2327 fd_write_all(uxsock
, ".\n", 2);
2328 } else if (cmd
.compose
) {
2331 if (cmd
.compose_mailto
) {
2332 compose_str
= g_strdup_printf
2333 ("compose %s\n", cmd
.compose_mailto
);
2335 compose_str
= g_strdup("compose\n");
2338 fd_write_all(uxsock
, compose_str
, strlen(compose_str
));
2339 g_free(compose_str
);
2340 } else if (cmd
.subscribe
) {
2341 gchar
*str
= g_strdup_printf("subscribe %s\n", cmd
.subscribe_uri
);
2342 fd_write_all(uxsock
, str
, strlen(str
));
2344 } else if (cmd
.send
) {
2345 fd_write_all(uxsock
, "send\n", 5);
2346 } else if (cmd
.online_mode
== ONLINE_MODE_ONLINE
) {
2347 fd_write(uxsock
, "online\n", 6);
2348 } else if (cmd
.online_mode
== ONLINE_MODE_OFFLINE
) {
2349 fd_write(uxsock
, "offline\n", 7);
2350 } else if (cmd
.debug
) {
2351 fd_write(uxsock
, "debug\n", 7);
2352 } else if (cmd
.status
|| cmd
.status_full
) {
2353 gchar buf
[BUFFSIZE
];
2355 const gchar
*command
;
2359 command
= cmd
.status_full
? "status-full\n" : "status\n";
2360 folders
= cmd
.status_full
? cmd
.status_full_folders
:
2363 fd_write_all(uxsock
, command
, strlen(command
));
2364 for (i
= 0; folders
&& i
< folders
->len
; ++i
) {
2365 folder
= g_ptr_array_index(folders
, i
);
2366 fd_write_all(uxsock
, folder
, strlen(folder
));
2367 fd_write_all(uxsock
, "\n", 1);
2369 fd_write_all(uxsock
, ".\n", 2);
2371 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2372 buf
[sizeof(buf
) - 1] = '\0';
2373 if (!strncmp(buf
, ".\n", 2)) break;
2376 } else if (cmd
.exit
) {
2377 fd_write_all(uxsock
, "exit\n", 5);
2378 } else if (cmd
.statistics
) {
2380 fd_write(uxsock
, "statistics\n", 11);
2382 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2383 buf
[sizeof(buf
) - 1] = '\0';
2384 if (!strncmp(buf
, ".\n", 2)) break;
2387 } else if (cmd
.reset_statistics
) {
2388 fd_write(uxsock
, "reset_statistics\n", 17);
2389 } else if (cmd
.target
) {
2390 gchar
*str
= g_strdup_printf("select %s\n", cmd
.target
);
2391 fd_write_all(uxsock
, str
, strlen(str
));
2393 } else if (cmd
.search
) {
2394 gchar buf
[BUFFSIZE
];
2396 g_strdup_printf("search %s\n%s\n%s\n%c\n",
2397 cmd
.search_folder
, cmd
.search_type
, cmd
.search_request
,
2398 (cmd
.search_recursive
==TRUE
)?'1':'0');
2399 fd_write_all(uxsock
, str
, strlen(str
));
2402 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2403 buf
[sizeof(buf
) - 1] = '\0';
2404 if (!strncmp(buf
, ".\n", 2)) break;
2410 fd_write_all(uxsock
, "get_display\n", 12);
2411 memset(buf
, 0, sizeof(buf
));
2412 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2413 buf
[sizeof(buf
) - 1] = '\0';
2414 if (strcmp2(buf
, x_display
)) {
2415 g_print("Claws Mail is already running on display %s.\n",
2419 uxsock
= fd_connect_unix(path
);
2420 fd_write_all(uxsock
, "popup\n", 6);
2423 fd_write_all(uxsock
, "popup\n", 6);
2431 static gint
lock_socket_remove(void)
2434 gchar
*filename
, *dirname
;
2436 if (lock_socket
< 0) {
2440 if (lock_socket_tag
> 0) {
2441 g_source_remove(lock_socket_tag
);
2443 fd_close(lock_socket
);
2446 filename
= claws_get_socket_name();
2447 dirname
= g_path_get_dirname(filename
);
2448 claws_unlink(filename
);
2456 static GPtrArray
*get_folder_item_list(gint sock
)
2458 gchar buf
[BUFFSIZE
];
2460 GPtrArray
*folders
= NULL
;
2463 fd_gets(sock
, buf
, sizeof(buf
) - 1);
2464 buf
[sizeof(buf
) - 1] = '\0';
2465 if (!strncmp(buf
, ".\n", 2)) {
2470 folders
= g_ptr_array_new();
2472 item
= folder_find_item_from_identifier(buf
);
2474 g_ptr_array_add(folders
, item
);
2476 g_warning("no such folder: %s", buf
);
2483 static void lock_socket_input_cb(gpointer data
,
2485 GIOCondition condition
)
2487 MainWindow
*mainwin
= (MainWindow
*)data
;
2489 gchar buf
[BUFFSIZE
];
2491 sock
= fd_accept(source
);
2495 fd_gets(sock
, buf
, sizeof(buf
) - 1);
2496 buf
[sizeof(buf
) - 1] = '\0';
2498 if (!strncmp(buf
, "popup", 5)) {
2499 main_window_popup(mainwin
);
2500 } else if (!strncmp(buf
, "get_display", 11)) {
2501 fd_write_all(sock
, x_display
, strlen(x_display
));
2502 } else if (!strncmp(buf
, "receive_all", 11)) {
2503 inc_all_account_mail(mainwin
, FALSE
,
2504 prefs_common
.newmail_notify_manu
);
2505 } else if (!strncmp(buf
, "receive", 7)) {
2506 inc_mail(mainwin
, prefs_common
.newmail_notify_manu
);
2507 } else if (!strncmp(buf
, "cancel_receiving", 16)) {
2510 } else if (!strncmp(buf
, "cancel_sending", 14)) {
2512 } else if (!strncmp(buf
, "compose_attach", 14)) {
2513 GList
*files
= NULL
, *curr
;
2517 mailto
= g_strdup(buf
+ strlen("compose_attach") + 1);
2518 while (fd_gets(sock
, buf
, sizeof(buf
) - 1) > 0) {
2519 buf
[sizeof(buf
) - 1] = '\0';
2521 if (!strcmp2(buf
, "."))
2524 ainfo
= g_new0(AttachInfo
, 1);
2525 ainfo
->file
= g_strdup(buf
);
2526 files
= g_list_append(files
, ainfo
);
2528 open_compose_new(mailto
, files
);
2530 curr
= g_list_first(files
);
2531 while (curr
!= NULL
) {
2532 ainfo
= (AttachInfo
*)curr
->data
;
2533 g_free(ainfo
->file
);
2539 } else if (!strncmp(buf
, "compose", 7)) {
2540 open_compose_new(buf
+ strlen("compose") + 1, NULL
);
2541 } else if (!strncmp(buf
, "subscribe", 9)) {
2542 main_window_popup(mainwin
);
2543 folder_subscribe(buf
+ strlen("subscribe") + 1);
2544 } else if (!strncmp(buf
, "send", 4)) {
2546 } else if (!strncmp(buf
, "online", 6)) {
2547 main_window_toggle_work_offline(mainwin
, FALSE
, FALSE
);
2548 } else if (!strncmp(buf
, "offline", 7)) {
2549 main_window_toggle_work_offline(mainwin
, TRUE
, FALSE
);
2550 } else if (!strncmp(buf
, "debug", 5)) {
2551 debug_set_mode(debug_get_mode() ? FALSE
: TRUE
);
2552 } else if (!strncmp(buf
, "status-full", 11) ||
2553 !strncmp(buf
, "status", 6)) {
2557 folders
= get_folder_item_list(sock
);
2558 status
= folder_get_status
2559 (folders
, !strncmp(buf
, "status-full", 11));
2560 fd_write_all(sock
, status
, strlen(status
));
2561 fd_write_all(sock
, ".\n", 2);
2563 if (folders
) g_ptr_array_free(folders
, TRUE
);
2564 } else if (!strncmp(buf
, "statistics", 10)) {
2567 g_snprintf(tmp
, sizeof(tmp
), _("Session statistics\n"));
2568 fd_write_all(sock
, tmp
, strlen(tmp
));
2570 if (prefs_common
.date_format
) {
2575 lt
= localtime(&session_stats
.time_started
);
2576 fast_strftime(date
, len
, prefs_common
.date_format
, lt
);
2577 g_snprintf(tmp
, sizeof(tmp
), _("Started: %s\n"),
2578 lt
? date
: ctime(&session_stats
.time_started
));
2580 g_snprintf(tmp
, sizeof(tmp
), _("Started: %s\n"),
2581 ctime(&session_stats
.time_started
));
2582 fd_write_all(sock
, tmp
, strlen(tmp
));
2584 fd_write_all(sock
, "\n", 1);
2586 g_snprintf(tmp
, sizeof(tmp
), _("Incoming traffic\n"));
2587 fd_write_all(sock
, tmp
, strlen(tmp
));
2589 g_snprintf(tmp
, sizeof(tmp
), _("Received messages: %d\n"),
2590 session_stats
.received
);
2591 fd_write_all(sock
, tmp
, strlen(tmp
));
2593 fd_write_all(sock
, "\n", 1);
2595 g_snprintf(tmp
, sizeof(tmp
), _("Outgoing traffic\n"));
2596 fd_write_all(sock
, tmp
, strlen(tmp
));
2598 g_snprintf(tmp
, sizeof(tmp
), _("New/redirected messages: %d\n"),
2599 session_stats
.sent
);
2600 fd_write_all(sock
, tmp
, strlen(tmp
));
2602 g_snprintf(tmp
, sizeof(tmp
), _("Replied messages: %d\n"),
2603 session_stats
.replied
);
2604 fd_write_all(sock
, tmp
, strlen(tmp
));
2606 g_snprintf(tmp
, sizeof(tmp
), _("Forwarded messages: %d\n"),
2607 session_stats
.forwarded
);
2608 fd_write_all(sock
, tmp
, strlen(tmp
));
2610 g_snprintf(tmp
, sizeof(tmp
), _("Total outgoing messages: %d\n"),
2611 (session_stats
.sent
+ session_stats
.replied
+
2612 session_stats
.forwarded
));
2613 fd_write_all(sock
, tmp
, strlen(tmp
));
2615 fd_write_all(sock
, ".\n", 2);
2616 } else if (!strncmp(buf
, "reset_statistics", 16)) {
2618 } else if (!strncmp(buf
, "select ", 7)) {
2619 const gchar
*target
= buf
+7;
2620 mainwindow_jump_to(target
, TRUE
);
2621 } else if (!strncmp(buf
, "search ", 7)) {
2622 FolderItem
* folderItem
= NULL
;
2623 GSList
*messages
= NULL
;
2624 gchar
*folder_name
= NULL
;
2625 gchar
*request
= NULL
;
2626 AdvancedSearch
*search
;
2628 AdvancedSearchType searchType
= ADVANCED_SEARCH_EXTENDED
;
2630 search
= advsearch_new();
2632 folder_name
= g_strdup(buf
+7);
2633 strretchomp(folder_name
);
2635 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) <= 0)
2637 buf
[sizeof(buf
) - 1] = '\0';
2639 switch (toupper(buf
[0])) {
2640 case 'S': searchType
= ADVANCED_SEARCH_SUBJECT
; break;
2641 case 'F': searchType
= ADVANCED_SEARCH_FROM
; break;
2642 case 'T': searchType
= ADVANCED_SEARCH_TO
; break;
2643 case 'M': searchType
= ADVANCED_SEARCH_MIXED
; break;
2644 case 'G': searchType
= ADVANCED_SEARCH_TAG
; break;
2645 case 'E': searchType
= ADVANCED_SEARCH_EXTENDED
; break;
2648 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) <= 0)
2651 buf
[sizeof(buf
) - 1] = '\0';
2652 request
= g_strdup(buf
);
2653 strretchomp(request
);
2656 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) > 0)
2657 recursive
= buf
[0] != '0';
2659 buf
[sizeof(buf
) - 1] = '\0';
2661 debug_print("search: %s %i %s %i\n", folder_name
, searchType
, request
, recursive
);
2663 folderItem
= folder_find_item_from_identifier(folder_name
);
2665 if (folderItem
== NULL
) {
2666 debug_print("Unknown folder item : '%s', searching folder\n",folder_name
);
2667 Folder
* folder
= folder_find_from_path(folder_name
);
2669 folderItem
= FOLDER_ITEM(folder
->node
->data
);
2671 debug_print("Unknown folder: '%s'\n",folder_name
);
2673 debug_print("%s %s\n",folderItem
->name
, folderItem
->path
);
2676 if (folderItem
!= NULL
) {
2677 advsearch_set(search
, searchType
, request
);
2678 advsearch_search_msgs_in_folders(search
, &messages
, folderItem
, recursive
);
2680 g_print("Folder '%s' not found.\n'", folder_name
);
2684 for (cur
= messages
; cur
!= NULL
; cur
= cur
->next
) {
2685 MsgInfo
* msg
= (MsgInfo
*)cur
->data
;
2686 gchar
*file
= procmsg_get_message_file_path(msg
);
2687 fd_write_all(sock
, file
, strlen(file
));
2688 fd_write_all(sock
, "\n", 1);
2691 fd_write_all(sock
, ".\n", 2);
2694 g_free(folder_name
);
2696 advsearch_free(search
);
2697 if (messages
!= NULL
)
2698 procmsg_msg_list_free(messages
);
2699 } else if (!strncmp(buf
, "exit", 4)) {
2700 if (prefs_common
.clean_on_exit
&& !prefs_common
.ask_on_clean
) {
2701 procmsg_empty_all_trash();
2703 app_will_exit(NULL
, mainwin
);
2709 static void open_compose_new(const gchar
*address
, GList
*attach_files
)
2714 Xstrdup_a(addr
, address
, return);
2718 compose_new(NULL
, addr
, attach_files
);
2721 static void send_queue(void)
2724 gchar
*errstr
= NULL
;
2725 gboolean error
= FALSE
;
2726 for (list
= folder_get_list(); list
!= NULL
; list
= list
->next
) {
2727 Folder
*folder
= list
->data
;
2729 if (folder
->queue
) {
2730 gint res
= procmsg_send_queue
2731 (folder
->queue
, prefs_common
.savemsg
,
2735 folder_item_scan(folder
->queue
);
2743 alertpanel_error_log(_("Some errors occurred "
2744 "while sending queued messages:\n%s"), errstr
);
2747 alertpanel_error_log("Some errors occurred "
2748 "while sending queued messages.");
2752 static void quit_signal_handler(int sig
)
2754 debug_print("Quitting on signal %d\n", sig
);
2756 g_timeout_add(0, clean_quit
, NULL
);
2759 static void install_basic_sighandlers()
2763 struct sigaction act
;
2768 sigaddset(&mask
, SIGTERM
);
2771 sigaddset(&mask
, SIGINT
);
2774 sigaddset(&mask
, SIGHUP
);
2777 act
.sa_handler
= quit_signal_handler
;
2782 sigaction(SIGTERM
, &act
, 0);
2785 sigaction(SIGINT
, &act
, 0);
2788 sigaction(SIGHUP
, &act
, 0);
2791 sigprocmask(SIG_UNBLOCK
, &mask
, 0);
2792 #endif /* !G_OS_WIN32 */
2795 #if (defined linux && defined SIGIO)
2796 static int mem_notify_fd
= 0;
2798 static gboolean
clean_caches(gpointer unused
)
2800 if (static_mainwindow
&& static_mainwindow
->lock_count
> 0)
2802 debug_print("/dev/mem_notify: callback: Freeing some memory now!\n");
2803 folder_clean_cache_memory_force();
2807 static void memory_signal_handler(int sig
)
2809 debug_print("/dev/mem_notify: Kernel says we should free up some memory!\n");
2810 g_timeout_add(10, clean_caches
, NULL
);
2813 static void install_memory_sighandler()
2816 struct sigaction act
;
2819 mem_notify_fd
= g_open("/dev/mem_notify", O_RDONLY
|O_NONBLOCK
, 0);
2820 if (mem_notify_fd
== -1) {
2821 debug_print("/dev/mem_notify not available (%s)\n",
2826 fcntl(mem_notify_fd
, F_SETOWN
, getpid());
2827 flags
= fcntl(mem_notify_fd
, F_GETFL
);
2828 fcntl(mem_notify_fd
, flags
|FASYNC
);
2832 sigaddset(&mask
, SIGIO
);
2834 act
.sa_handler
= memory_signal_handler
;
2838 sigaction(SIGIO
, &act
, 0);
2840 sigprocmask(SIG_UNBLOCK
, &mask
, 0);
2842 debug_print("/dev/mem_notify: installed handler\n");
2844 #endif /* linux && SIGIO */
2846 #ifdef HAVE_NETWORKMANAGER_SUPPORT
2847 static void networkmanager_state_change_cb(DBusGProxy
*proxy
, gchar
*dev
,
2850 MainWindow
*mainWin
;
2853 if (static_mainwindow
)
2854 mainWin
= static_mainwindow
;
2856 mainWin
= (MainWindow
*)data
;
2858 if (!prefs_common
.use_networkmanager
)
2862 GError
*error
= NULL
;
2865 online
= networkmanager_is_online(&error
);
2867 if(online
&& went_offline_nm
) {
2868 went_offline_nm
= FALSE
;
2869 main_window_toggle_work_offline(mainWin
, FALSE
, FALSE
);
2870 debug_print("NetworkManager: Went online\n");
2871 log_message(LOG_PROTOCOL
, _("NetworkManager: network is online.\n"));
2874 went_offline_nm
= TRUE
;
2875 main_window_toggle_work_offline(mainWin
, TRUE
, FALSE
);
2876 debug_print("NetworkManager: Went offline\n");
2877 log_message(LOG_PROTOCOL
, _("NetworkManager: network is offline.\n"));
2881 debug_print("Failed to get online information from NetworkManager: %s\n",
2883 g_error_free(error
);
2887 debug_print("NetworkManager: Cannot change connection state because "
2888 "main window does not exist\n");
2891 /* Returns true (and sets error appropriately, if given) in case of error */
2892 gboolean
networkmanager_is_online(GError
**error
)
2894 DBusGConnection
*connection
;
2896 GError
*tmp_error
= NULL
;
2900 if (!prefs_common
.use_networkmanager
)
2905 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &tmp_error
);
2908 /* If calling code doesn't do error checking, at least print some debug */
2909 if((error
== NULL
) || (*error
== NULL
))
2910 debug_print("Failed to open connection to system bus: %s\n",
2911 tmp_error
->message
);
2912 g_propagate_error(error
, tmp_error
);
2916 proxy
= dbus_g_proxy_new_for_name(connection
,
2917 "org.freedesktop.NetworkManager",
2918 "/org/freedesktop/NetworkManager",
2919 "org.freedesktop.NetworkManager");
2921 retVal
= dbus_g_proxy_call(proxy
,"state",&tmp_error
, G_TYPE_INVALID
,
2922 G_TYPE_UINT
, &state
, G_TYPE_INVALID
);
2925 g_object_unref(proxy
);
2927 dbus_g_connection_unref(connection
);
2930 /* If calling code doesn't do error checking, at least print some debug */
2931 if((error
== NULL
) || (*error
== NULL
))
2932 debug_print("Failed to get state info from NetworkManager: %s\n",
2933 tmp_error
->message
);
2934 g_propagate_error(error
, tmp_error
);
2937 #if NM_CHECK_VERSION(0,8,992)
2938 return (state
== NM_STATE_CONNECTED_LOCAL
||
2939 state
== NM_STATE_CONNECTED_SITE
||
2940 state
== NM_STATE_CONNECTED_GLOBAL
||
2941 state
== NM_STATE_UNKNOWN
);
2943 return (state
== NM_STATE_CONNECTED
||
2944 state
== NM_STATE_UNKNOWN
);